Version 105

This commit is contained in:
Hydrus 2014-02-26 16:09:54 -06:00
parent 443295843d
commit f2f188e104
18 changed files with 783 additions and 526 deletions

View File

@ -8,6 +8,21 @@
<div class="content">
<h3>changelog</h3>
<ul>
<li><h3>version 105</h3></li>
<ul>
<li>complete rewrite of message data handling and display</li>
<li>hidden gauge messages will now display correctly</li>
<li>fixed error-display bugs in the log page</li>
<li>massively improved how database errors are generated and displayed</li>
<li>improved and streamlined how other errors are generated and displayed</li>
<li>improved the way all gui elements are deleted from memory</li>
<li>fixed the frequent segfault in os x and linux when closing popup messages</li>
<li>fixed the common segfault in os x and linux when refreshing a query</li>
<li>fixed the occasional segfault in os x and linux when closing a page</li>
<li>fixed pattern shortcut buttons</li>
<li>the 'show deleted' checkbox on manage tags dialog makes a return</li>
<li>neatened several checkboxes so clicking the label text clicks the checkbox</li>
</ul>
<li><h3>version 104</h3></li>
<ul>
<li>first version of export folders is ready</li>

View File

@ -318,7 +318,7 @@ def CatchExceptionClient( etype, value, tb ):
trace = ''.join( trace_list )
HC.pubsub.pub( 'message', HC.Message( HC.MESSAGE_TYPE_ERROR, ( etype, value, trace ) ) )
HC.pubsub.pub( 'message', HC.Message( HC.MESSAGE_TYPE_ERROR, { 'error' : ( etype, value, trace ) } ) )
except:
@ -753,33 +753,30 @@ def ParseExportPhrase( phrase ):
def ShowExceptionClient( e ):
if not wx.Thread_IsMain():
if isinstance( e, HydrusExceptions.DBException ):
( etype, value, tb ) = sys.exc_info()
( caller_traceback, db_traceback ) = e.GetTracebacks()
if etype is not None: e = type( e )( os.linesep.join( traceback.format_exception( etype, value, tb ) ) )
info = {}
etype = type( e )
if etype == HydrusExceptions.DBException:
info[ 'text' ] = HC.u( e )
info[ 'caller_traceback' ] = caller_traceback
info[ 'db_traceback' ] = db_traceback
value = ''
trace = HC.u( e )
message = HC.Message( HC.MESSAGE_TYPE_DB_ERROR, info )
else:
value = HC.u( e )
( etype, value, tb ) = sys.exc_info()
trace_list = traceback.format_stack()
trace = ''.join( traceback.format_exception( etype, value, tb ) )
trace = ''.join( trace_list )
message = HC.Message( HC.MESSAGE_TYPE_ERROR, { 'error' : ( etype, value, trace ) } )
HC.pubsub.pub( 'message', HC.Message( HC.MESSAGE_TYPE_ERROR, ( etype, value, trace ) ) )
HC.pubsub.pub( 'message', message )
def ShowTextClient( text ): HC.pubsub.pub( 'message', HC.Message( HC.MESSAGE_TYPE_TEXT, text ) )
def ShowTextClient( text ): HC.pubsub.pub( 'message', HC.Message( HC.MESSAGE_TYPE_TEXT, { 'text' : text } ) )
class AutocompleteMatches():

View File

@ -309,7 +309,7 @@ The database will be locked while the backup occurs, which may lock up your gui
finally:
try: self._splash.Destroy()
try: wx.CallAfter( self._splash.Destroy )
except: pass

View File

@ -3619,7 +3619,12 @@ class ServiceDB( FileDB, MessageDB, TagDB, RatingDB ):
for ( post, timestamp ) in news_rows:
if now - timestamp < 86400 * 7: self.pub( 'message', HC.Message( HC.MESSAGE_TYPE_TEXT, service_identifier.GetName() + ' at ' + time.ctime( timestamp ) + ':' + os.linesep + os.linesep + post ) )
if now - timestamp < 86400 * 7:
text = service_identifier.GetName() + ' at ' + time.ctime( timestamp ) + ':' + os.linesep + os.linesep + post
self.pub( 'message', HC.Message( HC.MESSAGE_TYPE_TEXT, { 'text' : text } ) )
elif action == HC.SERVICE_UPDATE_NEXT_BEGIN:
@ -6762,7 +6767,9 @@ class DB( ServiceDB ):
( etype, value, tb ) = sys.exc_info()
new_e = type( e )( os.linesep.join( traceback.format_exception( etype, value, tb ) ) )
db_traceback = os.linesep.join( traceback.format_exception( etype, value, tb ) )
new_e = HydrusExceptions.DBException( HC.u( e ), 'Unknown Caller, probably GUI.', db_traceback )
if job.IsSynchronous(): job.PutResult( new_e )
else: HC.ShowException( new_e )
@ -7048,9 +7055,9 @@ def DAEMONCheckImportFolders():
details[ 'failed_imported_paths' ].add( path )
message = 'Import folder failed to import a file: ' + os.linesep + path + os.linesep + traceback.format_exc()
message = 'Import folder failed to import ' + path + ':' + os.linesep + traceback.format_exc()
HC.Message( HC.MESSAGE_TYPE_ERROR, Exception( message ) )
HC.ShowText( message )
should_action = False
@ -7071,9 +7078,9 @@ def DAEMONCheckImportFolders():
if len( successful_hashes ) > 0:
message_text = HC.u( len( successful_hashes ) ) + ' files imported from ' + folder_path
text = HC.u( len( successful_hashes ) ) + ' files imported from ' + folder_path
HC.pubsub.pub( 'message', HC.Message( HC.MESSAGE_TYPE_FILES, ( message_text, successful_hashes ) ) )
HC.pubsub.pub( 'message', HC.Message( HC.MESSAGE_TYPE_FILES, { 'text' : text, 'hashes' : successful_hashes } ) )
details[ 'last_checked' ] = now
@ -7496,137 +7503,141 @@ def DAEMONSynchroniseRepositories():
try: service = HC.app.ReadDaemon( 'service', service_identifier )
except: continue
job_key = HC.JobKey()
if service.CanUpdate(): HC.pubsub.pub( 'message', HC.Message( HC.MESSAGE_TYPE_GAUGE, ( job_key, False ) ) )
HC.pubsub.pub( 'message_gauge_info', job_key, None, 0, u'checking ' + name + ' repository' )
while service.CanUpdate():
if service.CanUpdate():
while HC.options[ 'pause_repo_sync' ]:
message = HC.MessageGauge( HC.MESSAGE_TYPE_GAUGE, 'checking ' + name + ' repository' )
HC.pubsub.pub( 'message', message )
while service.CanUpdate():
HC.pubsub.pub( 'message_gauge_info', job_key, None, 0, u'Repository synchronisation paused' )
time.sleep( 5 )
while HC.options[ 'pause_repo_sync' ]:
message.SetInfo( 'text', 'Repository synchronisation paused' )
time.sleep( 5 )
if HC.shutdown: raise Exception( 'Application shutting down!' )
if HC.repos_changed:
message.Close()
HC.pubsub.pub( 'notify_restart_repo_sync_daemon' )
return
if HC.shutdown: raise Exception( 'Application shutting down!' )
if HC.repos_changed:
now = HC.GetNow()
first_begin = service.GetFirstBegin()
next_begin = service.GetNextBegin()
if first_begin == 0:
HC.pubsub.pub( 'message_gauge_failed', job_key )
range = None
value = 0
HC.pubsub.pub( 'notify_restart_repo_sync_daemon' )
update_index_string = 'initial update'
return
else:
range = ( ( now - first_begin ) / HC.UPDATE_DURATION ) + 1
value = ( ( next_begin - first_begin ) / HC.UPDATE_DURATION ) + 1
update_index_string = 'update ' + HC.u( value )
if HC.shutdown: raise Exception( 'Application shutting down!' )
now = HC.GetNow()
first_begin = service.GetFirstBegin()
next_begin = service.GetNextBegin()
if first_begin == 0:
prefix_string = name + ' ' + update_index_string + ': '
range = None
value = 0
message.SetInfo( 'range', range )
message.SetInfo( 'value', value )
message.SetInfo( 'text', prefix_string + 'downloading and parsing' )
message.SetInfo( 'mode', 'gauge' )
update_index_string = 'initial update'
update = service.Request( HC.GET, 'update', { 'begin' : next_begin } )
else:
range = ( ( now - first_begin ) / HC.UPDATE_DURATION ) + 1
value = ( ( next_begin - first_begin ) / HC.UPDATE_DURATION ) + 1
update_index_string = 'update ' + HC.u( value )
prefix_string = name + ' ' + update_index_string + ': '
HC.pubsub.pub( 'message_gauge_info', job_key, range, value, prefix_string + 'downloading and parsing' )
update = service.Request( HC.GET, 'update', { 'begin' : next_begin } )
if service_type == HC.TAG_REPOSITORY:
HC.pubsub.pub( 'message_gauge_info', job_key, range, value, prefix_string + 'generating tags' )
HC.app.WriteSynchronous( 'generate_tag_ids', update.GetTags() )
i = 0
num_content_updates = update.GetNumContentUpdates()
content_updates = []
current_weight = 0
for content_update in update.IterateContentUpdates():
content_updates.append( content_update )
current_weight += len( content_update.GetHashes() )
i += 1
if current_weight > 50:
if service_type == HC.TAG_REPOSITORY:
while HC.options[ 'pause_repo_sync' ]:
message.SetInfo( 'text', prefix_string + 'generating tags' )
HC.app.WriteSynchronous( 'generate_tag_ids', update.GetTags() )
i = 0
num_content_updates = update.GetNumContentUpdates()
content_updates = []
current_weight = 0
for content_update in update.IterateContentUpdates():
content_updates.append( content_update )
current_weight += len( content_update.GetHashes() )
i += 1
if current_weight > 50:
HC.pubsub.pub( 'message_gauge_info', job_key, range, value, u'Repository synchronisation paused' )
time.sleep( 5 )
if HC.shutdown: raise Exception( 'Application shutting down!' )
if HC.repos_changed:
while HC.options[ 'pause_repo_sync' ]:
HC.pubsub.pub( 'message_gauge_failed', job_key )
message.SetInfo( 'text', 'Repository synchronisation paused' )
HC.pubsub.pub( 'notify_restart_repo_sync_daemon' )
time.sleep( 5 )
return
if HC.shutdown: raise Exception( 'Application shutting down!' )
if HC.repos_changed:
message.Close()
HC.pubsub.pub( 'notify_restart_repo_sync_daemon' )
return
HC.pubsub.pub( 'message_gauge_info', job_key, range, value, prefix_string + 'processing content ' + HC.ConvertIntToPrettyString( i ) + '/' + HC.ConvertIntToPrettyString( num_content_updates ) )
HC.app.WaitUntilGoodTimeToUseGUIThread()
time.sleep( 0.0001 )
HC.app.WriteSynchronous( 'content_updates', { service_identifier : content_updates } )
content_updates = []
current_weight = 0
message.SetInfo( 'text', prefix_string + 'processing content ' + HC.ConvertIntToPrettyString( i ) + '/' + HC.ConvertIntToPrettyString( num_content_updates ) )
HC.app.WaitUntilGoodTimeToUseGUIThread()
time.sleep( 0.0001 )
HC.app.WriteSynchronous( 'content_updates', { service_identifier : content_updates } )
content_updates = []
current_weight = 0
if len( content_updates ) > 0: HC.app.WriteSynchronous( 'content_updates', { service_identifier : content_updates } )
message.SetInfo( 'text', prefix_string + 'processing service info' )
service_updates = [ service_update for service_update in update.IterateServiceUpdates() ]
service_identifiers_to_service_updates = { service_identifier : service_updates }
HC.app.WriteSynchronous( 'service_updates', service_identifiers_to_service_updates )
HC.pubsub.pub( 'notify_new_pending' )
time.sleep( 0.10 )
try: service = HC.app.ReadDaemon( 'service', service_identifier )
except: break
if len( content_updates ) > 0: HC.app.WriteSynchronous( 'content_updates', { service_identifier : content_updates } )
message.Close()
HC.pubsub.pub( 'message_gauge_info', job_key, range, value, prefix_string + 'processing service info' )
service_updates = [ service_update for service_update in update.IterateServiceUpdates() ]
service_identifiers_to_service_updates = { service_identifier : service_updates }
HC.app.WriteSynchronous( 'service_updates', service_identifiers_to_service_updates )
HC.pubsub.pub( 'notify_new_pending' )
time.sleep( 0.10 )
try: service = HC.app.ReadDaemon( 'service', service_identifier )
except: break
HC.pubsub.pub( 'message_gauge_failed', job_key )
except Exception as e:
HC.pubsub.pub( 'message_gauge_failed', job_key )
message.Close()
message = 'Failed to update ' + name + ':' + os.linesep + os.linesep + HC.u( e )
@ -7670,11 +7681,9 @@ def DAEMONSynchroniseSubscriptions():
try:
job_key = HC.JobKey()
message = HC.MessageGauge( HC.MESSAGE_TYPE_GAUGE, 'checking ' + name + ' subscription' )
HC.pubsub.pub( 'message', HC.Message( HC.MESSAGE_TYPE_GAUGE, ( job_key, False ) ) )
HC.pubsub.pub( 'message_gauge_info', job_key, None, 0, u'checking ' + name + ' subscription' )
HC.pubsub.pub( 'message', message )
do_tags = len( advanced_tag_options ) > 0
@ -7740,7 +7749,7 @@ def DAEMONSynchroniseSubscriptions():
while HC.options[ 'pause_subs_sync' ]:
HC.pubsub.pub( 'message_gauge_info', job_key, None, 0, u'subscriptions paused' )
message.SetInfo( 'text', 'subscriptions paused' )
time.sleep( 5 )
@ -7748,7 +7757,7 @@ def DAEMONSynchroniseSubscriptions():
if HC.subs_changed:
HC.pubsub.pub( 'message_gauge_failed', job_key )
message.Close()
HC.pubsub.pub( 'notify_restart_subs_sync_daemon' )
@ -7774,7 +7783,7 @@ def DAEMONSynchroniseSubscriptions():
all_url_args.extend( fresh_url_args )
HC.pubsub.pub( 'message_gauge_info', job_key, None, 0, u'found ' + HC.ConvertIntToPrettyString( len( all_url_args ) ) + ' new files for ' + name )
message.SetInfo( 'text', 'found ' + HC.ConvertIntToPrettyString( len( all_url_args ) ) + ' new files for ' + name )
@ -7783,6 +7792,10 @@ def DAEMONSynchroniseSubscriptions():
if len( downloaders ) == 0: break
message.SetInfo( 'range', len( all_url_args ) )
message.SetInfo( 'value', 0 )
message.SetInfo( 'mode', 'gauge' )
all_url_args.reverse() # to do oldest first, which means we can save incrementally
i = 1
@ -7795,7 +7808,7 @@ def DAEMONSynchroniseSubscriptions():
while HC.options[ 'pause_subs_sync' ]:
HC.pubsub.pub( 'message_gauge_info', job_key, None, 0, u'subscriptions paused' )
message.SetInfo( 'text', 'subscriptions paused' )
time.sleep( 5 )
@ -7803,7 +7816,7 @@ def DAEMONSynchroniseSubscriptions():
if HC.subs_changed:
HC.pubsub.pub( 'message_gauge_failed', job_key )
message.Close()
HC.pubsub.pub( 'notify_restart_subs_sync_daemon' )
@ -7821,7 +7834,8 @@ def DAEMONSynchroniseSubscriptions():
x_out_of_y = HC.ConvertIntToPrettyString( i ) + '/' + HC.ConvertIntToPrettyString( len( all_url_args ) )
HC.pubsub.pub( 'message_gauge_info', job_key, len( all_url_args ), i, name + ': ' + x_out_of_y + ' : checking url status' )
message.SetInfo( 'value', i )
message.SetInfo( 'text', name + ': ' + x_out_of_y + ' : checking url status' )
( status, hash ) = HC.app.ReadDaemon( 'url_status', url )
@ -7833,7 +7847,7 @@ def DAEMONSynchroniseSubscriptions():
try:
HC.pubsub.pub( 'message_gauge_info', job_key, len( all_url_args ), i, name + ': ' + x_out_of_y + ' : found file in db, fetching tags' )
message.SetInfo( 'text', name + ': ' + x_out_of_y + ' : found file in db, fetching tags' )
tags = downloader.GetTags( *url_args )
@ -7850,7 +7864,7 @@ def DAEMONSynchroniseSubscriptions():
num_new += 1
HC.pubsub.pub( 'message_gauge_info', job_key, len( all_url_args ), i, name + ': ' + x_out_of_y + ' : downloading file' )
message.SetInfo( 'text', name + ': ' + x_out_of_y + ' : downloading file' )
if do_tags: ( temp_path, tags ) = downloader.GetFileAndTags( *url_args )
else:
@ -7862,7 +7876,7 @@ def DAEMONSynchroniseSubscriptions():
service_identifiers_to_tags = HydrusDownloading.ConvertTagsToServiceIdentifiersToTags( tags, advanced_tag_options )
HC.pubsub.pub( 'message_gauge_info', job_key, len( all_url_args ), i, name + ': ' + x_out_of_y + ' : importing file' )
message.SetInfo( 'text', name + ': ' + x_out_of_y + ' : importing file' )
( status, hash ) = HC.app.WriteSynchronous( 'import_file', temp_path, advanced_import_options = advanced_import_options, service_identifiers_to_tags = service_identifiers_to_tags, url = url )
@ -7901,21 +7915,25 @@ def DAEMONSynchroniseSubscriptions():
if len( successful_hashes ) > 0:
message_text = HC.u( len( successful_hashes ) ) + ' files imported from ' + name
text = HC.u( len( successful_hashes ) ) + ' files imported from ' + name
HC.pubsub.pub( 'message_gauge_show_file_button', job_key, message_text, successful_hashes )
message.SetInfo( 'text', text )
message.SetInfo( 'hashes', successful_hashes )
message.SetInfo( 'mode', 'files' )
else: HC.pubsub.pub( 'message_gauge_failed', job_key )
else: message.Close()
last_checked = now
except Exception as e:
message.Close()
last_checked = now + HC.UPDATE_DURATION
message = 'Problem with ' + name + ' ' + traceback.format_exc()
text = 'Problem with ' + name + ' ' + traceback.format_exc()
HC.ShowText( message )
HC.ShowText( text )
time.sleep( 3 )

View File

@ -133,9 +133,9 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
job_key = HC.JobKey()
HC.pubsub.pub( 'message', HC.Message( HC.MESSAGE_TYPE_GAUGE, ( job_key, True ) ) )
message = HC.MessageGauge( HC.MESSAGE_TYPE_GAUGE, 'gathering pending and petitioned' )
HC.pubsub.pub( 'message_gauge_info', job_key, 1, 0, u'gathering pending and petitioned' )
HC.pubsub.pub( 'message', message )
result = HC.app.Read( 'pending', service_identifier )
@ -159,7 +159,11 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
i = 1
HC.pubsub.pub( 'message_gauge_info', job_key, gauge_range, i, u'connecting to repository' )
message.SetInfo( 'job_key', job_key )
message.SetInfo( 'range', gauge_range )
message.SetInfo( 'value', i )
message.SetInfo( 'text', 'connecting to repository' )
message.SetInfo( 'mode', 'cancelable gauge' )
good_hashes = []
@ -167,15 +171,20 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
for media_result in media_results:
if job_key.IsCancelled(): return
if job_key.IsCancelled():
message.Close()
return
i += 1
hash = media_result.GetHash()
mime = media_result.GetMime()
HC.pubsub.pub( 'message_gauge_info', job_key, gauge_range, i, u'Uploading file ' + HC.ConvertIntToPrettyString( i ) + ' of ' + HC.ConvertIntToPrettyString( num_uploads ) )
message.SetInfo( 'value', i )
message.SetInfo( 'text', 'Uploading file ' + HC.ConvertIntToPrettyString( i ) + ' of ' + HC.ConvertIntToPrettyString( num_uploads ) )
try:
@ -213,7 +222,8 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
i += 1
HC.pubsub.pub( 'message_gauge_info', job_key, gauge_range, i, u'uploading petitions' )
message.SetInfo( 'value', i )
message.SetInfo( 'text', 'uploading petitions' )
service.Request( HC.POST, 'update', { 'update' : update } )
@ -236,15 +246,24 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
i = 1
HC.pubsub.pub( 'message_gauge_info', job_key, gauge_range, i, u'connecting to repository' )
message.SetInfo( 'range', gauge_range )
message.SetInfo( 'value', i )
message.SetInfo( 'text', 'connecting to repository' )
message.SetInfo( 'mode', 'cancelable gauge' )
for update in updates:
if job_key.IsCancelled(): return
if job_key.IsCancelled():
message.Close()
return
i += 1
HC.pubsub.pub( 'message_gauge_info', job_key, gauge_range, i, u'posting update' )
message.SetInfo( 'value', i )
message.SetInfo( 'text', 'posting update' )
service.Request( HC.POST, 'update', { 'update' : update } )
@ -260,7 +279,8 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
except Exception as e: HC.ShowException( e )
HC.pubsub.pub( 'message_gauge_info', job_key, None, None, u'upload done!' )
message.SetInfo( 'text', 'upload done' )
message.SetInfo( 'mode', 'text' )
HC.pubsub.pub( 'notify_new_pending' )
@ -557,7 +577,7 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
page.CleanBeforeDestroy()
page.Destroy()
wx.CallAfter( page.Destroy )
def _FetchIP( self, service_identifier ):
@ -990,11 +1010,9 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
def do_it():
job_key = HC.JobKey()
message = HC.Message( HC.MESSAGE_TYPE_TEXT, { 'text' : 'regenerating thumbnails - creating directories' } )
HC.pubsub.pub( 'message', HC.Message( HC.MESSAGE_TYPE_GAUGE, ( job_key, False ) ) )
HC.pubsub.pub( 'message_gauge_info', job_key, None, 0, 'regenerating thumbnails - creating directories' )
HC.pubsub.pub( 'message', message )
if not os.path.exists( HC.CLIENT_THUMBNAILS_DIR ): os.mkdir( HC.CLIENT_THUMBNAILS_DIR )
@ -1017,10 +1035,7 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
if mime in HC.MIMES_WITH_THUMBNAILS:
if i % 100 == 0:
HC.pubsub.pub( 'message_gauge_info', job_key, None, 0, 'regenerating thumbnails - ' + HC.ConvertIntToPrettyString( i ) + ' done' )
if i % 100 == 0: message.SetInfo( 'text', 'regenerating thumbnails - ' + HC.ConvertIntToPrettyString( i ) + ' done' )
i += 1
@ -1048,7 +1063,7 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
except: continue
HC.pubsub.pub( 'message_gauge_info', job_key, None, None, 'regenerating thumbnails - done' )
message.SetInfo( 'text', 'done regenerating thumbnails' )
threading.Thread( target = do_it ).start()
@ -1056,11 +1071,7 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
def _ReviewServices( self ):
try: FrameReviewServices()
except: wx.MessageBox( traceback.format_exc() )
def _ReviewServices( self ): FrameReviewServices()
def _SaveGUISession( self, name = None ):
@ -1162,13 +1173,13 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
url = dlg.GetValue()
job_key = HC.JobKey()
url_string = url
message_string = url
message = HC.MessageGauge( HC.MESSAGE_TYPE_GAUGE, url_string )
threading.Thread( target = HydrusDownloading.THREADDownloadURL, args = ( job_key, url, message_string ) ).start()
HC.pubsub.pub( 'message', message )
HC.pubsub.pub( 'message', HC.Message( HC.MESSAGE_TYPE_GAUGE, ( job_key, True ) ) )
threading.Thread( target = HydrusDownloading.THREADDownloadURL, args = ( message, url, url_string ) ).start()
@ -1311,7 +1322,7 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
HC.app.MaintainDB()
self.Destroy()
wx.CallAfter( self.Destroy )
def EventFocus( self, event ):
@ -1759,7 +1770,7 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
if total_num_pending > 0: menu.Append( pending, p( '&Pending (' + HC.ConvertIntToPrettyString( total_num_pending ) + ')' ) )
else: pending.Destroy()
else: wx.CallAfter( pending.Destroy )
services = wx.Menu()
@ -1899,7 +1910,7 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
self.SetMenuBar( menu )
if old_menu is not None: old_menu.Destroy()
if old_menu is not None: wx.CallAfter( old_menu.Destroy )
def RefreshStatusBar( self ): self._RefreshStatusBar()

View File

@ -1412,7 +1412,7 @@ class CanvasFullscreenMediaListBrowser( CanvasFullscreenMediaList ):
self._menu_open = False
menu.Destroy()
wx.CallAfter( menu.Destroy )
event.Skip()
@ -1756,7 +1756,7 @@ class CanvasFullscreenMediaListCustomFilter( CanvasFullscreenMediaList ):
self._menu_open = False
menu.Destroy()
wx.CallAfter( menu.Destroy )
event.Skip()
@ -3804,7 +3804,7 @@ class Image( wx.Window ):
dc.DrawBitmap( hydrus_bmp, 0, 0 )
hydrus_bmp.Destroy()
wx.CallAfter( hydrus_bmp.Destroy )
dc.SetUserScale( 1.0, 1.0 )

View File

@ -19,6 +19,7 @@ ID_TIMER_SLIDESHOW = wx.NewId()
ID_TIMER_MEDIA_INFO_DISPLAY = wx.NewId()
ID_TIMER_DROPDOWN_HIDE = wx.NewId()
ID_TIMER_AC_LAG = wx.NewId()
ID_TIMER_POPUP = wx.NewId()
# Zooms
@ -447,7 +448,7 @@ class AutoCompleteDropdownTags( AutoCompleteDropdown ):
self.PopupMenu( menu )
menu.Destroy()
wx.CallAfter( menu.Destroy )
def EventMenu( self, event ):
@ -509,7 +510,7 @@ class AutoCompleteDropdownTags( AutoCompleteDropdown ):
self.PopupMenu( menu )
menu.Destroy()
wx.CallAfter( menu.Destroy )
class AutoCompleteDropdownTagsRead( AutoCompleteDropdownTags ):
@ -1145,6 +1146,126 @@ class ChoiceSort( BetterChoice ):
if self._page_key is not None: self._BroadcastSort()
class ExportPatternButton( wx.Button ):
ID_HASH = 0
ID_TAGS = 1
ID_NN_TAGS = 2
ID_NAMESPACE = 3
ID_TAG = 4
def __init__( self, parent ):
wx.Button.__init__( self, parent, label = 'pattern shortcuts' )
self.Bind( wx.EVT_BUTTON, self.EventButton )
self.Bind( wx.EVT_MENU, self.EventMenu )
def EventButton( self, event ):
menu = wx.Menu()
menu.Append( -1, 'click on a phrase to copy to clipboard' )
menu.AppendSeparator()
menu.Append( self.ID_REGEX_WHITESPACE, r'whitespace character - \s' )
menu.Append( self.ID_REGEX_NUMBER, r'number character - \d' )
menu.Append( self.ID_REGEX_ALPHANUMERIC, r'alphanumeric or backspace character - \w' )
menu.Append( self.ID_REGEX_ANY, r'any character - .' )
menu.Append( self.ID_REGEX_BACKSPACE, r'backspace character - \\' )
menu.Append( self.ID_REGEX_BEGINNING, r'beginning of line - ^' )
menu.Append( self.ID_REGEX_END, r'end of line - $' )
menu.Append( self.ID_REGEX_SET, r'any of these - [...]' )
menu.Append( self.ID_REGEX_NOT_SET, r'anything other than these - [^...]' )
menu.AppendSeparator()
menu.Append( self.ID_REGEX_0_OR_MORE_GREEDY, r'0 or more matches, consuming as many as possible - *' )
menu.Append( self.ID_REGEX_1_OR_MORE_GREEDY, r'1 or more matches, consuming as many as possible - +' )
menu.Append( self.ID_REGEX_0_OR_1_GREEDY, r'0 or 1 matches, preferring 1 - ?' )
menu.Append( self.ID_REGEX_0_OR_MORE_MINIMAL, r'0 or more matches, consuming as few as possible - *?' )
menu.Append( self.ID_REGEX_1_OR_MORE_MINIMAL, r'1 or more matches, consuming as few as possible - +?' )
menu.Append( self.ID_REGEX_0_OR_1_MINIMAL, r'0 or 1 matches, preferring 0 - *' )
menu.Append( self.ID_REGEX_EXACTLY_M, r'exactly m matches - {m}' )
menu.Append( self.ID_REGEX_M_TO_N_GREEDY, r'm to n matches, consuming as many as possible - {m,n}' )
menu.Append( self.ID_REGEX_M_TO_N_MINIMAL, r'm to n matches, consuming as few as possible - {m,n}?' )
menu.AppendSeparator()
menu.Append( self.ID_REGEX_LOOKAHEAD, r'the next characters are: (non-consuming) - (?=...)' )
menu.Append( self.ID_REGEX_NEGATIVE_LOOKAHEAD, r'the next characters are not: (non-consuming) - (?!...)' )
menu.Append( self.ID_REGEX_LOOKBEHIND, r'the previous characters are: (non-consuming) - (?<=...)' )
menu.Append( self.ID_REGEX_NEGATIVE_LOOKBEHIND, r'the previous characters are not: (non-consuming) - (?<!...)' )
menu.AppendSeparator()
menu.Append( self.ID_REGEX_FILENAME, r'filename - (?<=' + os.path.sep.encode( 'string_escape' ) + r')[\w\s]*?(?=\..*$)' )
menu.AppendSeparator()
menu.Append( self.ID_REGEX_NUMBER_WITHOUT_ZEROES, r'0074 -> 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 )
wx.CallAfter( menu.Destroy )
def EventMenu( self, event ):
id = event.GetId()
phrase = None
if id == self.ID_HASH: phrase = r'{hash}'
if id == self.ID_TAGS: phrase = r'{tags}'
if id == self.ID_NN_TAGS: phrase = r'{nn tags}'
if id == self.ID_NAMESPACE: phrase = r'[...]'
if id == self.ID_TAG: phrase = r'(...)'
else: event.Skip()
if phrase is not None:
if wx.TheClipboard.Open():
data = wx.TextDataObject( phrase )
wx.TheClipboard.SetData( data )
wx.TheClipboard.Close()
else: wx.MessageBox( 'I could not get permission to access the clipboard.' )
def EventButton( self, event ):
menu = wx.Menu()
menu.Append( -1, 'click on a phrase to copy to clipboard' )
menu.AppendSeparator()
menu.Append( self.ID_HASH, r'the file\'s hash - {hash}' )
menu.Append( self.ID_TAGS, r'all the file\'s tags - {tags}' )
menu.Append( self.ID_NN_TAGS, r'all the file\'s non-namespaced tags - {nn tags}' )
menu.AppendSeparator()
menu.Append( self.ID_NAMESPACE, r'all instances of a particular namespace - [...]' )
menu.AppendSeparator()
menu.Append( self.ID_TAG, r'a particular tag, if the file has it - (...)' )
self.PopupMenu( menu )
wx.CallAfter( menu.Destroy )
class FileDropTarget( wx.FileDropTarget ):
def __init__( self, callable ):
@ -1468,7 +1589,12 @@ class ListBook( wx.Panel ):
panel_info = self._list_box.GetClientData( selection )
if type( panel_info ) != tuple: self._panel_sizer.Remove( panel_info )
if type( panel_info ) != tuple:
self._panel_sizer.Detach( panel_info )
wx.CallAfter( panel_info.Destroy )
self._list_box.Delete( selection )
@ -1845,7 +1971,7 @@ class ListBox( wx.ScrolledWindow ):
self.PopupMenu( menu )
menu.Destroy()
wx.CallAfter( menu.Destroy )
event.Skip()
@ -2219,7 +2345,7 @@ class OnOffButton( wx.Button ):
def IsOn( self ): return self._on
class PopupMessage( wx.Window ):
class PopupWindow( wx.Window ):
def __init__( self, parent ):
@ -2228,16 +2354,15 @@ class PopupMessage( wx.Window ):
self.Bind( wx.EVT_RIGHT_DOWN, self.EventDismiss )
def EventDismiss( self, event ):
self.GetParent().Dismiss( self )
def Dismiss( self ): self.GetParent().Dismiss( self )
class PopupMessageDismissAll( PopupMessage ):
def EventDismiss( self, event ): self.Dismiss()
class PopupDismissAll( PopupWindow ):
def __init__( self, parent ):
PopupMessage.__init__( self, parent )
PopupWindow.__init__( self, parent )
hbox = wx.BoxSizer( wx.HORIZONTAL )
@ -2258,13 +2383,120 @@ class PopupMessageDismissAll( PopupMessage ):
def SetNumMessages( self, num_messages_pending ): self._text.SetLabel( HC.ConvertIntToPrettyString( num_messages_pending ) + ' more messages' )
class PopupMessage( PopupWindow ):
def __init__( self, parent, message ):
PopupWindow.__init__( self, parent )
self._message = message
def IsClosed( self ): return self._message.IsClosed()
def Update( self ): pass
class PopupMessageDBError( PopupMessage ):
def __init__( self, parent, message ):
PopupMessage.__init__( self, parent, message )
text = message.GetInfo( 'text' )
caller_traceback = message.GetInfo( 'caller_traceback' )
db_traceback = message.GetInfo( 'db_traceback' )
self._copy_text = 'DBException: ' + text + os.linesep + os.linesep + caller_traceback + os.linesep + os.linesep + db_traceback
vbox = wx.BoxSizer( wx.VERTICAL )
error = wx.StaticText( self, label = 'DBException', style = wx.ALIGN_CENTER )
error.Bind( wx.EVT_RIGHT_DOWN, self.EventDismiss )
text = wx.StaticText( self, label = HC.u( text ) )
text.Wrap( 380 )
text.Bind( wx.EVT_RIGHT_DOWN, self.EventDismiss )
self._show_caller_tb_button = wx.Button( self, label = 'show caller traceback' )
self._show_caller_tb_button.Bind( wx.EVT_BUTTON, self.EventShowCallerButton )
self._show_caller_tb_button.Bind( wx.EVT_RIGHT_DOWN, self.EventDismiss )
self._caller_tb_text = wx.StaticText( self, label = caller_traceback )
self._caller_tb_text.Wrap( 380 )
self._caller_tb_text.Bind( wx.EVT_RIGHT_DOWN, self.EventDismiss )
self._caller_tb_text.Hide()
self._show_db_tb_button = wx.Button( self, label = 'show db traceback' )
self._show_db_tb_button.Bind( wx.EVT_BUTTON, self.EventShowDBButton )
self._show_db_tb_button.Bind( wx.EVT_RIGHT_DOWN, self.EventDismiss )
self._db_tb_text = wx.StaticText( self, label = db_traceback )
self._db_tb_text.Wrap( 380 )
self._db_tb_text.Bind( wx.EVT_RIGHT_DOWN, self.EventDismiss )
self._db_tb_text.Hide()
self._copy_tb_button = wx.Button( self, label = 'copy tracebacks' )
self._copy_tb_button.Bind( wx.EVT_BUTTON, self.EventCopyButton )
self._copy_tb_button.Bind( wx.EVT_RIGHT_DOWN, self.EventDismiss )
vbox.AddF( error, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( text, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._show_caller_tb_button, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._caller_tb_text, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._show_db_tb_button, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._db_tb_text, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._copy_tb_button, FLAGS_EXPAND_PERPENDICULAR )
self.SetSizer( vbox )
def EventCopyButton( self, event ): HC.pubsub.pub( 'clipboard', 'text', self._copy_text )
def EventShowCallerButton( self, event ):
if self._caller_tb_text.IsShown():
self._show_caller_tb_button.SetLabel( 'show caller traceback' )
self._caller_tb_text.Hide()
else:
self._show_caller_tb_button.SetLabel( 'hide caller traceback' )
self._caller_tb_text.Show()
self.GetParent().MakeSureEverythingFits()
def EventShowDBButton( self, event ):
if self._db_tb_text.IsShown():
self._show_db_tb_button.SetLabel( 'show db traceback' )
self._db_tb_text.Hide()
else:
self._show_db_tb_button.SetLabel( 'hide db traceback' )
self._db_tb_text.Show()
self.GetParent().MakeSureEverythingFits()
class PopupMessageError( PopupMessage ):
def __init__( self, parent, etype, value, trace ):
def __init__( self, parent, message ):
PopupMessage.__init__( self, parent )
PopupMessage.__init__( self, parent, message )
self._copy_text = HC.u( etype.__name__ ) + ': ' + HC.u( value ) + os.linesep + trace
( etype, value, trace ) = message.GetInfo( 'error' )
self._copy_text = HC.u( etype.__name__ ) + ': ' + HC.u( value ) + os.linesep + os.linesep + trace
vbox = wx.BoxSizer( wx.VERTICAL )
@ -2287,10 +2519,9 @@ class PopupMessageError( PopupMessage ):
self._tb_text.Bind( wx.EVT_RIGHT_DOWN, self.EventDismiss )
self._tb_text.Hide()
self._copy_tb_button = wx.Button( self, label = 'copy info' )
self._copy_tb_button = wx.Button( self, label = 'copy traceback' )
self._copy_tb_button.Bind( wx.EVT_BUTTON, self.EventCopyButton )
self._copy_tb_button.Bind( wx.EVT_RIGHT_DOWN, self.EventDismiss )
self._copy_tb_button.Hide()
vbox.AddF( error, FLAGS_EXPAND_PERPENDICULAR )
if len( HC.u( value ) ) > 0: vbox.AddF( text, FLAGS_EXPAND_PERPENDICULAR )
@ -2310,14 +2541,12 @@ class PopupMessageError( PopupMessage ):
self._show_tb_button.SetLabel( 'show traceback' )
self._tb_text.Hide()
self._copy_tb_button.Hide()
else:
self._show_tb_button.SetLabel( 'hide traceback' )
self._tb_text.Show()
self._copy_tb_button.Show()
self.GetParent().MakeSureEverythingFits()
@ -2325,15 +2554,15 @@ class PopupMessageError( PopupMessage ):
class PopupMessageFiles( PopupMessage ):
def __init__( self, parent, message_string, hashes ):
def __init__( self, parent, message ):
PopupMessage.__init__( self, parent )
PopupMessage.__init__( self, parent, message )
self._hashes = hashes
text = message.GetInfo( 'text' )
vbox = wx.BoxSizer( wx.VERTICAL )
button = wx.Button( self, label = message_string )
button = wx.Button( self, label = text )
button.Bind( wx.EVT_BUTTON, self.EventButton )
button.Bind( wx.EVT_RIGHT_DOWN, self.EventDismiss )
@ -2344,22 +2573,18 @@ class PopupMessageFiles( PopupMessage ):
def EventButton( self, event ):
media_results = HC.app.Read( 'media_results', HC.LOCAL_FILE_SERVICE_IDENTIFIER, self._hashes )
media_results = HC.app.Read( 'media_results', HC.LOCAL_FILE_SERVICE_IDENTIFIER, self._message.GetInfo( 'hashes' ) )
HC.pubsub.pub( 'new_page_query', HC.LOCAL_FILE_SERVICE_IDENTIFIER, initial_media_results = media_results )
class PopupMessageGauge( PopupMessage ):
def __init__( self, parent, job_key, show_cancel ):
def __init__( self, parent, message ):
PopupMessage.__init__( self, parent )
self._job_key = job_key
self._hashes = set()
PopupMessage.__init__( self, parent, message )
self._done = False
self._show_cancel = show_cancel
vbox = wx.BoxSizer( wx.VERTICAL )
@ -2376,8 +2601,6 @@ class PopupMessageGauge( PopupMessage ):
self._cancel_button.Bind( wx.EVT_BUTTON, self.EventCancelButton )
self._cancel_button.Bind( wx.EVT_RIGHT_DOWN, self.EventDismiss )
if not show_cancel: self._cancel_button.Hide()
hbox.AddF( self._gauge, FLAGS_EXPAND_BOTH_WAYS )
hbox.AddF( self._cancel_button, FLAGS_MIXED )
@ -2385,131 +2608,124 @@ class PopupMessageGauge( PopupMessage ):
self._show_file_button.Bind( wx.EVT_BUTTON, self.EventShowFileButton )
self._show_file_button.Bind( wx.EVT_RIGHT_DOWN, self.EventDismiss )
self._show_file_button.Hide()
vbox.AddF( self._text, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( hbox, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._show_file_button, FLAGS_EXPAND_PERPENDICULAR )
self.SetSizer( vbox )
HC.pubsub.sub( self, 'Failed', 'message_gauge_failed' )
HC.pubsub.sub( self, 'SetInfo', 'message_gauge_info' )
HC.pubsub.sub( self, 'ShowFileButton', 'message_gauge_show_file_button' )
def EventCancelButton( self, event ):
def Dismiss( self ):
self._job_key.Cancel()
self.GetParent().Dismiss( self )
def EventDismiss( self, event ):
if self._show_cancel and not self._done:
if not self._message.IsClosed() and self._message.GetInfo( 'mode' ) == 'cancelable gauge':
import ClientGUIDialogs
with ClientGUIDialogs.DialogYesNo( self, 'Do you want to continue in the background, or stop right now?', yes_label = 'continue', no_label = 'stop' ) as dlg:
if dlg.ShowModal() == wx.ID_NO: self._job_key.Cancel()
result = dlg.ShowModal()
if result == wx.ID_CANCEL: return
elif result == wx.ID_NO: self._message.GetInfo( 'job_key' ).Cancel()
self.GetParent().Dismiss( self )
PopupMessage.Dismiss( self )
def EventCancelButton( self, event ):
if self._message.GetInfo( 'mode' ) == 'cancelable gauge':
job_key = self._message.GetInfo( 'job_key' )
job_key.Cancel()
self._cancel_button.Disable()
def EventShowFileButton( self, event ):
media_results = HC.app.Read( 'media_results', HC.LOCAL_FILE_SERVICE_IDENTIFIER, self._hashes )
hashes = self._message.GetInfo( 'hashes' )
media_results = HC.app.Read( 'media_results', HC.LOCAL_FILE_SERVICE_IDENTIFIER, hashes )
HC.pubsub.pub( 'new_page_query', HC.LOCAL_FILE_SERVICE_IDENTIFIER, initial_media_results = media_results )
def Failed( self, job_key ):
def Update( self ):
if job_key == self._job_key: self.GetParent().Dismiss( self )
mode = self._message.GetInfo( 'mode' )
text = self._message.GetInfo( 'text' )
def SetInfo( self, job_key, range, value, message ):
if job_key == self._job_key:
if mode == 'files':
if value is None:
self._text.Hide()
self._cancel_button.Hide()
self._gauge.Hide()
self._show_file_button.Show()
if self._show_file_button.GetLabel() != text: self._show_file_button.SetLabel( text )
else:
self._text.Show()
if self._text.GetLabel() != text: self._text.SetLabel( text )
if mode == 'text':
self._done = True
self._gauge.Hide()
self._cancel_button.Hide()
self._gauge.Hide()
self._show_file_button.Hide()
else:
elif mode in ( 'gauge', 'cancelable gauge' ):
if mode == 'cancelable gauge': self._cancel_button.Show()
else: self._cancel_button.Hide()
self._gauge.Show()
if self._show_cancel: self._cancel_button.Show()
self._show_file_button.Hide()
if range is None:
self._gauge.Pulse()
byte_info = HC.ConvertIntToBytes( value )
range = self._message.GetInfo( 'range' )
value = self._message.GetInfo( 'value' )
if range is None or value is None: self._gauge.Pulse()
else:
if range == value: self._done = True
else: self._done = False
self._gauge.SetRange( range )
self._gauge.SetValue( value )
if self._done: self._cancel_button.Hide()
else:
if self._show_cancel: self._cancel_button.Show()
self._text.SetLabel( message )
self.GetParent().MakeSureEverythingFits()
def ShowFileButton( self, job_key, message, hashes ):
if job_key == self._job_key:
self._done = True
self._show_file_button.SetLabel( message )
self._hashes = hashes
self._text.Hide()
self._gauge.Hide()
self._show_file_button.Show()
self.GetParent().MakeSureEverythingFits()
class PopupMessageText( PopupMessage ):
def __init__( self, parent, message_string ):
def __init__( self, parent, message ):
PopupMessage.__init__( self, parent )
PopupMessage.__init__( self, parent, message )
vbox = wx.BoxSizer( wx.VERTICAL )
text = wx.StaticText( self, label = message_string )
text.Wrap( 380 )
text.Bind( wx.EVT_RIGHT_DOWN, self.EventDismiss )
text = message.GetInfo( 'text' )
vbox.AddF( text, FLAGS_EXPAND_PERPENDICULAR )
self._text = wx.StaticText( self, label = text )
self._text.Wrap( 380 )
self._text.Bind( wx.EVT_RIGHT_DOWN, self.EventDismiss )
vbox.AddF( self._text, FLAGS_EXPAND_PERPENDICULAR )
self.SetSizer( vbox )
def Update( self ):
text = self._message.GetInfo( 'text' )
if self._text.GetLabel() != text: self._text.SetLabel( text )
class PopupMessageManager( wx.Frame ):
def __init__( self, parent ):
@ -2524,7 +2740,7 @@ class PopupMessageManager( wx.Frame ):
self._message_vbox = wx.BoxSizer( wx.VERTICAL )
self._dismiss_all = PopupMessageDismissAll( self )
self._dismiss_all = PopupDismissAll( self )
self._dismiss_all.Hide()
vbox.AddF( self._message_vbox, FLAGS_EXPAND_SIZER_PERPENDICULAR )
@ -2549,6 +2765,12 @@ class PopupMessageManager( wx.Frame ):
HC.ShowException = CC.ShowExceptionClient
HC.ShowText = CC.ShowTextClient
self.Bind( wx.EVT_TIMER, self.TIMEREvent, id = ID_TIMER_POPUP )
self._timer = wx.Timer( self, id = ID_TIMER_POPUP )
self._timer.Start( 500, wx.TIMER_CONTINUOUS )
def _CheckPending( self ):
@ -2579,32 +2801,16 @@ class PopupMessageManager( wx.Frame ):
def _CreateMessageWindow( self, message ):
message_type = message.GetType()
info = message.GetInfo()
if message_type == HC.MESSAGE_TYPE_TEXT:
message_string = info
window = PopupMessageText( self, message_string )
elif message_type == HC.MESSAGE_TYPE_ERROR:
( etype, value, trace ) = info
window = PopupMessageError( self, etype, value, trace )
elif message_type == HC.MESSAGE_TYPE_FILES:
( message_string, hashes ) = info
window = PopupMessageFiles( self, message_string, hashes )
elif message_type == HC.MESSAGE_TYPE_GAUGE:
( job_key, show_cancel ) = info
window = PopupMessageGauge( self, job_key, show_cancel )
if message_type == HC.MESSAGE_TYPE_TEXT: c = PopupMessageText
elif message_type == HC.MESSAGE_TYPE_ERROR: c = PopupMessageError
elif message_type == HC.MESSAGE_TYPE_DB_ERROR: c = PopupMessageDBError
elif message_type == HC.MESSAGE_TYPE_FILES: c = PopupMessageFiles
elif message_type == HC.MESSAGE_TYPE_GAUGE: c = PopupMessageGauge
window = c( self, message )
window.Update()
return window
@ -2612,28 +2818,24 @@ class PopupMessageManager( wx.Frame ):
def _PrintMessage( self, message ):
message_type = message.GetType()
info = message.GetInfo()
if message_type == HC.MESSAGE_TYPE_TEXT:
message_string = HC.u( info )
if message_type == HC.MESSAGE_TYPE_TEXT: message_string = HC.u( message.GetInfo( 'text' ) )
elif message_type == HC.MESSAGE_TYPE_ERROR:
( etype, value, trace ) = info
( etype, value, trace ) = message.GetInfo( 'error' )
message_string = HC.u( etype.__name__ ) + ': ' + HC.u( value ) + os.linesep + HC.u( trace )
message_string = HC.u( etype.__name__ ) + ': ' + HC.u( value ) + os.linesep + os.linesep + trace
elif message_type == HC.MESSAGE_TYPE_FILES:
elif message_type == HC.MESSAGE_TYPE_DB_ERROR:
( message_string, hashes ) = info
text = message.GetInfo( 'text' )
caller_traceback = message.GetInfo( 'caller_traceback' )
db_traceback = message.GetInfo( 'db_traceback' )
message_string = HC.u( message_string )
elif message_type == HC.MESSAGE_TYPE_GAUGE:
return
message_string = 'DBException: ' + text + os.linesep + os.linesep + caller_traceback + os.linesep + os.linesep + db_traceback
elif message_type == HC.MESSAGE_TYPE_FILES: message_string = HC.u( message.GetInfo( 'text' ) )
elif message_type == HC.MESSAGE_TYPE_GAUGE: return
try: print( message_string )
except: print( repr( message_string ) )
@ -2662,11 +2864,15 @@ class PopupMessageManager( wx.Frame ):
def AddMessage( self, message ):
self._PrintMessage( message )
self._pending_messages.append( message )
self._CheckPending()
try:
self._PrintMessage( message )
self._pending_messages.append( message )
self._CheckPending()
except: print( traceback.format_exc() )
def CleanBeforeDestroy( self ):
@ -2680,7 +2886,7 @@ class PopupMessageManager( wx.Frame ):
self._message_vbox.Detach( window )
window.Destroy()
wx.CallAfter( window.Destroy )
self._SizeAndPositionAndShow()
@ -2710,6 +2916,21 @@ class PopupMessageManager( wx.Frame ):
def MakeSureEverythingFits( self ): self._SizeAndPositionAndShow()
def TIMEREvent( self, event ):
sizer_items = self._message_vbox.GetChildren()
for sizer_item in sizer_items:
message_window = sizer_item.GetWindow()
if message_window.IsClosed(): self.Dismiss( message_window )
else: message_window.Update()
self.MakeSureEverythingFits()
class RegexButton( wx.Button ):
ID_REGEX_WHITESPACE = 0
@ -2796,7 +3017,7 @@ class RegexButton( wx.Button ):
self.PopupMenu( menu )
menu.Destroy()
wx.CallAfter( menu.Destroy )
def EventMenu( self, event ):
@ -3335,9 +3556,9 @@ class AdvancedImportOptions( AdvancedOptions ):
panel = self._panel
self._auto_archive = wx.CheckBox( panel )
self._auto_archive = wx.CheckBox( panel, label = 'archive all imports' )
self._exclude_deleted = wx.CheckBox( panel )
self._exclude_deleted = wx.CheckBox( panel, label = 'exclude already deleted files' )
self._min_size = NoneableSpinCtrl( panel, 'minimum size (KB): ', multiplier = 1024 )
self._min_size.SetValue( 5120 )
@ -3345,20 +3566,10 @@ class AdvancedImportOptions( AdvancedOptions ):
self._min_resolution = NoneableSpinCtrl( panel, 'minimum resolution: ', num_dimensions = 2 )
self._min_resolution.SetValue( ( 50, 50 ) )
hbox1 = wx.BoxSizer( wx.HORIZONTAL )
hbox1.AddF( self._auto_archive, FLAGS_MIXED )
hbox1.AddF( wx.StaticText( panel, label = ' archive all imports' ), FLAGS_MIXED )
hbox2 = wx.BoxSizer( wx.HORIZONTAL )
hbox2.AddF( self._exclude_deleted, FLAGS_MIXED )
hbox2.AddF( wx.StaticText( panel, label = ' exclude already deleted files' ), FLAGS_MIXED )
vbox = wx.BoxSizer( wx.VERTICAL )
vbox.AddF( hbox1, FLAGS_EXPAND_SIZER_PERPENDICULAR )
vbox.AddF( hbox2, FLAGS_EXPAND_SIZER_PERPENDICULAR )
vbox.AddF( self._auto_archive, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._exclude_deleted, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._min_size, FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( self._min_resolution, FLAGS_EXPAND_PERPENDICULAR )
@ -3439,27 +3650,26 @@ class AdvancedTagOptions( AdvancedOptions ):
outer_gridbox.AddF( wx.StaticText( panel, label = service_identifier.GetName() ), FLAGS_MIXED )
gridbox = wx.FlexGridSizer( 0, 2 )
gridbox.AddGrowableCol( 1, 1 )
vbox = wx.BoxSizer( wx.VERTICAL )
for namespace in self._namespaces:
if namespace == '': text = wx.StaticText( panel, label = 'no namespace' )
else: text = wx.StaticText( panel, label = namespace )
if namespace == '': label = 'no namespace'
else: label = namespace
namespace_checkbox = wx.CheckBox( panel, label = label )
namespace_checkbox = wx.CheckBox( panel )
if service_identifier in self._initial_settings and namespace in self._initial_settings[ service_identifier ]: namespace_checkbox.SetValue( True )
else: namespace_checkbox.SetValue( False )
namespace_checkbox.Bind( wx.EVT_CHECKBOX, self.EventChecked )
self._service_identifiers_to_checkbox_info[ service_identifier ].append( ( namespace, namespace_checkbox ) )
gridbox.AddF( text, FLAGS_MIXED )
gridbox.AddF( namespace_checkbox, FLAGS_EXPAND_BOTH_WAYS )
vbox.AddF( namespace_checkbox, FLAGS_EXPAND_BOTH_WAYS )
outer_gridbox.AddF( gridbox, FLAGS_MIXED )
outer_gridbox.AddF( vbox, FLAGS_MIXED )
self._vbox.AddF( outer_gridbox, FLAGS_EXPAND_SIZER_PERPENDICULAR )
@ -3752,7 +3962,7 @@ class TagsBox( ListBox ):
self.PopupMenu( menu )
menu.Destroy()
wx.CallAfter( menu.Destroy )
event.Skip()
@ -4224,6 +4434,8 @@ class TagsBoxManage( TagsBox ):
self._callable = callable
self._show_deleted = False
self._current_tags = set( current_tags )
self._deleted_tags = set( deleted_tags )
self._pending_tags = set( pending_tags )
@ -4263,7 +4475,11 @@ class TagsBoxManage( TagsBox ):
if tag in self._deleted_tags: prefix = HC.ConvertStatusToPrefix( HC.DELETED_PENDING )
else: prefix = HC.ConvertStatusToPrefix( HC.PENDING )
else: prefix = HC.ConvertStatusToPrefix( HC.DELETED )
else:
if self._show_deleted: prefix = HC.ConvertStatusToPrefix( HC.DELETED )
else: continue
tag_string = prefix + tag
@ -4280,6 +4496,13 @@ class TagsBoxManage( TagsBox ):
self._TextsHaveChanged()
def HideDeleted( self ):
self._show_deleted = False
self._RebuildTagStrings()
def PetitionTag( self, tag ):
self._petitioned_tags.add( tag )
@ -4308,6 +4531,42 @@ class TagsBoxManage( TagsBox ):
self._RebuildTagStrings()
def ShowDeleted( self ):
self._show_deleted = True
self._RebuildTagStrings()
class TagsBoxManageWithShowDeleted( StaticBox ):
def __init__( self, parent, callable, current_tags, deleted_tags, pending_tags, petitioned_tags ):
StaticBox.__init__( self, parent, 'tags' )
self._tags_box = TagsBoxManage( self, callable, current_tags, deleted_tags, pending_tags, petitioned_tags )
self._show_deleted = wx.CheckBox( self, label = 'show deleted' )
self._show_deleted.Bind( wx.EVT_CHECKBOX, self.EventShowDeleted )
self.AddF( self._tags_box, FLAGS_EXPAND_BOTH_WAYS )
self.AddF( self._show_deleted, FLAGS_LONE_BUTTON )
def EventShowDeleted( self, event ):
if self._show_deleted.GetValue() == True: self._tags_box.ShowDeleted()
else: self._tags_box.HideDeleted()
def PetitionTag( self, tag ): self._tags_box.PetitionTag( tag )
def PendTag( self, tag ): self._tags_box.PendTag( tag )
def RescindPetition( self, tag ): self._tags_box.RescindPetition( tag )
def RescindPend( self, tag ): self._tags_box.RescindPend( tag )
class TagsBoxNamespaces( TagsBox ):
def _Activate( self, s, term ): self.RemoveNamespace( term )

View File

@ -4637,13 +4637,13 @@ class DialogSelectYoutubeURL( Dialog ):
( url, title ) = self._info[ ( extension, resolution ) ]
job_key = HC.JobKey()
url_string = title + ' ' + resolution + ' ' + extension
message_string = title + ' ' + resolution + ' ' + extension
message = HC.MessageGauge( HC.MESSAGE_TYPE_GAUGE, url_string )
threading.Thread( target = HydrusDownloading.THREADDownloadURL, args = ( job_key, url, message_string ) ).start()
threading.Thread( target = HydrusDownloading.THREADDownloadURL, args = ( message, url, url_string ) ).start()
HC.pubsub.pub( 'message', HC.Message( HC.MESSAGE_TYPE_GAUGE, ( job_key, True ) ) )
HC.pubsub.pub( 'message', message )
@ -4968,12 +4968,6 @@ class DialogSetupCustomFilterActions( Dialog ):
class DialogSetupExport( Dialog ):
ID_HASH = 0
ID_TAGS = 1
ID_NN_TAGS = 2
ID_NAMESPACE = 3
ID_TAG = 4
def __init__( self, parent, flat_media ):
def InitialiseControls():
@ -5003,8 +4997,7 @@ class DialogSetupExport( Dialog ):
self._update = wx.Button( self, label = 'update' )
self._update.Bind( wx.EVT_BUTTON, self.EventRecalcPaths )
self._examples = wx.Button( self, label = 'pattern shortcuts' )
self._examples.Bind( wx.EVT_BUTTON, self.EventPatternShortcuts )
self._examples = ClientGUICommon.ExportPatternButton( self )
self._export = wx.Button( self, label = 'export' )
self._export.Bind( wx.EVT_BUTTON, self.EventExport )
@ -5091,8 +5084,6 @@ class DialogSetupExport( Dialog ):
wx.CallAfter( self.EventSelectPath, None )
wx.CallAfter( self.EventRecalcPaths, None )
self.Bind( wx.EVT_MENU, self.EventMenu )
wx.CallAfter( self._export.SetFocus )
@ -5203,58 +5194,6 @@ class DialogSetupExport( Dialog ):
def EventMenu( self, event ):
id = event.GetId()
phrase = None
if id == self.ID_HASH: phrase = r'{hash}'
if id == self.ID_TAGS: phrase = r'{tags}'
if id == self.ID_NN_TAGS: phrase = r'{nn tags}'
if id == self.ID_NAMESPACE: phrase = r'[...]'
if id == self.ID_TAG: phrase = r'(...)'
else: event.Skip()
if phrase is not None:
if wx.TheClipboard.Open():
data = wx.TextDataObject( phrase )
wx.TheClipboard.SetData( data )
wx.TheClipboard.Close()
else: wx.MessageBox( 'I could not get permission to access the clipboard.' )
def EventPatternShortcuts( self, event ):
menu = wx.Menu()
menu.Append( -1, 'click on a phrase to copy to clipboard' )
menu.AppendSeparator()
menu.Append( self.ID_HASH, r'the file\'s hash - {hash}' )
menu.Append( self.ID_TAGS, r'all the file\'s tags - {tags}' )
menu.Append( self.ID_NN_TAGS, r'all the file\'s non-namespaced tags - {nn tags}' )
menu.AppendSeparator()
menu.Append( self.ID_NAMESPACE, r'all instances of a particular namespace - [...]' )
menu.AppendSeparator()
menu.Append( self.ID_TAG, r'a particular tag, if the file has it - (...)' )
self.PopupMenu( menu )
menu.Destroy()
def EventOpenLocation( self, event ):
directory = self._directory_picker.GetPath()

View File

@ -1615,8 +1615,7 @@ class DialogManageExportFoldersEdit( ClientGUIDialogs.Dialog ):
self._pattern = wx.TextCtrl( self )
self._examples = wx.Button( self, label = 'pattern shortcuts' )
self._examples.Bind( wx.EVT_BUTTON, self.EventPatternShortcuts )
self._examples = ClientGUICommon.ExportPatternButton( self )
self._ok = wx.Button( self, id = wx.ID_OK, label = 'ok' )
self._ok.Bind( wx.EVT_BUTTON, self.EventOK )
@ -1702,33 +1701,6 @@ class DialogManageExportFoldersEdit( ClientGUIDialogs.Dialog ):
def EventMenu( self, event ):
id = event.GetId()
phrase = None
if id == self.ID_HASH: phrase = r'{hash}'
if id == self.ID_TAGS: phrase = r'{tags}'
if id == self.ID_NN_TAGS: phrase = r'{nn tags}'
if id == self.ID_NAMESPACE: phrase = r'[...]'
if id == self.ID_TAG: phrase = r'(...)'
else: event.Skip()
if phrase is not None:
if wx.TheClipboard.Open():
data = wx.TextDataObject( phrase )
wx.TheClipboard.SetData( data )
wx.TheClipboard.Close()
else: wx.MessageBox( 'I could not get permission to access the clipboard.' )
def EventOK( self, event ):
phrase = self._pattern.GetValue()
@ -1744,31 +1716,6 @@ class DialogManageExportFoldersEdit( ClientGUIDialogs.Dialog ):
self.EndModal( wx.ID_OK )
def EventPatternShortcuts( self, event ):
menu = wx.Menu()
menu.Append( -1, 'click on a phrase to copy to clipboard' )
menu.AppendSeparator()
menu.Append( self.ID_HASH, r'the file\'s hash - {hash}' )
menu.Append( self.ID_TAGS, r'all the file\'s tags - {tags}' )
menu.Append( self.ID_NN_TAGS, r'all the file\'s non-namespaced tags - {nn tags}' )
menu.AppendSeparator()
menu.Append( self.ID_NAMESPACE, r'all instances of a particular namespace - [...]' )
menu.AppendSeparator()
menu.Append( self.ID_TAG, r'a particular tag, if the file has it - (...)' )
self.PopupMenu( menu )
menu.Destroy()
def GetInfo( self ):
path = self._path.GetPath()
@ -4591,7 +4538,7 @@ class DialogManageServer( ClientGUIDialogs.Dialog ):
if 'port' in self._options: self._port = wx.SpinCtrl( self._options_panel, min = 1, max = 65535 )
if 'max_monthly_data' in self._options: self._max_monthly_data = ClientGUICommon.NoneableSpinCtrl( self._options_panel, 'max monthly data (MB)', multiplier = 1048576 )
if 'max_storage' in self._options: self._max_storage = ClientGUICommon.NoneableSpinCtrl( self._options_panel, 'max storage (MB)', multiplier = 1048576 )
if 'log_uploader_ips' in self._options: self._log_uploader_ips = wx.CheckBox( self._options_panel, label = '' )
if 'log_uploader_ips' in self._options: self._log_uploader_ips = wx.CheckBox( self._options_panel )
if 'message' in self._options: self._message = wx.TextCtrl( self._options_panel )
if 'upnp' in self._options: self._upnp = ClientGUICommon.NoneableSpinCtrl( self._options_panel, 'external port', none_phrase = 'do not forward port', max = 65535 )
@ -7165,7 +7112,7 @@ class DialogManageTags( ClientGUIDialogs.Dialog ):
def InitialiseControls():
self._tags_box = ClientGUICommon.TagsBoxManage( self, self.AddTag, self._current_tags, self._deleted_tags, self._pending_tags, self._petitioned_tags )
self._tags_box = ClientGUICommon.TagsBoxManageWithShowDeleted( 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 )

View File

@ -158,7 +158,7 @@ class CaptchaControl( wx.Panel ):
dc.DrawBitmap( hydrus_bmp, 0, 0 )
hydrus_bmp.Destroy()
wx.CallAfter( hydrus_bmp.Destroy )
self._refresh_button.SetLabel( 'get new captcha' )
self._refresh_button.Enable()

View File

@ -1417,7 +1417,7 @@ class MediaPanelThumbnails( MediaPanel ):
else: self._RedrawCanvas()
old_canvas_bmp.Destroy()
wx.CallAfter( old_canvas_bmp.Destroy )
self._CleanCanvas()
@ -1975,7 +1975,7 @@ class MediaPanelThumbnails( MediaPanel ):
if menu.GetMenuItemCount() > 0: self.PopupMenu( menu )
menu.Destroy()
wx.CallAfter( menu.Destroy )
event.Skip()
@ -2307,7 +2307,7 @@ class Thumbnail( Selectable ):
dc.DrawBitmap( hydrus_bmp, x_offset, y_offset )
hydrus_bmp.Destroy()
wx.CallAfter( hydrus_bmp.Destroy )
collections_string = ''

View File

@ -288,7 +288,7 @@ class ConversationsListCtrl( wx.ListCtrl, ListCtrlAutoWidthMixin, ColumnSorterMi
self.PopupMenu( menu )
menu.Destroy()
wx.CallAfter( menu.Destroy )
def GetListCtrl( self ): return self
@ -433,7 +433,7 @@ class ConversationPanel( wx.Panel ):
self._drafts_vbox.Detach( draft_panel )
draft_panel.Close()
wx.CallAfter( draft_panel.Destroy )
self._scrolling_messages_window.FitInside()
@ -659,7 +659,7 @@ class DestinationPanel( wx.Panel ):
self.PopupMenu( menu )
menu.Destroy()
wx.CallAfter( menu.Destroy )
def EventRetryMenu( self, event ):
@ -670,7 +670,7 @@ class DestinationPanel( wx.Panel ):
self.PopupMenu( menu )
menu.Destroy()
wx.CallAfter( menu.Destroy )
def EventUnreadMenu( self, event ):
@ -681,7 +681,7 @@ class DestinationPanel( wx.Panel ):
self.PopupMenu( menu )
menu.Destroy()
wx.CallAfter( menu.Destroy )
def SetStatus( self, status ):

View File

@ -137,27 +137,36 @@ class PageLog( PageBase, wx.Panel ):
if timestamp is None: timestamp = HC.GetNow()
message_type = message.GetType()
info = message.GetInfo()
if message_type == HC.MESSAGE_TYPE_TEXT:
message_type_string = 'message'
message_string = info
message_string = message.GetInfo( 'text' )
elif message_type == HC.MESSAGE_TYPE_ERROR:
message_type_string = 'error'
exception = info
( etype, value, trace ) = message.GetInfo( 'error' )
message_string = HC.u( exception )
message_string = HC.u( etype.__name__ ) + ': ' + HC.u( value ) + os.linesep + HC.u( trace )
elif message_type == HC.MESSAGE_TYPE_DB_ERROR:
message_type_string = 'db error'
text = message.GetInfo( 'text' )
caller_traceback = message.GetInfo( 'caller_traceback' )
db_traceback = message.GetInfo( 'db_traceback' )
message_string = text + os.linesep + caller_traceback + os.linesep + db_traceback
elif message_type == HC.MESSAGE_TYPE_FILES:
message_type_string = 'files'
( message_string, hashes ) = info
message_string = message.GetInfo( 'text' )
else: return # gauge
@ -305,7 +314,7 @@ class PageWithMedia( PageBase, wx.SplitterWindow ):
self.ReplaceWindow( self._media_panel, new_panel )
self._media_panel.Destroy()
wx.CallAfter( self._media_panel.Destroy )
self._media_panel = new_panel

View File

@ -47,7 +47,7 @@ TEMP_DIR = BASE_DIR + os.path.sep + 'temp'
# Misc
NETWORK_VERSION = 13
SOFTWARE_VERSION = 104
SOFTWARE_VERSION = 105
UNSCALED_THUMBNAIL_DIMENSIONS = ( 200, 200 )
@ -115,6 +115,7 @@ MESSAGE_TYPE_TEXT = 0
MESSAGE_TYPE_ERROR = 1
MESSAGE_TYPE_FILES = 2
MESSAGE_TYPE_GAUGE = 3
MESSAGE_TYPE_DB_ERROR = 4
GET_DATA = 0
POST_DATA = 1
@ -1765,19 +1766,19 @@ class JobDatabase():
elif shutdown: raise Exception( 'Application quit before db could serve result!' )
if issubclass( type( self._result ), Exception ):
if isinstance( self._result, Exception ):
etype = type( self._result )
db_traceback = unicode( self._result )
trace_list = traceback.format_stack()
my_trace = 'Stack Trace (most recent call last):' + os.linesep + os.linesep + os.linesep.join( trace_list )
full_message = os.linesep.join( ( 'GUI Thread:', my_trace, 'DB Thread:', db_traceback ) )
raise HydrusExceptions.DBException( full_message )
if isinstance( self._result, HydrusExceptions.DBException ):
( gumpf, db_traceback ) = self._result.GetTracebacks()
trace_list = traceback.format_stack()
caller_traceback = 'Stack Trace (most recent call last):' + os.linesep + os.linesep + os.linesep.join( trace_list )
raise HydrusExceptions.DBException( u( self._result ), caller_traceback, db_traceback )
else: raise self._result
else: return self._result
@ -1931,11 +1932,44 @@ class Message():
self._message_type = message_type
self._info = info
self._closed = False
self._lock = threading.Lock()
def GetInfo( self ): return self._info
def Close( self ): self._closed = True
def GetInfo( self, name ):
with self._lock: return self._info[ name ]
def GetType( self ): return self._message_type
def HasInfo( self, name ):
with self._lock: return name in self._info
def IsClosed( self ): return self._closed
def SetInfo( self, name, value ):
with self._lock: self._info[ name ] = value
class MessageGauge( Message ):
def __init__( self, message_type, text ):
info = {}
info[ 'mode' ] = 'text'
info[ 'text' ] = text
Message.__init__( self, message_type, info )
class Predicate( HydrusYAMLBase ):
yaml_tag = u'!Predicate'

View File

@ -1025,7 +1025,7 @@ class ImportArgsGenerator():
if result == 'new':
( temp_path, service_identifiers_to_tags, url ) = self._GetArgs()
( name, temp_path, service_identifiers_to_tags, url ) = self._GetArgs()
self._job_key.SetVariable( 'status', 'importing' )
@ -1055,6 +1055,7 @@ class ImportArgsGenerator():
self._job_key.SetVariable( 'result', 'failed' )
HC.ShowText( 'Problem importing ' + name + '!' )
HC.ShowException( e )
time.sleep( 2 )
@ -1109,7 +1110,7 @@ class ImportArgsGeneratorGallery( ImportArgsGenerator ):
service_identifiers_to_tags = ConvertTagsToServiceIdentifiersToTags( tags, self._advanced_tag_options )
return ( temp_path, service_identifiers_to_tags, url )
return ( url, temp_path, service_identifiers_to_tags, url )
def _CheckCurrentStatus( self ):
@ -1206,7 +1207,7 @@ class ImportArgsGeneratorHDD( ImportArgsGenerator ):
if pretty_path in self._paths_to_tags: service_identifiers_to_tags = self._paths_to_tags[ pretty_path ]
return ( path, service_identifiers_to_tags, None )
return ( path, path, service_identifiers_to_tags, None )
class ImportArgsGeneratorThread( ImportArgsGenerator ):
@ -1241,7 +1242,7 @@ class ImportArgsGeneratorThread( ImportArgsGenerator ):
service_identifiers_to_tags = ConvertTagsToServiceIdentifiersToTags( tags, self._advanced_tag_options )
return ( temp_path, service_identifiers_to_tags, url )
return ( url, temp_path, service_identifiers_to_tags, url )
def _CheckCurrentStatus( self ):
@ -1281,7 +1282,7 @@ class ImportArgsGeneratorURLs( ImportArgsGenerator ):
service_identifiers_to_tags = {}
return ( temp_path, service_identifiers_to_tags, url )
return ( url, temp_path, service_identifiers_to_tags, url )
def _CheckCurrentStatus( self ):
@ -1747,30 +1748,46 @@ class ImportController():
threading.Thread( target = self.MainLoop ).start()
def THREADDownloadURL( job_key, url, message_string ):
def THREADDownloadURL( message, url, url_string ):
try:
def hook( range, value ):
if range is None: message = message_string + ' - ' + HC.ConvertIntToBytes( value )
else: message = message_string + ' - ' + HC.ConvertIntToBytes( value ) + '/' + HC.ConvertIntToBytes( range )
if range is None: text = url_string + ' - ' + HC.ConvertIntToBytes( value )
else: text = url_string + ' - ' + HC.ConvertIntToBytes( value ) + '/' + HC.ConvertIntToBytes( range )
wx.CallAfter( HC.pubsub.pub, 'message_gauge_info', job_key, range, value, message )
message.SetInfo( 'range', range )
message.SetInfo( 'value', value )
message.SetInfo( 'text', text )
message.SetInfo( 'range', None )
message.SetInfo( 'value', None )
message.SetInfo( 'mode', 'gauge' )
temp_path = HC.http.Request( HC.GET, url, response_to_path = True, report_hooks = [ hook ] )
HC.pubsub.pub( 'message_gauge_info', job_key, None, None, 'importing ' + message_string )
message.SetInfo( 'range', None )
message.SetInfo( 'value', None )
message.SetInfo( 'text', 'importing ' + url_string )
message.SetInfo( 'mode', 'gauge' )
( result, hash ) = HC.app.WriteSynchronous( 'import_file', temp_path )
if result in ( 'successful', 'redundant' ): HC.pubsub.pub( 'message_gauge_show_file_button', job_key, message_string, { hash } )
elif result == 'deleted': HC.pubsub.pub( 'message_gauge_info', job_key, None, None, 'File was already deleted!' )
if result in ( 'successful', 'redundant' ):
message.SetInfo( 'hashes', { hash } )
message.SetInfo( 'mode', 'files' )
elif result == 'deleted':
message.SetInfo( 'text', 'File was already deleted!' )
message.SetInfo( 'mode', 'text' )
except Exception as e:
HC.pubsub.pub( 'message_gauge_info', job_key, None, None, 'Error with ' + message_string + '!' )
message.Close()
HC.ShowException( e )

View File

@ -1,13 +1,25 @@
class DBException( Exception ): pass
class DBException( Exception ):
def __init__( self, text, caller_traceback, db_traceback ):
Exception.__init__( self, text )
self._caller_traceback = caller_traceback
self._db_traceback = db_traceback
def GetTracebacks( self ): return ( self._caller_traceback, self._db_traceback )
class DBAccessException( Exception ): pass
class FileException( Exception ): pass
class ForbiddenException( Exception ): pass
class MimeException( Exception ): pass
class SizeException( Exception ): pass
class NetworkVersionException( Exception ): pass
class NoContentException( Exception ): pass
class NotFoundException( Exception ): pass
class NotModifiedException( Exception ): pass
class ForbiddenException( Exception ): pass
class PermissionException( Exception ): pass
class SessionException( Exception ): pass
class ShutdownException( Exception ): pass
class SizeException( Exception ): pass
class WrongServiceTypeException( Exception ): pass

View File

@ -41,8 +41,7 @@ def GetFileInfo( path, hash ):
if mime in HC.IMAGES:
try: image_container = HydrusImageHandling.RenderImage( path, hash )
except: raise HydrusExceptions.ForbiddenException( 'Could not load that file as an image.' )
image_container = HydrusImageHandling.RenderImage( path, hash )
( width, height ) = image_container.GetSize()

View File

@ -34,7 +34,7 @@ class Controller( wx.App ):
def _Write( self, action, priority, *args, **kwargs ): return self._db.Write( action, priority, *args, **kwargs )
def EventExit( self, event ): self._tbicon.Destroy()
def EventExit( self, event ): wx.CallAfter( self._tbicon.Destroy )
def EventPubSub( self, event ): HC.pubsub.WXProcessQueueItem()