Version 75

This commit is contained in:
Hydrus 2013-07-03 13:49:26 -05:00
parent 9934544006
commit 62528976e3
12 changed files with 538 additions and 181 deletions

View File

@ -8,6 +8,27 @@
<div class="content">
<h3>changelog</h3>
<ul>
<li><h3>version 75</h3></li>
<ul>
<li>fullscreenpopup window added</li>
<li>fullscreenpopup window can be dragged about</li>
<li>fullscreenpopupfilterinbox</li>
<li>fullscreenpopupfilterlike</li>
<li>fullscreenpopupfilternumerical</li>
<li>accuracy slider moved to popup</li>
<li>compare same image until done added to popup</li>
<li>keep on left/random/right added to popup</li>
<li>'don't ratings filter this' added to popup</li>
<li>that annoying as hell thumbnail selection drawing state bug is fixed</li>
<li>display of flash with only one frame fixed</li>
<li>downloaded tags now work again, sorry for the disruption!</li>
<li>deleted tags will now always show in manage tags dialog</li>
<li>fixed the various problems that were stopping DELETED->PENDING->CURRENT working for tags</li>
<li>fixed the children can only have one parent bug</li>
<li>a little counting logic improved in the special deleted_pending case</li>
<li>fixed a typo re uploading file to a repo</li>
<li>main guis statusbar now has a little 'db locked' indicator</li>
</ul>
<li><h3>version 74</h3></li>
<ul>
<li>flash scanbar added</li>

View File

@ -2192,40 +2192,6 @@ class ServiceLocalRatingNumerical( Service ):
def GetExtraInfo( self ): return ( self._lower, self._upper )
class ServiceManager():
def __init__( self ):
self._lock = threading.Lock()
services = wx.GetApp().Read( 'services' )
self._service_identifiers_to_services = { service.GetServiceIdentifier() : service for service in services }
# pubsub for services changing
# maybe a variable that says services are not ready, so wait a second (for refresh)
# maybe refresh should be synchro with db? nah, that makes locking issues
# need to protect the actual service objects with a lock too, although the subobjects make this delicate
def GetService( self, service_identifier ):
with self._lock:
if service_identifier in self._service_identifiers_to_services: return self._service_identifiers_to_services[ service_identifier ]
else: raise Exception( 'Could not find that service!' )
def GetServices( self, service_types ):
with self._lock:
return { service for ( service_identifier, service ) in self._service_identifiers_to_services.items() if service_idenifier.GetType() in service_types }
class ServiceRemote( Service ):
yaml_tag = u'!ServiceRemote'

View File

@ -22,7 +22,6 @@ class Controller( wx.App ):
def _Read( self, action, *args, **kwargs ):
if action == 'options': return self._options
elif action == 'tag_service_precedence': return self._tag_service_precedence
elif action == 'file': return self._db.ReadFile( *args, **kwargs )
elif action == 'thumbnail': return self._db.ReadThumbnail( *args, **kwargs )
else: return self._db.Read( action, HC.HIGH_PRIORITY, *args, **kwargs )
@ -196,8 +195,6 @@ class Controller( wx.App ):
self._options = self._db.Read( 'options', HC.HIGH_PRIORITY )
self._tag_service_precedence = self._db.Read( 'tag_service_precedence', HC.HIGH_PRIORITY )
self._session_manager = HydrusSessions.HydrusSessionManagerClient()
self._web_session_manager = CC.WebSessionManagerClient()
self._tag_parents_manager = CC.TagParentsManager()

View File

@ -575,8 +575,8 @@ class MessageDB():
num_inbox = len( convo_ids )
if num_inbox == 0: inbox_string = 'inbox empty'
else: inbox_string = str( num_inbox ) + ' in inbox'
if num_inbox == 0: inbox_string = 'message inbox empty'
else: inbox_string = str( num_inbox ) + ' in message inbox'
self.pub( 'inbox_status', inbox_string )
@ -1407,7 +1407,7 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
c.execute( 'INSERT INTO tag_service_precedence ( service_id, precedence ) SELECT ?, CASE WHEN MAX( precedence ) NOT NULL THEN MAX( precedence ) + 1 ELSE 0 END FROM tag_service_precedence;', ( service_id, ) )
self._RebuildTagServicePrecedence( c )
self._RebuildTagServicePrecedenceCache( c )
#
@ -2547,7 +2547,7 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
all_hash_ids = { hash_id for hash_id in itertools.chain.from_iterable( ( hash_ids for ( hash_ids, reason ) in petitioned ) ) }
hash_ids_to_hashes = self._GetHashIdsToHashes( c, hash_ids )
hash_ids_to_hashes = self._GetHashIdsToHashes( c, all_hash_ids )
content_data[ HC.CONTENT_DATA_TYPE_FILES ][ HC.CONTENT_UPDATE_PETITION ] = petitioned
@ -3263,8 +3263,6 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
service_id = self._GetServiceId( c, service_identifier )
hash_ids = self._GetHashIds( c, hashes )
c.executemany( 'INSERT OR IGNORE INTO file_transfers ( service_id, hash_id ) VALUES ( ?, ? );', [ ( service_id, hash_id ) for hash_id in hash_ids ] )
if service_identifier == HC.LOCAL_FILE_SERVICE_IDENTIFIER: notify_new_downloads = True
@ -3385,8 +3383,8 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
( parent_namespace_id, parent_tag_id ) = self._GetNamespaceIdTagId( c, parent_tag )
c.execute( 'DELETE FROM tag_parents WHERE service_id = ? AND child_namespace_id = ? AND child_tag_id = ?;', ( service_id, child_namespace_id, child_tag_id ) )
c.execute( 'DELETE FROM tag_parent_petitions WHERE service_id = ? AND child_namespace_id = ? AND child_tag_id = ? AND status = ?;', ( service_id, child_namespace_id, child_tag_id, deletee_status ) )
c.execute( 'DELETE FROM tag_parents WHERE service_id = ? AND child_namespace_id = ? AND child_tag_id = ? AND parent_namespace_id = ? AND parent_tag_id = ?;', ( service_id, child_namespace_id, child_tag_id, parent_namespace_id, parent_tag_id ) )
c.execute( 'DELETE FROM tag_parent_petitions WHERE service_id = ? AND child_namespace_id = ? AND child_tag_id = ? AND parent_namespace_id = ? AND parent_tag_id = ? AND status = ?;', ( service_id, child_namespace_id, child_tag_id, parent_namespace_id, parent_tag_id, deletee_status ) )
c.execute( 'INSERT OR IGNORE INTO tag_parents ( service_id, child_namespace_id, child_tag_id, parent_namespace_id, parent_tag_id, status ) VALUES ( ?, ?, ?, ?, ?, ? );', ( service_id, child_namespace_id, child_tag_id, parent_namespace_id, parent_tag_id, new_status ) )
@ -3596,7 +3594,7 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
if do_new_permissions: self.pub( 'notify_new_permissions' )
def _RebuildTagServicePrecedence( self, c ):
def _RebuildTagServicePrecedenceCache( self, c ):
del self._tag_service_precedence[:]
@ -3665,7 +3663,7 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
if service_type == HC.TAG_REPOSITORY:
self._RebuildTagServicePrecedence( c )
self._RebuildTagServicePrecedenceCache( c )
self._RecalcCombinedMappings( c )
@ -3731,7 +3729,7 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
c.executemany( 'INSERT INTO tag_service_precedence ( service_id, precedence ) VALUES ( ?, ? );', [ ( service_id, precedence ) for ( precedence, service_id ) in enumerate( service_ids ) ] )
self._RebuildTagServicePrecedence( c )
self._RebuildTagServicePrecedenceCache( c )
self._RecalcCombinedMappings( c )
@ -3769,11 +3767,22 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
def ChangeMappingStatus( namespace_id, tag_id, hash_ids, old_status, new_status ):
# when we have a tag both deleted and pending made current, we merge two statuses into one!
# in this case, we have to be careful about the counts (decrement twice, but only increment once), hence why this returns two numbers
appropriate_hash_ids = [ id for ( id, ) in c.execute( 'SELECT hash_id FROM mappings WHERE service_id = ? AND namespace_id = ? AND tag_id = ? AND hash_id IN ' + HC.SplayListForDB( hash_ids ) + ' AND status = ?;', ( service_id, namespace_id, tag_id, old_status ) ) ]
existing_hash_ids = { id for ( id, ) in c.execute( 'SELECT hash_id FROM mappings WHERE service_id = ? AND namespace_id = ? AND tag_id = ? AND hash_id IN ' + HC.SplayListForDB( hash_ids ) + ' AND status = ?;', ( service_id, namespace_id, tag_id, new_status ) ) }
deletable_hash_ids = existing_hash_ids.intersection( appropriate_hash_ids )
c.execute( 'DELETE FROM mappings WHERE service_id = ? AND namespace_id = ? AND tag_id = ? AND hash_id IN ' + HC.SplayListForDB( deletable_hash_ids ) + ' AND status = ?;', ( service_id, namespace_id, tag_id, old_status ) )
num_old_deleted = self._GetRowCount( c )
c.execute( 'UPDATE mappings SET status = ? WHERE service_id = ? AND namespace_id = ? AND tag_id = ? AND hash_id IN ' + HC.SplayListForDB( appropriate_hash_ids ) + ' AND status = ?;', ( new_status, service_id, namespace_id, tag_id, old_status ) )
num_rows_changed = self._GetRowCount( c )
num_old_made_new = self._GetRowCount( c )
if old_status != HC.PENDING and new_status == HC.PENDING:
@ -3803,7 +3812,7 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
CheckIfCombinedMappingsNeedDeleting( namespace_id, tag_id, appropriate_hash_ids )
return num_rows_changed
return ( num_old_deleted + num_old_made_new, num_old_made_new )
def CheckIfCombinedMappingsNeedDeleting( namespace_id, tag_id, hash_ids ):
@ -3904,7 +3913,8 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
def InsertMappings( namespace_id, tag_id, hash_ids, status ):
existing_hash_ids = [ id for ( id, ) in c.execute( 'SELECT hash_id FROM mappings WHERE service_id = ? AND namespace_id = ? AND tag_id = ? AND hash_id IN ' + HC.SplayListForDB( hash_ids ) + ';', ( service_id, namespace_id, tag_id ) ) ]
if status == HC.PENDING: existing_hash_ids = [ id for ( id, ) in c.execute( 'SELECT hash_id FROM mappings WHERE service_id = ? AND namespace_id = ? AND tag_id = ? AND hash_id IN ' + HC.SplayListForDB( hash_ids ) + ' AND status != ?;', ( service_id, namespace_id, tag_id, HC.DELETED ) ) ]
else: existing_hash_ids = [ id for ( id, ) in c.execute( 'SELECT hash_id FROM mappings WHERE service_id = ? AND namespace_id = ? AND tag_id = ? AND hash_id IN ' + HC.SplayListForDB( hash_ids ) + ';', ( service_id, namespace_id, tag_id ) ) ]
new_hash_ids = set( hash_ids ).difference( existing_hash_ids )
@ -4020,23 +4030,23 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
for ( namespace_id, tag_id, hash_ids ) in mappings_ids:
num_deleted_rescinded = ChangeMappingStatus( namespace_id, tag_id, hash_ids, HC.DELETED, HC.CURRENT )
num_pending_committed = ChangeMappingStatus( namespace_id, tag_id, hash_ids, HC.PENDING, HC.CURRENT )
( num_deleted_deleted, num_deleted_made_current ) = ChangeMappingStatus( namespace_id, tag_id, hash_ids, HC.DELETED, HC.CURRENT )
( num_pending_deleted, num_pending_made_current ) = ChangeMappingStatus( namespace_id, tag_id, hash_ids, HC.PENDING, HC.CURRENT )
num_raw_adds = InsertMappings( namespace_id, tag_id, hash_ids, HC.CURRENT )
change_in_num_mappings += num_deleted_rescinded + num_pending_committed + num_raw_adds
change_in_num_deleted_mappings -= num_deleted_rescinded
change_in_num_pending_mappings -= num_pending_committed
change_in_num_mappings += num_deleted_made_current + num_pending_made_current + num_raw_adds
change_in_num_deleted_mappings -= num_deleted_deleted
change_in_num_pending_mappings -= num_pending_deleted
for ( namespace_id, tag_id, hash_ids ) in deleted_mappings_ids:
num_current_deleted = ChangeMappingStatus( namespace_id, tag_id, hash_ids, HC.CURRENT, HC.DELETED )
( num_current_deleted, num_current_made_deleted ) = ChangeMappingStatus( namespace_id, tag_id, hash_ids, HC.CURRENT, HC.DELETED )
num_raw_adds = InsertMappings( namespace_id, tag_id, hash_ids, HC.DELETED )
num_deleted_petitions = DeletePetitions( namespace_id, tag_id, hash_ids )
change_in_num_mappings -= num_current_deleted
change_in_num_deleted_mappings += num_current_deleted + num_raw_adds
change_in_num_deleted_mappings += num_current_made_deleted + num_raw_adds
change_in_num_petitioned_mappings -= num_deleted_petitions
@ -4170,7 +4180,7 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
if recalc_combined_mappings:
self._RebuildTagServicePrecedence( c )
self._RebuildTagServicePrecedenceCache( c )
self._RecalcCombinedMappings( c )
@ -4278,7 +4288,7 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
if recalc_combined_mappings:
self._RebuildTagServicePrecedence( c )
self._RebuildTagServicePrecedenceCache( c )
self._RecalcCombinedMappings( c )
@ -4360,7 +4370,9 @@ class DB( ServiceDB ):
( self._options, ) = c.execute( 'SELECT options FROM options;' ).fetchone()
self._tag_service_precedence = self._GetTagServicePrecedence( c )
self._tag_service_precedence = []
self._RebuildTagServicePrecedenceCache( c )
if not self._CheckPassword(): raise HC.PermissionException( 'No password!' )
@ -7041,7 +7053,7 @@ class DB( ServiceDB ):
self.WaitUntilGoodTimeToUseDBThread()
time.sleep( 0.25 )
time.sleep( 0.10 )
try: service = wx.GetApp().ReadDaemon( 'service', service_identifier )
except: break
@ -7364,6 +7376,8 @@ class DB( ServiceDB ):
def _MainLoop_JobInternal( self, c, job ):
HC.pubsub.pub( 'db_locked_status', 'db locked' )
action = job.GetAction()
job_type = job.GetType()
@ -7442,6 +7456,8 @@ class DB( ServiceDB ):
HC.pubsub.pub( 'db_locked_status', '' )
def _MainLoop_Read( self, c, action, args, kwargs ):
@ -7600,15 +7616,9 @@ class DB( ServiceDB ):
if action != 'do_file_query': return job.GetResult()
def ReadFile( self, hash ):
return self._GetFile( hash )
def ReadFile( self, hash ): return self._GetFile( hash )
def ReadThumbnail( self, hash, full_size = False ):
return self._GetThumbnail( hash, full_size )
def ReadThumbnail( self, hash, full_size = False ): return self._GetThumbnail( hash, full_size )
def WaitUntilGoodTimeToUseDBThread( self ):

View File

@ -46,13 +46,14 @@ class FrameGUI( ClientGUICommon.Frame ):
self.SetDropTarget( ClientGUICommon.FileDropTarget( self.ImportFiles ) )
self._statusbar = self.CreateStatusBar()
self._statusbar.SetFieldsCount( 4 )
self._statusbar.SetStatusWidths( [ -1, 400, 200, 200 ] )
self._statusbar.SetFieldsCount( 5 )
self._statusbar.SetStatusWidths( [ -1, -1, 100, 120, 50 ] )
self._statusbar_media = ''
self._statusbar_service = ''
self._statusbar_inbox = ''
self._statusbar_downloads = ''
self._statusbar_db_locked = ''
self.SetIcon( wx.Icon( HC.STATIC_DIR + os.path.sep + 'hydrus.ico', wx.BITMAP_TYPE_ICO ) )
@ -90,6 +91,7 @@ class FrameGUI( ClientGUICommon.Frame ):
HC.pubsub.sub( self, 'RefreshMenuBar', 'notify_new_services' )
HC.pubsub.sub( self, 'RefreshAcceleratorTable', 'options_updated' )
HC.pubsub.sub( self, 'RefreshStatusBar', 'refresh_status' )
HC.pubsub.sub( self, 'SetDBLockedStatus', 'db_locked_status' )
HC.pubsub.sub( self, 'SetDownloadsStatus', 'downloads_status' )
HC.pubsub.sub( self, 'SetInboxStatus', 'inbox_status' )
HC.pubsub.sub( self, 'SetServiceStatus', 'service_status' )
@ -349,7 +351,7 @@ class FrameGUI( ClientGUICommon.Frame ):
subprocess.Popen( [ 'explorer', HC.BASE_DIR + os.path.sep + 'server.exe' ] )
time.sleep( 5 ) # give it time to init its db
time.sleep( 10 ) # give it time to init its db
except:
@ -901,6 +903,7 @@ class FrameGUI( ClientGUICommon.Frame ):
self._statusbar.SetStatusText( self._statusbar_service, number = 1 )
self._statusbar.SetStatusText( self._statusbar_inbox, number = 2 )
self._statusbar.SetStatusText( self._statusbar_downloads, number = 3 )
self._statusbar.SetStatusText( self._statusbar_db_locked, number = 4 )
def _ReviewServices( self ):
@ -1470,6 +1473,16 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
def RefreshStatusBar( self ): self._RefreshStatusBar()
def SetDBLockedStatus( self, status ):
if self.IsShown():
self._statusbar_db_locked = status
self._RefreshStatusBar()
def SetDownloadsStatus( self, status ):
if self.IsShown():

View File

@ -1570,6 +1570,14 @@ class CanvasFullscreenMediaListFilter( CanvasFullscreenMediaList ):
self.SetMedia( self._GetFirst() )
def _Delete( self ):
self._deleted.add( self._current_media )
if self._current_media == self._GetLast(): self.EventClose( None )
else: self._ShowNext()
def _Keep( self ):
self._kept.add( self._current_media )
@ -1594,6 +1602,12 @@ class CanvasFullscreenMediaListFilter( CanvasFullscreenMediaList ):
def EventButtonBack( self, event ): self.EventBack( event )
def EventButtonDelete( self, event ): self._Delete()
def EventButtonDone( self, event ): self.EventClose( event )
def EventButtonKeep( self, event ): self._Keep()
def EventButtonSkip( self, event ): self._ShowNext()
def EventClose( self, event ):
if self._ShouldSkipInputDueToFlash(): event.Skip()
@ -1649,13 +1663,7 @@ class CanvasFullscreenMediaListFilter( CanvasFullscreenMediaList ):
def EventDelete( self, event ):
if self._ShouldSkipInputDueToFlash(): event.Skip()
else:
self._deleted.add( self._current_media )
if self._current_media == self._GetLast(): self.EventClose( event )
else: self._ShowNext()
else: self._Delete()
def EventKeyDown( self, event ):
@ -1768,6 +1776,374 @@ class CanvasFullscreenMediaListFilter( CanvasFullscreenMediaList ):
class CanvasFullscreenMediaListFilterInbox( CanvasFullscreenMediaListFilter ):
def __init__( self, my_parent, page_key, file_service_identifier, predicates, media_results ):
CanvasFullscreenMediaListFilter.__init__( self, my_parent, page_key, file_service_identifier, predicates, media_results )
FullscreenPopoutFilterInbox( self )
class FullscreenPopout( wx.Frame ):
def __init__( self, parent ):
wx.Frame.__init__( self, parent, style = wx.FRAME_TOOL_WINDOW | wx.FRAME_NO_TASKBAR | wx.FRAME_FLOAT_ON_PARENT | wx.BORDER_SIMPLE )
self._last_drag_coordinates = None
self._total_drag_delta = ( 0, 0 )
self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) )
self.SetCursor( wx.StockCursor( wx.CURSOR_ARROW ) )
hbox = wx.BoxSizer( wx.HORIZONTAL )
self._popout_window = self._InitialisePopoutWindow( hbox )
self._popout_window.Hide()
self._button_window = self._InitialiseButtonWindow( hbox )
hbox.AddF( self._popout_window, FLAGS_EXPAND_PERPENDICULAR )
hbox.AddF( self._button_window, FLAGS_EXPAND_PERPENDICULAR )
self.SetSizer( hbox )
self._SizeAndPosition()
tlp = self.GetParent().GetTopLevelParent()
tlp.Bind( wx.EVT_SIZE, self.EventResize )
tlp.Bind( wx.EVT_MOVE, self.EventMove )
self.Show()
def _InitialiseButtonWindow( self, sizer ):
button_window = wx.Window( self )
self._move_button = wx.Button( button_window, label = u'\u2022', size = ( 20, 20 ) )
self._move_button.SetCursor( wx.StockCursor( wx.CURSOR_SIZING ) )
self._move_button.Bind( wx.EVT_MOTION, self.EventDrag )
self._move_button.Bind( wx.EVT_LEFT_DOWN, self.EventDragBegin )
self._move_button.Bind( wx.EVT_LEFT_UP, self.EventDragEnd )
self._arrow_button = wx.Button( button_window, label = '>', size = ( 20, 80 ) )
self._arrow_button.Bind( wx.EVT_BUTTON, self.EventArrowClicked )
vbox = wx.BoxSizer( wx.VERTICAL )
vbox.AddF( self._move_button, FLAGS_MIXED )
vbox.AddF( self._arrow_button, FLAGS_EXPAND_BOTH_WAYS )
button_window.SetSizer( vbox )
return button_window
def _SizeAndPosition( self ):
self.Fit()
parent = self.GetParent()
( parent_width, parent_height ) = parent.GetClientSize()
( my_width, my_height ) = self.GetClientSize()
my_y = ( parent_height - my_height ) / 2
( offset_x, offset_y ) = self._total_drag_delta
self.SetPosition( parent.ClientToScreenXY( 0 + offset_x, my_y + offset_y ) )
def EventArrowClicked( self, event ):
if self._popout_window.IsShown():
self._popout_window.Hide()
self._arrow_button.SetLabel( '>' )
else:
self._popout_window.Show()
self._arrow_button.SetLabel( '<' )
self._SizeAndPosition()
self.Layout()
def EventMove( self, event ):
self._SizeAndPosition()
event.Skip()
def EventDrag( self, event ):
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 )
( 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._SizeAndPosition()
def EventDragBegin( self, event ):
self._last_drag_coordinates = event.GetPosition()
event.Skip()
def EventDragEnd( self, event ):
self._last_drag_coordinates = None
event.Skip()
def EventResize( self, event ):
self._SizeAndPosition()
event.Skip()
class FullscreenPopoutFilterInbox( FullscreenPopout ):
def _InitialisePopoutWindow( self, sizer ):
window = wx.Window( self )
vbox = wx.BoxSizer( wx.VERTICAL )
parent = self.GetParent()
keep = wx.Button( window, label = 'archive' )
keep.Bind( wx.EVT_BUTTON, parent.EventButtonKeep )
delete = wx.Button( window, label = 'delete' )
delete.Bind( wx.EVT_BUTTON, parent.EventButtonDelete )
skip = wx.Button( window, label = 'skip' )
skip.Bind( wx.EVT_BUTTON, parent.EventButtonSkip )
back = wx.Button( window, label = 'back' )
back.Bind( wx.EVT_BUTTON, parent.EventButtonBack )
done = wx.Button( window, label = 'done' )
done.Bind( wx.EVT_BUTTON, parent.EventButtonDone )
vbox.AddF( keep, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( delete, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( skip, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( back, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( done, FLAGS_EXPAND_PERPENDICULAR )
window.SetSizer( vbox )
return window
class FullscreenPopoutFilterLike( FullscreenPopout ):
def _InitialisePopoutWindow( self, sizer ):
window = wx.Window( self )
vbox = wx.BoxSizer( wx.VERTICAL )
parent = self.GetParent()
like = wx.Button( window, label = 'like' )
like.Bind( wx.EVT_BUTTON, parent.EventButtonKeep )
dislike = wx.Button( window, label = 'dislike' )
dislike.Bind( wx.EVT_BUTTON, parent.EventButtonDelete )
skip = wx.Button( window, label = 'skip' )
skip.Bind( wx.EVT_BUTTON, parent.EventButtonSkip )
back = wx.Button( window, label = 'back' )
back.Bind( wx.EVT_BUTTON, parent.EventButtonBack )
done = wx.Button( window, label = 'done' )
done.Bind( wx.EVT_BUTTON, parent.EventButtonDone )
vbox.AddF( like, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( dislike, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( skip, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( back, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( done, FLAGS_EXPAND_PERPENDICULAR )
window.SetSizer( vbox )
return window
class FullscreenPopoutFilterNumerical( FullscreenPopout ):
def __init__( self, parent, callable_parent ):
self._callable_parent = callable_parent
FullscreenPopout.__init__( self, parent )
def _InitialisePopoutWindow( self, sizer ):
window = wx.Window( self )
vbox = wx.BoxSizer( wx.VERTICAL )
parent = self.GetParent()
#
options = wx.GetApp().Read( 'options' )
accuracy_slider_hbox = wx.BoxSizer( wx.HORIZONTAL )
if 'ratings_filter_accuracy' not in options:
options[ 'ratings_filter_accuracy' ] = 1
wx.GetApp().Write( 'save_options' )
value = options[ 'ratings_filter_accuracy' ]
self._accuracy_slider = wx.Slider( window, size = ( 50, -1 ), value = value, minValue = 0, maxValue = 4 )
self._accuracy_slider.Bind( wx.EVT_SLIDER, self.EventAccuracySlider )
accuracy_slider_hbox.AddF( wx.StaticText( window, label = 'quick' ), FLAGS_MIXED )
accuracy_slider_hbox.AddF( self._accuracy_slider, FLAGS_EXPAND_BOTH_WAYS )
accuracy_slider_hbox.AddF( wx.StaticText( window, label = 'accurate' ), FLAGS_MIXED )
self.EventAccuracySlider( None )
#
if 'ratings_filter_compare_same' not in options:
options[ 'ratings_filter_compare_same' ] = False
wx.GetApp().Write( 'save_options' )
compare_same = options[ 'ratings_filter_compare_same' ]
self._compare_same = wx.CheckBox( window, label = 'compare same image until rating is done' )
self._compare_same.SetValue( compare_same )
self._compare_same.Bind( wx.EVT_CHECKBOX, self.EventCompareSame )
self.EventCompareSame( None )
#
self._left_right_slider_sizer = wx.BoxSizer( wx.HORIZONTAL )
if 'ratings_filter_left_right' not in options:
options[ 'ratings_filter_left_right' ] = 'left'
wx.GetApp().Write( 'save_options' )
left_right = options[ 'ratings_filter_left_right' ]
if left_right == 'left': left_right_value = 0
elif left_right == 'random': left_right_value = 1
else: left_right_value = 2
self._left_right_slider = wx.Slider( window, size = ( 30, -1 ), value = left_right_value, minValue = 0, maxValue = 2 )
self._left_right_slider.Bind( wx.EVT_SLIDER, self.EventLeftRight )
self._left_right_slider_sizer.AddF( wx.StaticText( window, label = 'left' ), FLAGS_MIXED )
self._left_right_slider_sizer.AddF( self._left_right_slider, FLAGS_EXPAND_BOTH_WAYS )
self._left_right_slider_sizer.AddF( wx.StaticText( window, label = 'right' ), FLAGS_MIXED )
self.EventLeftRight( None )
#
left = wx.Button( window, label = 'left is better' )
left.Bind( wx.EVT_BUTTON, self._callable_parent.EventButtonLeft )
right = wx.Button( window, label = 'right is better' )
right.Bind( wx.EVT_BUTTON, self._callable_parent.EventButtonRight )
equal = wx.Button( window, label = 'they are about the same' )
equal.Bind( wx.EVT_BUTTON, self._callable_parent.EventButtonEqual )
back = wx.Button( window, label = 'back' )
back.Bind( wx.EVT_BUTTON, self._callable_parent.EventButtonBack )
dont_filter = wx.Button( window, label = 'don\'t filter this file' )
dont_filter.Bind( wx.EVT_BUTTON, self._callable_parent.EventButtonDontFilter )
done = wx.Button( window, label = 'done' )
done.Bind( wx.EVT_BUTTON, self._callable_parent.EventButtonDone )
vbox.AddF( accuracy_slider_hbox, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._compare_same, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._left_right_slider_sizer, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( wx.StaticLine( window, style = wx.LI_HORIZONTAL ), FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( left, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( right, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( equal, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( back, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( dont_filter, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( done, FLAGS_EXPAND_PERPENDICULAR )
window.SetSizer( vbox )
return window
def EventAccuracySlider( self, event ):
value = self._accuracy_slider.GetValue()
self._callable_parent.SetAccuracy( value )
def EventCompareSame( self, event ):
compare_same = self._compare_same.GetValue()
self._callable_parent.SetCompareSame( compare_same )
def EventLeftRight( self, event ):
value = self._left_right_slider.GetValue()
if value == 0: left_right = 'left'
elif value == 1: left_right = 'random'
else: left_right = 'right'
self._callable_parent.SetLeftRight( left_right )
class RatingsFilterFrameLike( CanvasFullscreenMediaListFilter ):
def __init__( self, my_parent, page_key, service_identifier, media_results ):
@ -1777,6 +2153,8 @@ class RatingsFilterFrameLike( CanvasFullscreenMediaListFilter ):
self._rating_service_identifier = service_identifier
self._service = wx.GetApp().Read( 'service', service_identifier )
FullscreenPopoutFilterLike( self )
def EventClose( self, event ):
@ -1847,6 +2225,7 @@ class RatingsFilterFrameNumerical( ClientGUICommon.Frame ):
self._page_key = page_key
self._service_identifier = service_identifier
self._media_still_to_rate = { ClientGUIMixins.MediaSingleton( media_result ) for media_result in media_results }
self._current_media_to_rate = None
self._file_query_result = CC.FileQueryResult( HC.LOCAL_FILE_SERVICE_IDENTIFIER, [], media_results )
@ -1871,37 +2250,6 @@ class RatingsFilterFrameNumerical( ClientGUICommon.Frame ):
self._inequal_accuracy = self.RATINGS_FILTER_INEQUALITY_FULL
self._equal_accuracy = self.RATINGS_FILTER_EQUALITY_FULL
# panel
if service_identifier.GetType() == HC.LOCAL_RATING_NUMERICAL:
top_panel = wx.Panel( self )
hbox = wx.BoxSizer( wx.HORIZONTAL )
if 'ratings_filter_accuracy' not in self._options:
self._options[ 'ratings_filter_accuracy' ] = 1
wx.GetApp().Write( 'save_options' )
value = self._options[ 'ratings_filter_accuracy' ]
self._accuracy_slider = wx.Slider( top_panel, value = value, minValue = 0, maxValue = 4 )
self._accuracy_slider.Bind( wx.EVT_SLIDER, self.EventSlider )
self.EventSlider( None )
hbox.AddF( wx.StaticText( top_panel, label = 'quick' ), FLAGS_MIXED )
hbox.AddF( self._accuracy_slider, FLAGS_EXPAND_BOTH_WAYS )
hbox.AddF( wx.StaticText( top_panel, label = 'accurate' ), FLAGS_MIXED )
top_panel.SetSizer( hbox )
# end panel
self._statusbar = self.CreateStatusBar()
self._statusbar.SetFieldsCount( 3 )
self._statusbar.SetStatusWidths( [ -1, 500, -1 ] )
@ -1911,7 +2259,6 @@ class RatingsFilterFrameNumerical( ClientGUICommon.Frame ):
vbox = wx.BoxSizer( wx.VERTICAL )
if service_identifier.GetType() == HC.LOCAL_RATING_NUMERICAL: vbox.AddF( top_panel, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._splitter, FLAGS_EXPAND_BOTH_WAYS )
self.SetSizer( vbox )
@ -1933,6 +2280,8 @@ class RatingsFilterFrameNumerical( ClientGUICommon.Frame ):
wx.GetApp().SetTopWindow( self )
self._left_window = self._Panel( self._splitter )
FullscreenPopoutFilterNumerical( self._left_window, self )
self._right_window = self._Panel( self._splitter )
( my_width, my_height ) = self.GetClientSize()
@ -2110,7 +2459,10 @@ class RatingsFilterFrameNumerical( ClientGUICommon.Frame ):
def _ShowNewMedia( self ):
( self._current_media_to_rate, ) = random.sample( self._media_still_to_rate, 1 )
if not ( self._compare_same and self._current_media_to_rate in self._media_still_to_rate ):
( self._current_media_to_rate, ) = random.sample( self._media_still_to_rate, 1 )
( min, max ) = self._media_to_current_scores_dict[ self._current_media_to_rate ]
@ -2190,7 +2542,11 @@ class RatingsFilterFrameNumerical( ClientGUICommon.Frame ):
self._current_media_to_rate_against = media_to_rate_against
if random.randint( 0, 1 ) == 0:
if self._left_right == 'left': position = 0
elif self._left_right == 'random': position = random.randint( 0, 1 )
else: position = 1
if position == 0:
self._unrated_is_on_the_left = True
@ -2384,6 +2740,19 @@ class RatingsFilterFrameNumerical( ClientGUICommon.Frame ):
else: self._ShowNewMedia()
def EventButtonBack( self, event ): self._GoBack()
def EventButtonDone( self, event ): self.EventClose( event )
def EventButtonDontFilter( self, event ):
self._media_still_to_rate.discard( self._current_media_to_rate )
if len( self._media_still_to_rate ) == 0: self.EventClose( None )
else: self._ShowNewMedia()
def EventButtonEqual( self, event ): self._ProcessAction( 'equal' )
def EventButtonLeft( self, event ): self._ProcessAction( 'right' )
def EventButtonRight( self, event ): self._ProcessAction( 'left' )
def EventClose( self, event ):
if len( self._decision_log ) > 0:
@ -2469,23 +2838,6 @@ class RatingsFilterFrameNumerical( ClientGUICommon.Frame ):
elif event.ButtonDown( wx.MOUSE_BTN_MIDDLE ): self._ProcessAction( 'equal' )
def EventSlider( self, event ):
value = self._accuracy_slider.GetValue()
if value == 0: self._equal_accuracy = self.RATINGS_FILTER_EQUALITY_FULL
elif value <= 2: self._equal_accuracy = self.RATINGS_FILTER_EQUALITY_HALF
else: self._equal_accuracy = self.RATINGS_FILTER_EQUALITY_QUARTER
if value <= 1: self._inequal_accuracy = self.RATINGS_FILTER_INEQUALITY_FULL
elif value <= 3: self._inequal_accuracy = self.RATINGS_FILTER_INEQUALITY_HALF
else: self._inequal_accuracy = self.RATINGS_FILTER_INEQUALITY_QUARTER
self._options[ 'ratings_filter_accuracy' ] = value
wx.GetApp().Write( 'save_options' )
def ProcessContentUpdates( self, service_identifiers_to_content_updates ):
redraw = False
@ -2520,6 +2872,39 @@ class RatingsFilterFrameNumerical( ClientGUICommon.Frame ):
self._right_window.RefreshBackground()
def SetAccuracy( self, accuracy ):
if accuracy == 0: self._equal_accuracy = self.RATINGS_FILTER_EQUALITY_FULL
elif accuracy <= 2: self._equal_accuracy = self.RATINGS_FILTER_EQUALITY_HALF
else: self._equal_accuracy = self.RATINGS_FILTER_EQUALITY_QUARTER
if accuracy <= 1: self._inequal_accuracy = self.RATINGS_FILTER_INEQUALITY_FULL
elif accuracy <= 3: self._inequal_accuracy = self.RATINGS_FILTER_INEQUALITY_HALF
else: self._inequal_accuracy = self.RATINGS_FILTER_INEQUALITY_QUARTER
self._options[ 'ratings_filter_accuracy' ] = accuracy
wx.GetApp().Write( 'save_options' )
def SetCompareSame( self, compare_same ):
self._options[ 'ratings_filter_compare_same' ] = compare_same
wx.GetApp().Write( 'save_options' )
self._compare_same = compare_same
def SetLeftRight( self, left_right ):
self._options[ 'ratings_filter_left_right' ] = left_right
wx.GetApp().Write( 'save_options' )
self._left_right = left_right
class _Panel( Canvas, wx.Window ):
def __init__( self, parent ):

View File

@ -3169,8 +3169,6 @@ class TagsBoxManage( TagsBox ):
self._callable = callable
self._show_deleted_tags = False
self._current_tags = set( current_tags )
self._deleted_tags = set( deleted_tags )
self._pending_tags = set( pending_tags )
@ -3185,8 +3183,7 @@ class TagsBoxManage( TagsBox ):
siblings_manager = wx.GetApp().GetTagSiblingsManager()
if self._show_deleted_tags: all_tags = self._current_tags | self._deleted_tags | self._pending_tags | self._petitioned_tags
else: all_tags = self._current_tags | self._pending_tags | self._petitioned_tags
all_tags = self._current_tags | self._deleted_tags | self._pending_tags | self._petitioned_tags
self._ordered_strings = []
self._strings_to_terms = {}
@ -3245,13 +3242,6 @@ class TagsBoxManage( TagsBox ):
self._RebuildTagStrings()
def SetShowDeletedTags( self, value ):
self._show_deleted_tags = value
self._RebuildTagStrings()
class TagsBoxOptions( TagsBox ):
def __init__( self, parent, initial_namespace_colours ):

View File

@ -8463,9 +8463,6 @@ class DialogManageTags( Dialog ):
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 )
@ -8475,11 +8472,7 @@ class DialogManageTags( Dialog ):
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._show_deleted_tags.Hide()
self._modify_mappers.Hide()
if self._i_am_local_tag_service: self._modify_mappers.Hide()
else:
if not self._account.HasPermission( HC.POST_DATA ): self._add_tag_box.Hide()
@ -8491,11 +8484,6 @@ class DialogManageTags( Dialog ):
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 )
@ -8506,7 +8494,7 @@ class DialogManageTags( Dialog ):
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 )
vbox.AddF( self._modify_mappers, FLAGS_BUTTON_SIZERS )
self.SetSizer( vbox )
@ -8628,17 +8616,6 @@ class DialogManageTags( Dialog ):
elif tag in self._deleted_tags:
if self._account.HasPermission( HC.RESOLVE_PETITIONS ):
self._content_updates.append( HC.ContentUpdate( HC.CONTENT_DATA_TYPE_MAPPINGS, HC.CONTENT_UPDATE_PENDING, ( tag, self._hashes ) ) )
self._pending_tags.append( tag )
self._tags_box.PendTag( tag )
else:
self._content_updates.append( HC.ContentUpdate( HC.CONTENT_DATA_TYPE_MAPPINGS, HC.CONTENT_UPDATE_PENDING, ( tag, self._hashes ) ) )
@ -8719,8 +8696,6 @@ class DialogManageTags( Dialog ):
else: wx.MessageBox( 'I could not get permission to access the clipboard.' )
def EventShowDeletedTags( self, event ): self._tags_box.SetShowDeletedTags( self._show_deleted_tags.GetValue() )
def EventTagsBoxAction( self, event ):
tag = self._tags_box.GetSelectedTag()

View File

@ -261,7 +261,7 @@ class MediaPanel( ClientGUIMixins.ListeningMediaList, wx.ScrolledWindow ):
if len( media_results ) > 0:
try: ClientGUICanvas.CanvasFullscreenMediaListFilter( self.GetTopLevelParent(), self._page_key, self._file_service_identifier, self._predicates, media_results )
try: ClientGUICanvas.CanvasFullscreenMediaListFilterInbox( self.GetTopLevelParent(), self._page_key, self._file_service_identifier, self._predicates, media_results )
except: wx.MessageBox( traceback.format_exc() )
@ -807,7 +807,9 @@ class MediaPanelThumbnails( MediaPanel ):
bmp = thumbnail.GetBmp()
self._thumbnails_being_faded_in[ ( bmp, x, y ) ] = ( bmp, 0 )
hash = thumbnail.GetDisplayMedia().GetHash()
self._thumbnails_being_faded_in[ hash ] = ( bmp, bmp, x, y, 0 )
if not self._timer_animation.IsRunning(): self._timer_animation.Start( 0, wx.TIMER_ONE_SHOT )
@ -1543,13 +1545,11 @@ class MediaPanelThumbnails( MediaPanel ):
all_info = self._thumbnails_being_faded_in.items()
for ( key, ( alpha_bmp, num_frames_rendered ) ) in all_info:
( bmp, x, y ) = key
for ( hash, ( original_bmp, alpha_bmp, x, y, num_frames_rendered ) ) in all_info:
if num_frames_rendered == 0:
image = bmp.ConvertToImage()
image = original_bmp.ConvertToImage()
image.InitAlpha()
@ -1560,13 +1560,13 @@ class MediaPanelThumbnails( MediaPanel ):
num_frames_rendered += 1
self._thumbnails_being_faded_in[ key ] = ( alpha_bmp, num_frames_rendered )
self._thumbnails_being_faded_in[ hash ] = ( original_bmp, alpha_bmp, x, y, num_frames_rendered )
if y < min_y or y > max_y or num_frames_rendered == 9:
bmp_to_use = bmp
bmp_to_use = original_bmp
del self._thumbnails_being_faded_in[ key ]
del self._thumbnails_being_faded_in[ hash ]
else:

View File

@ -676,7 +676,7 @@ class MediaSingleton( Media ):
def HasArchive( self ): return not self._media_result.GetInbox()
def HasDuration( self ): return self._media_result.GetDuration() is not None
def HasDuration( self ): return self._media_result.GetDuration() is not None and self._media_result.GetNumFrames() > 1
def HasImages( self ): return self.IsImage()

View File

@ -31,7 +31,7 @@ TEMP_DIR = BASE_DIR + os.path.sep + 'temp'
# Misc
NETWORK_VERSION = 10
SOFTWARE_VERSION = 74
SOFTWARE_VERSION = 75
UNSCALED_THUMBNAIL_DIMENSIONS = ( 200, 200 )

View File

@ -61,7 +61,7 @@ def ConvertTagsToServiceIdentifiersToTags( tags, advanced_tag_options ):
if len( tags_to_add_here ) > 0:
tags_to_add_here = siblings_manager.CollapseTagList( tags_to_add_here )
tags_to_add_here = siblings_manager.CollapseTags( tags_to_add_here )
tags_to_add_here = parents_manager.ExpandTags( service_identifier, tags_to_add_here )
service_identifiers_to_tags[ service_identifier ] = tags_to_add_here