From 0d96611cff76e2869cea00469c162591a8095098 Mon Sep 17 00:00:00 2001 From: Hydrus Date: Sat, 23 Mar 2013 12:57:29 -0500 Subject: [PATCH] Version 62 --- help/changelog.html | 1884 ++++++++-------- include/ClientConstants.py | 20 +- include/ClientController.py | 14 + include/ClientDB.py | 77 +- include/ClientGUI.py | 14 +- include/ClientGUICanvas.py | 590 ++--- include/ClientGUICommon.py | 617 +++--- include/ClientGUIDialogs.py | 3724 ++++++++++++++++---------------- include/ClientGUIManagement.py | 21 +- include/ClientGUIMedia.py | 93 +- include/ClientGUIMixins.py | 6 + include/HydrusConstants.py | 20 +- include/HydrusServer.py | 30 +- 13 files changed, 3608 insertions(+), 3502 deletions(-) diff --git a/help/changelog.html b/help/changelog.html index 193b9c9f..4fa36b26 100755 --- a/help/changelog.html +++ b/help/changelog.html @@ -1,934 +1,952 @@ - - - changelog - - - - -
-

changelog

- -
- + + + changelog + + + + +
+

changelog

+ +
+ \ No newline at end of file diff --git a/include/ClientConstants.py b/include/ClientConstants.py index 3cb02743..99adabb7 100755 --- a/include/ClientConstants.py +++ b/include/ClientConstants.py @@ -510,7 +510,7 @@ class AdvancedHTTPConnection(): except: print( traceback.format_exc() ) - raise Exception( 'Could not connect to server' ) + raise except: print( traceback.format_exc() ) @@ -1367,24 +1367,6 @@ class ConnectionToService(): def Post( self, request, **kwargs ): response = self._SendRequest( HC.POST, request, kwargs ) -class ContentUpdate(): - - def __init__( self, action, service_identifier, hashes, info = None ): - - self._action = action - self._service_identifier = service_identifier - self._hashes = set( hashes ) - self._info = info - - - def GetAction( self ): return self._action - - def GetHashes( self ): return self._hashes - - def GetInfo( self ): return self._info - - def GetServiceIdentifier( self ): return self._service_identifier - class CPRemoteRatingsServiceIdentifiers(): def __init__( self, service_identifiers_to_cp ): diff --git a/include/ClientController.py b/include/ClientController.py index add0759c..d85dd738 100755 --- a/include/ClientController.py +++ b/include/ClientController.py @@ -51,6 +51,20 @@ class Controller( wx.App ): else: wx.MessageBox( 'Could not get permission to access the clipboard!' ) + elif type == 'text': + + text = data + + if wx.TheClipboard.Open(): + + data = wx.TextDataObject( text ) + + wx.TheClipboard.SetData( data ) + + wx.TheClipboard.Close() + + else: wx.MessageBox( 'I could not get permission to access the clipboard.' ) + def DeleteSessionKey( self, service_identifier ): self._session_manager.DeleteSessionKey( service_identifier ) diff --git a/include/ClientDB.py b/include/ClientDB.py index 5879af77..0b4b9f94 100755 --- a/include/ClientDB.py +++ b/include/ClientDB.py @@ -1192,8 +1192,8 @@ class RatingDB(): c.executemany( 'INSERT INTO ratings ( service_id, hash_id, count, rating, score ) VALUES ( ?, ?, ?, ?, ? );', [ ( service_id, self._GetHashId( c, hash ), count, rating, HC.CalculateScoreFromRating( count, rating ) ) for ( hash, count, rating ) in ratings if count > 0 ] ) # these need count and score in - #self.pub( 'content_updates_data', [ CC.ContentUpdate( CC.CONTENT_UPDATE_RATING_REMOTE, service_identifier, ( hash, ), rating ) for ( hash, rating ) in ratings ] ) - #self.pub( 'content_updates_gui', [ CC.ContentUpdate( CC.CONTENT_UPDATE_RATING_REMOTE, service_identifier, ( hash, ), rating ) for ( hash, rating ) in ratings ] ) + #self.pub( 'content_updates_data', [ HC.ContentUpdate( CC.CONTENT_UPDATE_RATING_REMOTE, service_identifier, ( hash, ), rating ) for ( hash, rating ) in ratings ] ) + #self.pub( 'content_updates_gui', [ HC.ContentUpdate( CC.CONTENT_UPDATE_RATING_REMOTE, service_identifier, ( hash, ), rating ) for ( hash, rating ) in ratings ] ) class TagDB(): @@ -1298,8 +1298,8 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ): c.executemany( 'INSERT OR IGNORE INTO file_transfers ( service_id_from, service_id_to, hash_id ) VALUES ( ?, ?, ? );', [ ( service_id, self._local_file_service_id, hash_id ) for hash_id in hash_ids ] ) self.pub( 'notify_new_downloads' ) - self.pub( 'content_updates_data', [ CC.ContentUpdate( CC.CONTENT_UPDATE_PENDING, CC.LOCAL_FILE_SERVICE_IDENTIFIER, hashes ) ] ) - self.pub( 'content_updates_gui', [ CC.ContentUpdate( CC.CONTENT_UPDATE_PENDING, CC.LOCAL_FILE_SERVICE_IDENTIFIER, hashes ) ] ) + self.pub( 'content_updates_data', [ HC.ContentUpdate( CC.CONTENT_UPDATE_PENDING, CC.LOCAL_FILE_SERVICE_IDENTIFIER, hashes ) ] ) + self.pub( 'content_updates_gui', [ HC.ContentUpdate( CC.CONTENT_UPDATE_PENDING, CC.LOCAL_FILE_SERVICE_IDENTIFIER, hashes ) ] ) def _AddFiles( self, c, files_info_rows ): @@ -1379,14 +1379,14 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ): if len( new_hashes ) > 0: - self.pub( 'content_updates_data', [ CC.ContentUpdate( CC.CONTENT_UPDATE_ADD, service_identifier, new_hashes ) ] ) - self.pub( 'content_updates_gui', [ CC.ContentUpdate( CC.CONTENT_UPDATE_ADD, service_identifier, new_hashes ) ] ) + self.pub( 'content_updates_data', [ HC.ContentUpdate( CC.CONTENT_UPDATE_ADD, service_identifier, new_hashes ) ] ) + self.pub( 'content_updates_gui', [ HC.ContentUpdate( CC.CONTENT_UPDATE_ADD, service_identifier, new_hashes ) ] ) if len( deleted_hashes ) > 0: - self.pub( 'content_updates_data', [ CC.ContentUpdate( CC.CONTENT_UPDATE_DELETE, service_identifier, deleted_hashes ) ] ) - self.pub( 'content_updates_gui', [ CC.ContentUpdate( CC.CONTENT_UPDATE_DELETE, service_identifier, deleted_hashes ) ] ) + self.pub( 'content_updates_data', [ HC.ContentUpdate( CC.CONTENT_UPDATE_DELETE, service_identifier, deleted_hashes ) ] ) + self.pub( 'content_updates_gui', [ HC.ContentUpdate( CC.CONTENT_UPDATE_DELETE, service_identifier, deleted_hashes ) ] ) if len( new_hashes ) > 0 or len( deleted_hashes ) > 0: self.pub( 'notify_new_thumbnails' ) @@ -1585,11 +1585,11 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ): deleted_mappings = [ deleted_mapping for deleted_mapping in update.GetDeletedMappings() ] # to clear generator if len( mappings ) > 0: - self.pub( 'content_updates_data', [ CC.ContentUpdate( CC.CONTENT_UPDATE_ADD, service_identifier, hashes, info = tag ) for ( tag, hashes ) in mappings ] ) - self.pub( 'content_updates_gui', [ CC.ContentUpdate( CC.CONTENT_UPDATE_ADD, service_identifier, hashes, info = tag ) for ( tag, hashes ) in mappings ] ) + self.pub( 'content_updates_data', [ HC.ContentUpdate( CC.CONTENT_UPDATE_ADD, service_identifier, hashes, info = tag ) for ( tag, hashes ) in mappings ] ) + self.pub( 'content_updates_gui', [ HC.ContentUpdate( CC.CONTENT_UPDATE_ADD, service_identifier, hashes, info = tag ) for ( tag, hashes ) in mappings ] ) if len( deleted_mappings ) > 0: - self.pub( 'content_updates_data', [ CC.ContentUpdate( CC.CONTENT_UPDATE_DELETE, service_identifier, hashes, info = tag ) for ( tag, hashes ) in deleted_mappings ] ) - self.pub( 'content_updates_gui', [ CC.ContentUpdate( CC.CONTENT_UPDATE_DELETE, service_identifier, hashes, info = tag ) for ( tag, hashes ) in deleted_mappings ] ) + self.pub( 'content_updates_data', [ HC.ContentUpdate( CC.CONTENT_UPDATE_DELETE, service_identifier, hashes, info = tag ) for ( tag, hashes ) in deleted_mappings ] ) + self.pub( 'content_updates_gui', [ HC.ContentUpdate( CC.CONTENT_UPDATE_DELETE, service_identifier, hashes, info = tag ) for ( tag, hashes ) in deleted_mappings ] ) def _AddUpdate( self, c, service_identifier, update ): @@ -1624,8 +1624,8 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ): c.executemany( 'INSERT OR IGNORE INTO file_transfers ( service_id_from, service_id_to, hash_id ) VALUES ( ?, ?, ? );', [ ( self._local_file_service_id, service_id, hash_id ) for hash_id in hash_ids ] ) self.pub( 'notify_new_pending' ) - self.pub( 'content_updates_data', [ CC.ContentUpdate( CC.CONTENT_UPDATE_PENDING, service_identifier, self._GetHashes( c, hash_ids ) ) ] ) - self.pub( 'content_updates_gui', [ CC.ContentUpdate( CC.CONTENT_UPDATE_PENDING, service_identifier, self._GetHashes( c, hash_ids ) ) ] ) + self.pub( 'content_updates_data', [ HC.ContentUpdate( CC.CONTENT_UPDATE_PENDING, service_identifier, self._GetHashes( c, hash_ids ) ) ] ) + self.pub( 'content_updates_gui', [ HC.ContentUpdate( CC.CONTENT_UPDATE_PENDING, service_identifier, self._GetHashes( c, hash_ids ) ) ] ) def _ArchiveFiles( self, c, hash_ids ): @@ -3095,7 +3095,7 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ): return ( 'new', None ) - def _ImportFile( self, c, file, advanced_import_options = {}, service_identifiers_to_tags = {}, generate_media_result = False, override_deleted = False ): + def _ImportFile( self, c, file, advanced_import_options = {}, service_identifiers_to_tags = {}, generate_media_result = False, override_deleted = False, url = None ): result = 'successful' @@ -3122,6 +3122,8 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ): hash_id = self._GetHashId( c, hash ) + if url is not None: c.execute( 'INSERT OR IGNORE INTO urls ( url, hash_id ) VALUES ( ?, ? );', ( url, hash_id ) ) + already_in_db = c.execute( 'SELECT 1 FROM files_info WHERE service_id = ? AND hash_id = ?;', ( self._local_file_service_id, hash_id ) ).fetchone() is not None if already_in_db: @@ -3132,8 +3134,8 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ): c.execute( 'DELETE FROM file_inbox WHERE hash_id = ?;', ( hash_id, ) ) - self.pub( 'content_updates_data', [ CC.ContentUpdate( CC.CONTENT_UPDATE_ARCHIVE, CC.LOCAL_FILE_SERVICE_IDENTIFIER, set( ( hash, ) ) ) ] ) - self.pub( 'content_updates_gui', [ CC.ContentUpdate( CC.CONTENT_UPDATE_ARCHIVE, CC.LOCAL_FILE_SERVICE_IDENTIFIER, set( ( hash, ) ) ) ] ) + self.pub( 'content_updates_data', [ HC.ContentUpdate( CC.CONTENT_UPDATE_ARCHIVE, CC.LOCAL_FILE_SERVICE_IDENTIFIER, set( ( hash, ) ) ) ] ) + self.pub( 'content_updates_gui', [ HC.ContentUpdate( CC.CONTENT_UPDATE_ARCHIVE, CC.LOCAL_FILE_SERVICE_IDENTIFIER, set( ( hash, ) ) ) ] ) can_add = False @@ -3249,7 +3251,7 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ): if service_identifier == CC.LOCAL_TAG_SERVICE_IDENTIFIER: edit_log = [ ( CC.CONTENT_UPDATE_ADD, tag ) for tag in tags ] else: edit_log = [ ( CC.CONTENT_UPDATE_PENDING, tag ) for tag in tags ] - content_updates = [ CC.ContentUpdate( CC.CONTENT_UPDATE_EDIT_LOG, service_identifier, ( hash, ), edit_log ) ] + content_updates = [ HC.ContentUpdate( CC.CONTENT_UPDATE_EDIT_LOG, service_identifier, ( hash, ), edit_log ) ] self._ProcessContentUpdates( c, content_updates ) @@ -3274,20 +3276,13 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ): try: - ( result, hash, media_result ) = self._ImportFile( c, file, advanced_import_options = advanced_import_options, service_identifiers_to_tags = service_identifiers_to_tags, generate_media_result = True ) - - if url is not None: - - hash_id = self._GetHashId( c, hash ) - - c.execute( 'INSERT OR IGNORE INTO urls ( url, hash_id ) VALUES ( ?, ? );', ( url, hash_id ) ) - + ( result, hash, media_result ) = self._ImportFile( c, file, advanced_import_options = advanced_import_options, service_identifiers_to_tags = service_identifiers_to_tags, generate_media_result = True, url = url ) if media_result is not None: self.pub( 'add_media_result', page_key, media_result ) if result == 'successful': - self.pub( 'content_updates_data', [ CC.ContentUpdate( CC.CONTENT_UPDATE_ADD, CC.LOCAL_FILE_SERVICE_IDENTIFIER, ( hash, ) ) ] ) - self.pub( 'content_updates_gui', [ CC.ContentUpdate( CC.CONTENT_UPDATE_ADD, CC.LOCAL_FILE_SERVICE_IDENTIFIER, ( hash, ) ) ] ) + self.pub( 'content_updates_data', [ HC.ContentUpdate( CC.CONTENT_UPDATE_ADD, CC.LOCAL_FILE_SERVICE_IDENTIFIER, ( hash, ) ) ] ) + self.pub( 'content_updates_gui', [ HC.ContentUpdate( CC.CONTENT_UPDATE_ADD, CC.LOCAL_FILE_SERVICE_IDENTIFIER, ( hash, ) ) ] ) self.pub( 'import_done', page_key, result ) @@ -3328,8 +3323,8 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ): c.executemany( 'INSERT OR IGNORE INTO file_petitions ( service_id, hash_id, reason_id ) VALUES ( ?, ?, ? );', [ ( service_id, hash_id, reason_id ) for hash_id in hash_ids ] ) self.pub( 'notify_new_pending' ) - self.pub( 'content_updates_data', [ CC.ContentUpdate( CC.CONTENT_UPDATE_PETITION, service_identifier, hashes ) ] ) - self.pub( 'content_updates_gui', [ CC.ContentUpdate( CC.CONTENT_UPDATE_PETITION, service_identifier, hashes ) ] ) + self.pub( 'content_updates_data', [ HC.ContentUpdate( CC.CONTENT_UPDATE_PETITION, service_identifier, hashes ) ] ) + self.pub( 'content_updates_gui', [ HC.ContentUpdate( CC.CONTENT_UPDATE_PETITION, service_identifier, hashes ) ] ) def _ProcessContentUpdates( self, c, content_updates ): @@ -4179,8 +4174,8 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ): content_updates = [] - content_updates += [ CC.ContentUpdate( CC.CONTENT_UPDATE_ADD, service_identifier, self._GetHashes( c, hash_ids ), info = self._GetNamespaceTag( c, namespace_id, tag_id ) ) for ( namespace_id, tag_id, hash_ids ) in mappings_ids ] - content_updates += [ CC.ContentUpdate( CC.CONTENT_UPDATE_DELETE, service_identifier, self._GetHashes( c, hash_ids ), info = self._GetNamespaceTag( c, namespace_id, tag_id ) ) for ( namespace_id, tag_id, hash_ids ) in deleted_mappings_ids ] + content_updates += [ HC.ContentUpdate( CC.CONTENT_UPDATE_ADD, service_identifier, self._GetHashes( c, hash_ids ), info = self._GetNamespaceTag( c, namespace_id, tag_id ) ) for ( namespace_id, tag_id, hash_ids ) in mappings_ids ] + content_updates += [ HC.ContentUpdate( CC.CONTENT_UPDATE_DELETE, service_identifier, self._GetHashes( c, hash_ids ), info = self._GetNamespaceTag( c, namespace_id, tag_id ) ) for ( namespace_id, tag_id, hash_ids ) in deleted_mappings_ids ] HC.pubsub.pub( 'progress_update', job_key, 6, 7, u'saving changes to gui' ) @@ -4249,8 +4244,8 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ): HC.pubsub.pub( 'progress_update', job_key, num_uploads + 2, num_uploads + 4, u'saving changes to gui' ) if len( good_hash_ids ) > 0: - self.pub( 'content_updates_data', [ CC.ContentUpdate( CC.CONTENT_UPDATE_ADD, service_identifier, self._GetHashes( c, good_hash_ids ) ) ] ) - self.pub( 'content_updates_gui', [ CC.ContentUpdate( CC.CONTENT_UPDATE_ADD, service_identifier, self._GetHashes( c, good_hash_ids ) ) ] ) + self.pub( 'content_updates_data', [ HC.ContentUpdate( CC.CONTENT_UPDATE_ADD, service_identifier, self._GetHashes( c, good_hash_ids ) ) ] ) + self.pub( 'content_updates_gui', [ HC.ContentUpdate( CC.CONTENT_UPDATE_ADD, service_identifier, self._GetHashes( c, good_hash_ids ) ) ] ) if num_petitions > 0: @@ -4267,8 +4262,8 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ): self._DeleteFiles( c, service_id, hash_ids ) - self.pub( 'content_updates_data', [ CC.ContentUpdate( CC.CONTENT_UPDATE_DELETE, service_identifier, self._GetHashes( c, hash_ids ) ) ] ) - self.pub( 'content_updates_gui', [ CC.ContentUpdate( CC.CONTENT_UPDATE_DELETE, service_identifier, self._GetHashes( c, hash_ids ) ) ] ) + self.pub( 'content_updates_data', [ HC.ContentUpdate( CC.CONTENT_UPDATE_DELETE, service_identifier, self._GetHashes( c, hash_ids ) ) ] ) + self.pub( 'content_updates_gui', [ HC.ContentUpdate( CC.CONTENT_UPDATE_DELETE, service_identifier, self._GetHashes( c, hash_ids ) ) ] ) except Exception as e: raise Exception( 'Encountered an error while trying to uploads petitions to '+ service_name + ':' + os.linesep + unicode( e ) ) @@ -4316,6 +4311,12 @@ class DB( ServiceDB ): if not os.path.exists( temp_dir ): os.mkdir( temp_dir ) except: pass + # clean up if last connection closed badly + ( db, c ) = self._GetDBCursor() + + db.close() + # ok should be fine + ( db, c ) = self._GetDBCursor() self._UpdateDB( c ) @@ -6014,8 +6015,8 @@ class DB( ServiceDB ): self.Write( 'import_file', HC.LOW_PRIORITY, file ) - HC.pubsub.pub( 'content_updates_data', [ CC.ContentUpdate( CC.CONTENT_UPDATE_ADD, CC.LOCAL_FILE_SERVICE_IDENTIFIER, ( hash, ) ) ] ) - HC.pubsub.pub( 'content_updates_gui', [ CC.ContentUpdate( CC.CONTENT_UPDATE_ADD, CC.LOCAL_FILE_SERVICE_IDENTIFIER, ( hash, ) ) ] ) + HC.pubsub.pub( 'content_updates_data', [ HC.ContentUpdate( CC.CONTENT_UPDATE_ADD, CC.LOCAL_FILE_SERVICE_IDENTIFIER, ( hash, ) ) ] ) + HC.pubsub.pub( 'content_updates_gui', [ HC.ContentUpdate( CC.CONTENT_UPDATE_ADD, CC.LOCAL_FILE_SERVICE_IDENTIFIER, ( hash, ) ) ] ) self.pub( 'log_message', 'download files daemon', 'downloaded ' + hash.encode( 'hex' ) + ' from ' + file_repository.GetServiceIdentifier().GetName() ) diff --git a/include/ClientGUI.py b/include/ClientGUI.py index 908dcd24..67f004ee 100755 --- a/include/ClientGUI.py +++ b/include/ClientGUI.py @@ -94,14 +94,14 @@ class FrameGUI( ClientGUICommon.Frame ): HC.pubsub.sub( self, 'SetInboxStatus', 'inbox_status' ) HC.pubsub.sub( self, 'SetServiceStatus', 'service_status' ) - self._NewPageQuery( CC.LOCAL_FILE_SERVICE_IDENTIFIER ) - self.RefreshMenuBar() self._RefreshStatusBar() self.Show( True ) + wx.CallAfter( self._NewPageQuery, CC.LOCAL_FILE_SERVICE_IDENTIFIER ) + def _THREADUploadPending( self, service_identifier, job_key, cancel_event ): @@ -156,8 +156,8 @@ class FrameGUI( ClientGUICommon.Frame ): content_updates = [] - content_updates += [ CC.ContentUpdate( CC.CONTENT_UPDATE_ADD, service_identifier, hashes, info = tag ) for ( tag, hashes ) in mappings_object ] - content_updates += [ CC.ContentUpdate( CC.CONTENT_UPDATE_DELETE, service_identifier, hashes, info = tag ) for ( reason, tag, hashes ) in petitions_object ] + content_updates += [ HC.ContentUpdate( CC.CONTENT_UPDATE_ADD, service_identifier, hashes, info = tag ) for ( tag, hashes ) in mappings_object ] + content_updates += [ HC.ContentUpdate( CC.CONTENT_UPDATE_DELETE, service_identifier, hashes, info = tag ) for ( reason, tag, hashes ) in petitions_object ] wx.GetApp().Write( 'content_updates', content_updates ) @@ -224,8 +224,8 @@ class FrameGUI( ClientGUICommon.Frame ): content_updates = [] - content_updates.append( CC.ContentUpdate( CC.CONTENT_UPDATE_ADD, service_identifier, good_hashes ) ) - content_updates.append( CC.ContentUpdate( CC.CONTENT_UPDATE_DELETE, service_identifier, petitions_object.GetHashes() ) ) + content_updates.append( HC.ContentUpdate( CC.CONTENT_UPDATE_ADD, service_identifier, good_hashes ) ) + content_updates.append( HC.ContentUpdate( CC.CONTENT_UPDATE_DELETE, service_identifier, petitions_object.GetHashes() ) ) wx.GetApp().Write( 'content_updates', content_updates ) @@ -811,7 +811,7 @@ class FrameGUI( ClientGUICommon.Frame ): self._notebook.AddPage( new_page, 'files', select = True ) - new_page.SetSearchFocus() + wx.CallAfter( new_page.SetSearchFocus ) diff --git a/include/ClientGUICanvas.py b/include/ClientGUICanvas.py index 67c404b4..fe4970b1 100755 --- a/include/ClientGUICanvas.py +++ b/include/ClientGUICanvas.py @@ -457,287 +457,6 @@ class Canvas(): - -class CanvasRatingsFilterPanel( Canvas, wx.Window ): - - def __init__( self, parent ): - - wx.Window.__init__( self, parent, style = wx.SIMPLE_BORDER | wx.WANTS_CHARS ) - Canvas.__init__( self, CC.LOCAL_FILE_SERVICE_IDENTIFIER, wx.GetApp().GetFullscreenImageCache() ) - - wx.CallAfter( self.Refresh ) - - self.Bind( wx.EVT_MOTION, self.EventDrag ) - self.Bind( wx.EVT_LEFT_DOWN, self.EventDragBegin ) - self.Bind( wx.EVT_RIGHT_DOWN, self.GetParent().GetParent().EventMouseDown ) - self.Bind( wx.EVT_MIDDLE_DOWN, self.GetParent().GetParent().EventMouseDown ) - self.Bind( wx.EVT_LEFT_UP, self.EventDragEnd ) - self.Bind( wx.EVT_MOUSEWHEEL, self.EventMouseWheel ) - self.Bind( wx.EVT_KEY_DOWN, self.EventKeyDown ) - - self._timer_media_info_display = wx.Timer( self, id = ID_TIMER_MEDIA_INFO_DISPLAY ) - - self.Bind( wx.EVT_TIMER, self.EventTimerMediaInfoDisplay, id = ID_TIMER_MEDIA_INFO_DISPLAY ) - - self.Bind( wx.EVT_MENU, self.EventMenu ) - - - def _ZoomIn( self ): - - if self._current_media is not None: - - if self._current_media.GetMime() == HC.APPLICATION_PDF: return - - for zoom in ZOOMINS: - - if self._current_zoom < zoom: - - if self._current_media.GetMime() in ( HC.APPLICATION_FLASH, HC.VIDEO_FLV ): - - # because of the event passing under mouse, we want to preserve whitespace around flash - - ( original_width, original_height ) = self._current_display_media.GetResolution() - - ( my_width, my_height ) = self.GetClientSize() - - new_media_width = int( round( original_width * zoom ) ) - new_media_height = int( round( original_height * zoom ) ) - - if new_media_width >= my_width or new_media_height >= my_height: return - - - with wx.FrozenWindow( self ): - - ( drag_x, drag_y ) = self._total_drag_delta - - zoom_ratio = zoom / self._current_zoom - - self._total_drag_delta = ( int( drag_x * zoom_ratio ), int( drag_y * zoom_ratio ) ) - - self._current_zoom = zoom - - self._DrawBackgroundBitmap() - - self._DrawCurrentMedia() - - - break - - - - - - def _ZoomOut( self ): - - if self._current_media is not None: - - for zoom in ZOOMOUTS: - - if self._current_zoom > zoom: - - with wx.FrozenWindow( self ): - - ( drag_x, drag_y ) = self._total_drag_delta - - zoom_ratio = zoom / self._current_zoom - - self._total_drag_delta = ( int( drag_x * zoom_ratio ), int( drag_y * zoom_ratio ) ) - - self._current_zoom = zoom - - self._DrawBackgroundBitmap() - - self._DrawCurrentMedia() - - - break - - - - - - def _ZoomSwitch( self ): - - ( my_width, my_height ) = self.GetClientSize() - - ( media_width, media_height ) = self._current_display_media.GetResolution() - - if self._current_media.GetMime() == HC.APPLICATION_PDF: return - - if self._current_media.GetMime() not in ( HC.APPLICATION_FLASH, HC.VIDEO_FLV ) or self._current_zoom > 1.0 or ( media_width < my_width and media_height < my_height ): - - new_zoom = self._current_zoom - - if self._current_zoom == 1.0: - - if media_width > my_width or media_height > my_height: - - width_zoom = my_width / float( media_width ) - - height_zoom = my_height / float( media_height ) - - new_zoom = min( ( width_zoom, height_zoom ) ) - - - else: new_zoom = 1.0 - - if new_zoom != self._current_zoom: - - ( drag_x, drag_y ) = self._total_drag_delta - - zoom_ratio = new_zoom / self._current_zoom - - self._total_drag_delta = ( int( drag_x * zoom_ratio ), int( drag_y * zoom_ratio ) ) - - self._current_zoom = new_zoom - - self._DrawBackgroundBitmap() - - self._DrawCurrentMedia() - - - - - def EventDrag( self, event ): - - if wx.Window.FindFocus() != self: self.SetFocus() - - if event.Dragging() and self._last_drag_coordinates is not None: - - ( old_x, old_y ) = self._last_drag_coordinates - - ( x, y ) = event.GetPosition() - - ( delta_x, delta_y ) = ( x - old_x, y - old_y ) - - try: self.WarpPointer( old_x, old_y ) - except: self._last_drag_coordinates = ( x, y ) - - ( old_delta_x, old_delta_y ) = self._total_drag_delta - - self._total_drag_delta = ( old_delta_x + delta_x, old_delta_y + delta_y ) - - self._DrawCurrentMedia() - - - self.SetCursor( wx.StockCursor( wx.CURSOR_ARROW ) ) - - self._timer_media_info_display.Start( 800, wx.TIMER_ONE_SHOT ) - - - def EventDragBegin( self, event ): - - if event.ShiftDown(): - - ( x, y ) = event.GetPosition() - - ( client_x, client_y ) = self.GetClientSize() - - if x < 20 or x > client_x - 20 or y < 20 or y > client_y -20: - - try: - - better_x = x - better_y = y - - if x < 20: better_x = 20 - if y < 20: better_y = 20 - - if x > client_x - 20: better_x = client_x - 20 - if y > client_y - 20: better_y = client_y - 20 - - self.WarpPointer( better_x, better_y ) - - x = better_x - y = better_y - - except: pass - - - self._last_drag_coordinates = ( x, y ) - - else: self.GetParent().GetParent().ProcessEvent( event ) - - - def EventDragEnd( self, event ): - - self._last_drag_coordinates = None - - event.Skip() - - - def EventKeyDown( self, event ): - - if self._ShouldSkipInputDueToFlash(): event.Skip() - else: - - keys_i_want_to_bump_up_regardless = [ wx.WXK_SPACE, wx.WXK_UP, wx.WXK_NUMPAD_UP, wx.WXK_DOWN, wx.WXK_NUMPAD_DOWN, wx.WXK_LEFT, wx.WXK_NUMPAD_LEFT, wx.WXK_RIGHT, wx.WXK_NUMPAD_RIGHT, wx.WXK_BACK, wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER, wx.WXK_ESCAPE ] - - ( modifier, key ) = HC.GetShortcutFromEvent( event ) - - key_dict = self._options[ 'shortcuts' ][ modifier ] - - if event.KeyCode not in keys_i_want_to_bump_up_regardless and key in key_dict: - - action = key_dict[ key ] - - self.ProcessEvent( wx.CommandEvent( commandType = wx.wxEVT_COMMAND_MENU_SELECTED, winid = CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( action ) ) ) - - else: - - if event.KeyCode in ( ord( '+' ), wx.WXK_ADD, wx.WXK_NUMPAD_ADD ): self._ZoomIn() - elif event.KeyCode in ( ord( '-' ), wx.WXK_SUBTRACT, wx.WXK_NUMPAD_SUBTRACT ): self._ZoomOut() - elif event.KeyCode == ord( 'Z' ): self._ZoomSwitch() - else: self.GetParent().ProcessEvent( event ) - - - - def EventMenu( self, event ): - - if self._ShouldSkipInputDueToFlash(): event.Skip() - else: - - action = CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetAction( event.GetId() ) - - if action is not None: - - try: - - ( command, data ) = action - - if command == 'frame_back': self._ChangeFrame( -1 ) - elif command == 'frame_next': self._ChangeFrame( 1 ) - elif command == 'manage_ratings': self._ManageRatings() - elif command == 'manage_tags': self._ManageTags() - elif command == 'zoom_in': self._ZoomIn() - elif command == 'zoom_out': self._ZoomOut() - else: event.Skip() - - except Exception as e: - - wx.MessageBox( unicode( e ) ) - - - - - - def EventMouseWheel( self, event ): - - if self._ShouldSkipInputDueToFlash(): event.Skip() - else: - - if event.CmdDown(): - - if event.GetWheelRotation() > 0: self._ZoomIn() - else: self._ZoomOut() - - - - - def EventTimerMediaInfoDisplay( self, event ): self.SetCursor( wx.StockCursor( wx.CURSOR_BLANK ) ) - - def RefreshBackground( self ): self._DrawBackgroundBitmap() - class CanvasPanel( Canvas, wx.Window ): def __init__( self, parent, page_key, file_service_identifier ): @@ -1233,7 +952,7 @@ class CanvasFullscreenMediaListBrowser( CanvasFullscreenMediaList ): else: self.SetMedia( self._GetMedia( { first_hash } )[0] ) - def _Archive( self ): wx.GetApp().Write( 'content_updates', [ CC.ContentUpdate( CC.CONTENT_UPDATE_ARCHIVE, CC.LOCAL_FILE_SERVICE_IDENTIFIER, ( self._current_media.GetHash(), ) ) ] ) + def _Archive( self ): wx.GetApp().Write( 'content_updates', [ HC.ContentUpdate( CC.CONTENT_UPDATE_ARCHIVE, CC.LOCAL_FILE_SERVICE_IDENTIFIER, ( self._current_media.GetHash(), ) ) ] ) def _CopyLocalUrlToClipboard( self ): @@ -1265,13 +984,13 @@ class CanvasFullscreenMediaListBrowser( CanvasFullscreenMediaList ): with ClientGUIDialogs.DialogYesNo( self, 'Delete this file from the database?' ) as dlg: - if dlg.ShowModal() == wx.ID_YES: wx.GetApp().Write( 'content_updates', [ CC.ContentUpdate( CC.CONTENT_UPDATE_DELETE, CC.LOCAL_FILE_SERVICE_IDENTIFIER, ( self._current_media.GetHash(), ) ) ] ) + if dlg.ShowModal() == wx.ID_YES: wx.GetApp().Write( 'content_updates', [ HC.ContentUpdate( CC.CONTENT_UPDATE_DELETE, CC.LOCAL_FILE_SERVICE_IDENTIFIER, ( self._current_media.GetHash(), ) ) ] ) self.SetFocus() # annoying bug because of the modal dialog - def _Inbox( self ): wx.GetApp().Write( 'content_updates', [ CC.ContentUpdate( CC.CONTENT_UPDATE_INBOX, CC.LOCAL_FILE_SERVICE_IDENTIFIER, ( self._current_media.GetHash(), ) ) ] ) + def _Inbox( self ): wx.GetApp().Write( 'content_updates', [ HC.ContentUpdate( CC.CONTENT_UPDATE_INBOX, CC.LOCAL_FILE_SERVICE_IDENTIFIER, ( self._current_media.GetHash(), ) ) ] ) def _PausePlaySlideshow( self ): @@ -1479,7 +1198,7 @@ class CanvasFullscreenMediaListCustomFilter( CanvasFullscreenMediaList ): self.SetMedia( self._GetFirst() ) - def _Archive( self ): wx.GetApp().Write( 'content_updates', [ CC.ContentUpdate( CC.CONTENT_UPDATE_ARCHIVE, CC.LOCAL_FILE_SERVICE_IDENTIFIER, ( self._current_media.GetHash(), ) ) ] ) + def _Archive( self ): wx.GetApp().Write( 'content_updates', [ HC.ContentUpdate( CC.CONTENT_UPDATE_ARCHIVE, CC.LOCAL_FILE_SERVICE_IDENTIFIER, ( self._current_media.GetHash(), ) ) ] ) def _CopyLocalUrlToClipboard( self ): @@ -1511,13 +1230,13 @@ class CanvasFullscreenMediaListCustomFilter( CanvasFullscreenMediaList ): with ClientGUIDialogs.DialogYesNo( self, 'Delete this file from the database?' ) as dlg: - if dlg.ShowModal() == wx.ID_YES: wx.GetApp().Write( 'content_updates', [ CC.ContentUpdate( CC.CONTENT_UPDATE_DELETE, CC.LOCAL_FILE_SERVICE_IDENTIFIER, ( self._current_media.GetHash(), ) ) ] ) + if dlg.ShowModal() == wx.ID_YES: wx.GetApp().Write( 'content_updates', [ HC.ContentUpdate( CC.CONTENT_UPDATE_DELETE, CC.LOCAL_FILE_SERVICE_IDENTIFIER, ( self._current_media.GetHash(), ) ) ] ) self.SetFocus() # annoying bug because of the modal dialog - def _Inbox( self ): wx.GetApp().Write( 'content_updates', [ CC.ContentUpdate( CC.CONTENT_UPDATE_INBOX, CC.LOCAL_FILE_SERVICE_IDENTIFIER, ( self._current_media.GetHash(), ) ) ] ) + def _Inbox( self ): wx.GetApp().Write( 'content_updates', [ HC.ContentUpdate( CC.CONTENT_UPDATE_INBOX, CC.LOCAL_FILE_SERVICE_IDENTIFIER, ( self._current_media.GetHash(), ) ) ] ) def EventKeyDown( self, event ): @@ -1584,11 +1303,11 @@ class CanvasFullscreenMediaListCustomFilter( CanvasFullscreenMediaList ): - content_update = CC.ContentUpdate( CC.CONTENT_UPDATE_EDIT_LOG, service_identifier, ( self._current_media.GetHash(), ), info = edit_log ) + content_update = HC.ContentUpdate( CC.CONTENT_UPDATE_EDIT_LOG, service_identifier, ( self._current_media.GetHash(), ), info = edit_log ) elif service_type in ( HC.LOCAL_RATING_LIKE, HC.LOCAL_RATING_NUMERICAL ): - content_update = CC.ContentUpdate( CC.CONTENT_UPDATE_RATING, service_identifier, ( self._current_media.GetHash(), ), info = action ) + content_update = HC.ContentUpdate( CC.CONTENT_UPDATE_RATING, service_identifier, ( self._current_media.GetHash(), ), info = action ) wx.GetApp().Write( 'content_updates', ( content_update, ) ) @@ -1798,8 +1517,8 @@ class CanvasFullscreenMediaListFilter( CanvasFullscreenMediaList ): content_updates = [] - content_updates.append( CC.ContentUpdate( CC.CONTENT_UPDATE_DELETE, CC.LOCAL_FILE_SERVICE_IDENTIFIER, self._deleted_hashes ) ) - content_updates.append( CC.ContentUpdate( CC.CONTENT_UPDATE_ARCHIVE, CC.LOCAL_FILE_SERVICE_IDENTIFIER, self._kept_hashes ) ) + content_updates.append( HC.ContentUpdate( CC.CONTENT_UPDATE_DELETE, CC.LOCAL_FILE_SERVICE_IDENTIFIER, self._deleted_hashes ) ) + content_updates.append( HC.ContentUpdate( CC.CONTENT_UPDATE_ARCHIVE, CC.LOCAL_FILE_SERVICE_IDENTIFIER, self._kept_hashes ) ) wx.GetApp().Write( 'content_updates', content_updates ) @@ -2029,8 +1748,8 @@ class RatingsFilterFrame( ClientGUICommon.Frame ): wx.GetApp().SetTopWindow( self ) - self._left_window = CanvasRatingsFilterPanel( self._splitter ) - self._right_window = CanvasRatingsFilterPanel( self._splitter ) + self._left_window = self._Panel( self._splitter ) + self._right_window = self._Panel( self._splitter ) ( my_width, my_height ) = self.GetClientSize() @@ -2506,8 +2225,8 @@ class RatingsFilterFrame( ClientGUICommon.Frame ): content_updates = [] - content_updates.extend( [ CC.ContentUpdate( CC.CONTENT_UPDATE_RATING, self._service_identifier, ( hash, ), info = rating ) for ( hash, rating ) in certain_ratings ] ) - content_updates.extend( [ CC.ContentUpdate( CC.CONTENT_UPDATE_RATINGS_FILTER, self._service_identifier, ( hash, ), info = ( min, max ) ) for ( hash, min, max ) in uncertain_ratings ] ) + content_updates.extend( [ HC.ContentUpdate( CC.CONTENT_UPDATE_RATING, self._service_identifier, ( hash, ), info = rating ) for ( hash, rating ) in certain_ratings ] ) + content_updates.extend( [ HC.ContentUpdate( CC.CONTENT_UPDATE_RATINGS_FILTER, self._service_identifier, ( hash, ), info = ( min, max ) ) for ( hash, min, max ) in uncertain_ratings ] ) wx.GetApp().Write( 'content_updates', content_updates ) @@ -2607,6 +2326,287 @@ class RatingsFilterFrame( ClientGUICommon.Frame ): self._right_window.RefreshBackground() + class _Panel( Canvas, wx.Window ): + + def __init__( self, parent ): + + wx.Window.__init__( self, parent, style = wx.SIMPLE_BORDER | wx.WANTS_CHARS ) + Canvas.__init__( self, CC.LOCAL_FILE_SERVICE_IDENTIFIER, wx.GetApp().GetFullscreenImageCache() ) + + wx.CallAfter( self.Refresh ) + + self.Bind( wx.EVT_MOTION, self.EventDrag ) + self.Bind( wx.EVT_LEFT_DOWN, self.EventDragBegin ) + self.Bind( wx.EVT_RIGHT_DOWN, self.GetParent().GetParent().EventMouseDown ) + self.Bind( wx.EVT_MIDDLE_DOWN, self.GetParent().GetParent().EventMouseDown ) + self.Bind( wx.EVT_LEFT_UP, self.EventDragEnd ) + self.Bind( wx.EVT_MOUSEWHEEL, self.EventMouseWheel ) + self.Bind( wx.EVT_KEY_DOWN, self.EventKeyDown ) + + self._timer_media_info_display = wx.Timer( self, id = ID_TIMER_MEDIA_INFO_DISPLAY ) + + self.Bind( wx.EVT_TIMER, self.EventTimerMediaInfoDisplay, id = ID_TIMER_MEDIA_INFO_DISPLAY ) + + self.Bind( wx.EVT_MENU, self.EventMenu ) + + + def _ZoomIn( self ): + + if self._current_media is not None: + + if self._current_media.GetMime() == HC.APPLICATION_PDF: return + + for zoom in ZOOMINS: + + if self._current_zoom < zoom: + + if self._current_media.GetMime() in ( HC.APPLICATION_FLASH, HC.VIDEO_FLV ): + + # because of the event passing under mouse, we want to preserve whitespace around flash + + ( original_width, original_height ) = self._current_display_media.GetResolution() + + ( my_width, my_height ) = self.GetClientSize() + + new_media_width = int( round( original_width * zoom ) ) + new_media_height = int( round( original_height * zoom ) ) + + if new_media_width >= my_width or new_media_height >= my_height: return + + + with wx.FrozenWindow( self ): + + ( drag_x, drag_y ) = self._total_drag_delta + + zoom_ratio = zoom / self._current_zoom + + self._total_drag_delta = ( int( drag_x * zoom_ratio ), int( drag_y * zoom_ratio ) ) + + self._current_zoom = zoom + + self._DrawBackgroundBitmap() + + self._DrawCurrentMedia() + + + break + + + + + + def _ZoomOut( self ): + + if self._current_media is not None: + + for zoom in ZOOMOUTS: + + if self._current_zoom > zoom: + + with wx.FrozenWindow( self ): + + ( drag_x, drag_y ) = self._total_drag_delta + + zoom_ratio = zoom / self._current_zoom + + self._total_drag_delta = ( int( drag_x * zoom_ratio ), int( drag_y * zoom_ratio ) ) + + self._current_zoom = zoom + + self._DrawBackgroundBitmap() + + self._DrawCurrentMedia() + + + break + + + + + + def _ZoomSwitch( self ): + + ( my_width, my_height ) = self.GetClientSize() + + ( media_width, media_height ) = self._current_display_media.GetResolution() + + if self._current_media.GetMime() == HC.APPLICATION_PDF: return + + if self._current_media.GetMime() not in ( HC.APPLICATION_FLASH, HC.VIDEO_FLV ) or self._current_zoom > 1.0 or ( media_width < my_width and media_height < my_height ): + + new_zoom = self._current_zoom + + if self._current_zoom == 1.0: + + if media_width > my_width or media_height > my_height: + + width_zoom = my_width / float( media_width ) + + height_zoom = my_height / float( media_height ) + + new_zoom = min( ( width_zoom, height_zoom ) ) + + + else: new_zoom = 1.0 + + if new_zoom != self._current_zoom: + + ( drag_x, drag_y ) = self._total_drag_delta + + zoom_ratio = new_zoom / self._current_zoom + + self._total_drag_delta = ( int( drag_x * zoom_ratio ), int( drag_y * zoom_ratio ) ) + + self._current_zoom = new_zoom + + self._DrawBackgroundBitmap() + + self._DrawCurrentMedia() + + + + + def EventDrag( self, event ): + + if wx.Window.FindFocus() != self: self.SetFocus() + + if event.Dragging() and self._last_drag_coordinates is not None: + + ( old_x, old_y ) = self._last_drag_coordinates + + ( x, y ) = event.GetPosition() + + ( delta_x, delta_y ) = ( x - old_x, y - old_y ) + + try: self.WarpPointer( old_x, old_y ) + except: self._last_drag_coordinates = ( x, y ) + + ( old_delta_x, old_delta_y ) = self._total_drag_delta + + self._total_drag_delta = ( old_delta_x + delta_x, old_delta_y + delta_y ) + + self._DrawCurrentMedia() + + + self.SetCursor( wx.StockCursor( wx.CURSOR_ARROW ) ) + + self._timer_media_info_display.Start( 800, wx.TIMER_ONE_SHOT ) + + + def EventDragBegin( self, event ): + + if event.ShiftDown(): + + ( x, y ) = event.GetPosition() + + ( client_x, client_y ) = self.GetClientSize() + + if x < 20 or x > client_x - 20 or y < 20 or y > client_y -20: + + try: + + better_x = x + better_y = y + + if x < 20: better_x = 20 + if y < 20: better_y = 20 + + if x > client_x - 20: better_x = client_x - 20 + if y > client_y - 20: better_y = client_y - 20 + + self.WarpPointer( better_x, better_y ) + + x = better_x + y = better_y + + except: pass + + + self._last_drag_coordinates = ( x, y ) + + else: self.GetParent().GetParent().ProcessEvent( event ) + + + def EventDragEnd( self, event ): + + self._last_drag_coordinates = None + + event.Skip() + + + def EventKeyDown( self, event ): + + if self._ShouldSkipInputDueToFlash(): event.Skip() + else: + + keys_i_want_to_bump_up_regardless = [ wx.WXK_SPACE, wx.WXK_UP, wx.WXK_NUMPAD_UP, wx.WXK_DOWN, wx.WXK_NUMPAD_DOWN, wx.WXK_LEFT, wx.WXK_NUMPAD_LEFT, wx.WXK_RIGHT, wx.WXK_NUMPAD_RIGHT, wx.WXK_BACK, wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER, wx.WXK_ESCAPE ] + + ( modifier, key ) = HC.GetShortcutFromEvent( event ) + + key_dict = self._options[ 'shortcuts' ][ modifier ] + + if event.KeyCode not in keys_i_want_to_bump_up_regardless and key in key_dict: + + action = key_dict[ key ] + + self.ProcessEvent( wx.CommandEvent( commandType = wx.wxEVT_COMMAND_MENU_SELECTED, winid = CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( action ) ) ) + + else: + + if event.KeyCode in ( ord( '+' ), wx.WXK_ADD, wx.WXK_NUMPAD_ADD ): self._ZoomIn() + elif event.KeyCode in ( ord( '-' ), wx.WXK_SUBTRACT, wx.WXK_NUMPAD_SUBTRACT ): self._ZoomOut() + elif event.KeyCode == ord( 'Z' ): self._ZoomSwitch() + else: self.GetParent().ProcessEvent( event ) + + + + def EventMenu( self, event ): + + if self._ShouldSkipInputDueToFlash(): event.Skip() + else: + + action = CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetAction( event.GetId() ) + + if action is not None: + + try: + + ( command, data ) = action + + if command == 'frame_back': self._ChangeFrame( -1 ) + elif command == 'frame_next': self._ChangeFrame( 1 ) + elif command == 'manage_ratings': self._ManageRatings() + elif command == 'manage_tags': self._ManageTags() + elif command == 'zoom_in': self._ZoomIn() + elif command == 'zoom_out': self._ZoomOut() + else: event.Skip() + + except Exception as e: + + wx.MessageBox( unicode( e ) ) + + + + + + def EventMouseWheel( self, event ): + + if self._ShouldSkipInputDueToFlash(): event.Skip() + else: + + if event.CmdDown(): + + if event.GetWheelRotation() > 0: self._ZoomIn() + else: self._ZoomOut() + + + + + def EventTimerMediaInfoDisplay( self, event ): self.SetCursor( wx.StockCursor( wx.CURSOR_BLANK ) ) + + def RefreshBackground( self ): self._DrawBackgroundBitmap() + + class Image( wx.Window ): def __init__( self, parent, media, image_cache, initial_size, initial_position ): diff --git a/include/ClientGUICommon.py b/include/ClientGUICommon.py index 2a4b29e9..10a649dd 100755 --- a/include/ClientGUICommon.py +++ b/include/ClientGUICommon.py @@ -83,14 +83,21 @@ class AutoCompleteDropdown( wx.TextCtrl ): wx.TextCtrl.__init__( self, parent, style=wx.TE_PROCESS_ENTER ) - self._dropdown_window = wx.PopupWindow( self, flags = wx.BORDER_RAISED ) + #self._dropdown_window = wx.PopupWindow( self, flags = wx.BORDER_RAISED ) + #self._dropdown_window = wx.PopupTransientWindow( self, style = wx.BORDER_RAISED ) + #self._dropdown_window = wx.Window( self, style = wx.BORDER_RAISED ) + + #self._dropdown_window = wx.Panel( self ) + + self._dropdown_window = wx.Frame( self.GetTopLevelParent(), style = wx.FRAME_TOOL_WINDOW | wx.FRAME_NO_TASKBAR | wx.FRAME_FLOAT_ON_PARENT | wx.BORDER_RAISED ) + self._dropdown_window.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) ) + self._dropdown_list = self._InitDropDownList() + self._first_letters = '' self._cached_results = self._InitCachedResults() - self._dropdown_list = self._InitDropDownList() - self.Bind( wx.EVT_SET_FOCUS, self.EventSetFocus ) self.Bind( wx.EVT_KILL_FOCUS, self.EventKillFocus ) @@ -112,7 +119,7 @@ class AutoCompleteDropdown( wx.TextCtrl ): tlp.Bind( wx.EVT_MOVE, self.EventMove ) - wx.CallAfter( self._UpdateList ) + self._initialised = False def _BroadcastChoice( self, predicate ): pass @@ -130,12 +137,10 @@ class AutoCompleteDropdown( wx.TextCtrl ): def _ShowDropdownIfFocussed( self ): - if self.GetTopLevelParent().IsActive() and wx.Window.FindFocus() == self and len( self._dropdown_list ) > 0: + if not self._dropdown_window.IsShown() and self.GetTopLevelParent().IsActive() and wx.Window.FindFocus() == self: ( my_width, my_height ) = self.GetSize() - #self._dropdown_list.Show() - self._dropdown_window.Fit() self._dropdown_window.SetSize( ( my_width, -1 ) ) @@ -174,7 +179,10 @@ class AutoCompleteDropdown( wx.TextCtrl ): def EventKillFocus( self, event ): - self._HideDropdown() + new_window = event.GetWindow() + + if new_window == self._dropdown_window or new_window in self._dropdown_window.GetChildren(): pass + else: self._HideDropdown() event.Skip() @@ -220,14 +228,10 @@ class AutoCompleteDropdown( wx.TextCtrl ): try: - self._HideDropdown() + try: self._HideDropdown() + except: pass - num_chars = len( self.GetValue() ) - - if num_chars == 0: lag = 0 - elif num_chars == 1: lag = 400 - elif num_chars == 2: lag = 250 - else: lag = 100 + lag = 100 self._move_hide_timer.Start( lag, wx.TIMER_ONE_SHOT ) @@ -238,6 +242,13 @@ class AutoCompleteDropdown( wx.TextCtrl ): def EventSetFocus( self, event ): + if not self._initialised: + + self._UpdateList() + + self._initialised = True + + self._ShowDropdownIfFocussed() event.Skip() @@ -390,29 +401,6 @@ class AutoCompleteDropdownTags( AutoCompleteDropdown ): def _InitDropDownList( self ): return TagsBoxActiveOnly( self._dropdown_window, self.BroadcastChoice ) - def _ShowDropdownIfFocussed( self ): - - # don't know why I have to do this fit and layout rubbish manually here; I guess it is popupwindow screwing up as usual - - if wx.Window.FindFocus() == self: - - ( my_width, my_height ) = self.GetSize() - - #if len( self._dropdown_list ) > 0: self._dropdown_list.Show() - #else: self._dropdown_list.Hide() - - self._dropdown_window.Fit() - - self._dropdown_window.SetSize( ( my_width, -1 ) ) - - self._dropdown_window.Layout() - - self._dropdown_window.SetPosition( self.ClientToScreenXY( -2, my_height - 2 ) ) - - self._dropdown_window.Show() - - - def _UpdateList( self ): matches = self._GenerateMatches() @@ -435,6 +423,8 @@ class AutoCompleteDropdownTags( AutoCompleteDropdown ): self.PopupMenu( menu ) + menu.Destroy() + def EventMenu( self, event ): @@ -505,6 +495,8 @@ class AutoCompleteDropdownTags( AutoCompleteDropdown ): self.PopupMenu( menu ) + menu.Destroy() + class AutoCompleteDropdownTagsRead( AutoCompleteDropdownTags ): @@ -830,7 +822,7 @@ class CheckboxCollect( wx.combo.ComboCtrl ): all_namespaces = list( all_namespaces ) all_namespaces.sort() - popup = CheckboxCollectDropdown( all_namespaces ) + popup = self._Popup( all_namespaces ) #self.UseAltPopupWindow( True ) @@ -861,72 +853,74 @@ class CheckboxCollect( wx.combo.ComboCtrl ): HC.pubsub.pub( 'collect_media', self._page_key, self._collect_by ) -class CheckboxCollectDropdown( wx.combo.ComboPopup ): - - def __init__( self, namespaces ): + class _Popup( wx.combo.ComboPopup ): - wx.combo.ComboPopup.__init__( self ) - - self._namespaces = namespaces - - - def Create( self, parent ): - - self._control = CheckboxCollectDropdownCheckListBox( parent, self.GetCombo(), self._namespaces ) - - return True - - - def GetAdjustedSize( self, preferred_width, preferred_height, max_height ): - - return( ( preferred_width, -1 ) ) - - - def GetControl( self ): return self._control - -class CheckboxCollectDropdownCheckListBox( wx.CheckListBox ): - - def __init__( self, parent, special_parent, namespaces ): - - wx.CheckListBox.__init__( self, parent, choices = namespaces ) - - self._special_parent = special_parent - - options = wx.GetApp().Read( 'options' ) - - default = options[ 'default_collect' ] # need to reset this to a list of a set in options! - - if default is not None: self.SetCheckedStrings( default ) - - self.Bind( wx.EVT_CHECKLISTBOX, self.EventChanged ) - - self.Bind( wx.EVT_LEFT_DOWN, self.EventLeftDown ) - - self.EventChanged( None ) - - - # as inspired by http://trac.wxwidgets.org/attachment/ticket/14413/test_clb_workaround.py - # what a clusterfuck - - def EventLeftDown( self, event ): - - index = self.HitTest( event.GetPosition() ) - - if index != wx.NOT_FOUND: + def __init__( self, namespaces ): - self.Check( index, not self.IsChecked( index ) ) + wx.combo.ComboPopup.__init__( self ) - self.EventChanged( event ) + self._namespaces = namespaces - event.Skip() + def Create( self, parent ): + + self._control = self._Control( parent, self.GetCombo(), self._namespaces ) + + return True + - - def EventChanged( self, event ): + def GetAdjustedSize( self, preferred_width, preferred_height, max_height ): + + return( ( preferred_width, -1 ) ) + - namespaces = self.GetCheckedStrings() + def GetControl( self ): return self._control - self._special_parent.SetNamespaces( namespaces ) + class _Control( wx.CheckListBox ): + + def __init__( self, parent, special_parent, namespaces ): + + wx.CheckListBox.__init__( self, parent, choices = namespaces ) + + self._special_parent = special_parent + + options = wx.GetApp().Read( 'options' ) + + default = options[ 'default_collect' ] # need to reset this to a list of a set in options! + + if default is not None: self.SetCheckedStrings( default ) + + self.Bind( wx.EVT_CHECKLISTBOX, self.EventChanged ) + + self.Bind( wx.EVT_LEFT_DOWN, self.EventLeftDown ) + + self.EventChanged( None ) + + + # as inspired by http://trac.wxwidgets.org/attachment/ticket/14413/test_clb_workaround.py + # what a clusterfuck + + def EventLeftDown( self, event ): + + index = self.HitTest( event.GetPosition() ) + + if index != wx.NOT_FOUND: + + self.Check( index, not self.IsChecked( index ) ) + + self.EventChanged( event ) + + + event.Skip() + + + def EventChanged( self, event ): + + namespaces = self.GetCheckedStrings() + + self._special_parent.SetNamespaces( namespaces ) + + class ChoiceCollect( BetterChoice ): @@ -1118,37 +1112,34 @@ class ListBook( wx.Panel ): def _Select( self, selection ): - with wx.FrozenWindow( self ): + if selection == wx.NOT_FOUND: self._current_name = None + else: self._current_name = self._list_box.GetString( selection ) + + self._current_panel.Hide() + + self._list_box.SetSelection( selection ) + + if selection == wx.NOT_FOUND: self._current_panel = self._empty_panel + else: - if selection == wx.NOT_FOUND: self._current_name = None - else: self._current_name = self._list_box.GetString( selection ) + panel_info = self._list_box.GetClientData( selection ) - self._current_panel.Hide() + if type( panel_info ) == tuple: + + ( classname, args, kwargs ) = panel_info + + page = classname( *args, **kwargs ) + + page.Hide() + + self._panel_sizer.AddF( page, FLAGS_EXPAND_SIZER_BOTH_WAYS ) + + self._list_box.SetClientData( selection, page ) + + self._RecalcListBoxWidth() + - self._list_box.SetSelection( selection ) - - if selection == wx.NOT_FOUND: self._current_panel = self._empty_panel - else: - - panel_info = self._list_box.GetClientData( selection ) - - if type( panel_info ) == tuple: - - ( classname, args, kwargs ) = panel_info - - page = classname( *args, **kwargs ) - - page.Hide() - - self._panel_sizer.AddF( page, FLAGS_EXPAND_SIZER_BOTH_WAYS ) - - self._list_box.SetClientData( selection, page ) - - self._RecalcListBoxWidth() - - - self._current_panel = self._list_box.GetClientData( selection ) - + self._current_panel = self._list_box.GetClientData( selection ) self._current_panel.Show() @@ -1363,165 +1354,6 @@ class ListCtrlAutoWidth( wx.ListCtrl, ListCtrlAutoWidthMixin ): for index in indices: self.DeleteItem( index ) -class OnOffButton( wx.Button ): - - def __init__( self, parent, page_key, topic, on_label, off_label = None, start_on = True ): - - if start_on: label = on_label - else: label = off_label - - wx.Button.__init__( self, parent, label = label ) - - self._page_key = page_key - self._topic = topic - self._on_label = on_label - - if off_label is None: self._off_label = on_label - else: self._off_label = off_label - - self._on = start_on - - if self._on: self.SetForegroundColour( ( 0, 128, 0 ) ) - else: self.SetForegroundColour( ( 128, 0, 0 ) ) - - self.Bind( wx.EVT_BUTTON, self.EventButton ) - - HC.pubsub.sub( self, 'HitButton', 'hit_on_off_button' ) - - - def EventButton( self, event ): - - if self._on: - - self._on = False - - self.SetLabel( self._off_label ) - - self.SetForegroundColour( ( 128, 0, 0 ) ) - - HC.pubsub.pub( self._topic, self._page_key, False ) - - else: - - self._on = True - - self.SetLabel( self._on_label ) - - self.SetForegroundColour( ( 0, 128, 0 ) ) - - HC.pubsub.pub( self._topic, self._page_key, True ) - - - - def IsOn( self ): return self._on - -class NoneableSpinCtrl( wx.Panel ): - - def __init__( self, parent, message, value, none_phrase = 'no limit', max = 1000000, multiplier = 1, num_dimensions = 1 ): - - wx.Panel.__init__( self, parent ) - - self._num_dimensions = num_dimensions - self._multiplier = multiplier - - self._checkbox = wx.CheckBox( self, label = none_phrase ) - self._checkbox.Bind( wx.EVT_CHECKBOX, self.EventCheckBox ) - - if value is None: - - self._one = wx.SpinCtrl( self, initial = 0, max = max, size = ( 80, -1 ) ) - self._one.Disable() - - if num_dimensions == 2: - - self._two = wx.SpinCtrl( self, initial = 0, max = max, size = ( 80, -1 ) ) - self._two.Disable() - - - self._checkbox.SetValue( True ) - - else: - - if num_dimensions == 2: - - ( value, value_2 ) = value - - self._two = wx.SpinCtrl( self, max = max, size = ( 80, -1 ) ) - self._two.SetValue( value_2 / multiplier ) - - - self._one = wx.SpinCtrl( self, max = max, size = ( 80, -1 ) ) - self._one.SetValue( value / multiplier ) - - self._checkbox.SetValue( False ) - - - hbox = wx.BoxSizer( wx.HORIZONTAL ) - hbox.AddF( wx.StaticText( self, label=message + ': ' ), FLAGS_MIXED ) - hbox.AddF( self._one, FLAGS_MIXED ) - - if self._num_dimensions == 2: - - hbox.AddF( wx.StaticText( self, label = 'x' ), FLAGS_MIXED ) - hbox.AddF( self._two, FLAGS_MIXED ) - - - hbox.AddF( self._checkbox, FLAGS_MIXED ) - - self.SetSizer( hbox ) - - - def EventCheckBox( self, event ): - - if self._checkbox.GetValue(): - - self._one.Disable() - if self._num_dimensions == 2: self._two.Disable() - - else: - - self._one.Enable() - if self._num_dimensions == 2: self._two.Enable() - - - - def GetValue( self ): - - if self._checkbox.GetValue(): return None - else: - - if self._num_dimensions == 2: return ( self._one.GetValue() * self._multiplier, self._two.GetValue() * self._multiplier ) - else: return self._one.GetValue() * self._multiplier - - - - def SetValue( self, value ): - - if value is None: - - self._checkbox.SetValue( True ) - - self._one.Disable() - if self._num_dimensions == 2: self._two.Disable() - - else: - - self._checkbox.SetValue( False ) - - self._one.Enable() - if self._num_dimensions == 2: self._two.Enable() - - if self._num_dimensions == 2: - - ( value, y ) = value - - self._two.SetValue( y / self._multiplier ) - - - self._one.SetValue( value / self._multiplier ) - - - class ListBox( wx.ScrolledWindow ): def __init__( self, parent, min_height = 250 ): @@ -1554,9 +1386,12 @@ class ListBox( wx.ScrolledWindow ): self.Bind( wx.EVT_LEFT_DOWN, self.EventMouseSelect ) self.Bind( wx.EVT_LEFT_DCLICK, self.EventDClick ) + self.Bind( wx.EVT_RIGHT_DOWN, self.EventMouseRightClick ) self.Bind( wx.EVT_KEY_DOWN, self.EventKeyDown ) + self.Bind( wx.EVT_MENU, self.EventMenu ) + def __len__( self ): return len( self._ordered_strings ) @@ -1707,6 +1542,61 @@ class ListBox( wx.ScrolledWindow ): else: event.Skip() + def EventMenu( self, event ): + + action = CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetAction( event.GetId() ) + + if action is not None: + + try: + + ( command, data ) = action + + if command == 'copy': HC.pubsub.pub( 'clipboard', 'text', data ) + else: + + event.Skip() + + return # this is about select_up and select_down + + + except Exception as e: + + wx.MessageBox( unicode( e ) ) + wx.MessageBox( traceback.format_exc() ) + + + + + def EventMouseRightClick( self, event ): + + index = self._GetIndexUnderMouse( event ) + + self._Select( index ) + + if self._current_selected_index is not None: + + menu = wx.Menu() + + term = self._strings_to_terms[ self._ordered_strings[ self._current_selected_index ] ] + + menu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'copy', term ), 'copy ' + term ) + + if ':' in term: + + sub_term = term.split( ':', 1 )[1] + + menu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'copy', sub_term ), 'copy ' + sub_term ) + + + self.PopupMenu( menu ) + + menu.Destroy() + + + event.Skip() + + def EventMouseSelect( self, event ): index = self._GetIndexUnderMouse( event ) @@ -1865,6 +1755,165 @@ class ListBoxMessagesPredicates( ListBoxMessages ): self._TextsHaveChanged() +class NoneableSpinCtrl( wx.Panel ): + + def __init__( self, parent, message, value, none_phrase = 'no limit', max = 1000000, multiplier = 1, num_dimensions = 1 ): + + wx.Panel.__init__( self, parent ) + + self._num_dimensions = num_dimensions + self._multiplier = multiplier + + self._checkbox = wx.CheckBox( self, label = none_phrase ) + self._checkbox.Bind( wx.EVT_CHECKBOX, self.EventCheckBox ) + + if value is None: + + self._one = wx.SpinCtrl( self, initial = 0, max = max, size = ( 80, -1 ) ) + self._one.Disable() + + if num_dimensions == 2: + + self._two = wx.SpinCtrl( self, initial = 0, max = max, size = ( 80, -1 ) ) + self._two.Disable() + + + self._checkbox.SetValue( True ) + + else: + + if num_dimensions == 2: + + ( value, value_2 ) = value + + self._two = wx.SpinCtrl( self, max = max, size = ( 80, -1 ) ) + self._two.SetValue( value_2 / multiplier ) + + + self._one = wx.SpinCtrl( self, max = max, size = ( 80, -1 ) ) + self._one.SetValue( value / multiplier ) + + self._checkbox.SetValue( False ) + + + hbox = wx.BoxSizer( wx.HORIZONTAL ) + hbox.AddF( wx.StaticText( self, label=message + ': ' ), FLAGS_MIXED ) + hbox.AddF( self._one, FLAGS_MIXED ) + + if self._num_dimensions == 2: + + hbox.AddF( wx.StaticText( self, label = 'x' ), FLAGS_MIXED ) + hbox.AddF( self._two, FLAGS_MIXED ) + + + hbox.AddF( self._checkbox, FLAGS_MIXED ) + + self.SetSizer( hbox ) + + + def EventCheckBox( self, event ): + + if self._checkbox.GetValue(): + + self._one.Disable() + if self._num_dimensions == 2: self._two.Disable() + + else: + + self._one.Enable() + if self._num_dimensions == 2: self._two.Enable() + + + + def GetValue( self ): + + if self._checkbox.GetValue(): return None + else: + + if self._num_dimensions == 2: return ( self._one.GetValue() * self._multiplier, self._two.GetValue() * self._multiplier ) + else: return self._one.GetValue() * self._multiplier + + + + def SetValue( self, value ): + + if value is None: + + self._checkbox.SetValue( True ) + + self._one.Disable() + if self._num_dimensions == 2: self._two.Disable() + + else: + + self._checkbox.SetValue( False ) + + self._one.Enable() + if self._num_dimensions == 2: self._two.Enable() + + if self._num_dimensions == 2: + + ( value, y ) = value + + self._two.SetValue( y / self._multiplier ) + + + self._one.SetValue( value / self._multiplier ) + + + +class OnOffButton( wx.Button ): + + def __init__( self, parent, page_key, topic, on_label, off_label = None, start_on = True ): + + if start_on: label = on_label + else: label = off_label + + wx.Button.__init__( self, parent, label = label ) + + self._page_key = page_key + self._topic = topic + self._on_label = on_label + + if off_label is None: self._off_label = on_label + else: self._off_label = off_label + + self._on = start_on + + if self._on: self.SetForegroundColour( ( 0, 128, 0 ) ) + else: self.SetForegroundColour( ( 128, 0, 0 ) ) + + self.Bind( wx.EVT_BUTTON, self.EventButton ) + + HC.pubsub.sub( self, 'HitButton', 'hit_on_off_button' ) + + + def EventButton( self, event ): + + if self._on: + + self._on = False + + self.SetLabel( self._off_label ) + + self.SetForegroundColour( ( 128, 0, 0 ) ) + + HC.pubsub.pub( self._topic, self._page_key, False ) + + else: + + self._on = True + + self.SetLabel( self._on_label ) + + self.SetForegroundColour( ( 0, 128, 0 ) ) + + HC.pubsub.pub( self._topic, self._page_key, True ) + + + + def IsOn( self ): return self._on + class SaneListCtrl( wx.ListCtrl, ListCtrlAutoWidthMixin, ColumnSorterMixin ): def __init__( self, parent, height, columns ): diff --git a/include/ClientGUIDialogs.py b/include/ClientGUIDialogs.py index 6e7e3f83..d17a0589 100755 --- a/include/ClientGUIDialogs.py +++ b/include/ClientGUIDialogs.py @@ -2142,7 +2142,7 @@ class DialogManageBoorus( Dialog ): name = booru.GetName() - page_info = ( DialogManageBoorusBooruPanel, ( self._boorus, booru ), {} ) + page_info = ( self._Panel, ( self._boorus, booru ), {} ) self._boorus.AddPage( page_info, name ) @@ -2217,7 +2217,7 @@ class DialogManageBoorus( Dialog ): self._edit_log.append( ( 'add', name ) ) - page = DialogManageBoorusBooruPanel( self._boorus, booru ) + page = self._Panel( self._boorus, booru ) self._boorus.AddPage( page, name, select = True ) @@ -2305,7 +2305,7 @@ class DialogManageBoorus( Dialog ): self._edit_log.append( ( 'add', name ) ) - page = DialogManageBoorusBooruPanel( self._boorus, new_booru ) + page = self._Panel( self._boorus, new_booru ) self._boorus.AddPage( page, name, select = True ) @@ -2322,51 +2322,251 @@ class DialogManageBoorus( Dialog ): -class DialogManageBoorusBooruPanel( wx.Panel ): - - def __init__( self, parent, booru ): + class _Panel( wx.Panel ): - wx.Panel.__init__( self, parent ) + def __init__( self, parent, booru ): + + wx.Panel.__init__( self, parent ) + + self._booru = booru + + ( search_url, search_separator, gallery_advance_num, thumb_classname, image_id, image_data, tag_classnames_to_namespaces ) = booru.GetData() + + def InitialiseControls(): + + self._booru_panel = ClientGUICommon.StaticBox( self, 'booru' ) + + # + + self._search_panel = ClientGUICommon.StaticBox( self._booru_panel, 'search' ) + + self._search_url = wx.TextCtrl( self._search_panel, value = search_url ) + self._search_url.Bind( wx.EVT_TEXT, self.EventHTML ) + + self._search_separator = wx.Choice( self._search_panel, choices = [ '+', '&', '%20' ] ) + self._search_separator.Select( self._search_separator.FindString( search_separator ) ) + self._search_separator.Bind( wx.EVT_CHOICE, self.EventHTML ) + + self._gallery_advance_num = wx.SpinCtrl( self._search_panel, min = 1, max = 1000, initial = gallery_advance_num ) + self._gallery_advance_num.Bind( wx.EVT_SPIN, self.EventHTML ) + + self._thumb_classname = wx.TextCtrl( self._search_panel, value = thumb_classname ) + self._thumb_classname.Bind( wx.EVT_TEXT, self.EventHTML ) + + self._example_html_search = wx.StaticText( self._search_panel, style = wx.ST_NO_AUTORESIZE ) + + # + + self._image_panel = ClientGUICommon.StaticBox( self._booru_panel, 'image' ) + + self._image_info = wx.TextCtrl( self._image_panel ) + self._image_info.Bind( wx.EVT_TEXT, self.EventHTML ) + + self._image_id = wx.RadioButton( self._image_panel, style = wx.RB_GROUP ) + self._image_id.Bind( wx.EVT_RADIOBUTTON, self.EventHTML ) + + self._image_data = wx.RadioButton( self._image_panel ) + self._image_data.Bind( wx.EVT_RADIOBUTTON, self.EventHTML ) + + if image_id is None: + + self._image_info.SetValue( image_data ) + self._image_data.SetValue( True ) + + else: + + self._image_info.SetValue( image_id ) + self._image_id.SetValue( True ) + + + self._example_html_image = wx.StaticText( self._image_panel, style = wx.ST_NO_AUTORESIZE ) + + # + + self._tag_panel = ClientGUICommon.StaticBox( self._booru_panel, 'tags' ) + + self._tag_classnames_to_namespaces = wx.ListBox( self._tag_panel, style = wx.LB_SORT ) + self._tag_classnames_to_namespaces.Bind( wx.EVT_LEFT_DCLICK, self.EventRemove ) + + for ( tag_classname, namespace ) in tag_classnames_to_namespaces.items(): self._tag_classnames_to_namespaces.Append( tag_classname + ' : ' + namespace, ( tag_classname, namespace ) ) + + self._tag_classname = wx.TextCtrl( self._tag_panel ) + self._namespace = wx.TextCtrl( self._tag_panel ) + + self._add = wx.Button( self._tag_panel, label = 'add' ) + self._add.Bind( wx.EVT_BUTTON, self.EventAdd ) + + self._example_html_tags = wx.StaticText( self._tag_panel, style = wx.ST_NO_AUTORESIZE ) + + + def InitialisePanel(): + + self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) ) + + gridbox = wx.FlexGridSizer( 0, 2 ) + + gridbox.AddGrowableCol( 1, 1 ) + + gridbox.AddF( wx.StaticText( self._search_panel, label='search url' ), FLAGS_MIXED ) + gridbox.AddF( self._search_url, FLAGS_EXPAND_BOTH_WAYS ) + gridbox.AddF( wx.StaticText( self._search_panel, label='search tag separator' ), FLAGS_MIXED ) + gridbox.AddF( self._search_separator, FLAGS_EXPAND_BOTH_WAYS ) + gridbox.AddF( wx.StaticText( self._search_panel, label='gallery page advance' ), FLAGS_MIXED ) + gridbox.AddF( self._gallery_advance_num, FLAGS_EXPAND_BOTH_WAYS ) + gridbox.AddF( wx.StaticText( self._search_panel, label='thumbnail classname' ), FLAGS_MIXED ) + gridbox.AddF( self._thumb_classname, FLAGS_EXPAND_BOTH_WAYS ) + + self._search_panel.AddF( gridbox, FLAGS_EXPAND_SIZER_PERPENDICULAR ) + self._search_panel.AddF( self._example_html_search, FLAGS_EXPAND_PERPENDICULAR ) + + # + + gridbox = wx.FlexGridSizer( 0, 2 ) + + gridbox.AddGrowableCol( 1, 1 ) + + gridbox.AddF( wx.StaticText( self._image_panel, label='text' ), FLAGS_MIXED ) + gridbox.AddF( self._image_info, FLAGS_EXPAND_BOTH_WAYS ) + gridbox.AddF( wx.StaticText( self._image_panel, label='id of ' ), FLAGS_MIXED ) + gridbox.AddF( self._image_id, FLAGS_EXPAND_BOTH_WAYS ) + gridbox.AddF( wx.StaticText( self._image_panel, label='text of ' ), FLAGS_MIXED ) + gridbox.AddF( self._image_data, FLAGS_EXPAND_BOTH_WAYS ) + + self._image_panel.AddF( gridbox, FLAGS_EXPAND_SIZER_PERPENDICULAR ) + self._image_panel.AddF( self._example_html_image, FLAGS_EXPAND_PERPENDICULAR ) + + # + + hbox = wx.BoxSizer( wx.HORIZONTAL ) + + hbox.AddF( self._tag_classname, FLAGS_MIXED ) + hbox.AddF( self._namespace, FLAGS_MIXED ) + hbox.AddF( self._add, FLAGS_MIXED ) + + self._tag_panel.AddF( self._tag_classnames_to_namespaces, FLAGS_EXPAND_BOTH_WAYS ) + self._tag_panel.AddF( hbox, FLAGS_EXPAND_SIZER_PERPENDICULAR ) + self._tag_panel.AddF( self._example_html_tags, FLAGS_EXPAND_PERPENDICULAR ) + + # + + self._booru_panel.AddF( self._search_panel, FLAGS_EXPAND_PERPENDICULAR ) + self._booru_panel.AddF( self._image_panel, FLAGS_EXPAND_PERPENDICULAR ) + self._booru_panel.AddF( self._tag_panel, FLAGS_EXPAND_BOTH_WAYS ) + + vbox = wx.BoxSizer( wx.VERTICAL ) + + vbox.AddF( self._booru_panel, FLAGS_EXPAND_BOTH_WAYS ) + + self.SetSizer( vbox ) + + + InitialiseControls() + + InitialisePanel() + - self._booru = booru + def _GetInfo( self ): + + booru_name = self._booru.GetName() + + search_url = self._search_url.GetValue() + + search_separator = self._search_separator.GetStringSelection() + + gallery_advance_num = self._gallery_advance_num.GetValue() + + thumb_classname = self._thumb_classname.GetValue() + + if self._image_id.GetValue(): + + image_id = self._image_info.GetValue() + image_data = None + + else: + + image_id = None + image_data = self._image_info.GetValue() + + + tag_classnames_to_namespaces = { tag_classname : namespace for ( tag_classname, namespace ) in [ self._tag_classnames_to_namespaces.GetClientData( i ) for i in range( self._tag_classnames_to_namespaces.GetCount() ) ] } + + return ( booru_name, search_url, search_separator, gallery_advance_num, thumb_classname, image_id, image_data, tag_classnames_to_namespaces ) + - ( search_url, search_separator, gallery_advance_num, thumb_classname, image_id, image_data, tag_classnames_to_namespaces ) = booru.GetData() + def EventAdd( self, event ): + + tag_classname = self._tag_classname.GetValue() + namespace = self._namespace.GetValue() + + if tag_classname != '': + + self._tag_classnames_to_namespaces.Append( tag_classname + ' : ' + namespace, ( tag_classname, namespace ) ) + + self._tag_classname.SetValue( '' ) + self._namespace.SetValue( '' ) + + self.EventHTML( event ) + + - def InitialiseControls(): + def EventHTML( self, event ): - self._booru_panel = ClientGUICommon.StaticBox( self, 'booru' ) + pass - # + + def EventRemove( self, event ): - self._search_panel = ClientGUICommon.StaticBox( self._booru_panel, 'search' ) + selection = self._tag_classnames_to_namespaces.GetSelection() - self._search_url = wx.TextCtrl( self._search_panel, value = search_url ) - self._search_url.Bind( wx.EVT_TEXT, self.EventHTML ) + if selection != wx.NOT_FOUND: + + self._tag_classnames_to_namespaces.Delete( selection ) + + self.EventHTML( event ) + + + + def GetBooru( self ): + + ( booru_name, search_url, search_separator, gallery_advance_num, thumb_classname, image_id, image_data, tag_classnames_to_namespaces ) = self._GetInfo() + + return CC.Booru( booru_name, search_url, search_separator, gallery_advance_num, thumb_classname, image_id, image_data, tag_classnames_to_namespaces ) + + + def HasChanges( self ): + + ( booru_name, my_search_url, my_search_separator, my_gallery_advance_num, my_thumb_classname, my_image_id, my_image_data, my_tag_classnames_to_namespaces ) = self._GetInfo() + + ( search_url, search_separator, gallery_advance_num, thumb_classname, image_id, image_data, tag_classnames_to_namespaces ) = self._booru.GetData() + + if search_url != my_search_url: return True + + if search_separator != my_search_separator: return True + + if gallery_advance_num != my_gallery_advance_num: return True + + if thumb_classname != my_thumb_classname: return True + + if image_id != my_image_id: return True + + if image_data != my_image_data: return True + + if tag_classnames_to_namespaces != my_tag_classnames_to_namespaces: return True + + return False + + + def Update( self, booru ): + + ( search_url, search_separator, gallery_advance_num, thumb_classname, image_id, image_data, tag_classnames_to_namespaces ) = booru.GetData() + + self._search_url.SetValue( search_url ) - self._search_separator = wx.Choice( self._search_panel, choices = [ '+', '&', '%20' ] ) self._search_separator.Select( self._search_separator.FindString( search_separator ) ) - self._search_separator.Bind( wx.EVT_CHOICE, self.EventHTML ) - self._gallery_advance_num = wx.SpinCtrl( self._search_panel, min = 1, max = 1000, initial = gallery_advance_num ) - self._gallery_advance_num.Bind( wx.EVT_SPIN, self.EventHTML ) + self._gallery_advance_num.SetValue( gallery_advance_num ) - self._thumb_classname = wx.TextCtrl( self._search_panel, value = thumb_classname ) - self._thumb_classname.Bind( wx.EVT_TEXT, self.EventHTML ) - - self._example_html_search = wx.StaticText( self._search_panel, style = wx.ST_NO_AUTORESIZE ) - - # - - self._image_panel = ClientGUICommon.StaticBox( self._booru_panel, 'image' ) - - self._image_info = wx.TextCtrl( self._image_panel ) - self._image_info.Bind( wx.EVT_TEXT, self.EventHTML ) - - self._image_id = wx.RadioButton( self._image_panel, style = wx.RB_GROUP ) - self._image_id.Bind( wx.EVT_RADIOBUTTON, self.EventHTML ) - - self._image_data = wx.RadioButton( self._image_panel ) - self._image_data.Bind( wx.EVT_RADIOBUTTON, self.EventHTML ) + self._thumb_classname.SetValue( thumb_classname ) if image_id is None: @@ -2379,209 +2579,10 @@ class DialogManageBoorusBooruPanel( wx.Panel ): self._image_id.SetValue( True ) - self._example_html_image = wx.StaticText( self._image_panel, style = wx.ST_NO_AUTORESIZE ) - - # - - self._tag_panel = ClientGUICommon.StaticBox( self._booru_panel, 'tags' ) - - self._tag_classnames_to_namespaces = wx.ListBox( self._tag_panel, style = wx.LB_SORT ) - self._tag_classnames_to_namespaces.Bind( wx.EVT_LEFT_DCLICK, self.EventRemove ) + self._tag_classnames_to_namespaces.Clear() for ( tag_classname, namespace ) in tag_classnames_to_namespaces.items(): self._tag_classnames_to_namespaces.Append( tag_classname + ' : ' + namespace, ( tag_classname, namespace ) ) - self._tag_classname = wx.TextCtrl( self._tag_panel ) - self._namespace = wx.TextCtrl( self._tag_panel ) - - self._add = wx.Button( self._tag_panel, label = 'add' ) - self._add.Bind( wx.EVT_BUTTON, self.EventAdd ) - - self._example_html_tags = wx.StaticText( self._tag_panel, style = wx.ST_NO_AUTORESIZE ) - - - def InitialisePanel(): - - self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) ) - - gridbox = wx.FlexGridSizer( 0, 2 ) - - gridbox.AddGrowableCol( 1, 1 ) - - gridbox.AddF( wx.StaticText( self._search_panel, label='search url' ), FLAGS_MIXED ) - gridbox.AddF( self._search_url, FLAGS_EXPAND_BOTH_WAYS ) - gridbox.AddF( wx.StaticText( self._search_panel, label='search tag separator' ), FLAGS_MIXED ) - gridbox.AddF( self._search_separator, FLAGS_EXPAND_BOTH_WAYS ) - gridbox.AddF( wx.StaticText( self._search_panel, label='gallery page advance' ), FLAGS_MIXED ) - gridbox.AddF( self._gallery_advance_num, FLAGS_EXPAND_BOTH_WAYS ) - gridbox.AddF( wx.StaticText( self._search_panel, label='thumbnail classname' ), FLAGS_MIXED ) - gridbox.AddF( self._thumb_classname, FLAGS_EXPAND_BOTH_WAYS ) - - self._search_panel.AddF( gridbox, FLAGS_EXPAND_SIZER_PERPENDICULAR ) - self._search_panel.AddF( self._example_html_search, FLAGS_EXPAND_PERPENDICULAR ) - - # - - gridbox = wx.FlexGridSizer( 0, 2 ) - - gridbox.AddGrowableCol( 1, 1 ) - - gridbox.AddF( wx.StaticText( self._image_panel, label='text' ), FLAGS_MIXED ) - gridbox.AddF( self._image_info, FLAGS_EXPAND_BOTH_WAYS ) - gridbox.AddF( wx.StaticText( self._image_panel, label='id of ' ), FLAGS_MIXED ) - gridbox.AddF( self._image_id, FLAGS_EXPAND_BOTH_WAYS ) - gridbox.AddF( wx.StaticText( self._image_panel, label='text of ' ), FLAGS_MIXED ) - gridbox.AddF( self._image_data, FLAGS_EXPAND_BOTH_WAYS ) - - self._image_panel.AddF( gridbox, FLAGS_EXPAND_SIZER_PERPENDICULAR ) - self._image_panel.AddF( self._example_html_image, FLAGS_EXPAND_PERPENDICULAR ) - - # - - hbox = wx.BoxSizer( wx.HORIZONTAL ) - - hbox.AddF( self._tag_classname, FLAGS_MIXED ) - hbox.AddF( self._namespace, FLAGS_MIXED ) - hbox.AddF( self._add, FLAGS_MIXED ) - - self._tag_panel.AddF( self._tag_classnames_to_namespaces, FLAGS_EXPAND_BOTH_WAYS ) - self._tag_panel.AddF( hbox, FLAGS_EXPAND_SIZER_PERPENDICULAR ) - self._tag_panel.AddF( self._example_html_tags, FLAGS_EXPAND_PERPENDICULAR ) - - # - - self._booru_panel.AddF( self._search_panel, FLAGS_EXPAND_PERPENDICULAR ) - self._booru_panel.AddF( self._image_panel, FLAGS_EXPAND_PERPENDICULAR ) - self._booru_panel.AddF( self._tag_panel, FLAGS_EXPAND_BOTH_WAYS ) - - vbox = wx.BoxSizer( wx.VERTICAL ) - - vbox.AddF( self._booru_panel, FLAGS_EXPAND_BOTH_WAYS ) - - self.SetSizer( vbox ) - - - InitialiseControls() - - InitialisePanel() - - - def _GetInfo( self ): - - booru_name = self._booru.GetName() - - search_url = self._search_url.GetValue() - - search_separator = self._search_separator.GetStringSelection() - - gallery_advance_num = self._gallery_advance_num.GetValue() - - thumb_classname = self._thumb_classname.GetValue() - - if self._image_id.GetValue(): - - image_id = self._image_info.GetValue() - image_data = None - - else: - - image_id = None - image_data = self._image_info.GetValue() - - - tag_classnames_to_namespaces = { tag_classname : namespace for ( tag_classname, namespace ) in [ self._tag_classnames_to_namespaces.GetClientData( i ) for i in range( self._tag_classnames_to_namespaces.GetCount() ) ] } - - return ( booru_name, search_url, search_separator, gallery_advance_num, thumb_classname, image_id, image_data, tag_classnames_to_namespaces ) - - - def EventAdd( self, event ): - - tag_classname = self._tag_classname.GetValue() - namespace = self._namespace.GetValue() - - if tag_classname != '': - - self._tag_classnames_to_namespaces.Append( tag_classname + ' : ' + namespace, ( tag_classname, namespace ) ) - - self._tag_classname.SetValue( '' ) - self._namespace.SetValue( '' ) - - self.EventHTML( event ) - - - - def EventHTML( self, event ): - - pass - - - def EventRemove( self, event ): - - selection = self._tag_classnames_to_namespaces.GetSelection() - - if selection != wx.NOT_FOUND: - - self._tag_classnames_to_namespaces.Delete( selection ) - - self.EventHTML( event ) - - - - def GetBooru( self ): - - ( booru_name, search_url, search_separator, gallery_advance_num, thumb_classname, image_id, image_data, tag_classnames_to_namespaces ) = self._GetInfo() - - return CC.Booru( booru_name, search_url, search_separator, gallery_advance_num, thumb_classname, image_id, image_data, tag_classnames_to_namespaces ) - - - def HasChanges( self ): - - ( booru_name, my_search_url, my_search_separator, my_gallery_advance_num, my_thumb_classname, my_image_id, my_image_data, my_tag_classnames_to_namespaces ) = self._GetInfo() - - ( search_url, search_separator, gallery_advance_num, thumb_classname, image_id, image_data, tag_classnames_to_namespaces ) = self._booru.GetData() - - if search_url != my_search_url: return True - - if search_separator != my_search_separator: return True - - if gallery_advance_num != my_gallery_advance_num: return True - - if thumb_classname != my_thumb_classname: return True - - if image_id != my_image_id: return True - - if image_data != my_image_data: return True - - if tag_classnames_to_namespaces != my_tag_classnames_to_namespaces: return True - - return False - - - def Update( self, booru ): - - ( search_url, search_separator, gallery_advance_num, thumb_classname, image_id, image_data, tag_classnames_to_namespaces ) = booru.GetData() - - self._search_url.SetValue( search_url ) - - self._search_separator.Select( self._search_separator.FindString( search_separator ) ) - - self._gallery_advance_num.SetValue( gallery_advance_num ) - - self._thumb_classname.SetValue( thumb_classname ) - - if image_id is None: - - self._image_info.SetValue( image_data ) - self._image_data.SetValue( True ) - - else: - - self._image_info.SetValue( image_id ) - self._image_id.SetValue( True ) - - - self._tag_classnames_to_namespaces.Clear() - - for ( tag_classname, namespace ) in tag_classnames_to_namespaces.items(): self._tag_classnames_to_namespaces.Append( tag_classname + ' : ' + namespace, ( tag_classname, namespace ) ) class DialogManageContacts( Dialog ): @@ -2602,7 +2603,7 @@ class DialogManageContacts( Dialog ): name = identity.GetName() - page_info = ( DialogManageContactsContactPanel, ( self._contacts, identity ), { 'is_identity' : True } ) + page_info = ( self._Panel, ( self._contacts, identity ), { 'is_identity' : True } ) self._contacts.AddPage( page_info, ' identity - ' + name ) @@ -2611,7 +2612,7 @@ class DialogManageContacts( Dialog ): name = contact.GetName() - page_info = ( DialogManageContactsContactPanel, ( self._contacts, contact ), { 'is_identity' : False } ) + page_info = ( self._Panel, ( self._contacts, contact ), { 'is_identity' : False } ) self._contacts.AddPage( page_info, name ) @@ -2746,7 +2747,7 @@ class DialogManageContacts( Dialog ): self._edit_log.append( ( 'add', contact ) ) - page = DialogManageContactsContactPanel( self._contacts, contact, is_identity = False ) + page = self._Panel( self._contacts, contact, is_identity = False ) self._deletable_names.add( name ) @@ -2792,7 +2793,7 @@ class DialogManageContacts( Dialog ): self._edit_log.append( ( 'add', contact ) ) - page = DialogManageContactsContactPanel( self._contacts, contact, is_identity = False ) + page = self._Panel( self._contacts, contact, is_identity = False ) self._deletable_names.add( name ) @@ -2959,7 +2960,7 @@ class DialogManageContacts( Dialog ): self._deletable_names.add( name ) - page = DialogManageContactsContactPanel( self._contacts, contact, False ) + page = self._Panel( self._contacts, contact, False ) self._contacts.AddPage( page, name, select = True ) @@ -2975,7 +2976,7 @@ class DialogManageContacts( Dialog ): self._deletable_names.add( name ) - page = DialogManageContactsContactPanel( self._contacts, contact, False ) + page = self._Panel( self._contacts, contact, False ) self._contacts.AddPage( page, name, select = True ) @@ -2988,145 +2989,146 @@ class DialogManageContacts( Dialog ): -class DialogManageContactsContactPanel( wx.Panel ): - - def __init__( self, parent, contact, is_identity ): + class _Panel( wx.Panel ): - wx.Panel.__init__( self, parent ) - - self._contact = contact - self._is_identity = is_identity - - ( public_key, name, host, port ) = contact.GetInfo() - - contact_key = contact.GetContactKey() - - def InitialiseControls(): + def __init__( self, parent, contact, is_identity ): - self._contact_panel = ClientGUICommon.StaticBox( self, 'contact' ) + wx.Panel.__init__( self, parent ) - self._name = wx.TextCtrl( self._contact_panel, value = name ) + self._contact = contact + self._is_identity = is_identity + + ( public_key, name, host, port ) = contact.GetInfo() + + contact_key = contact.GetContactKey() + + def InitialiseControls(): + + self._contact_panel = ClientGUICommon.StaticBox( self, 'contact' ) + + self._name = wx.TextCtrl( self._contact_panel, value = name ) + + contact_address = host + ':' + str( port ) + + if contact_key is not None: contact_address = contact_key.encode( 'hex' ) + '@' + contact_address + + self._contact_address = wx.TextCtrl( self._contact_panel, value = contact_address ) + + self._public_key = wx.TextCtrl( self._contact_panel, style = wx.TE_MULTILINE ) + + if public_key is not None: self._public_key.SetValue( public_key ) + + + def InitialisePanel(): + + self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) ) + + gridbox = wx.FlexGridSizer( 0, 2 ) + + gridbox.AddGrowableCol( 1, 1 ) + + gridbox.AddF( wx.StaticText( self._contact_panel, label='name' ), FLAGS_MIXED ) + gridbox.AddF( self._name, FLAGS_EXPAND_BOTH_WAYS ) + gridbox.AddF( wx.StaticText( self._contact_panel, label='contact address' ), FLAGS_MIXED ) + gridbox.AddF( self._contact_address, FLAGS_EXPAND_BOTH_WAYS ) + gridbox.AddF( wx.StaticText( self._contact_panel, label = 'public key' ), FLAGS_MIXED ) + gridbox.AddF( self._public_key, FLAGS_EXPAND_BOTH_WAYS ) + + self._contact_panel.AddF( gridbox, FLAGS_EXPAND_SIZER_PERPENDICULAR ) + + vbox = wx.BoxSizer( wx.VERTICAL ) + + vbox.AddF( self._contact_panel, FLAGS_EXPAND_BOTH_WAYS ) + + self.SetSizer( vbox ) + + + InitialiseControls() + + InitialisePanel() + + + def _GetInfo( self ): + + public_key = self._public_key.GetValue() + + if public_key == '': public_key = None + + name = self._name.GetValue() + + contact_address = self._contact_address.GetValue() + + try: + + if '@' in contact_address: ( contact_key, address ) = contact_address.split( '@' ) + else: address = contact_address + + ( host, port ) = address.split( ':' ) + + try: port = int( port ) + except: + + port = 45871 + + wx.MessageBox( 'Could not parse the port!' ) + + + except: + + host = 'hostname' + port = 45871 + + wx.MessageBox( 'Could not parse the contact\'s address!' ) + + + return [ public_key, name, host, port ] + + + def GetContact( self ): + + [ public_key, name, host, port ] = self._GetInfo() + + return ClientConstantsMessages.Contact( public_key, name, host, port ) + + + def GetOriginalName( self ): return self._contact.GetName() + + def HasChanges( self ): + + [ my_public_key, my_name, my_host, my_port ] = self._GetInfo() + + [ public_key, name, host, port ] = self._contact.GetInfo() + + if my_public_key != public_key: return True + + if my_name != name: return True + + if my_host != host: return True + + if my_port != port: return True + + return False + + + def Update( self, contact ): + + ( public_key, name, host, port ) = contact.GetInfo() + + contact_key = contact.GetContactKey() + + self._name.SetValue( name ) contact_address = host + ':' + str( port ) if contact_key is not None: contact_address = contact_key.encode( 'hex' ) + '@' + contact_address - self._contact_address = wx.TextCtrl( self._contact_panel, value = contact_address ) + self._contact_address.SetValue( contact_address ) - self._public_key = wx.TextCtrl( self._contact_panel, style = wx.TE_MULTILINE ) + if public_key is None: public_key = '' - if public_key is not None: self._public_key.SetValue( public_key ) + self._public_key.SetValue( public_key ) - def InitialisePanel(): - - self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) ) - - gridbox = wx.FlexGridSizer( 0, 2 ) - - gridbox.AddGrowableCol( 1, 1 ) - - gridbox.AddF( wx.StaticText( self._contact_panel, label='name' ), FLAGS_MIXED ) - gridbox.AddF( self._name, FLAGS_EXPAND_BOTH_WAYS ) - gridbox.AddF( wx.StaticText( self._contact_panel, label='contact address' ), FLAGS_MIXED ) - gridbox.AddF( self._contact_address, FLAGS_EXPAND_BOTH_WAYS ) - gridbox.AddF( wx.StaticText( self._contact_panel, label = 'public key' ), FLAGS_MIXED ) - gridbox.AddF( self._public_key, FLAGS_EXPAND_BOTH_WAYS ) - - self._contact_panel.AddF( gridbox, FLAGS_EXPAND_SIZER_PERPENDICULAR ) - - vbox = wx.BoxSizer( wx.VERTICAL ) - - vbox.AddF( self._contact_panel, FLAGS_EXPAND_BOTH_WAYS ) - - self.SetSizer( vbox ) - - - InitialiseControls() - - InitialisePanel() - - - def _GetInfo( self ): - - public_key = self._public_key.GetValue() - - if public_key == '': public_key = None - - name = self._name.GetValue() - - contact_address = self._contact_address.GetValue() - - try: - - if '@' in contact_address: ( contact_key, address ) = contact_address.split( '@' ) - else: address = contact_address - - ( host, port ) = address.split( ':' ) - - try: port = int( port ) - except: - - port = 45871 - - wx.MessageBox( 'Could not parse the port!' ) - - - except: - - host = 'hostname' - port = 45871 - - wx.MessageBox( 'Could not parse the contact\'s address!' ) - - - return [ public_key, name, host, port ] - - - def GetContact( self ): - - [ public_key, name, host, port ] = self._GetInfo() - - return ClientConstantsMessages.Contact( public_key, name, host, port ) - - - def GetOriginalName( self ): return self._contact.GetName() - - def HasChanges( self ): - - [ my_public_key, my_name, my_host, my_port ] = self._GetInfo() - - [ public_key, name, host, port ] = self._contact.GetInfo() - - if my_public_key != public_key: return True - - if my_name != name: return True - - if my_host != host: return True - - if my_port != port: return True - - return False - - - def Update( self, contact ): - - ( public_key, name, host, port ) = contact.GetInfo() - - contact_key = contact.GetContactKey() - - self._name.SetValue( name ) - - contact_address = host + ':' + str( port ) - - if contact_key is not None: contact_address = contact_key.encode( 'hex' ) + '@' + contact_address - - self._contact_address.SetValue( contact_address ) - - if public_key is None: public_key = '' - - self._public_key.SetValue( public_key ) - class DialogManage4chanPass( Dialog ): @@ -3262,7 +3264,7 @@ class DialogManageImageboards( Dialog ): for ( name, imageboards ) in sites: - page_info = ( DialogManageImageboardsSitePanel, ( self._sites, imageboards ), {} ) + page_info = ( self._Panel, ( self._sites, imageboards ), {} ) self._sites.AddPage( page_info, name ) @@ -3335,7 +3337,7 @@ class DialogManageImageboards( Dialog ): self._edit_log.append( ( 'add', name ) ) - page = DialogManageImageboardsSitePanel( self._sites, [] ) + page = self._Panel( self._sites, [] ) self._sites.AddPage( page, name, select = True ) @@ -3421,7 +3423,7 @@ class DialogManageImageboards( Dialog ): self._edit_log.append( ( 'add', name ) ) - page = DialogManageImageboardsSitePanel( self._sites, [] ) + page = self._Panel( self._sites, [] ) self._sites.AddPage( page, name, select = True ) @@ -3449,489 +3451,491 @@ class DialogManageImageboards( Dialog ): -class DialogManageImageboardsSitePanel( wx.Panel ): - - def __init__( self, parent, imageboards ): + class _Panel( wx.Panel ): - wx.Panel.__init__( self, parent ) - - def InitialiseControls(): + def __init__( self, parent, imageboards ): - self._edit_log = [] + wx.Panel.__init__( self, parent ) - self._site_panel = ClientGUICommon.StaticBox( self, 'site' ) - - self._imageboards = ClientGUICommon.ListBook( self._site_panel ) - - for imageboard in imageboards: + def InitialiseControls(): - name = imageboard.GetName() + self._edit_log = [] - page_info = ( DialogManageImageboardsImageboardPanel, ( self._imageboards, imageboard ), {} ) + self._site_panel = ClientGUICommon.StaticBox( self, 'site' ) - self._imageboards.AddPage( page_info, name ) + self._imageboards = ClientGUICommon.ListBook( self._site_panel ) - - self._add = wx.Button( self._site_panel, label='add' ) - self._add.Bind( wx.EVT_BUTTON, self.EventAdd ) - self._add.SetForegroundColour( ( 0, 128, 0 ) ) - - self._remove = wx.Button( self._site_panel, label='remove' ) - self._remove.Bind( wx.EVT_BUTTON, self.EventRemove ) - self._remove.SetForegroundColour( ( 128, 0, 0 ) ) - - self._export = wx.Button( self._site_panel, label='export' ) - self._export.Bind( wx.EVT_BUTTON, self.EventExport ) - - - def InitialisePanel(): - - add_remove_hbox = wx.BoxSizer( wx.HORIZONTAL ) - add_remove_hbox.AddF( self._add, FLAGS_MIXED ) - add_remove_hbox.AddF( self._remove, FLAGS_MIXED ) - add_remove_hbox.AddF( self._export, FLAGS_MIXED ) - - self._site_panel.AddF( self._imageboards, FLAGS_EXPAND_BOTH_WAYS ) - self._site_panel.AddF( add_remove_hbox, FLAGS_SMALL_INDENT ) - - vbox = wx.BoxSizer( wx.VERTICAL ) - - vbox.AddF( self._site_panel, FLAGS_EXPAND_BOTH_WAYS ) - - self.SetSizer( vbox ) - - ( x, y ) = self.GetEffectiveMinSize() - - self.SetInitialSize( ( 980, y ) ) - - - InitialiseControls() - - InitialisePanel() - - - def EventAdd( self, event ): - - with wx.TextEntryDialog( self, 'Enter new imageboard\'s name' ) as dlg: - - if dlg.ShowModal() == wx.ID_OK: - - try: + for imageboard in imageboards: - name = dlg.GetValue() + name = imageboard.GetName() - if self._imageboards.NameExists( name ): raise Exception( 'That name is already in use!' ) + page_info = ( self._Panel, ( self._imageboards, imageboard ), {} ) - if name == '': raise Exception( 'Please enter a nickname for the service.' ) - - imageboard = CC.Imageboard( name, '', 60, [], {} ) - - self._edit_log.append( ( 'add', name ) ) - - page = DialogManageImageboardsImageboardPanel( self._imageboards, imageboard ) - - self._imageboards.AddPage( page, name, select = True ) - - except Exception as e: - - wx.MessageBox( unicode( e ) ) - - self.EventAdd( event ) + self._imageboards.AddPage( page_info, name ) + self._add = wx.Button( self._site_panel, label='add' ) + self._add.Bind( wx.EVT_BUTTON, self.EventAdd ) + self._add.SetForegroundColour( ( 0, 128, 0 ) ) + + self._remove = wx.Button( self._site_panel, label='remove' ) + self._remove.Bind( wx.EVT_BUTTON, self.EventRemove ) + self._remove.SetForegroundColour( ( 128, 0, 0 ) ) + + self._export = wx.Button( self._site_panel, label='export' ) + self._export.Bind( wx.EVT_BUTTON, self.EventExport ) + + + def InitialisePanel(): + + add_remove_hbox = wx.BoxSizer( wx.HORIZONTAL ) + add_remove_hbox.AddF( self._add, FLAGS_MIXED ) + add_remove_hbox.AddF( self._remove, FLAGS_MIXED ) + add_remove_hbox.AddF( self._export, FLAGS_MIXED ) + + self._site_panel.AddF( self._imageboards, FLAGS_EXPAND_BOTH_WAYS ) + self._site_panel.AddF( add_remove_hbox, FLAGS_SMALL_INDENT ) + + vbox = wx.BoxSizer( wx.VERTICAL ) + + vbox.AddF( self._site_panel, FLAGS_EXPAND_BOTH_WAYS ) + + self.SetSizer( vbox ) + + ( x, y ) = self.GetEffectiveMinSize() + + self.SetInitialSize( ( 980, y ) ) + + + InitialiseControls() + + InitialisePanel() - - def EventExport( self, event ): - - imageboard_panel = self._imageboards.GetCurrentPage() - - if imageboard_panel is not None: + def EventAdd( self, event ): - imageboard = imageboard_panel.GetImageboard() - - with wx.FileDialog( self, 'select where to export imageboard', defaultFile = 'imageboard.yaml', style = wx.FD_SAVE ) as dlg: + with wx.TextEntryDialog( self, 'Enter new imageboard\'s name' ) as dlg: if dlg.ShowModal() == wx.ID_OK: - with open( dlg.GetPath(), 'wb' ) as f: f.write( yaml.safe_dump( imageboard ) ) - - - - - - def EventRemove( self, event ): - - imageboard_panel = self._imageboards.GetCurrentPage() - - if imageboard_panel is not None: - - name = self._imageboards.GetCurrentName() - - self._edit_log.append( ( 'delete', name ) ) - - self._imageboards.DeleteCurrentPage() - - - - def GetChanges( self ): - - for page in self._imageboards.GetNameToPageDict().values(): - - if page.HasChanges(): self._edit_log.append( ( 'edit', page.GetImageboard() ) ) - - - return self._edit_log - - - def GetImageboards( self ): return [ page.GetImageboard() for page in self._imageboards.GetNameToPageDict().values() ] - - def HasChanges( self ): return len( self._edit_log ) > 0 or True in ( page.HasChanges() for page in self._imageboards.GetNameToPageDict().values() ) - - def UpdateImageboard( self, imageboard ): - - name = imageboard.GetName() - - if not self._imageboards.NameExists( name ): - - new_imageboard = CC.Imageboard( name, '', 60, [], {} ) - - self._edit_log.append( ( 'add', name ) ) - - page = DialogManageImageboardsImageboardPanel( self._imageboards, new_imageboard ) - - self._imageboards.AddPage( page, name, select = True ) - - - page = self._imageboards.GetNameToPageDict()[ name ] - - page.Update( imageboard ) - - -class DialogManageImageboardsImageboardPanel( wx.Panel ): - - def __init__( self, parent, imageboard ): - - wx.Panel.__init__( self, parent ) - - self._imageboard = imageboard - - ( post_url, flood_time, form_fields, restrictions ) = self._imageboard.GetBoardInfo() - - def InitialiseControls(): - - self._imageboard_panel = ClientGUICommon.StaticBox( self, 'imageboard' ) - - # - - self._basic_info_panel = ClientGUICommon.StaticBox( self._imageboard_panel, 'basic info' ) - - self._post_url = wx.TextCtrl( self._basic_info_panel, value = post_url ) - - self._flood_time = wx.SpinCtrl( self._basic_info_panel, min = 5, max = 1200, initial = flood_time ) - - # - - self._form_fields_panel = ClientGUICommon.StaticBox( self._imageboard_panel, 'form fields' ) - - self._form_fields = ClientGUICommon.SaneListCtrl( self._form_fields_panel, 350, [ ( 'name', 120 ), ( 'type', 120 ), ( 'default', -1 ), ( 'editable', 120 ) ] ) - - for ( name, type, default, editable ) in form_fields: - - self._form_fields.Append( ( name, CC.field_string_lookup[ type ], str( default ), str( editable ) ), ( name, type, default, editable ) ) - - - self._add = wx.Button( self._form_fields_panel, label='add' ) - self._add.Bind( wx.EVT_BUTTON, self.EventAdd ) - - self._edit = wx.Button( self._form_fields_panel, label='edit' ) - self._edit.Bind( wx.EVT_BUTTON, self.EventEdit ) - - self._delete = wx.Button( self._form_fields_panel, label='delete' ) - self._delete.Bind( wx.EVT_BUTTON, self.EventDelete ) - - # - - self._restrictions_panel = ClientGUICommon.StaticBox( self._imageboard_panel, 'restrictions' ) - - if CC.RESTRICTION_MIN_RESOLUTION in restrictions: value = restrictions[ CC.RESTRICTION_MIN_RESOLUTION ] - else: value = None - - self._min_resolution = ClientGUICommon.NoneableSpinCtrl( self._restrictions_panel, 'min resolution', value, num_dimensions = 2 ) - - if CC.RESTRICTION_MAX_RESOLUTION in restrictions: value = restrictions[ CC.RESTRICTION_MAX_RESOLUTION ] - else: value = None - - self._max_resolution = ClientGUICommon.NoneableSpinCtrl( self._restrictions_panel, 'max resolution', value, num_dimensions = 2 ) - - if CC.RESTRICTION_MAX_FILE_SIZE in restrictions: value = restrictions[ CC.RESTRICTION_MAX_FILE_SIZE ] - else: value = None - - self._max_file_size = ClientGUICommon.NoneableSpinCtrl( self._restrictions_panel, 'max file size (KB)', value, multiplier = 1024 ) - - self._allowed_mimes_panel = ClientGUICommon.StaticBox( self._restrictions_panel, 'allowed mimes' ) - - self._mimes = wx.ListBox( self._allowed_mimes_panel ) - - if CC.RESTRICTION_ALLOWED_MIMES in restrictions: mimes = restrictions[ CC.RESTRICTION_ALLOWED_MIMES ] - else: mimes = [] - - for mime in mimes: self._mimes.Append( HC.mime_string_lookup[ mime ], mime ) - - self._mime_choice = wx.Choice( self._allowed_mimes_panel ) - - for mime in HC.ALLOWED_MIMES: self._mime_choice.Append( HC.mime_string_lookup[ mime ], mime ) - - self._mime_choice.SetSelection( 0 ) - - self._add_mime = wx.Button( self._allowed_mimes_panel, label = 'add' ) - self._add_mime.Bind( wx.EVT_BUTTON, self.EventAddMime ) - - self._remove_mime = wx.Button( self._allowed_mimes_panel, label = 'remove' ) - self._remove_mime.Bind( wx.EVT_BUTTON, self.EventRemoveMime ) - - - def InitialisePanel(): - - self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) ) - - # - - gridbox = wx.FlexGridSizer( 0, 2 ) - - gridbox.AddGrowableCol( 1, 1 ) - - gridbox.AddF( wx.StaticText( self._basic_info_panel, label='POST URL' ), FLAGS_MIXED ) - gridbox.AddF( self._post_url, FLAGS_EXPAND_BOTH_WAYS ) - gridbox.AddF( wx.StaticText( self._basic_info_panel, label='flood time' ), FLAGS_MIXED ) - gridbox.AddF( self._flood_time, FLAGS_EXPAND_BOTH_WAYS ) - - self._basic_info_panel.AddF( gridbox, FLAGS_EXPAND_SIZER_PERPENDICULAR ) - - # - - h_b_box = wx.BoxSizer( wx.HORIZONTAL ) - h_b_box.AddF( self._add, FLAGS_MIXED ) - h_b_box.AddF( self._edit, FLAGS_MIXED ) - h_b_box.AddF( self._delete, FLAGS_MIXED ) - - self._form_fields_panel.AddF( self._form_fields, FLAGS_EXPAND_BOTH_WAYS ) - self._form_fields_panel.AddF( h_b_box, FLAGS_BUTTON_SIZERS ) - - # - - mime_buttons_box = wx.BoxSizer( wx.HORIZONTAL ) - mime_buttons_box.AddF( self._mime_choice, FLAGS_MIXED ) - mime_buttons_box.AddF( self._add_mime, FLAGS_MIXED ) - mime_buttons_box.AddF( self._remove_mime, FLAGS_MIXED ) - - self._allowed_mimes_panel.AddF( self._mimes, FLAGS_EXPAND_BOTH_WAYS ) - self._allowed_mimes_panel.AddF( mime_buttons_box, FLAGS_EXPAND_SIZER_PERPENDICULAR ) - - self._restrictions_panel.AddF( self._min_resolution, FLAGS_EXPAND_PERPENDICULAR ) - self._restrictions_panel.AddF( self._max_resolution, FLAGS_EXPAND_PERPENDICULAR ) - self._restrictions_panel.AddF( self._max_file_size, FLAGS_EXPAND_PERPENDICULAR ) - self._restrictions_panel.AddF( self._allowed_mimes_panel, FLAGS_EXPAND_BOTH_WAYS ) - - # - - self._imageboard_panel.AddF( self._basic_info_panel, FLAGS_EXPAND_PERPENDICULAR ) - self._imageboard_panel.AddF( self._form_fields_panel, FLAGS_EXPAND_BOTH_WAYS ) - self._imageboard_panel.AddF( self._restrictions_panel, FLAGS_EXPAND_PERPENDICULAR ) - - vbox = wx.BoxSizer( wx.VERTICAL ) - - vbox.AddF( self._imageboard_panel, FLAGS_EXPAND_BOTH_WAYS ) - - self.SetSizer( vbox ) - - - InitialiseControls() - - InitialisePanel() - - - def _GetInfo( self ): - - imageboard_name = self._imageboard.GetName() - - post_url = self._post_url.GetValue() - - flood_time = self._flood_time.GetValue() - - # list instead of tumple cause of yaml comparisons - form_fields = self._form_fields.GetClientData() - - restrictions = {} - - # yaml list again - value = self._min_resolution.GetValue() - if value is not None: restrictions[ CC.RESTRICTION_MIN_RESOLUTION ] = list( value ) - - # yaml list again - value = self._max_resolution.GetValue() - if value is not None: restrictions[ CC.RESTRICTION_MAX_RESOLUTION ] = list( value ) - - value = self._max_file_size.GetValue() - if value is not None: restrictions[ CC.RESTRICTION_MAX_FILE_SIZE ] = value - - mimes = [ self._mimes.GetClientData( i ) for i in range( self._mimes.GetCount() ) ] - - if len( mimes ) > 0: restrictions[ CC.RESTRICTION_ALLOWED_MIMES ] = mimes - - return ( imageboard_name, post_url, flood_time, form_fields, restrictions ) - - - def EventAdd( self, event ): - - try: - - with DialogInputNewFormField( self ) as dlg: - - if dlg.ShowModal() == wx.ID_OK: - - ( name, type, default, editable ) = dlg.GetFormField() - - if name in [ form_field[0] for form_field in self._form_fields.GetClientData() ]: + try: - wx.MessageBox( 'There is already a field named ' + name ) + name = dlg.GetValue() + + if self._imageboards.NameExists( name ): raise Exception( 'That name is already in use!' ) + + if name == '': raise Exception( 'Please enter a nickname for the service.' ) + + imageboard = CC.Imageboard( name, '', 60, [], {} ) + + self._edit_log.append( ( 'add', name ) ) + + page = self._Panel( self._imageboards, imageboard ) + + self._imageboards.AddPage( page, name, select = True ) + + except Exception as e: + + wx.MessageBox( unicode( e ) ) self.EventAdd( event ) - return + + + + + def EventExport( self, event ): + + imageboard_panel = self._imageboards.GetCurrentPage() + + if imageboard_panel is not None: + + imageboard = imageboard_panel.GetImageboard() + + with wx.FileDialog( self, 'select where to export imageboard', defaultFile = 'imageboard.yaml', style = wx.FD_SAVE ) as dlg: + + if dlg.ShowModal() == wx.ID_OK: + with open( dlg.GetPath(), 'wb' ) as f: f.write( yaml.safe_dump( imageboard ) ) + + + + + + def EventRemove( self, event ): + + imageboard_panel = self._imageboards.GetCurrentPage() + + if imageboard_panel is not None: + + name = self._imageboards.GetCurrentName() + + self._edit_log.append( ( 'delete', name ) ) + + self._imageboards.DeleteCurrentPage() + + + + def GetChanges( self ): + + for page in self._imageboards.GetNameToPageDict().values(): + + if page.HasChanges(): self._edit_log.append( ( 'edit', page.GetImageboard() ) ) + + + return self._edit_log + + + def GetImageboards( self ): return [ page.GetImageboard() for page in self._imageboards.GetNameToPageDict().values() ] + + def HasChanges( self ): return len( self._edit_log ) > 0 or True in ( page.HasChanges() for page in self._imageboards.GetNameToPageDict().values() ) + + def UpdateImageboard( self, imageboard ): + + name = imageboard.GetName() + + if not self._imageboards.NameExists( name ): + + new_imageboard = CC.Imageboard( name, '', 60, [], {} ) + + self._edit_log.append( ( 'add', name ) ) + + page = self._Panel( self._imageboards, new_imageboard ) + + self._imageboards.AddPage( page, name, select = True ) + + + page = self._imageboards.GetNameToPageDict()[ name ] + + page.Update( imageboard ) + + + class _Panel( wx.Panel ): + + def __init__( self, parent, imageboard ): + + wx.Panel.__init__( self, parent ) + + self._imageboard = imageboard + + ( post_url, flood_time, form_fields, restrictions ) = self._imageboard.GetBoardInfo() + + def InitialiseControls(): + + self._imageboard_panel = ClientGUICommon.StaticBox( self, 'imageboard' ) + + # + + self._basic_info_panel = ClientGUICommon.StaticBox( self._imageboard_panel, 'basic info' ) + + self._post_url = wx.TextCtrl( self._basic_info_panel, value = post_url ) + + self._flood_time = wx.SpinCtrl( self._basic_info_panel, min = 5, max = 1200, initial = flood_time ) + + # + + self._form_fields_panel = ClientGUICommon.StaticBox( self._imageboard_panel, 'form fields' ) + + self._form_fields = ClientGUICommon.SaneListCtrl( self._form_fields_panel, 350, [ ( 'name', 120 ), ( 'type', 120 ), ( 'default', -1 ), ( 'editable', 120 ) ] ) + + for ( name, type, default, editable ) in form_fields: + + self._form_fields.Append( ( name, CC.field_string_lookup[ type ], str( default ), str( editable ) ), ( name, type, default, editable ) ) + + + self._add = wx.Button( self._form_fields_panel, label='add' ) + self._add.Bind( wx.EVT_BUTTON, self.EventAdd ) + + self._edit = wx.Button( self._form_fields_panel, label='edit' ) + self._edit.Bind( wx.EVT_BUTTON, self.EventEdit ) + + self._delete = wx.Button( self._form_fields_panel, label='delete' ) + self._delete.Bind( wx.EVT_BUTTON, self.EventDelete ) + + # + + self._restrictions_panel = ClientGUICommon.StaticBox( self._imageboard_panel, 'restrictions' ) + + if CC.RESTRICTION_MIN_RESOLUTION in restrictions: value = restrictions[ CC.RESTRICTION_MIN_RESOLUTION ] + else: value = None + + self._min_resolution = ClientGUICommon.NoneableSpinCtrl( self._restrictions_panel, 'min resolution', value, num_dimensions = 2 ) + + if CC.RESTRICTION_MAX_RESOLUTION in restrictions: value = restrictions[ CC.RESTRICTION_MAX_RESOLUTION ] + else: value = None + + self._max_resolution = ClientGUICommon.NoneableSpinCtrl( self._restrictions_panel, 'max resolution', value, num_dimensions = 2 ) + + if CC.RESTRICTION_MAX_FILE_SIZE in restrictions: value = restrictions[ CC.RESTRICTION_MAX_FILE_SIZE ] + else: value = None + + self._max_file_size = ClientGUICommon.NoneableSpinCtrl( self._restrictions_panel, 'max file size (KB)', value, multiplier = 1024 ) + + self._allowed_mimes_panel = ClientGUICommon.StaticBox( self._restrictions_panel, 'allowed mimes' ) + + self._mimes = wx.ListBox( self._allowed_mimes_panel ) + + if CC.RESTRICTION_ALLOWED_MIMES in restrictions: mimes = restrictions[ CC.RESTRICTION_ALLOWED_MIMES ] + else: mimes = [] + + for mime in mimes: self._mimes.Append( HC.mime_string_lookup[ mime ], mime ) + + self._mime_choice = wx.Choice( self._allowed_mimes_panel ) + + for mime in HC.ALLOWED_MIMES: self._mime_choice.Append( HC.mime_string_lookup[ mime ], mime ) + + self._mime_choice.SetSelection( 0 ) + + self._add_mime = wx.Button( self._allowed_mimes_panel, label = 'add' ) + self._add_mime.Bind( wx.EVT_BUTTON, self.EventAddMime ) + + self._remove_mime = wx.Button( self._allowed_mimes_panel, label = 'remove' ) + self._remove_mime.Bind( wx.EVT_BUTTON, self.EventRemoveMime ) + + + def InitialisePanel(): + + self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) ) + + # + + gridbox = wx.FlexGridSizer( 0, 2 ) + + gridbox.AddGrowableCol( 1, 1 ) + + gridbox.AddF( wx.StaticText( self._basic_info_panel, label='POST URL' ), FLAGS_MIXED ) + gridbox.AddF( self._post_url, FLAGS_EXPAND_BOTH_WAYS ) + gridbox.AddF( wx.StaticText( self._basic_info_panel, label='flood time' ), FLAGS_MIXED ) + gridbox.AddF( self._flood_time, FLAGS_EXPAND_BOTH_WAYS ) + + self._basic_info_panel.AddF( gridbox, FLAGS_EXPAND_SIZER_PERPENDICULAR ) + + # + + h_b_box = wx.BoxSizer( wx.HORIZONTAL ) + h_b_box.AddF( self._add, FLAGS_MIXED ) + h_b_box.AddF( self._edit, FLAGS_MIXED ) + h_b_box.AddF( self._delete, FLAGS_MIXED ) + + self._form_fields_panel.AddF( self._form_fields, FLAGS_EXPAND_BOTH_WAYS ) + self._form_fields_panel.AddF( h_b_box, FLAGS_BUTTON_SIZERS ) + + # + + mime_buttons_box = wx.BoxSizer( wx.HORIZONTAL ) + mime_buttons_box.AddF( self._mime_choice, FLAGS_MIXED ) + mime_buttons_box.AddF( self._add_mime, FLAGS_MIXED ) + mime_buttons_box.AddF( self._remove_mime, FLAGS_MIXED ) + + self._allowed_mimes_panel.AddF( self._mimes, FLAGS_EXPAND_BOTH_WAYS ) + self._allowed_mimes_panel.AddF( mime_buttons_box, FLAGS_EXPAND_SIZER_PERPENDICULAR ) + + self._restrictions_panel.AddF( self._min_resolution, FLAGS_EXPAND_PERPENDICULAR ) + self._restrictions_panel.AddF( self._max_resolution, FLAGS_EXPAND_PERPENDICULAR ) + self._restrictions_panel.AddF( self._max_file_size, FLAGS_EXPAND_PERPENDICULAR ) + self._restrictions_panel.AddF( self._allowed_mimes_panel, FLAGS_EXPAND_BOTH_WAYS ) + + # + + self._imageboard_panel.AddF( self._basic_info_panel, FLAGS_EXPAND_PERPENDICULAR ) + self._imageboard_panel.AddF( self._form_fields_panel, FLAGS_EXPAND_BOTH_WAYS ) + self._imageboard_panel.AddF( self._restrictions_panel, FLAGS_EXPAND_PERPENDICULAR ) + + vbox = wx.BoxSizer( wx.VERTICAL ) + + vbox.AddF( self._imageboard_panel, FLAGS_EXPAND_BOTH_WAYS ) + + self.SetSizer( vbox ) + + + InitialiseControls() + + InitialisePanel() + + + def _GetInfo( self ): + + imageboard_name = self._imageboard.GetName() + + post_url = self._post_url.GetValue() + + flood_time = self._flood_time.GetValue() + + # list instead of tumple cause of yaml comparisons + form_fields = self._form_fields.GetClientData() + + restrictions = {} + + # yaml list again + value = self._min_resolution.GetValue() + if value is not None: restrictions[ CC.RESTRICTION_MIN_RESOLUTION ] = list( value ) + + # yaml list again + value = self._max_resolution.GetValue() + if value is not None: restrictions[ CC.RESTRICTION_MAX_RESOLUTION ] = list( value ) + + value = self._max_file_size.GetValue() + if value is not None: restrictions[ CC.RESTRICTION_MAX_FILE_SIZE ] = value + + mimes = [ self._mimes.GetClientData( i ) for i in range( self._mimes.GetCount() ) ] + + if len( mimes ) > 0: restrictions[ CC.RESTRICTION_ALLOWED_MIMES ] = mimes + + return ( imageboard_name, post_url, flood_time, form_fields, restrictions ) + + + def EventAdd( self, event ): + + try: + + with DialogInputNewFormField( self ) as dlg: + + if dlg.ShowModal() == wx.ID_OK: + + ( name, type, default, editable ) = dlg.GetFormField() + + if name in [ form_field[0] for form_field in self._form_fields.GetClientData() ]: + + wx.MessageBox( 'There is already a field named ' + name ) + + self.EventAdd( event ) + + return + + + self._form_fields.Append( ( name, CC.field_string_lookup[ type ], str( default ), str( editable ) ), ( name, type, default, editable ) ) + + + + except Exception as e: wx.MessageBox( unicode( e ) ) + + + def EventAddMime( self, event ): + + selection = self._mime_choice.GetSelection() + + if selection != wx.NOT_FOUND: + + mime = self._mime_choice.GetClientData( selection ) + + existing_mimes = [ self._mimes.GetClientData( i ) for i in range( self._mimes.GetCount() ) ] + + if mime not in existing_mimes: self._mimes.Append( HC.mime_string_lookup[ mime ], mime ) + + + + def EventDelete( self, event ): self._form_fields.RemoveAllSelected() + + def EventRemoveMime( self, event ): + + selection = self._mimes.GetSelection() + + if selection != wx.NOT_FOUND: self._mimes.Delete( selection ) + + + def EventEdit( self, event ): + + indices = self._form_fields.GetAllSelected() + + for index in indices: + + ( name, type, default, editable ) = self._form_fields.GetClientData( index ) + + form_field = ( name, type, default, editable ) + + try: + + with DialogInputNewFormField( self, form_field ) as dlg: + + if dlg.ShowModal() == wx.ID_OK: + + old_name = name + + ( name, type, default, editable ) = dlg.GetFormField() + + if old_name != name: + + if name in [ form_field[0] for form_field in self._form_fields.GetClientData() ]: raise Exception( 'You already have a form field called ' + name + '; delete or edit that one first' ) + + + self._form_fields.UpdateRow( index, ( name, CC.field_string_lookup[ type ], str( default ), str( editable ) ), ( name, type, default, editable ) ) + + + + except Exception as e: wx.MessageBox( unicode( e ) ) + + + + def GetImageboard( self ): + + ( name, post_url, flood_time, form_fields, restrictions ) = self._GetInfo() + + return CC.Imageboard( name, post_url, flood_time, form_fields, restrictions ) + + + def HasChanges( self ): + + ( my_name, my_post_url, my_flood_time, my_form_fields, my_restrictions ) = self._GetInfo() + + ( post_url, flood_time, form_fields, restrictions ) = self._imageboard.GetBoardInfo() + + if post_url != my_post_url: return True + + if flood_time != my_flood_time: return True + + if set( [ tuple( item ) for item in form_fields ] ) != set( [ tuple( item ) for item in my_form_fields ] ): return True + + if restrictions != my_restrictions: return True + + return False + + + def Update( self, imageboard ): + + ( post_url, flood_time, form_fields, restrictions ) = imageboard.GetBoardInfo() + + self._post_url.SetValue( post_url ) + self._flood_time.SetValue( flood_time ) + + self._form_fields.ClearAll() + + self._form_fields.InsertColumn( 0, 'name', width = 120 ) + self._form_fields.InsertColumn( 1, 'type', width = 120 ) + self._form_fields.InsertColumn( 2, 'default' ) + self._form_fields.InsertColumn( 3, 'editable', width = 120 ) + + self._form_fields.setResizeColumn( 3 ) # default + + for ( name, type, default, editable ) in form_fields: self._form_fields.Append( ( name, CC.field_string_lookup[ type ], str( default ), str( editable ) ), ( name, type, default, editable ) ) - - except Exception as e: wx.MessageBox( unicode( e ) ) - - - def EventAddMime( self, event ): - - selection = self._mime_choice.GetSelection() - - if selection != wx.NOT_FOUND: - - mime = self._mime_choice.GetClientData( selection ) - - existing_mimes = [ self._mimes.GetClientData( i ) for i in range( self._mimes.GetCount() ) ] - - if mime not in existing_mimes: self._mimes.Append( HC.mime_string_lookup[ mime ], mime ) - - - - def EventDelete( self, event ): self._form_fields.RemoveAllSelected() - - def EventRemoveMime( self, event ): - - selection = self._mimes.GetSelection() - - if selection != wx.NOT_FOUND: self._mimes.Delete( selection ) - - - def EventEdit( self, event ): - - indices = self._form_fields.GetAllSelected() - - for index in indices: - - ( name, type, default, editable ) = self._form_fields.GetClientData( index ) - - form_field = ( name, type, default, editable ) - - try: + if CC.RESTRICTION_MIN_RESOLUTION in restrictions: value = restrictions[ CC.RESTRICTION_MIN_RESOLUTION ] + else: value = None - with DialogInputNewFormField( self, form_field ) as dlg: - - if dlg.ShowModal() == wx.ID_OK: - - old_name = name - - ( name, type, default, editable ) = dlg.GetFormField() - - if old_name != name: - - if name in [ form_field[0] for form_field in self._form_fields.GetClientData() ]: raise Exception( 'You already have a form field called ' + name + '; delete or edit that one first' ) - - - self._form_fields.UpdateRow( index, ( name, CC.field_string_lookup[ type ], str( default ), str( editable ) ), ( name, type, default, editable ) ) - - + self._min_resolution.SetValue( value ) + + if CC.RESTRICTION_MAX_RESOLUTION in restrictions: value = restrictions[ CC.RESTRICTION_MAX_RESOLUTION ] + else: value = None + + self._max_resolution.SetValue( value ) + + if CC.RESTRICTION_MAX_FILE_SIZE in restrictions: value = restrictions[ CC.RESTRICTION_MAX_FILE_SIZE ] + else: value = None + + self._max_file_size.SetValue( value ) + + self._mimes.Clear() + + if CC.RESTRICTION_ALLOWED_MIMES in restrictions: mimes = restrictions[ CC.RESTRICTION_ALLOWED_MIMES ] + else: mimes = [] + + for mime in mimes: self._mimes.Append( HC.mime_string_lookup[ mime ], mime ) - except Exception as e: wx.MessageBox( unicode( e ) ) - def GetImageboard( self ): - - ( name, post_url, flood_time, form_fields, restrictions ) = self._GetInfo() - - return CC.Imageboard( name, post_url, flood_time, form_fields, restrictions ) - - - def HasChanges( self ): - - ( my_name, my_post_url, my_flood_time, my_form_fields, my_restrictions ) = self._GetInfo() - - ( post_url, flood_time, form_fields, restrictions ) = self._imageboard.GetBoardInfo() - - if post_url != my_post_url: return True - - if flood_time != my_flood_time: return True - - if set( [ tuple( item ) for item in form_fields ] ) != set( [ tuple( item ) for item in my_form_fields ] ): return True - - if restrictions != my_restrictions: return True - - return False - - - def Update( self, imageboard ): - - ( post_url, flood_time, form_fields, restrictions ) = imageboard.GetBoardInfo() - - self._post_url.SetValue( post_url ) - self._flood_time.SetValue( flood_time ) - - self._form_fields.ClearAll() - - self._form_fields.InsertColumn( 0, 'name', width = 120 ) - self._form_fields.InsertColumn( 1, 'type', width = 120 ) - self._form_fields.InsertColumn( 2, 'default' ) - self._form_fields.InsertColumn( 3, 'editable', width = 120 ) - - self._form_fields.setResizeColumn( 3 ) # default - - for ( name, type, default, editable ) in form_fields: - - self._form_fields.Append( ( name, CC.field_string_lookup[ type ], str( default ), str( editable ) ), ( name, type, default, editable ) ) - - - if CC.RESTRICTION_MIN_RESOLUTION in restrictions: value = restrictions[ CC.RESTRICTION_MIN_RESOLUTION ] - else: value = None - - self._min_resolution.SetValue( value ) - - if CC.RESTRICTION_MAX_RESOLUTION in restrictions: value = restrictions[ CC.RESTRICTION_MAX_RESOLUTION ] - else: value = None - - self._max_resolution.SetValue( value ) - - if CC.RESTRICTION_MAX_FILE_SIZE in restrictions: value = restrictions[ CC.RESTRICTION_MAX_FILE_SIZE ] - else: value = None - - self._max_file_size.SetValue( value ) - - self._mimes.Clear() - - if CC.RESTRICTION_ALLOWED_MIMES in restrictions: mimes = restrictions[ CC.RESTRICTION_ALLOWED_MIMES ] - else: mimes = [] - - for mime in mimes: self._mimes.Append( HC.mime_string_lookup[ mime ], mime ) - - class DialogManageOptionsFileRepository( Dialog ): def __init__( self, parent, service_identifier ): @@ -5071,7 +5075,7 @@ class DialogManageRatings( Dialog ): self._panels = [] - for service_identifier in service_identifiers: self._panels.append( DialogManageRatingsPanel( self, service_identifier, media ) ) + for service_identifier in service_identifiers: self._panels.append( self._Panel( self, service_identifier, media ) ) self._apply = wx.Button( self, label='Apply' ) self._apply.Bind( wx.EVT_BUTTON, self.EventOk ) @@ -5144,7 +5148,7 @@ class DialogManageRatings( Dialog ): rating = panel.GetRating() - content_updates.append( CC.ContentUpdate( CC.CONTENT_UPDATE_RATING, service_identifier, self._hashes, info = rating ) ) + content_updates.append( HC.ContentUpdate( CC.CONTENT_UPDATE_RATING, service_identifier, self._hashes, info = rating ) ) @@ -5166,268 +5170,269 @@ class DialogManageRatings( Dialog ): self.SetAcceleratorTable( wx.AcceleratorTable( entries ) ) -class DialogManageRatingsPanel( wx.Panel ): - - def __init__( self, parent, service_identifier, media ): + class _Panel( wx.Panel ): - wx.Panel.__init__( self, parent ) - - self._service_identifier = service_identifier - self._service = wx.GetApp().Read( 'service', service_identifier ) - - extra_info = self._service.GetExtraInfo() - - self._media = media - - service_type = service_identifier.GetType() - - def InitialiseControls(): + def __init__( self, parent, service_identifier, media ): - self._ratings_panel = ClientGUICommon.StaticBox( self, self._service_identifier.GetName() ) + wx.Panel.__init__( self, parent ) - self._current_score = wx.StaticText( self._ratings_panel, style = wx.ALIGN_CENTER ) + self._service_identifier = service_identifier + self._service = wx.GetApp().Read( 'service', service_identifier ) - score_font = self._GetScoreFont() + extra_info = self._service.GetExtraInfo() - self._current_score.SetFont( score_font ) + self._media = media - if service_type in ( HC.LOCAL_RATING_LIKE, HC.LOCAL_RATING_NUMERICAL ): all_rating_services = [ local_ratings for ( local_ratings, remote_ratings ) in [ media.GetRatings() for media in self._media ] ] - elif service_type in ( HC.RATING_LIKE_REPOSITORY, HC.RATING_NUMERICAL_REPOSITORY ): all_rating_services = [ remote_ratings for ( local_ratings, remote_ratings ) in [ media.GetRatings() for media in self._media ] ] + service_type = service_identifier.GetType() - if service_type in ( HC.LOCAL_RATING_LIKE, HC.RATING_LIKE_REPOSITORY ): + def InitialiseControls(): - ( like, dislike ) = extra_info + self._ratings_panel = ClientGUICommon.StaticBox( self, self._service_identifier.GetName() ) - if service_type == HC.LOCAL_RATING_LIKE: + self._current_score = wx.StaticText( self._ratings_panel, style = wx.ALIGN_CENTER ) + + score_font = self._GetScoreFont() + + self._current_score.SetFont( score_font ) + + if service_type in ( HC.LOCAL_RATING_LIKE, HC.LOCAL_RATING_NUMERICAL ): all_rating_services = [ local_ratings for ( local_ratings, remote_ratings ) in [ media.GetRatings() for media in self._media ] ] + elif service_type in ( HC.RATING_LIKE_REPOSITORY, HC.RATING_NUMERICAL_REPOSITORY ): all_rating_services = [ remote_ratings for ( local_ratings, remote_ratings ) in [ media.GetRatings() for media in self._media ] ] + + if service_type in ( HC.LOCAL_RATING_LIKE, HC.RATING_LIKE_REPOSITORY ): - ratings = [ rating_services.GetRating( self._service_identifier ) for rating_services in all_rating_services ] + ( like, dislike ) = extra_info - if all( ( i is None for i in ratings ) ): + if service_type == HC.LOCAL_RATING_LIKE: - choices = [ like, dislike, 'make no changes' ] + ratings = [ rating_services.GetRating( self._service_identifier ) for rating_services in all_rating_services ] - if len( self._media ) > 1: self._current_score.SetLabel( 'none rated' ) - else: self._current_score.SetLabel( 'not rated' ) - - elif None in ratings: - - choices = [ like, dislike, 'remove rating', 'make no changes' ] - - self._current_score.SetLabel( 'not all rated' ) - - else: - - if all( ( i == 1 for i in ratings ) ): + if all( ( i is None for i in ratings ) ): - choices = [ dislike, 'remove rating', 'make no changes' ] + choices = [ like, dislike, 'make no changes' ] - if len( self._media ) > 1: self._current_score.SetLabel( 'all ' + like ) - else: self._current_score.SetLabel( like ) + if len( self._media ) > 1: self._current_score.SetLabel( 'none rated' ) + else: self._current_score.SetLabel( 'not rated' ) - elif all( ( i == 0 for i in ratings ) ): - - choices = [ like, 'remove rating', 'make no changes' ] - - if len( self._media ) > 1: self._current_score.SetLabel( 'all ' + dislike ) - else: self._current_score.SetLabel( dislike ) - - else: + elif None in ratings: choices = [ like, dislike, 'remove rating', 'make no changes' ] + self._current_score.SetLabel( 'not all rated' ) + + else: + + if all( ( i == 1 for i in ratings ) ): + + choices = [ dislike, 'remove rating', 'make no changes' ] + + if len( self._media ) > 1: self._current_score.SetLabel( 'all ' + like ) + else: self._current_score.SetLabel( like ) + + elif all( ( i == 0 for i in ratings ) ): + + choices = [ like, 'remove rating', 'make no changes' ] + + if len( self._media ) > 1: self._current_score.SetLabel( 'all ' + dislike ) + else: self._current_score.SetLabel( dislike ) + + else: + + choices = [ like, dislike, 'remove rating', 'make no changes' ] + + + overall_rating = float( sum( ratings ) ) / float( len( ratings ) ) + + self._current_score.SetLabel( str( '%.2f' % overall_rating ) ) + - overall_rating = float( sum( ratings ) ) / float( len( ratings ) ) - - self._current_score.SetLabel( str( '%.2f' % overall_rating ) ) - - - if len( self._media ) > 1: - - ratings_counter = collections.Counter( ratings ) - - likes = ratings_counter[ 1 ] - dislikes = ratings_counter[ 0 ] - nones = ratings_counter[ None ] - - scores = [] - - if likes > 0: scores.append( str( likes ) + ' likes' ) - if dislikes > 0: scores.append( str( dislikes ) + ' dislikes' ) - if nones > 0: scores.append( str( nones ) + ' not rated' ) - - self._current_score.SetLabel( ', '.join( scores ) ) + if len( self._media ) > 1: + + ratings_counter = collections.Counter( ratings ) + + likes = ratings_counter[ 1 ] + dislikes = ratings_counter[ 0 ] + nones = ratings_counter[ None ] + + scores = [] + + if likes > 0: scores.append( str( likes ) + ' likes' ) + if dislikes > 0: scores.append( str( dislikes ) + ' dislikes' ) + if nones > 0: scores.append( str( nones ) + ' not rated' ) + + self._current_score.SetLabel( ', '.join( scores ) ) + + else: + + ( rating, ) = ratings + + if rating is None: self._current_score.SetLabel( 'not rated' ) + elif rating == 1: self._current_score.SetLabel( like ) + elif rating == 0: self._current_score.SetLabel( dislike ) + else: - ( rating, ) = ratings - - if rating is None: self._current_score.SetLabel( 'not rated' ) - elif rating == 1: self._current_score.SetLabel( like ) - elif rating == 0: self._current_score.SetLabel( dislike ) + self._current_score.SetLabel( '23 ' + like + 's, 44 ' + dislike + 's' ) - else: + elif service_type in ( HC.LOCAL_RATING_NUMERICAL, HC.RATING_NUMERICAL_REPOSITORY ): - self._current_score.SetLabel( '23 ' + like + 's, 44 ' + dislike + 's' ) - - - elif service_type in ( HC.LOCAL_RATING_NUMERICAL, HC.RATING_NUMERICAL_REPOSITORY ): - - if service_type == HC.LOCAL_RATING_NUMERICAL: - - ( min, max ) = extra_info - - self._slider = wx.Slider( self._ratings_panel, minValue = min, maxValue = max, style = wx.SL_AUTOTICKS | wx.SL_LABELS ) - self._slider.Bind( wx.EVT_SLIDER, self.EventSlider ) - - ratings = [ rating_services.GetRating( self._service_identifier ) for rating_services in all_rating_services ] - - if all( ( i is None for i in ratings ) ): + if service_type == HC.LOCAL_RATING_NUMERICAL: - choices = [ 'set rating', 'make no changes' ] + ( min, max ) = extra_info - if len( self._media ) > 1: self._current_score.SetLabel( 'none rated' ) - else: self._current_score.SetLabel( 'not rated' ) + self._slider = wx.Slider( self._ratings_panel, minValue = min, maxValue = max, style = wx.SL_AUTOTICKS | wx.SL_LABELS ) + self._slider.Bind( wx.EVT_SLIDER, self.EventSlider ) - elif None in ratings: + ratings = [ rating_services.GetRating( self._service_identifier ) for rating_services in all_rating_services ] - choices = [ 'set rating', 'remove rating', 'make no changes' ] - - if len( self._media ) > 1: self._current_score.SetLabel( 'not all rated' ) - else: self._current_score.SetLabel( 'not rated' ) + if all( ( i is None for i in ratings ) ): + + choices = [ 'set rating', 'make no changes' ] + + if len( self._media ) > 1: self._current_score.SetLabel( 'none rated' ) + else: self._current_score.SetLabel( 'not rated' ) + + elif None in ratings: + + choices = [ 'set rating', 'remove rating', 'make no changes' ] + + if len( self._media ) > 1: self._current_score.SetLabel( 'not all rated' ) + else: self._current_score.SetLabel( 'not rated' ) + + else: + + # you know what? this should really be a bargraph or something! + # * + # * + # * + # * * + # * * * * + # None 0 1 2 3 4 5 + # but we can't rely on integers, so just think about it + # some kind of sense of distribution would be helpful though + + choices = [ 'set rating', 'remove rating', 'make no changes' ] + + overall_rating = float( sum( ratings ) ) / float( len( ratings ) ) + + overall_rating_converted = ( overall_rating * ( max - min ) ) + min + + self._slider.SetValue( int( overall_rating_converted + 0.5 ) ) + + str_overall_rating = str( '%.2f' % overall_rating_converted ) + + if min in ( 0, 1 ): str_overall_rating += '/' + str( '%.2f' % max ) + + self._current_score.SetLabel( str_overall_rating ) + else: - # you know what? this should really be a bargraph or something! - # * - # * - # * - # * * - # * * * * - # None 0 1 2 3 4 5 - # but we can't rely on integers, so just think about it - # some kind of sense of distribution would be helpful though - - choices = [ 'set rating', 'remove rating', 'make no changes' ] - - overall_rating = float( sum( ratings ) ) / float( len( ratings ) ) - - overall_rating_converted = ( overall_rating * ( max - min ) ) + min - - self._slider.SetValue( int( overall_rating_converted + 0.5 ) ) - - str_overall_rating = str( '%.2f' % overall_rating_converted ) - - if min in ( 0, 1 ): str_overall_rating += '/' + str( '%.2f' % max ) - - self._current_score.SetLabel( str_overall_rating ) + self._current_score.SetLabel( '3.82/5' ) - else: + + if service_type in ( HC.LOCAL_RATING_LIKE, HC.LOCAL_RATING_NUMERICAL ): - self._current_score.SetLabel( '3.82/5' ) + self._choices = wx.Choice( self._ratings_panel, choices = choices ) + + self._choices.SetSelection( self._choices.FindString( 'make no changes' ) ) - if service_type in ( HC.LOCAL_RATING_LIKE, HC.LOCAL_RATING_NUMERICAL ): + def InitialisePanel(): - self._choices = wx.Choice( self._ratings_panel, choices = choices ) + self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) ) - self._choices.SetSelection( self._choices.FindString( 'make no changes' ) ) + if service_type in ( HC.LOCAL_RATING_LIKE, HC.LOCAL_RATING_NUMERICAL ): label = 'local rating' + elif service_type in ( HC.RATING_LIKE_REPOSITORY, HC.RATING_NUMERICAL_REPOSITORY ): label = 'remote rating' + self._ratings_panel.AddF( self._current_score, FLAGS_EXPAND_PERPENDICULAR ) + + if service_type in ( HC.LOCAL_RATING_LIKE, HC.LOCAL_RATING_NUMERICAL ): + + if service_type == HC.LOCAL_RATING_LIKE: + + self._ratings_panel.AddF( self._choices, FLAGS_EXPAND_PERPENDICULAR ) + + elif service_type == HC.LOCAL_RATING_NUMERICAL: + + self._ratings_panel.AddF( self._slider, FLAGS_EXPAND_PERPENDICULAR ) + self._ratings_panel.AddF( self._choices, FLAGS_EXPAND_PERPENDICULAR ) + + + + vbox = wx.BoxSizer( wx.VERTICAL ) + + vbox.AddF( self._ratings_panel, FLAGS_EXPAND_PERPENDICULAR ) + + self.SetSizer( vbox ) + + + InitialiseControls() + + InitialisePanel() - def InitialisePanel(): + def _GetScoreFont( self ): - self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) ) + normal_font = wx.SystemSettings.GetFont( wx.SYS_DEFAULT_GUI_FONT ) - if service_type in ( HC.LOCAL_RATING_LIKE, HC.LOCAL_RATING_NUMERICAL ): label = 'local rating' - elif service_type in ( HC.RATING_LIKE_REPOSITORY, HC.RATING_NUMERICAL_REPOSITORY ): label = 'remote rating' + normal_font_size = normal_font.GetPointSize() + normal_font_family = normal_font.GetFamily() - self._ratings_panel.AddF( self._current_score, FLAGS_EXPAND_PERPENDICULAR ) + return wx.Font( normal_font_size * 2, normal_font_family, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD ) - if service_type in ( HC.LOCAL_RATING_LIKE, HC.LOCAL_RATING_NUMERICAL ): + + def EventSlider( self, event ): + + rating = self._slider.GetValue() + + self._choices.SetSelection( 0 ) + + self._choices.SetString( 0, 'set rating to ' + str( rating ) ) + + event.Skip() + + + def GetRating( self ): + + service_type = self._service_identifier.GetType() + + selection = self._choices.GetSelection() + + s = self._choices.GetString( selection ) + + if s == 'remove rating': return None + else: if service_type == HC.LOCAL_RATING_LIKE: - self._ratings_panel.AddF( self._choices, FLAGS_EXPAND_PERPENDICULAR ) + ( like, dislike ) = self._service.GetExtraInfo() - elif service_type == HC.LOCAL_RATING_NUMERICAL: - - self._ratings_panel.AddF( self._slider, FLAGS_EXPAND_PERPENDICULAR ) - self._ratings_panel.AddF( self._choices, FLAGS_EXPAND_PERPENDICULAR ) + if s == like: rating = 1 + elif s == dislike: rating = 0 + elif service_type == HC.LOCAL_RATING_NUMERICAL: rating = float( self._slider.GetValue() - self._slider.GetMin() ) / float( self._slider.GetMax() - self._slider.GetMin() ) - vbox = wx.BoxSizer( wx.VERTICAL ) - - vbox.AddF( self._ratings_panel, FLAGS_EXPAND_PERPENDICULAR ) - - self.SetSizer( vbox ) + return rating - InitialiseControls() - - InitialisePanel() - - - def _GetScoreFont( self ): - - normal_font = wx.SystemSettings.GetFont( wx.SYS_DEFAULT_GUI_FONT ) - - normal_font_size = normal_font.GetPointSize() - normal_font_family = normal_font.GetFamily() - - return wx.Font( normal_font_size * 2, normal_font_family, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD ) - - - def EventSlider( self, event ): - - rating = self._slider.GetValue() - - self._choices.SetSelection( 0 ) - - self._choices.SetString( 0, 'set rating to ' + str( rating ) ) - - event.Skip() - - - def GetRating( self ): - - service_type = self._service_identifier.GetType() - - selection = self._choices.GetSelection() - - s = self._choices.GetString( selection ) - - if s == 'remove rating': return None - else: + def HasChanges( self ): - if service_type == HC.LOCAL_RATING_LIKE: - - ( like, dislike ) = self._service.GetExtraInfo() - - if s == like: rating = 1 - elif s == dislike: rating = 0 - - elif service_type == HC.LOCAL_RATING_NUMERICAL: rating = float( self._slider.GetValue() - self._slider.GetMin() ) / float( self._slider.GetMax() - self._slider.GetMin() ) + selection = self._choices.GetSelection() + + s = self._choices.GetString( selection ) + + if s == 'make no changes': return False + else: return True - return rating + def GetServiceIdentifier( self ): return self._service_identifier - def HasChanges( self ): - - selection = self._choices.GetSelection() - - s = self._choices.GetString( selection ) - - if s == 'make no changes': return False - else: return True - - - def GetServiceIdentifier( self ): return self._service_identifier - class DialogManageServer( Dialog ): def __init__( self, parent, service_identifier ): @@ -5466,7 +5471,7 @@ class DialogManageServer( Dialog ): for service_identifier in self._service_identifiers: - page = DialogManageServerServicePanel( self._services_listbook, service_identifier ) + page = self._Panel( self._services_listbook, service_identifier ) name = HC.service_string_lookup[ service_identifier.GetType() ] @@ -5550,7 +5555,7 @@ class DialogManageServer( Dialog ): self._edit_log.append( ( HC.ADD, service_identifier ) ) - page = DialogManageServerServicePanel( self._services_listbook, service_identifier ) + page = self._Panel( self._services_listbook, service_identifier ) name = HC.service_string_lookup[ service_type ] @@ -5625,67 +5630,68 @@ class DialogManageServer( Dialog ): -class DialogManageServerServicePanel( wx.Panel ): - - def __init__( self, parent, service_identifier ): + class _Panel( wx.Panel ): - wx.Panel.__init__( self, parent ) - - self._service_identifier = service_identifier - - service_type = service_identifier.GetType() - - def InitialiseControls(): + def __init__( self, parent, service_identifier ): - self._service_panel = ClientGUICommon.StaticBox( self, 'service' ) + wx.Panel.__init__( self, parent ) - self._service_port = wx.SpinCtrl( self._service_panel, min = 1, max = 65535 ) - self._service_port.SetValue( service_identifier.GetPort() ) + self._service_identifier = service_identifier + + service_type = service_identifier.GetType() + + def InitialiseControls(): + + self._service_panel = ClientGUICommon.StaticBox( self, 'service' ) + + self._service_port = wx.SpinCtrl( self._service_panel, min = 1, max = 65535 ) + self._service_port.SetValue( service_identifier.GetPort() ) + + + def InitialisePanel(): + + self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) ) + + vbox = wx.BoxSizer( wx.VERTICAL ) + + gridbox = wx.FlexGridSizer( 0, 2 ) + + gridbox.AddGrowableCol( 1, 1 ) + + gridbox.AddF( wx.StaticText( self._service_panel, label='port' ), FLAGS_MIXED ) + gridbox.AddF( self._service_port, FLAGS_EXPAND_BOTH_WAYS ) + + self._service_panel.AddF( gridbox, FLAGS_EXPAND_SIZER_BOTH_WAYS ) + + vbox.AddF( self._service_panel, FLAGS_EXPAND_BOTH_WAYS ) + + self.SetSizer( vbox ) + + + InitialiseControls() + + InitialisePanel() - def InitialisePanel(): + def GetInfo( self ): - self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) ) + port = self._service_port.GetValue() - vbox = wx.BoxSizer( wx.VERTICAL ) - - gridbox = wx.FlexGridSizer( 0, 2 ) - - gridbox.AddGrowableCol( 1, 1 ) - - gridbox.AddF( wx.StaticText( self._service_panel, label='port' ), FLAGS_MIXED ) - gridbox.AddF( self._service_port, FLAGS_EXPAND_BOTH_WAYS ) - - self._service_panel.AddF( gridbox, FLAGS_EXPAND_SIZER_BOTH_WAYS ) - - vbox.AddF( self._service_panel, FLAGS_EXPAND_BOTH_WAYS ) - - self.SetSizer( vbox ) + return port - InitialiseControls() + def HasChanges( self ): + + port = self.GetInfo() + + if port != self._service_identifier.GetPort(): return True + + return False + - InitialisePanel() + def GetOriginalServiceIdentifier( self ): return self._service_identifier - def GetInfo( self ): - - port = self._service_port.GetValue() - - return port - - - def HasChanges( self ): - - port = self.GetInfo() - - if port != self._service_identifier.GetPort(): return True - - return False - - - def GetOriginalServiceIdentifier( self ): return self._service_identifier - class DialogManageServices( Dialog ): def __init__( self, parent ): @@ -5737,7 +5743,7 @@ class DialogManageServices( Dialog ): elif service_type == HC.SERVER_ADMIN: listbook = self._servers_admin else: continue - page_info = ( DialogManageServicesServicePanel, ( listbook, service_identifier, credentials, extra_info ), {} ) + page_info = ( self._Panel, ( listbook, service_identifier, credentials, extra_info ), {} ) listbook.AddPage( page_info, name ) @@ -5897,7 +5903,7 @@ class DialogManageServices( Dialog ): self._edit_log.append( ( 'add', ( service_identifier, credentials, extra_info ) ) ) - page = DialogManageServicesServicePanel( services_listbook, service_identifier, credentials, extra_info ) + page = self._Panel( services_listbook, service_identifier, credentials, extra_info ) services_listbook.AddPage( page, name, select = True ) @@ -6082,7 +6088,7 @@ class DialogManageServices( Dialog ): self._edit_log.append( ( 'add', ( service_identifier, credentials, extra_info ) ) ) - page = DialogManageServicesServicePanel( services_listbook, service_identifier, credentials, extra_info ) + page = self._Panel( services_listbook, service_identifier, credentials, extra_info ) services_listbook.AddPage( page, name, select = True ) @@ -6094,232 +6100,233 @@ class DialogManageServices( Dialog ): -class DialogManageServicesServicePanel( wx.Panel ): - - def __init__( self, parent, service_identifier, credentials, extra_info ): + class _Panel( wx.Panel ): - wx.Panel.__init__( self, parent ) - - self._service_identifier = service_identifier - self._credentials = credentials - self._extra_info = extra_info - - service_type = service_identifier.GetType() - - def InitialiseControls(): + def __init__( self, parent, service_identifier, credentials, extra_info ): - self._service_panel = ClientGUICommon.StaticBox( self, 'service' ) + wx.Panel.__init__( self, parent ) - self._service_name = wx.TextCtrl( self._service_panel, value = self._service_identifier.GetName() ) + self._service_identifier = service_identifier + self._credentials = credentials + self._extra_info = extra_info - if service_type in HC.REMOTE_SERVICES: self._service_credentials = wx.TextCtrl( self._service_panel, value = self._credentials.GetConnectionString() ) + service_type = service_identifier.GetType() - if service_type == HC.MESSAGE_DEPOT: + def InitialiseControls(): - ( identity_name, check_period, private_key, receive_anon ) = self._extra_info + self._service_panel = ClientGUICommon.StaticBox( self, 'service' ) - self._identity_name = wx.TextCtrl( self._service_panel, value = identity_name ) + self._service_name = wx.TextCtrl( self._service_panel, value = self._service_identifier.GetName() ) - self._check_period = wx.SpinCtrl( self._service_panel, min = 60, max = 86400 * 7 ) - self._check_period.SetValue( check_period ) + if service_type in HC.REMOTE_SERVICES: self._service_credentials = wx.TextCtrl( self._service_panel, value = self._credentials.GetConnectionString() ) - self._private_key = wx.TextCtrl( self._service_panel, value = private_key, style = wx.TE_MULTILINE ) + if service_type == HC.MESSAGE_DEPOT: + + ( identity_name, check_period, private_key, receive_anon ) = self._extra_info + + self._identity_name = wx.TextCtrl( self._service_panel, value = identity_name ) + + self._check_period = wx.SpinCtrl( self._service_panel, min = 60, max = 86400 * 7 ) + self._check_period.SetValue( check_period ) + + self._private_key = wx.TextCtrl( self._service_panel, value = private_key, style = wx.TE_MULTILINE ) + + self._receive_anon = wx.CheckBox( self._service_panel ) + self._receive_anon.SetValue( receive_anon ) + + elif service_identifier.GetType() == HC.LOCAL_RATING_LIKE: + + ( like, dislike ) = self._extra_info + + self._like = wx.TextCtrl( self._service_panel, value = like ) + self._dislike = wx.TextCtrl( self._service_panel, value = dislike ) + + elif service_identifier.GetType() == HC.LOCAL_RATING_NUMERICAL: + + ( lower, upper ) = self._extra_info + + self._lower = wx.SpinCtrl( self._service_panel, min = -2000, max = 2000 ) + self._lower.SetValue( lower ) + self._upper = wx.SpinCtrl( self._service_panel, min = -2000, max = 2000 ) + self._upper.SetValue( upper ) - self._receive_anon = wx.CheckBox( self._service_panel ) - self._receive_anon.SetValue( receive_anon ) + + def InitialisePanel(): - elif service_identifier.GetType() == HC.LOCAL_RATING_LIKE: + self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) ) - ( like, dislike ) = self._extra_info + vbox = wx.BoxSizer( wx.VERTICAL ) - self._like = wx.TextCtrl( self._service_panel, value = like ) - self._dislike = wx.TextCtrl( self._service_panel, value = dislike ) + gridbox = wx.FlexGridSizer( 0, 2 ) - elif service_identifier.GetType() == HC.LOCAL_RATING_NUMERICAL: + gridbox.AddGrowableCol( 1, 1 ) - ( lower, upper ) = self._extra_info + gridbox.AddF( wx.StaticText( self._service_panel, label='name' ), FLAGS_MIXED ) + gridbox.AddF( self._service_name, FLAGS_EXPAND_BOTH_WAYS ) - self._lower = wx.SpinCtrl( self._service_panel, min = -2000, max = 2000 ) - self._lower.SetValue( lower ) - self._upper = wx.SpinCtrl( self._service_panel, min = -2000, max = 2000 ) - self._upper.SetValue( upper ) + if service_type in HC.REMOTE_SERVICES: + + gridbox.AddF( wx.StaticText( self._service_panel, label='credentials' ), FLAGS_MIXED ) + gridbox.AddF( self._service_credentials, FLAGS_EXPAND_BOTH_WAYS ) + + + if service_type == HC.MESSAGE_DEPOT: + + gridbox.AddF( wx.StaticText( self._service_panel, label='identity name' ), FLAGS_MIXED ) + gridbox.AddF( self._identity_name, FLAGS_EXPAND_BOTH_WAYS ) + + gridbox.AddF( wx.StaticText( self._service_panel, label='update period' ), FLAGS_MIXED ) + gridbox.AddF( self._check_period, FLAGS_EXPAND_BOTH_WAYS ) + + gridbox.AddF( wx.StaticText( self._service_panel, label='private key' ), FLAGS_MIXED ) + gridbox.AddF( self._private_key, FLAGS_EXPAND_BOTH_WAYS ) + + gridbox.AddF( wx.StaticText( self._service_panel, label='receive messages from Anonymous?' ), FLAGS_MIXED ) + gridbox.AddF( self._receive_anon, FLAGS_EXPAND_BOTH_WAYS ) + + elif service_identifier.GetType() == HC.LOCAL_RATING_LIKE: + + gridbox.AddF( wx.StaticText( self._service_panel, label='like' ), FLAGS_MIXED ) + gridbox.AddF( self._like, FLAGS_EXPAND_BOTH_WAYS ) + + gridbox.AddF( wx.StaticText( self._service_panel, label='dislike' ), FLAGS_MIXED ) + gridbox.AddF( self._dislike, FLAGS_EXPAND_BOTH_WAYS ) + + elif service_identifier.GetType() == HC.LOCAL_RATING_NUMERICAL: + + gridbox.AddF( wx.StaticText( self._service_panel, label='lower limit' ), FLAGS_MIXED ) + gridbox.AddF( self._lower, FLAGS_EXPAND_BOTH_WAYS ) + + gridbox.AddF( wx.StaticText( self._service_panel, label='upper limit' ), FLAGS_MIXED ) + gridbox.AddF( self._upper, FLAGS_EXPAND_BOTH_WAYS ) + + + self._service_panel.AddF( gridbox, FLAGS_EXPAND_SIZER_BOTH_WAYS ) + + vbox.AddF( self._service_panel, FLAGS_EXPAND_BOTH_WAYS ) + + self.SetSizer( vbox ) + + + InitialiseControls() + + InitialisePanel() - def InitialisePanel(): + def GetInfo( self ): - self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) ) + service_key = self._service_identifier.GetServiceKey() - vbox = wx.BoxSizer( wx.VERTICAL ) + service_type = self._service_identifier.GetType() - gridbox = wx.FlexGridSizer( 0, 2 ) + name = self._service_name.GetValue() - gridbox.AddGrowableCol( 1, 1 ) + if name == '': raise Exception( 'Please enter a name' ) - gridbox.AddF( wx.StaticText( self._service_panel, label='name' ), FLAGS_MIXED ) - gridbox.AddF( self._service_name, FLAGS_EXPAND_BOTH_WAYS ) + service_identifier = HC.ClientServiceIdentifier( service_key, service_type, name ) if service_type in HC.REMOTE_SERVICES: - gridbox.AddF( wx.StaticText( self._service_panel, label='credentials' ), FLAGS_MIXED ) - gridbox.AddF( self._service_credentials, FLAGS_EXPAND_BOTH_WAYS ) + connection_string = self._service_credentials.GetValue() + if connection_string == '': raise Exception( 'Please enter some credentials' ) + + if '@' in connection_string: + + try: ( access_key, address ) = connection_string.split( '@' ) + except: raise Exception( 'Could not parse those credentials - no \'@\' symbol!' ) + + try: access_key = access_key.decode( 'hex' ) + except: raise Exception( 'Could not parse those credentials - could not understand access key!' ) + + try: ( host, port ) = address.split( ':' ) + except: raise Exception( 'Could not parse those credentials - no \':\' symbol!' ) + + try: port = int( port ) + except: raise Exception( 'Could not parse those credentials - could not understand the port!' ) + + credentials = CC.Credentials( host, port, access_key ) + + else: + + try: ( host, port ) = connection_string.split( ':' ) + except: raise Exception( 'Could not parse those credentials - no \':\' symbol!' ) + + try: port = int( port ) + except: raise Exception( 'Could not parse those credentials - could not understand the port!' ) + + credentials = CC.Credentials( host, port ) + + + else: credentials = None + + if service_type == HC.MESSAGE_DEPOT: extra_info = ( self._identity_name.GetValue(), self._check_period.GetValue(), self._private_key.GetValue(), self._receive_anon.GetValue() ) + elif service_type == HC.LOCAL_RATING_LIKE: extra_info = ( self._like.GetValue(), self._dislike.GetValue() ) + elif service_type == HC.LOCAL_RATING_NUMERICAL: + + ( lower, upper ) = ( self._lower.GetValue(), self._upper.GetValue() ) + + if upper < lower: upper = lower + 1 + + extra_info = ( lower, upper ) + + else: extra_info = None + + return ( service_identifier, credentials, extra_info ) + + + def HasChanges( self ): + + ( service_identifier, credentials, extra_info ) = self.GetInfo() + + if service_identifier != self._service_identifier: return True + + if credentials != self._credentials: return True + + if extra_info != self._extra_info: return True + + return False + + + def GetOriginalServiceIdentifier( self ): return self._service_identifier + + def Update( self, service_identifier, credentials, extra_info ): + + service_type = service_identifier.GetType() + + self._service_name.SetValue( service_identifier.GetName() ) + + if service_type in HC.REMOTE_SERVICES: self._service_credentials.SetValue( credentials.GetConnectionString() ) if service_type == HC.MESSAGE_DEPOT: - gridbox.AddF( wx.StaticText( self._service_panel, label='identity name' ), FLAGS_MIXED ) - gridbox.AddF( self._identity_name, FLAGS_EXPAND_BOTH_WAYS ) + if len( extra_info ) == 3: + ( identity_name, check_period, private_key ) = extra_info + receive_anon = True + else: ( identity_name, check_period, private_key, receive_anon ) = extra_info - gridbox.AddF( wx.StaticText( self._service_panel, label='update period' ), FLAGS_MIXED ) - gridbox.AddF( self._check_period, FLAGS_EXPAND_BOTH_WAYS ) + self._identity_name.SetValue( identity_name ) - gridbox.AddF( wx.StaticText( self._service_panel, label='private key' ), FLAGS_MIXED ) - gridbox.AddF( self._private_key, FLAGS_EXPAND_BOTH_WAYS ) + self._check_period.SetValue( check_period ) - gridbox.AddF( wx.StaticText( self._service_panel, label='receive messages from Anonymous?' ), FLAGS_MIXED ) - gridbox.AddF( self._receive_anon, FLAGS_EXPAND_BOTH_WAYS ) + self._private_key.SetValue( private_key ) - elif service_identifier.GetType() == HC.LOCAL_RATING_LIKE: + self._receive_anon.SetValue( receive_anon ) - gridbox.AddF( wx.StaticText( self._service_panel, label='like' ), FLAGS_MIXED ) - gridbox.AddF( self._like, FLAGS_EXPAND_BOTH_WAYS ) + elif service_type == HC.LOCAL_RATING_LIKE: - gridbox.AddF( wx.StaticText( self._service_panel, label='dislike' ), FLAGS_MIXED ) - gridbox.AddF( self._dislike, FLAGS_EXPAND_BOTH_WAYS ) + ( like, dislike ) = extra_info - elif service_identifier.GetType() == HC.LOCAL_RATING_NUMERICAL: + self._like.SetValue( like ) + self._dislike.SetValue( dislike ) - gridbox.AddF( wx.StaticText( self._service_panel, label='lower limit' ), FLAGS_MIXED ) - gridbox.AddF( self._lower, FLAGS_EXPAND_BOTH_WAYS ) + elif service_type == HC.LOCAL_RATING_NUMERICAL: - gridbox.AddF( wx.StaticText( self._service_panel, label='upper limit' ), FLAGS_MIXED ) - gridbox.AddF( self._upper, FLAGS_EXPAND_BOTH_WAYS ) + ( lower, upper ) = extra_info - - self._service_panel.AddF( gridbox, FLAGS_EXPAND_SIZER_BOTH_WAYS ) - - vbox.AddF( self._service_panel, FLAGS_EXPAND_BOTH_WAYS ) - - self.SetSizer( vbox ) - - - InitialiseControls() - - InitialisePanel() - - - def GetInfo( self ): - - service_key = self._service_identifier.GetServiceKey() - - service_type = self._service_identifier.GetType() - - name = self._service_name.GetValue() - - if name == '': raise Exception( 'Please enter a name' ) - - service_identifier = HC.ClientServiceIdentifier( service_key, service_type, name ) - - if service_type in HC.REMOTE_SERVICES: - - connection_string = self._service_credentials.GetValue() - - if connection_string == '': raise Exception( 'Please enter some credentials' ) - - if '@' in connection_string: + self._lower.SetValue( lower ) + self._upper.SetValue( upper ) - try: ( access_key, address ) = connection_string.split( '@' ) - except: raise Exception( 'Could not parse those credentials - no \'@\' symbol!' ) - - try: access_key = access_key.decode( 'hex' ) - except: raise Exception( 'Could not parse those credentials - could not understand access key!' ) - - try: ( host, port ) = address.split( ':' ) - except: raise Exception( 'Could not parse those credentials - no \':\' symbol!' ) - - try: port = int( port ) - except: raise Exception( 'Could not parse those credentials - could not understand the port!' ) - - credentials = CC.Credentials( host, port, access_key ) - - else: - - try: ( host, port ) = connection_string.split( ':' ) - except: raise Exception( 'Could not parse those credentials - no \':\' symbol!' ) - - try: port = int( port ) - except: raise Exception( 'Could not parse those credentials - could not understand the port!' ) - - credentials = CC.Credentials( host, port ) - - - else: credentials = None - - if service_type == HC.MESSAGE_DEPOT: extra_info = ( self._identity_name.GetValue(), self._check_period.GetValue(), self._private_key.GetValue(), self._receive_anon.GetValue() ) - elif service_type == HC.LOCAL_RATING_LIKE: extra_info = ( self._like.GetValue(), self._dislike.GetValue() ) - elif service_type == HC.LOCAL_RATING_NUMERICAL: - - ( lower, upper ) = ( self._lower.GetValue(), self._upper.GetValue() ) - - if upper < lower: upper = lower + 1 - - extra_info = ( lower, upper ) - - else: extra_info = None - - return ( service_identifier, credentials, extra_info ) - - - def HasChanges( self ): - - ( service_identifier, credentials, extra_info ) = self.GetInfo() - - if service_identifier != self._service_identifier: return True - - if credentials != self._credentials: return True - - if extra_info != self._extra_info: return True - - return False - - - def GetOriginalServiceIdentifier( self ): return self._service_identifier - - def Update( self, service_identifier, credentials, extra_info ): - - service_type = service_identifier.GetType() - - self._service_name.SetValue( service_identifier.GetName() ) - - if service_type in HC.REMOTE_SERVICES: self._service_credentials.SetValue( credentials.GetConnectionString() ) - - if service_type == HC.MESSAGE_DEPOT: - - if len( extra_info ) == 3: - ( identity_name, check_period, private_key ) = extra_info - receive_anon = True - else: ( identity_name, check_period, private_key, receive_anon ) = extra_info - - self._identity_name.SetValue( identity_name ) - - self._check_period.SetValue( check_period ) - - self._private_key.SetValue( private_key ) - - self._receive_anon.SetValue( receive_anon ) - - elif service_type == HC.LOCAL_RATING_LIKE: - - ( like, dislike ) = extra_info - - self._like.SetValue( like ) - self._dislike.SetValue( dislike ) - - elif service_type == HC.LOCAL_RATING_NUMERICAL: - - ( lower, upper ) = extra_info - - self._lower.SetValue( lower ) - self._upper.SetValue( upper ) @@ -6470,7 +6477,7 @@ class DialogManageTags( Dialog ): service_type = service_identifier.GetType() - page_info = ( DialogManageTagsPanel, ( self._tag_repositories, self._file_service_identifier, service_identifier, media ), {} ) + page_info = ( self._Panel, ( self._tag_repositories, self._file_service_identifier, service_identifier, media ), {} ) name = service_identifier.GetName() @@ -6561,7 +6568,7 @@ class DialogManageTags( Dialog ): edit_log = page.GetEditLog() - content_updates.append( CC.ContentUpdate( CC.CONTENT_UPDATE_EDIT_LOG, service_identifier, self._hashes, info = edit_log ) ) + content_updates.append( HC.ContentUpdate( CC.CONTENT_UPDATE_EDIT_LOG, service_identifier, self._hashes, info = edit_log ) ) @@ -6590,175 +6597,184 @@ class DialogManageTags( Dialog ): self.SetAcceleratorTable( wx.AcceleratorTable( entries ) ) -class DialogManageTagsPanel( wx.Panel ): - - def __init__( self, parent, file_service_identifier, tag_service_identifier, media ): + class _Panel( wx.Panel ): - def InitialiseControls(): + def __init__( self, parent, file_service_identifier, tag_service_identifier, media ): - self._tags_box = ClientGUICommon.TagsBoxManage( self, self.AddTag, self._current_tags, self._deleted_tags, self._pending_tags, self._petitioned_tags ) - - self._add_tag_box = ClientGUICommon.AutoCompleteDropdownTagsWrite( self, self.AddTag, self._file_service_identifier, self._tag_service_identifier ) - - self._show_deleted_tags = wx.CheckBox( self, label='Show deleted tags' ) - self._show_deleted_tags.Bind( wx.EVT_CHECKBOX, self.EventShowDeletedTags ) - - self._modify_mappers = wx.Button( self, label='Modify mappers' ) - self._modify_mappers.Bind( wx.EVT_BUTTON, self.EventModify ) - - self._copy_tags = wx.Button( self, label = 'copy tags' ) - self._copy_tags.Bind( wx.EVT_BUTTON, self.EventCopyTags ) - - self._paste_tags = wx.Button( self, label = 'paste tags' ) - self._paste_tags.Bind( wx.EVT_BUTTON, self.EventPasteTags ) - - if self._i_am_local_tag_service: + def InitialiseControls(): - self._show_deleted_tags.Hide() - self._modify_mappers.Hide() + self._tags_box = ClientGUICommon.TagsBoxManage( self, self.AddTag, self._current_tags, self._deleted_tags, self._pending_tags, self._petitioned_tags ) - else: + self._add_tag_box = ClientGUICommon.AutoCompleteDropdownTagsWrite( self, self.AddTag, self._file_service_identifier, self._tag_service_identifier ) - if not self._account.HasPermission( HC.POST_DATA ): self._add_tag_box.Hide() - if not self._account.HasPermission( HC.MANAGE_USERS ): self._modify_mappers.Hide() + self._show_deleted_tags = wx.CheckBox( self, label='Show deleted tags' ) + self._show_deleted_tags.Bind( wx.EVT_CHECKBOX, self.EventShowDeletedTags ) - - - def InitialisePanel(): - - self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) ) - - special_hbox = wx.BoxSizer( wx.HORIZONTAL ) - - special_hbox.AddF( self._show_deleted_tags, FLAGS_MIXED ) - special_hbox.AddF( self._modify_mappers, FLAGS_MIXED ) - - copy_paste_hbox = wx.BoxSizer( wx.HORIZONTAL ) - - copy_paste_hbox.AddF( self._copy_tags, FLAGS_MIXED ) - copy_paste_hbox.AddF( self._paste_tags, FLAGS_MIXED ) - - vbox = wx.BoxSizer( wx.VERTICAL ) - - vbox.AddF( self._tags_box, FLAGS_EXPAND_BOTH_WAYS ) - vbox.AddF( self._add_tag_box, FLAGS_EXPAND_PERPENDICULAR ) - vbox.AddF( copy_paste_hbox, FLAGS_BUTTON_SIZERS ) - vbox.AddF( special_hbox, FLAGS_BUTTON_SIZERS ) - - self.SetSizer( vbox ) - - - wx.Panel.__init__( self, parent ) - - self._file_service_identifier = file_service_identifier - self._tag_service_identifier = tag_service_identifier - - self._i_am_local_tag_service = self._tag_service_identifier.GetType() == HC.LOCAL_TAG - - self._edit_log = [] - - if not self._i_am_local_tag_service: - - service = wx.GetApp().Read( 'service', tag_service_identifier ) - - self._account = service.GetAccount() - - - ( self._current_tags, self._deleted_tags, self._pending_tags, self._petitioned_tags ) = CC.MediaIntersectCDPPTagServiceIdentifiers( media, tag_service_identifier ) - - self._current_tags.sort() - self._pending_tags.sort() - - InitialiseControls() - - InitialisePanel() - - - def AddTag( self, tag ): - - if tag is None: wx.PostEvent( self, wx.CommandEvent( commandType = wx.wxEVT_COMMAND_MENU_SELECTED, winid = CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'ok' ) ) ) - else: - - if self._i_am_local_tag_service: + self._modify_mappers = wx.Button( self, label='Modify mappers' ) + self._modify_mappers.Bind( wx.EVT_BUTTON, self.EventModify ) - if tag in self._pending_tags: + self._copy_tags = wx.Button( self, label = 'copy tags' ) + self._copy_tags.Bind( wx.EVT_BUTTON, self.EventCopyTags ) + + self._paste_tags = wx.Button( self, label = 'paste tags' ) + self._paste_tags.Bind( wx.EVT_BUTTON, self.EventPasteTags ) + + if self._i_am_local_tag_service: - self._pending_tags.remove( tag ) - - self._tags_box.RescindPend( tag ) - - elif tag in self._petitioned_tags: - - self._petitioned_tags.remove( tag ) - - self._tags_box.RescindPetition( tag ) - - elif tag in self._current_tags: - - self._petitioned_tags.append( tag ) - - self._tags_box.PetitionTag( tag ) + self._show_deleted_tags.Hide() + self._modify_mappers.Hide() else: - self._pending_tags.append( tag ) - - self._tags_box.PendTag( tag ) + if not self._account.HasPermission( HC.POST_DATA ): self._add_tag_box.Hide() + if not self._account.HasPermission( HC.MANAGE_USERS ): self._modify_mappers.Hide() - self._edit_log = [] + + def InitialisePanel(): - self._edit_log.extend( [ ( CC.CONTENT_UPDATE_ADD, tag ) for tag in self._pending_tags ] ) - self._edit_log.extend( [ ( CC.CONTENT_UPDATE_DELETE, tag ) for tag in self._petitioned_tags ] ) + self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) ) + special_hbox = wx.BoxSizer( wx.HORIZONTAL ) + + special_hbox.AddF( self._show_deleted_tags, FLAGS_MIXED ) + special_hbox.AddF( self._modify_mappers, FLAGS_MIXED ) + + copy_paste_hbox = wx.BoxSizer( wx.HORIZONTAL ) + + copy_paste_hbox.AddF( self._copy_tags, FLAGS_MIXED ) + copy_paste_hbox.AddF( self._paste_tags, FLAGS_MIXED ) + + vbox = wx.BoxSizer( wx.VERTICAL ) + + vbox.AddF( self._tags_box, FLAGS_EXPAND_BOTH_WAYS ) + vbox.AddF( self._add_tag_box, FLAGS_EXPAND_PERPENDICULAR ) + vbox.AddF( copy_paste_hbox, FLAGS_BUTTON_SIZERS ) + vbox.AddF( special_hbox, FLAGS_BUTTON_SIZERS ) + + self.SetSizer( vbox ) + + + wx.Panel.__init__( self, parent ) + + self._file_service_identifier = file_service_identifier + self._tag_service_identifier = tag_service_identifier + + self._i_am_local_tag_service = self._tag_service_identifier.GetType() == HC.LOCAL_TAG + + self._edit_log = [] + + if not self._i_am_local_tag_service: + + service = wx.GetApp().Read( 'service', tag_service_identifier ) + + self._account = service.GetAccount() + + + ( self._current_tags, self._deleted_tags, self._pending_tags, self._petitioned_tags ) = CC.MediaIntersectCDPPTagServiceIdentifiers( media, tag_service_identifier ) + + self._current_tags.sort() + self._pending_tags.sort() + + InitialiseControls() + + InitialisePanel() + + + def AddTag( self, tag ): + + if tag is None: wx.PostEvent( self, wx.CommandEvent( commandType = wx.wxEVT_COMMAND_MENU_SELECTED, winid = CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'ok' ) ) ) else: - if tag in self._pending_tags: + if self._i_am_local_tag_service: - self._pending_tags.remove( tag ) - - self._tags_box.RescindPend( tag ) - - self._edit_log.append( ( CC.CONTENT_UPDATE_RESCIND_PENDING, tag ) ) - - elif tag in self._petitioned_tags: - - self._petitioned_tags.remove( tag ) - - self._tags_box.RescindPetition( tag ) - - self._edit_log.append( ( CC.CONTENT_UPDATE_RESCIND_PETITION, tag ) ) - - elif tag in self._current_tags: - - if self._account.HasPermission( HC.RESOLVE_PETITIONS ): + if tag in self._pending_tags: - self._edit_log.append( ( CC.CONTENT_UPDATE_PETITION, ( tag, 'admin' ) ) ) + self._pending_tags.remove( tag ) + + self._tags_box.RescindPend( tag ) + + elif tag in self._petitioned_tags: + + self._petitioned_tags.remove( tag ) + + self._tags_box.RescindPetition( tag ) + + elif tag in self._current_tags: self._petitioned_tags.append( tag ) self._tags_box.PetitionTag( tag ) - elif self._account.HasPermission( HC.POST_PETITIONS ): + else: - message = 'Enter a reason for this tag to be removed. A janitor will review your petition.' + self._pending_tags.append( tag ) - with wx.TextEntryDialog( self, message ) as dlg: + self._tags_box.PendTag( tag ) + + + self._edit_log = [] + + self._edit_log.extend( [ ( CC.CONTENT_UPDATE_ADD, tag ) for tag in self._pending_tags ] ) + self._edit_log.extend( [ ( CC.CONTENT_UPDATE_DELETE, tag ) for tag in self._petitioned_tags ] ) + + else: + + if tag in self._pending_tags: + + self._pending_tags.remove( tag ) + + self._tags_box.RescindPend( tag ) + + self._edit_log.append( ( CC.CONTENT_UPDATE_RESCIND_PENDING, tag ) ) + + elif tag in self._petitioned_tags: + + self._petitioned_tags.remove( tag ) + + self._tags_box.RescindPetition( tag ) + + self._edit_log.append( ( CC.CONTENT_UPDATE_RESCIND_PETITION, tag ) ) + + elif tag in self._current_tags: + + if self._account.HasPermission( HC.RESOLVE_PETITIONS ): - if dlg.ShowModal() == wx.ID_OK: + self._edit_log.append( ( CC.CONTENT_UPDATE_PETITION, ( tag, 'admin' ) ) ) + + self._petitioned_tags.append( tag ) + + self._tags_box.PetitionTag( tag ) + + elif self._account.HasPermission( HC.POST_PETITIONS ): + + message = 'Enter a reason for this tag to be removed. A janitor will review your petition.' + + with wx.TextEntryDialog( self, message ) as dlg: - self._edit_log.append( ( CC.CONTENT_UPDATE_PETITION, ( tag, dlg.GetValue() ) ) ) - - self._petitioned_tags.append( tag ) - - self._tags_box.PetitionTag( tag ) + if dlg.ShowModal() == wx.ID_OK: + + self._edit_log.append( ( CC.CONTENT_UPDATE_PETITION, ( tag, dlg.GetValue() ) ) ) + + self._petitioned_tags.append( tag ) + + self._tags_box.PetitionTag( tag ) + - - elif tag in self._deleted_tags: - - if self._account.HasPermission( HC.RESOLVE_PETITIONS ): + elif tag in self._deleted_tags: + + if self._account.HasPermission( HC.RESOLVE_PETITIONS ): + + self._edit_log.append( ( CC.CONTENT_UPDATE_PENDING, tag ) ) + + self._pending_tags.append( tag ) + + self._tags_box.PendTag( tag ) + + + else: self._edit_log.append( ( CC.CONTENT_UPDATE_PENDING, tag ) ) @@ -6767,94 +6783,86 @@ class DialogManageTagsPanel( wx.Panel ): self._tags_box.PendTag( tag ) - else: + + + + def EventCopyTags( self, event ): + + if wx.TheClipboard.Open(): + + tags = self._current_tags + self._pending_tags + + text = yaml.safe_dump( tags ) + + data = wx.TextDataObject( text ) + + wx.TheClipboard.SetData( data ) + + wx.TheClipboard.Close() + + else: wx.MessageBox( 'I could not get permission to access the clipboard.' ) + + + def EventModify( self, event ): + + tag = self._tags_box.GetSelectedTag() + + if tag is not None and tag in self._current_tags or tag in self._petitioned_tags: + + subject_identifiers = [ HC.AccountIdentifier( hash = hash, tag = tag ) for hash in self._hashes ] + + try: - self._edit_log.append( ( CC.CONTENT_UPDATE_PENDING, tag ) ) + with DialogModifyAccounts( self, self._tag_service_identifier, subject_identifiers ) as dlg: dlg.ShowModal() - self._pending_tags.append( tag ) + except Exception as e: wx.MessageBox( unicode( e ) ) + + + + def EventPasteTags( self, event ): + + if wx.TheClipboard.Open(): + + data = wx.TextDataObject() + + wx.TheClipboard.GetData( data ) + + wx.TheClipboard.Close() + + text = data.GetText() + + try: - self._tags_box.PendTag( tag ) + tags = yaml.safe_load( text ) + tags = [ tag for tag in tags if tag not in self._current_tags and tag not in self._pending_tags ] + + for tag in tags: self.AddTag( tag ) + + except: wx.MessageBox( 'I could not understand what was in the clipboard' ) + else: wx.MessageBox( 'I could not get permission to access the clipboard.' ) - - def EventCopyTags( self, event ): + def EventShowDeletedTags( self, event ): self._tags_box.SetShowDeletedTags( self._show_deleted_tags.GetValue() ) - if wx.TheClipboard.Open(): + def EventTagsBoxAction( self, event ): - tags = self._current_tags + self._pending_tags + tag = self._tags_box.GetSelectedTag() - text = yaml.safe_dump( tags ) - - data = wx.TextDataObject( text ) - - wx.TheClipboard.SetData( data ) - - wx.TheClipboard.Close() - - else: wx.MessageBox( 'I could not get permission to access the clipboard.' ) - - - def EventModify( self, event ): - - tag = self._tags_box.GetSelectedTag() - - if tag is not None and tag in self._current_tags or tag in self._petitioned_tags: - - subject_identifiers = [ HC.AccountIdentifier( hash = hash, tag = tag ) for hash in self._hashes ] - - try: - - with DialogModifyAccounts( self, self._tag_service_identifier, subject_identifiers ) as dlg: dlg.ShowModal() - - except Exception as e: wx.MessageBox( unicode( e ) ) + if tag is not None: self.AddTag( tag ) - - def EventPasteTags( self, event ): + def GetEditLog( self ): return self._edit_log - if wx.TheClipboard.Open(): - - data = wx.TextDataObject() - - wx.TheClipboard.GetData( data ) - - wx.TheClipboard.Close() - - text = data.GetText() - - try: - - tags = yaml.safe_load( text ) - - tags = [ tag for tag in tags if tag not in self._current_tags and tag not in self._pending_tags ] - - for tag in tags: self.AddTag( tag ) - - except: wx.MessageBox( 'I could not understand what was in the clipboard' ) - - else: wx.MessageBox( 'I could not get permission to access the clipboard.' ) + def GetServiceIdentifier( self ): return self._tag_service_identifier - - def EventShowDeletedTags( self, event ): self._tags_box.SetShowDeletedTags( self._show_deleted_tags.GetValue() ) - - def EventTagsBoxAction( self, event ): + def HasChanges( self ): return len( self._edit_log ) > 0 - tag = self._tags_box.GetSelectedTag() - - if tag is not None: self.AddTag( tag ) - - - def GetEditLog( self ): return self._edit_log - - def GetServiceIdentifier( self ): return self._tag_service_identifier - - def HasChanges( self ): return len( self._edit_log ) > 0 - - def SetTagBoxFocus( self ): - - if self._i_am_local_tag_service or self._account.HasPermission( HC.POST_DATA ): self._add_tag_box.SetFocus() + def SetTagBoxFocus( self ): + + if self._i_am_local_tag_service or self._account.HasPermission( HC.POST_DATA ): self._add_tag_box.SetFocus() + class DialogMessage( Dialog ): @@ -7180,7 +7188,7 @@ class DialogPathsToTagsRegex( Dialog ): service_identifier = service.GetServiceIdentifier() - page_info = ( DialogPathsToTagsRegexPanel, ( self._tag_repositories, service_identifier, paths ), {} ) + page_info = ( self._Panel, ( self._tag_repositories, service_identifier, paths ), {} ) name = service_identifier.GetName() @@ -7188,7 +7196,7 @@ class DialogPathsToTagsRegex( Dialog ): - page = DialogPathsToTagsRegexPanel( self._tag_repositories, CC.LOCAL_TAG_SERVICE_IDENTIFIER, paths ) + page = self._Panel( self._tag_repositories, CC.LOCAL_TAG_SERVICE_IDENTIFIER, paths ) name = CC.LOCAL_TAG_SERVICE_IDENTIFIER.GetName() @@ -7312,252 +7320,423 @@ class DialogPathsToTagsRegex( Dialog ): return paths_to_tags -class DialogPathsToTagsRegexPanel( wx.Panel ): - - ID_REGEX_WHITESPACE = 0 - ID_REGEX_NUMBER = 1 - ID_REGEX_ALPHANUMERIC = 2 - ID_REGEX_ANY = 3 - ID_REGEX_BEGINNING = 4 - ID_REGEX_END = 5 - ID_REGEX_0_OR_MORE_GREEDY = 6 - ID_REGEX_1_OR_MORE_GREEDY = 7 - ID_REGEX_0_OR_1_GREEDY = 8 - ID_REGEX_0_OR_MORE_MINIMAL = 9 - ID_REGEX_1_OR_MORE_MINIMAL = 10 - ID_REGEX_0_OR_1_MINIMAL = 11 - ID_REGEX_EXACTLY_M = 12 - ID_REGEX_M_TO_N_GREEDY = 13 - ID_REGEX_M_TO_N_MINIMAL = 14 - ID_REGEX_LOOKAHEAD = 15 - ID_REGEX_NEGATIVE_LOOKAHEAD = 16 - ID_REGEX_LOOKBEHIND = 17 - ID_REGEX_NEGATIVE_LOOKBEHIND = 18 - ID_REGEX_NUMBER_WITHOUT_ZEROES = 19 - ID_REGEX_NUMBER_EXT = 20 - ID_REGEX_AUTHOR = 21 - ID_REGEX_BACKSPACE = 22 - ID_REGEX_SET = 23 - ID_REGEX_NOT_SET = 24 - - def __init__( self, parent, service_identifier, paths ): + class _Panel( wx.Panel ): - def InitialiseControls(): + ID_REGEX_WHITESPACE = 0 + ID_REGEX_NUMBER = 1 + ID_REGEX_ALPHANUMERIC = 2 + ID_REGEX_ANY = 3 + ID_REGEX_BEGINNING = 4 + ID_REGEX_END = 5 + ID_REGEX_0_OR_MORE_GREEDY = 6 + ID_REGEX_1_OR_MORE_GREEDY = 7 + ID_REGEX_0_OR_1_GREEDY = 8 + ID_REGEX_0_OR_MORE_MINIMAL = 9 + ID_REGEX_1_OR_MORE_MINIMAL = 10 + ID_REGEX_0_OR_1_MINIMAL = 11 + ID_REGEX_EXACTLY_M = 12 + ID_REGEX_M_TO_N_GREEDY = 13 + ID_REGEX_M_TO_N_MINIMAL = 14 + ID_REGEX_LOOKAHEAD = 15 + ID_REGEX_NEGATIVE_LOOKAHEAD = 16 + ID_REGEX_LOOKBEHIND = 17 + ID_REGEX_NEGATIVE_LOOKBEHIND = 18 + ID_REGEX_NUMBER_WITHOUT_ZEROES = 19 + ID_REGEX_NUMBER_EXT = 20 + ID_REGEX_AUTHOR = 21 + ID_REGEX_BACKSPACE = 22 + ID_REGEX_SET = 23 + ID_REGEX_NOT_SET = 24 + + def __init__( self, parent, service_identifier, paths ): - self._paths_list = ClientGUICommon.SaneListCtrl( self, 300, [ ( 'path', 400 ), ( 'tags', -1 ) ] ) + def InitialiseControls(): + + self._paths_list = ClientGUICommon.SaneListCtrl( self, 300, [ ( 'path', 400 ), ( 'tags', -1 ) ] ) + + self._paths_list.Bind( wx.EVT_LIST_ITEM_SELECTED, self.EventItemSelected ) + self._paths_list.Bind( wx.EVT_LIST_ITEM_DESELECTED, self.EventItemSelected ) + + # + + self._quick_namespaces_panel = ClientGUICommon.StaticBox( self, 'quick namespaces' ) + + self._page_regex = wx.TextCtrl( self._quick_namespaces_panel ) + self._chapter_regex = wx.TextCtrl( self._quick_namespaces_panel ) + self._volume_regex = wx.TextCtrl( self._quick_namespaces_panel ) + self._title_regex = wx.TextCtrl( self._quick_namespaces_panel ) + self._series_regex = wx.TextCtrl( self._quick_namespaces_panel ) + self._creator_regex = wx.TextCtrl( self._quick_namespaces_panel ) + + self._update_button = wx.Button( self._quick_namespaces_panel, label='update' ) + self._update_button.Bind( wx.EVT_BUTTON, self.EventUpdate ) + + self._regex_shortcuts = wx.Button( self._quick_namespaces_panel, label = 'regex shortcuts' ) + self._regex_shortcuts.Bind( wx.EVT_BUTTON, self.EventRegexShortcuts ) + + self._regex_link = wx.HyperlinkCtrl( self._quick_namespaces_panel, id = -1, label = 'a good regex introduction', url = 'http://www.aivosto.com/vbtips/regex.html' ) + + # + + self._regexes_panel = ClientGUICommon.StaticBox( self, 'regexes' ) + + self._regexes = wx.ListBox( self._regexes_panel ) + self._regexes.Bind( wx.EVT_LISTBOX_DCLICK, self.EventRemoveRegex ) + + self._regex_box = wx.TextCtrl( self._regexes_panel, style=wx.TE_PROCESS_ENTER ) + self._regex_box.Bind( wx.EVT_TEXT_ENTER, self.EventAddRegex ) + + # + + self._tags_panel = ClientGUICommon.StaticBox( self, 'tags for all' ) + + self._tags = ClientGUICommon.TagsBoxFlat( self._tags_panel, self.TagRemoved ) + + self._tag_box = ClientGUICommon.AutoCompleteDropdownTagsWrite( self._tags_panel, self.AddTag, CC.LOCAL_FILE_SERVICE_IDENTIFIER, service_identifier ) + + # + + self._single_tags_panel = ClientGUICommon.StaticBox( self, 'tags just for this file' ) + + self._paths_to_single_tags = collections.defaultdict( list ) + + self._single_tags = ClientGUICommon.TagsBoxFlat( self._single_tags_panel, self.SingleTagRemoved ) + + self._single_tag_box = ClientGUICommon.AutoCompleteDropdownTagsWrite( self._single_tags_panel, self.AddTagSingle, CC.LOCAL_FILE_SERVICE_IDENTIFIER, service_identifier ) + self._single_tag_box.Disable() + + for path in self._paths: + + tags = self._GetTags( path ) + + tags_string = ', '.join( tags ) + + self._paths_list.Append( ( path, tags_string ), ( path, tags ) ) + + - self._paths_list.Bind( wx.EVT_LIST_ITEM_SELECTED, self.EventItemSelected ) - self._paths_list.Bind( wx.EVT_LIST_ITEM_DESELECTED, self.EventItemSelected ) + def InitialisePanel(): + + gridbox = wx.FlexGridSizer( 0, 2 ) + + gridbox.AddGrowableCol( 1, 1 ) + + gridbox.AddF( wx.StaticText( self._quick_namespaces_panel, label='Page regex ' ), FLAGS_MIXED ) + gridbox.AddF( self._page_regex, FLAGS_EXPAND_BOTH_WAYS ) + gridbox.AddF( wx.StaticText( self._quick_namespaces_panel, label='Chapter regex ' ), FLAGS_MIXED ) + gridbox.AddF( self._chapter_regex, FLAGS_EXPAND_BOTH_WAYS ) + gridbox.AddF( wx.StaticText( self._quick_namespaces_panel, label='Volume regex ' ), FLAGS_MIXED ) + gridbox.AddF( self._volume_regex, FLAGS_EXPAND_BOTH_WAYS ) + gridbox.AddF( wx.StaticText( self._quick_namespaces_panel, label='Title regex ' ), FLAGS_MIXED ) + gridbox.AddF( self._title_regex, FLAGS_EXPAND_BOTH_WAYS ) + gridbox.AddF( wx.StaticText( self._quick_namespaces_panel, label='Series regex ' ), FLAGS_MIXED ) + gridbox.AddF( self._series_regex, FLAGS_EXPAND_BOTH_WAYS ) + gridbox.AddF( wx.StaticText( self._quick_namespaces_panel, label='Creator regex ' ), FLAGS_MIXED ) + gridbox.AddF( self._creator_regex, FLAGS_EXPAND_BOTH_WAYS ) + + self._quick_namespaces_panel.AddF( gridbox, FLAGS_EXPAND_SIZER_PERPENDICULAR ) + self._quick_namespaces_panel.AddF( self._update_button, FLAGS_LONE_BUTTON ) + self._quick_namespaces_panel.AddF( self._regex_shortcuts, FLAGS_LONE_BUTTON ) + self._quick_namespaces_panel.AddF( self._regex_link, FLAGS_LONE_BUTTON ) + + self._regexes_panel.AddF( self._regexes, FLAGS_EXPAND_BOTH_WAYS ) + self._regexes_panel.AddF( self._regex_box, FLAGS_EXPAND_PERPENDICULAR ) + + self._tags_panel.AddF( self._tags, FLAGS_EXPAND_BOTH_WAYS ) + self._tags_panel.AddF( self._tag_box, FLAGS_EXPAND_PERPENDICULAR ) + + self._single_tags_panel.AddF( self._single_tags, FLAGS_EXPAND_BOTH_WAYS ) + self._single_tags_panel.AddF( self._single_tag_box, FLAGS_EXPAND_PERPENDICULAR ) + + hbox = wx.BoxSizer( wx.HORIZONTAL ) + + hbox.AddF( self._quick_namespaces_panel, FLAGS_EXPAND_BOTH_WAYS ) + hbox.AddF( self._regexes_panel, FLAGS_EXPAND_BOTH_WAYS ) + hbox.AddF( self._tags_panel, FLAGS_EXPAND_BOTH_WAYS ) + hbox.AddF( self._single_tags_panel, FLAGS_EXPAND_BOTH_WAYS ) + + vbox = wx.BoxSizer( wx.VERTICAL ) + + vbox.AddF( self._paths_list, FLAGS_EXPAND_BOTH_WAYS ) + vbox.AddF( hbox, FLAGS_EXPAND_SIZER_BOTH_WAYS ) + + self.SetSizer( vbox ) + - # + wx.Panel.__init__( self, parent ) - self._quick_namespaces_panel = ClientGUICommon.StaticBox( self, 'quick namespaces' ) + self._service_identifier = service_identifier + self._paths = paths - self._page_regex = wx.TextCtrl( self._quick_namespaces_panel ) - self._chapter_regex = wx.TextCtrl( self._quick_namespaces_panel ) - self._volume_regex = wx.TextCtrl( self._quick_namespaces_panel ) - self._title_regex = wx.TextCtrl( self._quick_namespaces_panel ) - self._series_regex = wx.TextCtrl( self._quick_namespaces_panel ) - self._creator_regex = wx.TextCtrl( self._quick_namespaces_panel ) + InitialiseControls() - self._update_button = wx.Button( self._quick_namespaces_panel, label='update' ) - self._update_button.Bind( wx.EVT_BUTTON, self.EventUpdate ) + InitialisePanel() - self._regex_shortcuts = wx.Button( self._quick_namespaces_panel, label = 'regex shortcuts' ) - self._regex_shortcuts.Bind( wx.EVT_BUTTON, self.EventRegexShortcuts ) + self.Bind( wx.EVT_MENU, self.EventMenu ) - self._regex_link = wx.HyperlinkCtrl( self._quick_namespaces_panel, id = -1, label = 'a good regex introduction', url = 'http://www.aivosto.com/vbtips/regex.html' ) + + + def _GetTags( self, path ): - # + tags = [] - self._regexes_panel = ClientGUICommon.StaticBox( self, 'regexes' ) + tags.extend( self._tags.GetTags() ) - self._regexes = wx.ListBox( self._regexes_panel ) - self._regexes.Bind( wx.EVT_LISTBOX_DCLICK, self.EventRemoveRegex ) + for regex in self._regexes.GetStrings(): + + try: + + m = re.search( regex, path ) + + if m is not None: + + match = m.group() + + if len( match ) > 0: tags.append( match ) + + + except: pass + - self._regex_box = wx.TextCtrl( self._regexes_panel, style=wx.TE_PROCESS_ENTER ) - self._regex_box.Bind( wx.EVT_TEXT_ENTER, self.EventAddRegex ) + namespaced_regexes = [] - # + namespaced_regexes.append( ( self._page_regex, 'page:' ) ) + namespaced_regexes.append( ( self._chapter_regex, 'chapter:' ) ) + namespaced_regexes.append( ( self._volume_regex, 'volume:' ) ) + namespaced_regexes.append( ( self._title_regex, 'title:' ) ) + namespaced_regexes.append( ( self._series_regex, 'series:' ) ) + namespaced_regexes.append( ( self._creator_regex, 'creator:' ) ) - self._tags_panel = ClientGUICommon.StaticBox( self, 'tags for all' ) + for ( control, prefix ) in namespaced_regexes: + + try: + + m = re.search( control.GetValue(), path ) + + if m is not None: + + match = m.group() + + if len( match ) > 0: tags.append( prefix + match ) + + + except: pass + - self._tags = ClientGUICommon.TagsBoxFlat( self._tags_panel, self.TagRemoved ) + if path in self._paths_to_single_tags: tags.extend( self._paths_to_single_tags[ path ] ) - self._tag_box = ClientGUICommon.AutoCompleteDropdownTagsWrite( self._tags_panel, self.AddTag, CC.LOCAL_FILE_SERVICE_IDENTIFIER, service_identifier ) + tags = [ HC.CleanTag( tag ) for tag in tags ] - # + return tags - self._single_tags_panel = ClientGUICommon.StaticBox( self, 'tags just for this file' ) + + def _RefreshFileList( self ): - self._paths_to_single_tags = collections.defaultdict( list ) - - self._single_tags = ClientGUICommon.TagsBoxFlat( self._single_tags_panel, self.SingleTagRemoved ) - - self._single_tag_box = ClientGUICommon.AutoCompleteDropdownTagsWrite( self._single_tags_panel, self.AddTagSingle, CC.LOCAL_FILE_SERVICE_IDENTIFIER, service_identifier ) - self._single_tag_box.Disable() - - for path in self._paths: + for ( index, ( path, old_tags ) ) in enumerate( self._paths_list.GetClientData() ): + + # when doing regexes, make sure not to include '' results, same for system: and - started tags. tags = self._GetTags( path ) - tags_string = ', '.join( tags ) - - self._paths_list.Append( ( path, tags_string ), ( path, tags ) ) - - - - def InitialisePanel(): - - gridbox = wx.FlexGridSizer( 0, 2 ) - - gridbox.AddGrowableCol( 1, 1 ) - - gridbox.AddF( wx.StaticText( self._quick_namespaces_panel, label='Page regex ' ), FLAGS_MIXED ) - gridbox.AddF( self._page_regex, FLAGS_EXPAND_BOTH_WAYS ) - gridbox.AddF( wx.StaticText( self._quick_namespaces_panel, label='Chapter regex ' ), FLAGS_MIXED ) - gridbox.AddF( self._chapter_regex, FLAGS_EXPAND_BOTH_WAYS ) - gridbox.AddF( wx.StaticText( self._quick_namespaces_panel, label='Volume regex ' ), FLAGS_MIXED ) - gridbox.AddF( self._volume_regex, FLAGS_EXPAND_BOTH_WAYS ) - gridbox.AddF( wx.StaticText( self._quick_namespaces_panel, label='Title regex ' ), FLAGS_MIXED ) - gridbox.AddF( self._title_regex, FLAGS_EXPAND_BOTH_WAYS ) - gridbox.AddF( wx.StaticText( self._quick_namespaces_panel, label='Series regex ' ), FLAGS_MIXED ) - gridbox.AddF( self._series_regex, FLAGS_EXPAND_BOTH_WAYS ) - gridbox.AddF( wx.StaticText( self._quick_namespaces_panel, label='Creator regex ' ), FLAGS_MIXED ) - gridbox.AddF( self._creator_regex, FLAGS_EXPAND_BOTH_WAYS ) - - self._quick_namespaces_panel.AddF( gridbox, FLAGS_EXPAND_SIZER_PERPENDICULAR ) - self._quick_namespaces_panel.AddF( self._update_button, FLAGS_LONE_BUTTON ) - self._quick_namespaces_panel.AddF( self._regex_shortcuts, FLAGS_LONE_BUTTON ) - self._quick_namespaces_panel.AddF( self._regex_link, FLAGS_LONE_BUTTON ) - - self._regexes_panel.AddF( self._regexes, FLAGS_EXPAND_BOTH_WAYS ) - self._regexes_panel.AddF( self._regex_box, FLAGS_EXPAND_PERPENDICULAR ) - - self._tags_panel.AddF( self._tags, FLAGS_EXPAND_BOTH_WAYS ) - self._tags_panel.AddF( self._tag_box, FLAGS_EXPAND_PERPENDICULAR ) - - self._single_tags_panel.AddF( self._single_tags, FLAGS_EXPAND_BOTH_WAYS ) - self._single_tags_panel.AddF( self._single_tag_box, FLAGS_EXPAND_PERPENDICULAR ) - - hbox = wx.BoxSizer( wx.HORIZONTAL ) - - hbox.AddF( self._quick_namespaces_panel, FLAGS_EXPAND_BOTH_WAYS ) - hbox.AddF( self._regexes_panel, FLAGS_EXPAND_BOTH_WAYS ) - hbox.AddF( self._tags_panel, FLAGS_EXPAND_BOTH_WAYS ) - hbox.AddF( self._single_tags_panel, FLAGS_EXPAND_BOTH_WAYS ) - - vbox = wx.BoxSizer( wx.VERTICAL ) - - vbox.AddF( self._paths_list, FLAGS_EXPAND_BOTH_WAYS ) - vbox.AddF( hbox, FLAGS_EXPAND_SIZER_BOTH_WAYS ) - - self.SetSizer( vbox ) - - - wx.Panel.__init__( self, parent ) - - self._service_identifier = service_identifier - self._paths = paths - - InitialiseControls() - - InitialisePanel() - - self.Bind( wx.EVT_MENU, self.EventMenu ) - - - - def _GetTags( self, path ): - - tags = [] - - tags.extend( self._tags.GetTags() ) - - for regex in self._regexes.GetStrings(): - - try: - - m = re.search( regex, path ) - - if m is not None: + if tags != old_tags: - match = m.group() + tags_string = ', '.join( tags ) - if len( match ) > 0: tags.append( match ) + self._paths_list.UpdateRow( index, ( path, tags_string ), ( path, tags ) ) - except: pass - namespaced_regexes = [] - - namespaced_regexes.append( ( self._page_regex, 'page:' ) ) - namespaced_regexes.append( ( self._chapter_regex, 'chapter:' ) ) - namespaced_regexes.append( ( self._volume_regex, 'volume:' ) ) - namespaced_regexes.append( ( self._title_regex, 'title:' ) ) - namespaced_regexes.append( ( self._series_regex, 'series:' ) ) - namespaced_regexes.append( ( self._creator_regex, 'creator:' ) ) - - for ( control, prefix ) in namespaced_regexes: + def AddTag( self, tag ): - try: + if tag is not None: - m = re.search( control.GetValue(), path ) + self._tags.AddTag( tag ) - if m is not None: + self._tag_box.Clear() + + self._RefreshFileList() + + + + def AddTagSingle( self, tag ): + + if tag is not None: + + self._single_tags.AddTag( tag ) + + self._single_tag_box.Clear() + + indices = self._paths_list.GetAllSelected() + + for index in indices: - match = m.group() + ( path, old_tags ) = self._paths_list.GetClientData( index ) - if len( match ) > 0: tags.append( prefix + match ) + if tag not in self._paths_to_single_tags[ path ]: self._paths_to_single_tags[ path ].append( tag ) - except: pass - - - if path in self._paths_to_single_tags: tags.extend( self._paths_to_single_tags[ path ] ) - - tags = [ HC.CleanTag( tag ) for tag in tags ] - - return tags - - - def _RefreshFileList( self ): - - for ( index, ( path, old_tags ) ) in enumerate( self._paths_list.GetClientData() ): - - # when doing regexes, make sure not to include '' results, same for system: and - started tags. - - tags = self._GetTags( path ) - - if tags != old_tags: - - tags_string = ', '.join( tags ) - - self._paths_list.UpdateRow( index, ( path, tags_string ), ( path, tags ) ) + self._RefreshFileList() # make this more clever - - def AddTag( self, tag ): - - if tag is not None: + def EventAddRegex( self, event ): - self._tags.AddTag( tag ) + regex = self._regex_box.GetValue() - self._tag_box.Clear() - - self._RefreshFileList() + if regex != '': + + self._regexes.Append( regex ) + + self._regex_box.Clear() + + self._RefreshFileList() + - - def AddTagSingle( self, tag ): + def EventItemSelected( self, event ): + + single_tags = set() + + indices = self._paths_list.GetAllSelected() + + if len( indices ) > 0: + + for index in indices: + + path = self._paths_list.GetClientData( index )[0] + + if path in self._paths_to_single_tags: single_tags.update( self._paths_to_single_tags[ path ] ) + + + self._single_tag_box.Enable() + + else: self._single_tag_box.Disable() + + single_tags = list( single_tags ) + + single_tags.sort() + + self._single_tags.SetTags( single_tags ) + - if tag is not None: + def EventMenu( self, event ): - self._single_tags.AddTag( tag ) + id = event.GetId() - self._single_tag_box.Clear() + phrase = None + + if id == self.ID_REGEX_WHITESPACE: phrase = r'\s' + elif id == self.ID_REGEX_NUMBER: phrase = r'\d' + elif id == self.ID_REGEX_ALPHANUMERIC: phrase = r'\w' + elif id == self.ID_REGEX_ANY: phrase = r'.' + elif id == self.ID_REGEX_BACKSPACE: phrase = r'\\' + elif id == self.ID_REGEX_BEGINNING: phrase = r'^' + elif id == self.ID_REGEX_END: phrase = r'$' + elif id == self.ID_REGEX_SET: phrase = r'[...]' + elif id == self.ID_REGEX_NOT_SET: phrase = r'[^...]' + elif id == self.ID_REGEX_0_OR_MORE_GREEDY: phrase = r'*' + elif id == self.ID_REGEX_1_OR_MORE_GREEDY: phrase = r'+' + elif id == self.ID_REGEX_0_OR_1_GREEDY: phrase = r'?' + elif id == self.ID_REGEX_0_OR_MORE_MINIMAL: phrase = r'*?' + elif id == self.ID_REGEX_1_OR_MORE_MINIMAL: phrase = r'+?' + elif id == self.ID_REGEX_0_OR_1_MINIMAL: phrase = r'*' + elif id == self.ID_REGEX_EXACTLY_M: phrase = r'{m}' + elif id == self.ID_REGEX_M_TO_N_GREEDY: phrase = r'{m,n}' + elif id == self.ID_REGEX_M_TO_N_MINIMAL: phrase = r'{m,n}?' + elif id == self.ID_REGEX_LOOKAHEAD: phrase = r'(?=...)' + elif id == self.ID_REGEX_NEGATIVE_LOOKAHEAD: phrase = r'(?!...)' + elif id == self.ID_REGEX_LOOKBEHIND: phrase = r'(?<=...)' + elif id == self.ID_REGEX_NEGATIVE_LOOKBEHIND: phrase = r'(? 74 - [1-9]+\d*' ) + menu.Append( self.ID_REGEX_NUMBER_EXT, r'...0074.jpg -> 74 - [1-9]+\d*(?=.{4}$)' ) + menu.Append( self.ID_REGEX_AUTHOR, r'E:\my collection\author name - v4c1p0074.jpg -> author name - [^\\][\w\s]*(?=\s-)' ) + + self.PopupMenu( menu ) + + + def EventRemoveRegex( self, event ): + + selection = self._regexes.GetSelection() + + if selection != wx.NOT_FOUND: + + if len( self._regex_box.GetValue() ) == 0: self._regex_box.SetValue( self._regexes.GetString( selection ) ) + + self._regexes.Delete( selection ) + + self._RefreshFileList() + + + + def EventUpdate( self, event ): self._RefreshFileList() + + def GetServiceIdentifier( self ): return self._service_identifier + + # this prob needs to be made cleverer if I do the extra column + def GetTags( self, path ): return self._GetTags( path ) + + def SetTagBoxFocus( self ): self._tag_box.SetFocus() + + def SingleTagRemoved( self, tag ): indices = self._paths_list.GetAllSelected() @@ -7565,184 +7744,14 @@ class DialogPathsToTagsRegexPanel( wx.Panel ): ( path, old_tags ) = self._paths_list.GetClientData( index ) - if tag not in self._paths_to_single_tags[ path ]: self._paths_to_single_tags[ path ].append( tag ) + if tag in self._paths_to_single_tags[ path ]: self._paths_to_single_tags[ path ].remove( tag ) - self._RefreshFileList() # make this more clever - - - - def EventAddRegex( self, event ): - - regex = self._regex_box.GetValue() - - if regex != '': - - self._regexes.Append( regex ) - - self._regex_box.Clear() - self._RefreshFileList() - - def EventItemSelected( self, event ): + def TagRemoved( self, tag ): self._RefreshFileList() - single_tags = set() - - indices = self._paths_list.GetAllSelected() - - if len( indices ) > 0: - - for index in indices: - - path = self._paths_list.GetClientData( index )[0] - - if path in self._paths_to_single_tags: single_tags.update( self._paths_to_single_tags[ path ] ) - - - self._single_tag_box.Enable() - - else: self._single_tag_box.Disable() - - single_tags = list( single_tags ) - - single_tags.sort() - - self._single_tags.SetTags( single_tags ) - - - def EventMenu( self, event ): - - id = event.GetId() - - phrase = None - - if id == self.ID_REGEX_WHITESPACE: phrase = r'\s' - elif id == self.ID_REGEX_NUMBER: phrase = r'\d' - elif id == self.ID_REGEX_ALPHANUMERIC: phrase = r'\w' - elif id == self.ID_REGEX_ANY: phrase = r'.' - elif id == self.ID_REGEX_BACKSPACE: phrase = r'\\' - elif id == self.ID_REGEX_BEGINNING: phrase = r'^' - elif id == self.ID_REGEX_END: phrase = r'$' - elif id == self.ID_REGEX_SET: phrase = r'[...]' - elif id == self.ID_REGEX_NOT_SET: phrase = r'[^...]' - elif id == self.ID_REGEX_0_OR_MORE_GREEDY: phrase = r'*' - elif id == self.ID_REGEX_1_OR_MORE_GREEDY: phrase = r'+' - elif id == self.ID_REGEX_0_OR_1_GREEDY: phrase = r'?' - elif id == self.ID_REGEX_0_OR_MORE_MINIMAL: phrase = r'*?' - elif id == self.ID_REGEX_1_OR_MORE_MINIMAL: phrase = r'+?' - elif id == self.ID_REGEX_0_OR_1_MINIMAL: phrase = r'*' - elif id == self.ID_REGEX_EXACTLY_M: phrase = r'{m}' - elif id == self.ID_REGEX_M_TO_N_GREEDY: phrase = r'{m,n}' - elif id == self.ID_REGEX_M_TO_N_MINIMAL: phrase = r'{m,n}?' - elif id == self.ID_REGEX_LOOKAHEAD: phrase = r'(?=...)' - elif id == self.ID_REGEX_NEGATIVE_LOOKAHEAD: phrase = r'(?!...)' - elif id == self.ID_REGEX_LOOKBEHIND: phrase = r'(?<=...)' - elif id == self.ID_REGEX_NEGATIVE_LOOKBEHIND: phrase = r'(? 74 - [1-9]+\d*' ) - menu.Append( self.ID_REGEX_NUMBER_EXT, r'...0074.jpg -> 74 - [1-9]+\d*(?=.{4}$)' ) - menu.Append( self.ID_REGEX_AUTHOR, r'E:\my collection\author name - v4c1p0074.jpg -> author name - [^\\][\w\s]*(?=\s-)' ) - - self.PopupMenu( menu ) - - - def EventRemoveRegex( self, event ): - - selection = self._regexes.GetSelection() - - if selection != wx.NOT_FOUND: - - if len( self._regex_box.GetValue() ) == 0: self._regex_box.SetValue( self._regexes.GetString( selection ) ) - - self._regexes.Delete( selection ) - - self._RefreshFileList() - - - - def EventUpdate( self, event ): self._RefreshFileList() - - def GetServiceIdentifier( self ): return self._service_identifier - - # this prob needs to be made cleverer if I do the extra column - def GetTags( self, path ): return self._GetTags( path ) - - def SetTagBoxFocus( self ): self._tag_box.SetFocus() - - def SingleTagRemoved( self, tag ): - - indices = self._paths_list.GetAllSelected() - - for index in indices: - - ( path, old_tags ) = self._paths_list.GetClientData( index ) - - if tag in self._paths_to_single_tags[ path ]: self._paths_to_single_tags[ path ].remove( tag ) - - - self._RefreshFileList() - - - def TagRemoved( self, tag ): self._RefreshFileList() class DialogProgress( Dialog ): @@ -8566,6 +8575,19 @@ class DialogSetupCustomFilterActions( Dialog ): self._actions.DeleteAllItems() + name = self._favourites.GetString( selection ) + + if name in ( 'default', 'previous' ): + + self._save_favourite.Disable() + self._delete_favourite.Disable() + + else: + + self._save_favourite.Enable() + self._delete_favourite.Enable() + + actions = self._favourites.GetClientData( selection ) for ( modifier, key, service_identifier, action ) in actions: diff --git a/include/ClientGUIManagement.py b/include/ClientGUIManagement.py index b7627c6e..1e6da158 100755 --- a/include/ClientGUIManagement.py +++ b/include/ClientGUIManagement.py @@ -1061,6 +1061,17 @@ class ManagementPanelDumper( ManagementPanel ): + def TryToClose( self ): + + if self._dumping: + + with ClientGUIDialogs.DialogYesNo( self, 'This page is still dumping. Are you sure you want to close it?' ) as dlg: + + if dlg.ShowModal() == wx.ID_NO: raise Exception() + + + + class ManagementPanelImport( ManagementPanel ): def __init__( self, parent, page, page_key ): @@ -1280,7 +1291,7 @@ class ManagementPanelImport( ManagementPanel ): def TryToClose( self ): - if self._currently_processing_import_queue: + if self._currently_processing_import_queue and not self._pause_import: with ClientGUIDialogs.DialogYesNo( self, 'This page is still importing. Are you sure you want to close it?' ) as dlg: @@ -1604,7 +1615,7 @@ class ManagementPanelImportWithQueueAdvanced( ManagementPanelImportWithQueue ): edit_log = [ ( action, tag ) for tag in tags_to_add_here ] - content_updates.append( CC.ContentUpdate( CC.CONTENT_UPDATE_EDIT_LOG, service_identifier, ( hash, ), info = edit_log ) ) + content_updates.append( HC.ContentUpdate( CC.CONTENT_UPDATE_EDIT_LOG, service_identifier, ( hash, ), info = edit_log ) ) @@ -3132,7 +3143,7 @@ class ManagementPanelImportThreadWatcher( ManagementPanelImport ): def _GetPreprocessStatus( self ): - status = 'reading ' + str( self._import_queue_position + 1 ) + '/' + str( len( self._import_queue ) ) + status = 'checking url/hash status ' + str( self._import_queue_position + 1 ) + '/' + str( len( self._import_queue ) ) return status @@ -3364,13 +3375,13 @@ class ManagementPanelPetitions( ManagementPanel ): hashes = self._current_petition.GetPetitionHashes() - content_updates = [ CC.ContentUpdate( CC.CONTENT_UPDATE_DELETE, self._file_service_identifier, hashes ) ] + content_updates = [ HC.ContentUpdate( CC.CONTENT_UPDATE_DELETE, self._file_service_identifier, hashes ) ] elif isinstance( self._current_petition, HC.ServerMappingPetition ): ( reason, tag, hashes ) = self._current_petition.GetPetitionInfo() - content_updates = [ CC.ContentUpdate( CC.CONTENT_UPDATE_DELETE, self._file_service_identifier, hashes, tag ) ] + content_updates = [ HC.ContentUpdate( CC.CONTENT_UPDATE_DELETE, self._file_service_identifier, hashes, tag ) ] wx.GetApp().Write( 'content_updates', content_updates ) diff --git a/include/ClientGUIMedia.py b/include/ClientGUIMedia.py index 310c7dc8..b31d769b 100755 --- a/include/ClientGUIMedia.py +++ b/include/ClientGUIMedia.py @@ -97,7 +97,7 @@ class MediaPanel( ClientGUIMixins.ListeningMediaList, wx.ScrolledWindow ): hashes = self._GetSelectedHashes( CC.DISCRIMINANT_INBOX ) - if len( hashes ) > 0: wx.GetApp().Write( 'content_updates', [ CC.ContentUpdate( CC.CONTENT_UPDATE_ARCHIVE, CC.LOCAL_FILE_SERVICE_IDENTIFIER, hashes ) ] ) + if len( hashes ) > 0: wx.GetApp().Write( 'content_updates', [ HC.ContentUpdate( CC.CONTENT_UPDATE_ARCHIVE, CC.LOCAL_FILE_SERVICE_IDENTIFIER, hashes ) ] ) def _CopyHashToClipboard( self ): @@ -188,7 +188,7 @@ class MediaPanel( ClientGUIMixins.ListeningMediaList, wx.ScrolledWindow ): if dlg.ShowModal() == wx.ID_YES: - try: wx.GetApp().Write( 'content_updates', [ CC.ContentUpdate( CC.CONTENT_UPDATE_DELETE, file_service_identifier, hashes ) ] ) + try: wx.GetApp().Write( 'content_updates', [ HC.ContentUpdate( CC.CONTENT_UPDATE_DELETE, file_service_identifier, hashes ) ] ) except: wx.MessageBox( traceback.format_exc() ) @@ -215,7 +215,7 @@ class MediaPanel( ClientGUIMixins.ListeningMediaList, wx.ScrolledWindow ): self._SetFocussedMedia( None ) self._shift_focussed_media = None - with wx.FrozenWindow( self ): self._ReblitCanvas() + self._ReblitCanvas() self._PublishSelectionChange() @@ -376,7 +376,7 @@ class MediaPanel( ClientGUIMixins.ListeningMediaList, wx.ScrolledWindow ): hashes = self._GetSelectedHashes( CC.DISCRIMINANT_ARCHIVE ) - if len( hashes ) > 0: wx.GetApp().Write( 'content_updates', [ CC.ContentUpdate( CC.CONTENT_UPDATE_INBOX, CC.LOCAL_FILE_SERVICE_IDENTIFIER, hashes ) ] ) + if len( hashes ) > 0: wx.GetApp().Write( 'content_updates', [ HC.ContentUpdate( CC.CONTENT_UPDATE_INBOX, CC.LOCAL_FILE_SERVICE_IDENTIFIER, hashes ) ] ) def _ManageRatings( self ): @@ -514,12 +514,9 @@ class MediaPanel( ClientGUIMixins.ListeningMediaList, wx.ScrolledWindow ): self._shift_focussed_media = None - with wx.FrozenWindow( self ): - - self._RefitCanvas() - - self._ReblitCanvas() - + self._RefitCanvas() + + self._ReblitCanvas() self._PublishSelectionChange() @@ -556,7 +553,7 @@ class MediaPanel( ClientGUIMixins.ListeningMediaList, wx.ScrolledWindow ): self._selected_media = set( self._sorted_media ) - with wx.FrozenWindow( self ): self._ReblitCanvas() + self._ReblitCanvas() self._PublishSelectionChange() @@ -605,7 +602,7 @@ class MediaPanel( ClientGUIMixins.ListeningMediaList, wx.ScrolledWindow ): self._DeselectAll() - with wx.FrozenWindow( self ): self._RefitCanvas() + self._RefitCanvas() # no refresh needed since the sort call that always comes after will do it @@ -674,12 +671,9 @@ class MediaPanel( ClientGUIMixins.ListeningMediaList, wx.ScrolledWindow ): if action in ( CC.SERVICE_UPDATE_DELETE_PENDING, CC.SERVICE_UPDATE_RESET ): - with wx.FrozenWindow( self ): - - self._RefitCanvas() - - self._ReblitCanvas() - + self._RefitCanvas() + + self._ReblitCanvas() self._PublishSelectionChange() @@ -711,7 +705,7 @@ class MediaPanel( ClientGUIMixins.ListeningMediaList, wx.ScrolledWindow ): ClientGUIMixins.ListeningMediaList.Sort( self, sort_by ) - with wx.FrozenWindow( self ): self._ReblitCanvas() + self._ReblitCanvas() HC.pubsub.pub( 'sorted_media_pulse', self._page_key, self.GenerateMediaResults() ) @@ -1043,12 +1037,9 @@ class MediaPanelThumbnails( MediaPanel ): if old_num_rows != num_rows: - with wx.FrozenWindow( self ): - - self._RefitCanvas() - - self._ReblitCanvas() - + self._RefitCanvas() + + self._ReblitCanvas() self._BlitThumbnail( media ) @@ -1157,12 +1148,9 @@ class MediaPanelThumbnails( MediaPanel ): if self._num_columns != old_numcols: - with wx.FrozenWindow( self ): - - self._RefitCanvas() - - self._ReblitCanvas() - + self._RefitCanvas() + + self._ReblitCanvas() else: @@ -1174,7 +1162,7 @@ class MediaPanelThumbnails( MediaPanel ): if self._num_rows_in_client_height > old_numclientrows: - with wx.FrozenWindow( self ): self._ReblitCanvas() + self._ReblitCanvas() @@ -1403,20 +1391,23 @@ class MediaPanelThumbnails( MediaPanel ): if selection_has_local: - if multiple_selected: menu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'filter' ), 'filter' ) - - if i_can_post_ratings: + if multiple_selected or i_can_post_ratings: - ratings_filter_menu = wx.Menu() + if multiple_selected: menu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'filter' ), 'filter' ) - for service in local_ratings_services: ratings_filter_menu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'ratings_filter', service.GetServiceIdentifier() ), service.GetServiceIdentifier().GetName() ) + if i_can_post_ratings: + + ratings_filter_menu = wx.Menu() + + for service in local_ratings_services: ratings_filter_menu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'ratings_filter', service.GetServiceIdentifier() ), service.GetServiceIdentifier().GetName() ) + + menu.AppendMenu( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'ratings_filter' ), 'ratings filter', ratings_filter_menu ) + - menu.AppendMenu( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'ratings_filter' ), 'ratings filter', ratings_filter_menu ) + if multiple_selected: menu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'custom_filter' ), 'custom filter' ) + + menu.AppendSeparator() - - if multiple_selected: menu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'custom_filter' ), 'custom filter' ) - - if multiple_selected or i_can_post_ratings: menu.AppendSeparator() if selection_has_inbox: menu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'archive' ), archive_phrase ) if selection_has_archive: menu.Append( CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'inbox' ), inbox_phrase ) @@ -1468,12 +1459,9 @@ class MediaPanelThumbnails( MediaPanel ): if self._last_visible_row < num_rows and current_last_visible_row > int( self._last_visible_row * 0.75 ): - with wx.FrozenWindow( self ): - - self._RefitCanvas() - - self._ReblitCanvas() - + self._RefitCanvas() + + self._ReblitCanvas() event.Skip() @@ -1620,12 +1608,9 @@ class MediaPanelThumbnails( MediaPanel ): for t in self._sorted_media: t.ReloadFromDBLater() - with wx.FrozenWindow( self ): - - self._RefitCanvas() - - self._ReblitCanvas() - + self._RefitCanvas() + + self._ReblitCanvas() class Selectable(): diff --git a/include/ClientGUIMixins.py b/include/ClientGUIMixins.py index 5640d869..08418793 100755 --- a/include/ClientGUIMixins.py +++ b/include/ClientGUIMixins.py @@ -491,6 +491,8 @@ class MediaCollection( MediaList, Media ): def GetNumFrames( self ): return sum( [ media.GetNumFrames() for media in self._sorted_media ] ) + def GetNumWords( self ): return sum( [ media.GetNumWords() for media in self._sorted_media ] ) + def GetPrettyAge( self ): return HC.ConvertTimestampToPrettyAge( self._timestamp ) def GetPrettyInfo( self ): @@ -594,6 +596,8 @@ class MediaSingleton( Media ): def GetNumFrames( self ): return self._media_result.GetNumFrames() + def GetNumWords( self ): return self._media_result.GetNumWords() + def GetTimestamp( self ): timestamp = self._media_result.GetTimestamp() @@ -616,6 +620,8 @@ class MediaSingleton( Media ): if num_frames is not None: info_string += ' (' + HC.ConvertIntToPrettyString( num_frames ) + ' frames)' + if num_words is not None: info_string += ' (' + HC.ConvertIntToPrettyString( num_words ) + ' words)' + return info_string diff --git a/include/HydrusConstants.py b/include/HydrusConstants.py index 1878b500..a219b25f 100755 --- a/include/HydrusConstants.py +++ b/include/HydrusConstants.py @@ -30,7 +30,7 @@ TEMP_DIR = BASE_DIR + os.path.sep + 'temp' # Misc NETWORK_VERSION = 9 -SOFTWARE_VERSION = 61 +SOFTWARE_VERSION = 62 UNSCALED_THUMBNAIL_DIMENSIONS = ( 200, 200 ) @@ -1253,6 +1253,24 @@ class ClientServiceIdentifier( HydrusYAMLBase ): def GetType( self ): return self._type +class ContentUpdate(): + + def __init__( self, action, service_identifier, hashes, info = None ): + + self._action = action + self._service_identifier = service_identifier + self._hashes = set( hashes ) + self._info = info + + + def GetAction( self ): return self._action + + def GetHashes( self ): return self._hashes + + def GetInfo( self ): return self._info + + def GetServiceIdentifier( self ): return self._service_identifier + class DAEMON( threading.Thread ): def __init__( self, name, callable, period = 1200 ): diff --git a/include/HydrusServer.py b/include/HydrusServer.py index 0b25d689..72fdb050 100755 --- a/include/HydrusServer.py +++ b/include/HydrusServer.py @@ -425,7 +425,8 @@ class HydrusHTTPRequestHandler( BaseHTTPServer.BaseHTTPRequestHandler ): try: - hydrus_client = False + default_mime = HC.TEXT_HTML + default_encoding = lambda x: unicode( x ) user_agent_text = self.headers.getheader( 'User-Agent' ) @@ -441,24 +442,23 @@ class HydrusHTTPRequestHandler( BaseHTTPServer.BaseHTTPRequestHandler ): if client == 'hydrus': - if int( network_version ) == HC.NETWORK_VERSION: hydrus_client = True - else: raise HC.NetworkVersionException( 'Network version mismatch! This repository\'s network version is ' + str( HC.NETWORK_VERSION ) + ' whereas yours is ' + network_version + '! Please download the latest release.' ) + default_mime = HC.APPLICATION_YAML + default_encoding = lambda x: yaml.safe_dump( unicode( x ) ) + + network_version = int( network_version ) + + if network_version != HC.NETWORK_VERSION: + + if network_version < HC.NETWORK_VERSION: message = 'Please download the latest release.' + else: message = 'Please ask this server\'s admin to update to the latest release.' + + raise HC.NetworkVersionException( 'Network version mismatch! This server\'s network version is ' + str( HC.NETWORK_VERSION ) + ', whereas your client\'s is ' + str( network_version ) + '! ' + message ) + - if hydrus_client: - - default_mime = HC.APPLICATION_YAML - default_encoding = lambda x: yaml.safe_dump( unicode( x ) ) - - else: - - default_mime = HC.TEXT_HTML - default_encoding = lambda x: unicode( x ) - - ( ip, port ) = self.client_address service_type = self._service_identifier.GetType() @@ -517,7 +517,7 @@ class HydrusHTTPRequestHandler( BaseHTTPServer.BaseHTTPRequestHandler ): except KeyError: response_context = HC.ResponseContext( 403, mime = default_mime, body = default_encoding( 'It appears one or more parameters required for that request were missing.' ) ) except HC.PermissionException as e: response_context = HC.ResponseContext( 401, mime = default_mime, body = default_encoding( e ) ) except HC.ForbiddenException as e: response_context = HC.ResponseContext( 403, mime = default_mime, body = default_encoding( e ) ) - except HC.NotFoundException as e: response_context = HC.ResponseContext( 404, mime = default_mime, body = default_encoding( e ) ) + except HC.NotFoundException as e:response_context = HC.ResponseContext( 404, mime = default_mime, body = default_encoding( e ) ) except HC.NetworkVersionException as e: response_context = HC.ResponseContext( 426, mime = default_mime, body = default_encoding( e ) ) except HC.SessionException as e: response_context = HC.ResponseContext( 403, mime = default_mime, body = default_encoding( 'Session not found!' ) ) except Exception as e: