hydrus/include/ClientGUIPages.py

480 lines
19 KiB
Python
Executable File

import HydrusConstants as HC
import ClientConstants as CC
import ClientGUICommon
import ClientGUIDialogs
import ClientGUIManagement
import ClientGUIMedia
import ClientGUIMessages
import ClientGUICanvas
import inspect
import os
import sys
import time
import traceback
import wx
# Sizer Flags
FLAGS_NONE = wx.SizerFlags( 0 )
FLAGS_SMALL_INDENT = wx.SizerFlags( 0 ).Border( wx.ALL, 2 )
FLAGS_EXPAND_PERPENDICULAR = wx.SizerFlags( 0 ).Border( wx.ALL, 2 ).Expand()
FLAGS_EXPAND_BOTH_WAYS = wx.SizerFlags( 2 ).Border( wx.ALL, 2 ).Expand()
FLAGS_EXPAND_DEPTH_ONLY = wx.SizerFlags( 2 ).Border( wx.ALL, 2 ).Align( wx.ALIGN_CENTER_VERTICAL )
FLAGS_EXPAND_SIZER_PERPENDICULAR = wx.SizerFlags( 0 ).Expand()
FLAGS_EXPAND_SIZER_BOTH_WAYS = wx.SizerFlags( 2 ).Expand()
FLAGS_EXPAND_SIZER_DEPTH_ONLY = wx.SizerFlags( 2 ).Align( wx.ALIGN_CENTER_VERTICAL )
FLAGS_BUTTON_SIZERS = wx.SizerFlags( 0 ).Align( wx.ALIGN_RIGHT )
FLAGS_LONE_BUTTON = wx.SizerFlags( 0 ).Border( wx.ALL, 2 ).Align( wx.ALIGN_RIGHT )
FLAGS_MIXED = wx.SizerFlags( 0 ).Border( wx.ALL, 2 ).Align( wx.ALIGN_CENTER_VERTICAL )
class PageBase():
def __init__( self, starting_from_session = False ):
self._starting_from_session = starting_from_session
self._page_key = os.urandom( 32 )
self._pretty_status = ''
HC.pubsub.sub( self, 'SetPrettyStatus', 'new_page_status' )
def GetPrettyStatus( self ): return self._pretty_status
def GetSashPositions( self ):
x = HC.options[ 'hpos' ]
y = HC.options[ 'vpos' ]
return ( x, y )
def PageHidden( self ): HC.pubsub.pub( 'page_hidden', self._page_key )
def PageShown( self ): HC.pubsub.pub( 'page_shown', self._page_key )
def Pause( self ):
HC.pubsub.pub( 'pause', self._page_key )
HC.pubsub.pub( 'set_focus', self._page_key, None )
def SetPrettyStatus( self, page_key, status ):
if page_key == self._page_key:
self._pretty_status = status
HC.pubsub.pub( 'refresh_status' )
def RefreshQuery( self ): HC.pubsub.pub( 'refresh_query', self._page_key )
def SetMediaFocus( self ): pass
def SetSearchFocus( self ): HC.pubsub.pub( 'set_search_focus', self._page_key )
def SetSynchronisedWait( self ): HC.pubsub.pub( 'synchronised_wait_switch', self._page_key )
def ShowHideSplit( self ): pass
def TryToClose( self ): pass
def Resume( self ): HC.pubsub.pub( 'resume', self._page_key )
class PageLog( PageBase, wx.Panel ):
def __init__( self, parent, starting_from_session = False ):
wx.Panel.__init__( self, parent )
PageBase.__init__( self, starting_from_session = starting_from_session )
log = HC.app.GetLog()
self._log_list_ctrl = ClientGUICommon.SaneListCtrl( self, 480, [ ( 'type', 60 ), ( 'message', -1 ), ( 'time', 120 ) ] )
for ( message, timestamp ) in log: self.AddMessage( message, timestamp )
vbox = wx.BoxSizer( wx.VERTICAL )
vbox.AddF( self._log_list_ctrl, FLAGS_EXPAND_BOTH_WAYS )
self.SetSizer( vbox )
HC.pubsub.sub( self, 'AddMessage', 'message' )
def _AddEntry( self, message_type_string, message_string, timestamp ): self._log_list_ctrl.Append( ( message_type_string, message_string, HC.ConvertTimestampToPrettyTime( timestamp ) ), ( message_type_string, message_string, timestamp ) )
def AddMessage( self, message, timestamp = None ):
if timestamp is None: timestamp = HC.GetNow()
message_type = message.GetType()
info = message.GetInfo()
if message_type == HC.MESSAGE_TYPE_TEXT:
message_type_string = 'message'
message_string = info
elif message_type == HC.MESSAGE_TYPE_ERROR:
message_type_string = 'error'
exception = info
message_string = HC.u( exception )
elif message_type == HC.MESSAGE_TYPE_FILES:
message_type_string = 'files'
( message_string, hashes ) = info
else: return # gauge
self._AddEntry( message_type_string, message_string, timestamp )
def GetSessionArgs( self ):
args = tuple()
kwargs = dict()
return ( args, kwargs )
class PageMessages( PageBase, wx.SplitterWindow ):
def __init__( self, parent, identity, starting_from_session = False ):
wx.SplitterWindow.__init__( self, parent )
PageBase.__init__( self, starting_from_session = starting_from_session )
self.SetMinimumPaneSize( 120 )
self.SetSashGravity( 0.0 )
self._identity = identity
self._search_preview_split = wx.SplitterWindow( self, style=wx.SP_NOBORDER )
self._search_preview_split.SetMinimumPaneSize( 180 )
self._search_preview_split.SetSashGravity( 0.5 )
self._search_preview_split.Bind( wx.EVT_SPLITTER_DCLICK, self.EventPreviewUnsplit )
self._InitManagementPanel()
self._preview_panel = ClientGUICanvas.CanvasPanel( self._search_preview_split, self._page_key, HC.LOCAL_FILE_SERVICE_IDENTIFIER )
self._InitMessagesPanel()
self.SplitVertically( self._search_preview_split, self._messages_panel, HC.options[ 'hpos' ] )
wx.CallAfter( self._search_preview_split.SplitHorizontally, self._management_panel, self._preview_panel, HC.options[ 'vpos' ] )
def _InitManagementPanel( self ): self._management_panel = ClientGUIManagement.ManagementPanelMessages( self._search_preview_split, self._page_key, self._identity, starting_from_session = self._starting_from_session )
def _InitMessagesPanel( self ): self._messages_panel = ClientGUIMessages.ConversationSplitter( self, self._page_key, self._identity )
def EventPreviewUnsplit( self, event ): self._search_preview_split.Unsplit( self._preview_panel )
def GetSashPositions( self ):
if self.IsSplit(): x = self.GetSashPosition()
else: x = HC.options[ 'hpos' ]
if self._search_preview_split.IsSplit(): y = -1 * self._preview_panel.GetSize()[1]
else: y = HC.options[ 'vpos' ]
return ( x, y )
def ShowHideSplit( self ):
if self._search_preview_split.IsSplit(): self._search_preview_split.Unsplit( self._preview_panel )
else: self._search_preview_split.SplitHorizontally( self._management_panel, self._preview_panel, HC.options[ 'vpos' ] )
def TryToClose( self ): self._management_panel.TryToClose()
class PageWithMedia( PageBase, wx.SplitterWindow ):
def __init__( self, parent, file_service_identifier = HC.LOCAL_FILE_SERVICE_IDENTIFIER, initial_hashes = [], initial_media_results = [], starting_from_session = False ):
wx.SplitterWindow.__init__( self, parent )
PageBase.__init__( self, starting_from_session = starting_from_session )
if len( initial_hashes ) > 0:
initial_media_results = HC.app.Read( 'media_results', file_service_identifier, initial_hashes )
self._file_service_identifier = file_service_identifier
self._initial_media_results = initial_media_results
self.SetMinimumPaneSize( 120 )
self.SetSashGravity( 0.0 )
self.Bind( wx.EVT_SPLITTER_DCLICK, self.EventUnsplit )
self._search_preview_split = wx.SplitterWindow( self, style=wx.SP_NOBORDER )
self._search_preview_split.SetMinimumPaneSize( 180 )
self._search_preview_split.SetSashGravity( 0.5 )
self._search_preview_split.Bind( wx.EVT_SPLITTER_DCLICK, self.EventPreviewUnsplit )
self._InitManagementPanel()
self._preview_panel = ClientGUICanvas.CanvasPanel( self._search_preview_split, self._page_key, self._file_service_identifier )
self._InitMediaPanel()
self.SplitVertically( self._search_preview_split, self._media_panel, HC.options[ 'hpos' ] )
wx.CallAfter( self._search_preview_split.SplitHorizontally, self._management_panel, self._preview_panel, HC.options[ 'vpos' ] )
HC.pubsub.sub( self, 'SwapMediaPanel', 'swap_media_panel' )
def EventPreviewUnsplit( self, event ): self._search_preview_split.Unsplit( self._preview_panel )
def EventUnsplit( self, event ): self.Unsplit( self._search_preview_split )
# used by autocomplete
def GetMedia( self ): return self._media_panel.GetSortedMedia()
def GetSashPositions( self ):
if self.IsSplit(): x = self.GetSashPosition()
else: x = HC.options[ 'hpos' ]
if self._search_preview_split.IsSplit(): y = -1 * self._preview_panel.GetSize()[1]
else: y = HC.options[ 'vpos' ]
return ( x, y )
def ShowHideSplit( self ):
if self.IsSplit():
self.Unsplit( self._search_preview_split )
else:
self.SplitVertically( self._search_preview_split, self._media_panel, HC.options[ 'hpos' ] )
self._search_preview_split.SplitHorizontally( self._management_panel, self._preview_panel, HC.options[ 'vpos' ] )
def SetMediaFocus( self ): self._media_panel.SetFocus()
def SwapMediaPanel( self, page_key, new_panel ):
if page_key == self._page_key:
self._preview_panel.SetMedia( None )
self.ReplaceWindow( self._media_panel, new_panel )
self._media_panel.Destroy()
self._media_panel = new_panel
def TryToClose( self ): self._management_panel.TryToClose()
class PageImport( PageWithMedia ):
def _InitMediaPanel( self ): self._media_panel = ClientGUIMedia.MediaPanelThumbnails( self, self._page_key, self._file_service_identifier, self._initial_media_results )
def GetSessionArgs( self ):
hashes = [ media.GetHash() for media in self._media_panel.GetFlatMedia() ]
args = tuple()
kwargs = { 'initial_hashes' : hashes }
return ( args, kwargs )
class PageImportBooru( PageImport ):
def __init__( self, parent, booru, initial_hashes = [], starting_from_session = False ):
self._booru = booru
PageImport.__init__( self, parent, initial_hashes = initial_hashes, starting_from_session = starting_from_session )
def _InitManagementPanel( self ): self._management_panel = ClientGUIManagement.ManagementPanelImportWithQueueAdvancedBooru( self._search_preview_split, self, self._page_key, self._booru, starting_from_session = self._starting_from_session )
def GetSessionArgs( self ):
hashes = [ media.GetHash() for media in self._media_panel.GetFlatMedia() ]
args = ( self._booru, )
kwargs = { 'initial_hashes' : hashes }
return ( args, kwargs )
class PageImportGallery( PageImport ):
def __init__( self, parent, name, initial_hashes = [], starting_from_session = False ):
self._name = name
PageImport.__init__( self, parent, initial_hashes = initial_hashes, starting_from_session = starting_from_session )
def _InitManagementPanel( self ):
if self._name == 'deviant art by artist': c = ClientGUIManagement.ManagementPanelImportWithQueueAdvancedDeviantArt
elif self._name == 'hentai foundry by artist': c = ClientGUIManagement.ManagementPanelImportWithQueueAdvancedHentaiFoundryArtist
elif self._name == 'hentai foundry by tags': c = ClientGUIManagement.ManagementPanelImportWithQueueAdvancedHentaiFoundryTags
elif self._name == 'giphy': c = ClientGUIManagement.ManagementPanelImportWithQueueAdvancedGiphy
elif self._name == 'newgrounds': c = ClientGUIManagement.ManagementPanelImportWithQueueAdvancedNewgrounds
elif self._name == 'pixiv by artist': c = ClientGUIManagement.ManagementPanelImportWithQueueAdvancedPixivArtist
elif self._name == 'pixiv by tag': c = ClientGUIManagement.ManagementPanelImportWithQueueAdvancedPixivTag
elif self._name == 'tumblr': c = ClientGUIManagement.ManagementPanelImportWithQueueAdvancedTumblr
self._management_panel = c( self._search_preview_split, self, self._page_key, starting_from_session = self._starting_from_session )
def GetSessionArgs( self ):
hashes = [ media.GetHash() for media in self._media_panel.GetFlatMedia() ]
args = ( self._name, )
kwargs = { 'initial_hashes' : hashes }
return ( args, kwargs )
class PageImportHDD( PageImport ):
def __init__( self, parent, paths_info, initial_hashes = [], advanced_import_options = {}, paths_to_tags = {}, delete_after_success = False, starting_from_session = False ):
self._paths_info = paths_info
self._advanced_import_options = advanced_import_options
self._paths_to_tags = paths_to_tags
self._delete_after_success = delete_after_success
PageImport.__init__( self, parent, initial_hashes = initial_hashes, starting_from_session = starting_from_session )
def _InitManagementPanel( self ): self._management_panel = ClientGUIManagement.ManagementPanelImportHDD( self._search_preview_split, self, self._page_key, self._paths_info, advanced_import_options = self._advanced_import_options, paths_to_tags = self._paths_to_tags, delete_after_success = self._delete_after_success, starting_from_session = self._starting_from_session )
def GetSessionArgs( self ):
hashes = [ media.GetHash() for media in self._media_panel.GetFlatMedia() ]
args = ( [], )
kwargs = { 'initial_hashes' : hashes }
return ( args, kwargs )
class PageImportThreadWatcher( PageImport ):
def _InitManagementPanel( self ): self._management_panel = ClientGUIManagement.ManagementPanelImportThreadWatcher( self._search_preview_split, self, self._page_key, starting_from_session = self._starting_from_session )
class PageImportURL( PageImport ):
def _InitManagementPanel( self ): self._management_panel = ClientGUIManagement.ManagementPanelImportWithQueueURL( self._search_preview_split, self, self._page_key, starting_from_session = self._starting_from_session )
class PagePetitions( PageWithMedia ):
def __init__( self, parent, petition_service_identifier, starting_from_session = False ):
self._petition_service_identifier = petition_service_identifier
petition_service_type = petition_service_identifier.GetType()
if petition_service_type in ( HC.LOCAL_FILE, HC.FILE_REPOSITORY ): self._file_service_identifier = self._petition_service_identifier
else: self._file_service_identifier = HC.COMBINED_FILE_SERVICE_IDENTIFIER
PageWithMedia.__init__( self, parent, self._file_service_identifier, starting_from_session = starting_from_session )
def _InitManagementPanel( self ): self._management_panel = ClientGUIManagement.ManagementPanelPetitions( self._search_preview_split, self, self._page_key, self._file_service_identifier, self._petition_service_identifier, starting_from_session = self._starting_from_session )
def _InitMediaPanel( self ): self._media_panel = ClientGUIMedia.MediaPanelNoQuery( self, self._page_key, self._file_service_identifier )
class PageQuery( PageWithMedia ):
def __init__( self, parent, file_service_identifier, initial_hashes = [], initial_media_results = [], initial_predicates = [], starting_from_session = False ):
self._initial_predicates = initial_predicates
PageWithMedia.__init__( self, parent, file_service_identifier, initial_hashes = initial_hashes, initial_media_results = initial_media_results, starting_from_session = starting_from_session )
def _InitManagementPanel( self ):
show_search = len( self._initial_predicates ) > 0 or len( self._initial_media_results ) == 0
self._management_panel = ClientGUIManagement.ManagementPanelQuery( self._search_preview_split, self, self._page_key, self._file_service_identifier, show_search = show_search, initial_predicates = self._initial_predicates, starting_from_session = self._starting_from_session )
def _InitMediaPanel( self ):
if len( self._initial_media_results ) == 0: self._media_panel = ClientGUIMedia.MediaPanelNoQuery( self, self._page_key, self._file_service_identifier )
else: self._media_panel = ClientGUIMedia.MediaPanelThumbnails( self, self._page_key, self._file_service_identifier, self._initial_media_results )
def GetSessionArgs( self ):
hashes = [ media.GetHash() for media in self._media_panel.GetFlatMedia() ]
predicates = self._management_panel.GetPredicates()
args = ( self._file_service_identifier, )
kwargs = { 'initial_hashes' : hashes, 'initial_predicates' : predicates }
return ( args, kwargs )
class PageThreadDumper( PageWithMedia ):
def __init__( self, parent, imageboard, hashes, starting_from_session = False ):
self._imageboard = imageboard
media_results = HC.app.Read( 'media_results', HC.LOCAL_FILE_SERVICE_IDENTIFIER, hashes )
hashes_to_media_results = { media_result.GetHash() : media_result for media_result in media_results }
self._media_results = [ hashes_to_media_results[ hash ] for hash in hashes ]
self._media_results = filter( self._imageboard.IsOkToPost, self._media_results )
PageWithMedia.__init__( self, parent, HC.LOCAL_FILE_SERVICE_IDENTIFIER, starting_from_session = starting_from_session )
def _InitManagementPanel( self ): self._management_panel = ClientGUIManagement.ManagementPanelDumper( self._search_preview_split, self, self._page_key, self._imageboard, self._media_results, starting_from_session = self._starting_from_session )
def _InitMediaPanel( self ): self._media_panel = ClientGUIMedia.MediaPanelThumbnails( self, self._page_key, HC.LOCAL_FILE_SERVICE_IDENTIFIER, self._media_results )
class_to_text = {}
text_to_class = {}
current_module = sys.modules[ __name__ ]
for ( name, c ) in inspect.getmembers( current_module ):
if inspect.isclass( c ):
class_to_text[ c ] = name
text_to_class[ name ] = c