Version 160

This commit is contained in:
Hydrus 2015-06-10 14:40:25 -05:00
parent 527d9e532f
commit 54238debc3
19 changed files with 629 additions and 163 deletions

View File

@ -8,6 +8,28 @@
<div class="content">
<h3>changelog</h3>
<ul>
<li><h3>version 160</h3></li>
<ul>
<li>added options for http, socks4, socks5 proxying</li>
<li>improved some network-related errors</li>
<li>ratings services can have custom border and fill colours for their various states</li>
<li>ratings services can now also be squares or stars instead of circles</li>
<li>numerical ratings services can disallow zero ratings</li>
<li>fixed the JSON parsing error that broke the thread checker</li>
<li>shrank the width of the thread checker to make it a little less ugly</li>
<li>the autocomplete tag search dropdowns will now accept and search with quickly entered text</li>
<li>this new system will substitute siblings in the manage tags dialog</li>
<li>fixed rows/s average calculation</li>
<li>rows/s is more accurate</li>
<li>content update popup string update is less laggy</li>
<li>content update popup now shows content rows, rather than content parts</li>
<li>removed update 'taking a break' component, as it was not doing the job I wanted it to</li>
<li>db debug profile mode can now be turned off lol</li>
<li>fixed an error from middle-clicking greyspace in the linux notebook tab area</li>
<li>general code cleanup</li>
<li>some string conversion code cleanup</li>
<li>fixed a missing canvas bmp error with flash/flv embed buttons</li>
</ul>
<li><h3>version 159</h3></li>
<ul>
<li>split previously monolithic repository updates into smaller pieces</li>

View File

@ -241,6 +241,13 @@ class Controller( HydrusController.HydrusController ):
self._caches[ 'preview' ] = ClientCaches.RenderedImageCache( 'preview' )
self._caches[ 'thumbnail' ] = ClientCaches.ThumbnailCache()
if HC.options[ 'proxy' ] is not None:
( proxytype, host, port, username, password ) = HC.options[ 'proxy' ]
HydrusNetworking.SetProxy( proxytype, host, port, username, password )
CC.GlobalBMPs.STATICInitialise()
self._gui = ClientGUI.FrameGUI()
@ -351,11 +358,9 @@ class Controller( HydrusController.HydrusController ):
try:
connection = httplib.HTTPConnection( '127.0.0.1', port, timeout = 10 )
try:
connection.connect()
connection = HydrusNetworking.GetLocalConnection( port )
connection.close()
text = 'The client\'s booru server could not start because something was already bound to port ' + HydrusData.ToString( port ) + '.'
@ -370,16 +375,16 @@ class Controller( HydrusController.HydrusController ):
self._booru_service = reactor.listenTCP( port, HydrusServer.HydrusServiceBooru( CC.LOCAL_BOORU_SERVICE_KEY, HC.LOCAL_BOORU, 'This is the local booru.' ) )
connection = httplib.HTTPConnection( '127.0.0.1', port, timeout = 10 )
try:
connection.connect()
connection = HydrusNetworking.GetLocalConnection( port )
connection.close()
except:
except Exception as e:
text = 'Tried to bind port ' + HydrusData.ToString( port ) + ' for the local booru, but it failed.'
text = 'Tried to bind port ' + HydrusData.ToString( port ) + ' for the local booru, but it failed:'
text += os.linesep * 2
text += HydrusData.ToString( e )
wx.CallLater( 1, HydrusData.ShowText, text )
@ -413,11 +418,9 @@ class Controller( HydrusController.HydrusController ):
try:
connection = httplib.HTTPConnection( '127.0.0.1', port, timeout = 10 )
try:
connection.connect()
connection = HydrusNetworking.GetLocalConnection( port )
connection.close()
text = 'The client\'s local server could not start because something was already bound to port ' + HydrusData.ToString( port ) + '.'
@ -432,16 +435,16 @@ class Controller( HydrusController.HydrusController ):
self._local_service = reactor.listenTCP( port, HydrusServer.HydrusServiceLocal( CC.LOCAL_FILE_SERVICE_KEY, HC.LOCAL_FILE, 'This is the local file service.' ) )
connection = httplib.HTTPConnection( '127.0.0.1', port, timeout = 10 )
try:
connection.connect()
connection = HydrusNetworking.GetLocalConnection( port )
connection.close()
except:
except Exception as e:
text = 'Tried to bind port ' + HydrusData.ToString( port ) + ' for the local server, but it failed.'
text = 'Tried to bind port ' + HydrusData.ToString( port ) + ' for the local server, but it failed:'
text += os.linesep * 2
text += HydrusData.ToString( e )
wx.CallLater( 1, HydrusData.ShowText, text )

View File

@ -1222,7 +1222,7 @@ class DB( HydrusDB.HydrusDB ):
if HydrusGlobals.shutdown: return
job_key.SetVariable( 'popup_message_text_1', prefix_string + HydrusData.ConvertIntToPrettyString( i ) + '/' + HydrusData.ConvertIntToPrettyString( len( info ) ) )
job_key.SetVariable( 'popup_message_text_1', prefix_string + HydrusData.ConvertValueRangeToPrettyString( i, len( info ) ) )
job_key.SetVariable( 'popup_message_gauge_1', ( i, len( info ) ) )
hash = self._GetHash( hash_id )
@ -1772,7 +1772,7 @@ class DB( HydrusDB.HydrusDB ):
if i % 100 == 0:
job_key.SetVariable( 'popup_message_text_1', prefix_string + HydrusData.ConvertIntToPrettyString( i ) + '/' + HydrusData.ConvertIntToPrettyString( len( hash_ids ) ) )
job_key.SetVariable( 'popup_message_text_1', prefix_string + HydrusData.ConvertValueRangeToPrettyString( i, len( hash_ids ) ) )
job_key.SetVariable( 'popup_message_gauge_1', ( i, len( hash_ids ) ) )
@ -4832,7 +4832,7 @@ class DB( HydrusDB.HydrusDB ):
if i % 100 == 0:
job_key.SetVariable( 'popup_message_text_1', prefix_string + HydrusData.ConvertIntToPrettyString( i ) + '/' + HydrusData.ConvertIntToPrettyString( len( hash_ids ) ) )
job_key.SetVariable( 'popup_message_text_1', prefix_string + HydrusData.ConvertValueRangeToPrettyString( i, len( hash_ids ) ) )
job_key.SetVariable( 'popup_message_gauge_1', ( i, len( hash_ids ) ) )
@ -4862,15 +4862,6 @@ class DB( HydrusDB.HydrusDB ):
HydrusGlobals.pubsub.pub( 'splash_set_text', 'updating db to v' + HydrusData.ToString( version + 1 ) )
if version == 109:
self._c.execute( 'DELETE FROM yaml_dumps WHERE dump_type = ?;', ( YAML_DUMP_ID_GUI_SESSION, ) )
self._c.execute( 'DROP TABLE processed_mappings;' )
self._c.execute( 'DROP INDEX mappings_status_index;' )
if version == 110:
all_services = self._c.execute( 'SELECT service_id, service_type, info FROM services;' ).fetchall()
@ -5388,6 +5379,18 @@ class DB( HydrusDB.HydrusDB ):
if version == 159:
results = self._c.execute( 'SELECT service_id, service_type, info FROM services WHERE service_type = ?;', ( HC.LOCAL_RATING_NUMERICAL, ) ).fetchall()
for ( service_id, service_type, info ) in results:
info[ 'allow_zero' ] = True
self._c.execute( 'UPDATE services SET info = ? WHERE service_id = ?;', ( info, service_id ) )
self._c.execute( 'UPDATE version SET version = ?;', ( version + 1, ) )
HydrusGlobals.is_db_updated = True

View File

@ -533,7 +533,7 @@ def DAEMONSynchroniseRepositories():
gauge_range = ( ( now - first_timestamp ) / HC.UPDATE_DURATION ) + 1
gauge_value = ( ( next_download_timestamp - first_timestamp ) / HC.UPDATE_DURATION ) + 1
update_index_string = 'update ' + HydrusData.ConvertIntToPrettyString( gauge_value ) + '/' + HydrusData.ConvertIntToPrettyString( gauge_range ) + ': '
update_index_string = 'update ' + HydrusData.ConvertValueRangeToPrettyString( gauge_value, gauge_range ) + ': '
subupdate_index_string = 'service update: '
@ -553,7 +553,7 @@ def DAEMONSynchroniseRepositories():
if not os.path.exists( path ):
subupdate_index_string = 'content update ' + HydrusData.ConvertIntToPrettyString( subindex + 1 ) + '/' + HydrusData.ConvertIntToPrettyString( subindex_count ) + ': '
subupdate_index_string = 'content update ' + HydrusData.ConvertValueRangeToPrettyString( subindex + 1, subindex_count ) + ': '
job_key.SetVariable( 'popup_message_text_1', update_index_string + subupdate_index_string + 'downloading and parsing' )
@ -647,7 +647,7 @@ def DAEMONSynchroniseRepositories():
if next_processing_timestamp == 0: gauge_value = 0
else: gauge_value = ( ( next_processing_timestamp - first_timestamp ) / HC.UPDATE_DURATION ) + 1
update_index_string = 'update ' + HydrusData.ConvertIntToPrettyString( gauge_value ) + '/' + HydrusData.ConvertIntToPrettyString( gauge_range ) + ': '
update_index_string = 'update ' + HydrusData.ConvertValueRangeToPrettyString( gauge_value, gauge_range ) + ': '
subupdate_index_string = 'service update: '
@ -664,7 +664,7 @@ def DAEMONSynchroniseRepositories():
for subindex in range( subindex_count ):
subupdate_index_string = 'content update ' + HydrusData.ConvertIntToPrettyString( subindex + 1 ) + '/' + HydrusData.ConvertIntToPrettyString( subindex_count ) + ': '
subupdate_index_string = 'content update ' + HydrusData.ConvertValueRangeToPrettyString( subindex + 1, subindex_count ) + ': '
path = ClientFiles.GetExpectedContentUpdatePackagePath( service_key, next_processing_timestamp, subindex )
@ -678,9 +678,11 @@ def DAEMONSynchroniseRepositories():
job_key.SetVariable( 'popup_message_text_1', update_index_string + subupdate_index_string + 'processing' )
num_content_updates = content_update_package.GetNumContentUpdates()
content_updates = []
current_weight = 0
num_rows = content_update_package.GetNumRows()
total_weight_processed = 0
wait_begin_precise = HydrusData.GetNowPrecise()
for ( i, content_update ) in enumerate( content_update_package.IterateContentUpdates() ):
@ -719,46 +721,44 @@ def DAEMONSynchroniseRepositories():
content_update_index_string = 'content part ' + HydrusData.ConvertIntToPrettyString( i ) + '/' + HydrusData.ConvertIntToPrettyString( num_content_updates ) + ': '
job_key.SetVariable( 'popup_message_gauge_2', ( i, num_content_updates ) )
content_updates.append( content_update )
current_weight += len( content_update.GetHashes() )
content_update_weight = len( content_update.GetHashes() )
current_weight += content_update_weight
total_weight_processed += content_update_weight
content_update_index_string = 'content row ' + HydrusData.ConvertValueRangeToPrettyString( total_weight_processed, num_rows ) + ': '
job_key.SetVariable( 'popup_message_text_2', content_update_index_string + 'committing' + update_speed_string )
job_key.SetVariable( 'popup_message_gauge_2', ( total_weight_processed, num_rows ) )
if current_weight > WEIGHT_THRESHOLD:
job_key.SetVariable( 'popup_message_text_2', content_update_index_string + 'committing' + update_speed_string )
wx.GetApp().WaitUntilWXThreadIdle()
wait_end_precise = HydrusData.GetNowPrecise()
waiting_took = wait_end_precise - wait_begin_precise
before_precise = HydrusData.GetNowPrecise()
wx.GetApp().WriteSynchronous( 'content_updates', { service_key : content_updates } )
after_precise = HydrusData.GetNowPrecise()
wait_begin_precise = HydrusData.GetNowPrecise()
if wx.GetApp().CurrentlyIdle(): ideal_packet_time = 10.0
else: ideal_packet_time = 0.5
it_took = after_precise - before_precise
db_took = after_precise - before_precise
too_long = ideal_packet_time * 1.5
too_short = ideal_packet_time * 0.8
really_too_long = ideal_packet_time * 10
if it_took > too_long: WEIGHT_THRESHOLD /= 1.5
elif it_took < too_short: WEIGHT_THRESHOLD *= 1.05
if it_took > really_too_long or WEIGHT_THRESHOLD < 1.0:
job_key.SetVariable( 'popup_message_text_2', 'taking a break' )
time.sleep( 10 )
WEIGHT_THRESHOLD = 1.0
if db_took > too_long: WEIGHT_THRESHOLD = max( 10.0, WEIGHT_THRESHOLD / 1.5 )
elif db_took < too_short: WEIGHT_THRESHOLD *= 1.05
total_content_weight_processed += current_weight
@ -766,18 +766,18 @@ def DAEMONSynchroniseRepositories():
if len( update_time_tracker ) > 10:
update_time_tracker.pop()
update_time_tracker.pop( 0 )
update_time_tracker.append( ( current_weight, it_took ) )
update_time_tracker.append( ( current_weight, db_took + waiting_took ) )
recent_total_weight = 0
recent_total_time = 0.0
for ( weight, took ) in update_time_tracker:
for ( weight, it_took ) in update_time_tracker:
recent_total_weight += weight
recent_total_time += took
recent_total_time += it_took
recent_speed = int( recent_total_weight / recent_total_time )
@ -793,7 +793,7 @@ def DAEMONSynchroniseRepositories():
if len( content_updates ) > 0:
content_update_index_string = 'content part ' + HydrusData.ConvertIntToPrettyString( num_content_updates ) + '/' + HydrusData.ConvertIntToPrettyString( num_content_updates ) + ': '
content_update_index_string = 'content row ' + HydrusData.ConvertValueRangeToPrettyString( num_rows, num_rows ) + ': '
job_key.SetVariable( 'popup_message_text_2', content_update_index_string + 'committing' + update_speed_string )
@ -893,7 +893,7 @@ def DAEMONSynchroniseRepositories():
for ( i, hash ) in enumerate( thumbnail_hashes_i_need ):
job_key.SetVariable( 'popup_message_text_1', 'downloading thumbnail ' + HydrusData.ConvertIntToPrettyString( i ) + '/' + HydrusData.ConvertIntToPrettyString( len( thumbnail_hashes_i_need ) ) )
job_key.SetVariable( 'popup_message_text_1', 'downloading thumbnail ' + HydrusData.ConvertValueRangeToPrettyString( i, len( thumbnail_hashes_i_need ) ) )
job_key.SetVariable( 'popup_message_gauge_1', ( i, len( thumbnail_hashes_i_need ) ) )
request_args = { 'hash' : hash.encode( 'hex' ) }
@ -1188,7 +1188,7 @@ def DAEMONSynchroniseSubscriptions():
url_cache.add( url )
x_out_of_y = 'file ' + HydrusData.ConvertIntToPrettyString( i ) + '/' + HydrusData.ConvertIntToPrettyString( len( all_urls ) ) + ': '
x_out_of_y = 'file ' + HydrusData.ConvertValueRangeToPrettyString( i, len( all_urls ) ) + ': '
job_key.SetVariable( 'popup_message_text_1', x_out_of_y + 'checking url status' )
job_key.SetVariable( 'popup_message_gauge_1', ( i, len( all_urls ) ) )

View File

@ -1160,7 +1160,7 @@ class Service( HydrusData.HydrusYAMLBase ):
num_updates_processed = ( next_processing_timestamp - first_timestamp ) / HC.UPDATE_DURATION
downloaded_text = HydrusData.ConvertIntToPrettyString( num_updates_downloaded ) + '/' + HydrusData.ConvertIntToPrettyString( num_updates )
downloaded_text = HydrusData.ConvertValueRangeToPrettyString( num_updates_downloaded, num_updates )
if not self._info[ 'account' ].HasPermission( HC.GET_DATA ): status = 'updates on hold'
else:

View File

@ -136,6 +136,8 @@ def GetClientDefaultOptions():
shortcuts[ wx.ACCEL_SHIFT ][ wx.WXK_LEFT ] = 'pan_left'
shortcuts[ wx.ACCEL_SHIFT ][ wx.WXK_RIGHT ] = 'pan_right'
options[ 'proxy' ] = None
options[ 'shortcuts' ] = shortcuts
options[ 'confirm_client_exit' ] = False

View File

@ -1646,7 +1646,7 @@ class ImportController( object ):
self._import_queue_job_key.SetVariable( 'queue_position', queue_position )
position_string = HydrusData.ToString( queue_position + 1 ) + '/' + HydrusData.ToString( len( queue ) )
position_string = HydrusData.ConvertValueRangeToPrettyString( queue_position + 1, len( queue ) )
if self._import_queue_job_key.IsPaused(): self._import_queue_job_key.SetVariable( 'status', 'paused at ' + position_string )
elif self._import_queue_job_key.IsWorking():
@ -2043,7 +2043,7 @@ def THREADDownloadURL( job_key, url, url_string ):
def hook( gauge_range, gauge_value ):
if gauge_range is None: text = url_string + ' - ' + HydrusData.ConvertIntToBytes( gauge_value )
else: text = url_string + ' - ' + HydrusData.ConvertIntToBytes( gauge_value ) + '/' + HydrusData.ConvertIntToBytes( gauge_range )
else: text = url_string + ' - ' + HydrusData.ConvertValueRangeToPrettyString( gauge_value, gauge_range )
job_key.SetVariable( 'popup_message_text_1', text )
job_key.SetVariable( 'popup_message_gauge_1', ( gauge_value, gauge_range ) )

View File

@ -9,10 +9,14 @@ import ClientGUIDialogs
import ClientGUIDialogsManage
import ClientGUIPages
import ClientDownloading
import ClientSearch
import HydrusData
import HydrusExceptions
import HydrusFileHandling
import HydrusGlobals
import HydrusImageHandling
import HydrusNATPunch
import HydrusNetworking
import HydrusThreading
import itertools
import os
@ -26,10 +30,6 @@ import traceback
import webbrowser
import wx
import yaml
import HydrusData
import ClientSearch
import HydrusNetworking
import HydrusGlobals
# timers
@ -212,10 +212,7 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
try:
connection = httplib.HTTPConnection( '127.0.0.1', HC.DEFAULT_SERVER_ADMIN_PORT, timeout = 20 )
connection.connect()
connection = HydrusNetworking.GetLocalConnection( port )
connection.close()
already_running = True
@ -262,9 +259,7 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
try:
connection = httplib.HTTPConnection( '127.0.0.1', HC.DEFAULT_SERVER_ADMIN_PORT, timeout = 20 )
connection.connect()
connection = HydrusNetworking.GetLocalConnection( port )
connection.close()
@ -743,7 +738,7 @@ class FrameGUI( ClientGUICommon.FrameThatResizes ):
submenu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'upload_pending', service_key ), p( '&Upload' ), p( 'Upload ' + name + '\'s Pending and Petitions.' ) )
submenu.Append( ClientCaches.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'delete_pending', service_key ), p( '&Forget' ), p( 'Clear ' + name + '\'s Pending and Petitions.' ) )
menu.AppendMenu( CC.ID_NULL, p( name + ' Pending (' + HydrusData.ConvertIntToPrettyString( num_pending ) + '/' + HydrusData.ConvertIntToPrettyString( num_petitioned ) + ')' ), submenu )
menu.AppendMenu( CC.ID_NULL, p( name + ' Pending (' + HydrusData.ConvertValueRangeToPrettyString( num_pending, num_petitioned ) + ')' ), submenu )
total_num_pending += num_pending + num_petitioned
@ -1710,7 +1705,7 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
if HydrusGlobals.shutdown: return
job_key.SetVariable( 'popup_message_text_1', prefix + 'posting update: ' + HydrusData.ConvertIntToPrettyString( i + 1 ) + '/' + HydrusData.ConvertIntToPrettyString( len( updates ) ) )
job_key.SetVariable( 'popup_message_text_1', prefix + 'posting update: ' + HydrusData.ConvertValueRangeToPrettyString( i + 1, len( updates ) ) )
job_key.SetVariable( 'popup_message_gauge_1', ( i, len( updates ) ) )
service.Request( HC.POST, 'content_update_package', { 'update' : update } )
@ -1832,7 +1827,7 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
elif command == 'close_page': self._CloseCurrentPage()
elif command == 'db_profile_mode':
HydrusGlobals.db_profile_mode = True
HydrusGlobals.db_profile_mode = not HydrusGlobals.db_profile_mode
elif command == 'debug_garbage':
@ -1974,7 +1969,10 @@ The password is cleartext here but obscured in the entry dialog. Enter a blank p
( tab_index, flags ) = self._notebook.HitTest( ( event.GetX(), event.GetY() ) )
self._ClosePage( tab_index )
if tab_index != -1:
self._ClosePage( tab_index )
def EventNotebookPageChanged( self, event ):
@ -2618,7 +2616,7 @@ class FrameReviewServices( ClientGUICommon.Frame ):
self._bytes.SetRange( max_monthly_data )
self._bytes.SetValue( used_monthly_data )
self._bytes_text.SetLabel( 'used ' + HydrusData.ConvertIntToBytes( used_monthly_data ) + '/' + HydrusData.ConvertIntToBytes( max_monthly_data ) + monthly_requests_text + ' this month' )
self._bytes_text.SetLabel( 'used ' + HydrusData.ConvertValueRangeToPrettyString( used_monthly_data, max_monthly_data ) + monthly_requests_text + ' this month' )
@ -2714,7 +2712,7 @@ class FrameReviewServices( ClientGUICommon.Frame ):
self._thumbnails.SetRange( self._num_thumbs )
self._thumbnails.SetValue( min( self._num_local_thumbs, self._num_thumbs ) )
self._thumbnails_text.SetLabel( HydrusData.ConvertIntToPrettyString( self._num_local_thumbs ) + '/' + HydrusData.ConvertIntToPrettyString( self._num_thumbs ) + ' thumbnails downloaded' )
self._thumbnails_text.SetLabel( HydrusData.ConvertValueRangeToPrettyString( self._num_local_thumbs, self._num_thumbs ) + ' thumbnails downloaded' )
def _DisplayService( self ):

View File

@ -378,7 +378,7 @@ class AnimationBar( wx.Window ):
dc.SetTextForeground( wx.BLACK )
s = HydrusData.ConvertIntToPrettyString( self._current_frame_index + 1 ) + '/' + HydrusData.ConvertIntToPrettyString( self._num_frames )
s = HydrusData.ConvertValueRangeToPrettyString( self._current_frame_index + 1, self._num_frames )
( x, y ) = dc.GetTextExtent( s )
@ -1050,9 +1050,7 @@ class CanvasWithDetails( Canvas ):
rating_state = ClientRatings.GetLikeStateFromMedia( ( self._current_display_media, ), service_key )
( pen_colour, brush_colour ) = ClientRatings.GetPenAndBrushColours( service_key, rating_state )
ClientRatings.DrawLike( dc, like_rating_current_x, current_y, pen_colour, brush_colour )
ClientRatings.DrawLike( dc, like_rating_current_x, current_y, service_key, rating_state )
like_rating_current_x -= 16
@ -1068,11 +1066,9 @@ class CanvasWithDetails( Canvas ):
( rating_state, rating ) = ClientRatings.GetNumericalStateFromMedia( ( self._current_display_media, ), service_key )
stars = ClientRatings.GetStars( service_key, rating_state, rating )
numerical_width = ClientRatings.GetNumericalWidth( service_key )
ClientRatings.DrawNumerical( dc, client_width - numerical_width, current_y, stars )
ClientRatings.DrawNumerical( dc, client_width - numerical_width, current_y, service_key, rating_state, rating )
current_y += 20
@ -1315,7 +1311,7 @@ class CanvasFullscreenMediaList( ClientMedia.ListeningMediaList, CanvasWithDetai
def _GetIndexString( self ):
index_string = HydrusData.ConvertIntToPrettyString( self._sorted_media.index( self._current_media ) + 1 ) + '/' + HydrusData.ConvertIntToPrettyString( len( self._sorted_media ) )
index_string = HydrusData.ConvertValueRangeToPrettyString( self._sorted_media.index( self._current_media ) + 1, len( self._sorted_media ) )
return index_string
@ -4252,6 +4248,8 @@ class EmbedButton( wx.Window ):
self._dirty = True
self._canvas_bmp = wx.EmptyBitmap( 0, 0, 24 )
self.Bind( wx.EVT_PAINT, self.EventPaint )
self.Bind( wx.EVT_SIZE, self.EventResize )
self.Bind( wx.EVT_ERASE_BACKGROUND, self.EventEraseBackground )

View File

@ -83,6 +83,8 @@ class AutoCompleteDropdown( wx.Panel ):
wx.Panel.__init__( self, parent )
self._last_search_text = ''
tlp = self.GetTopLevelParent()
# There's a big bug in wx where FRAME_FLOAT_ON_PARENT Frames don't get passed their mouse events if their parent is a Dialog jej
@ -187,6 +189,13 @@ class AutoCompleteDropdown( wx.Panel ):
def _BroadcastChoice( self, predicate ): pass
def _BroadcastCurrentText( self ):
text = self._text_ctrl.GetValue()
self._BroadcastChoice( text )
def _GenerateMatches( self ):
raise NotImplementedError()
@ -225,15 +234,13 @@ class AutoCompleteDropdown( wx.Panel ):
def _UpdateList( self ): pass
def _UpdateList( self ):
pass
def BroadcastChoice( self, predicate ):
if self._text_ctrl.GetValue() != '':
self._text_ctrl.SetValue( '' )
self._BroadcastChoice( predicate )
@ -244,7 +251,17 @@ class AutoCompleteDropdown( wx.Panel ):
def EventKeyDown( self, event ):
if event.KeyCode in ( wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER ) and self._text_ctrl.GetValue() == '' and len( self._dropdown_list ) == 0: self._BroadcastChoice( None )
if event.KeyCode in ( wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER ) and self._last_search_text == '':
if self._text_ctrl.GetValue() == '':
self._BroadcastChoice( None )
else:
self._BroadcastCurrentText()
elif event.KeyCode == wx.WXK_ESCAPE: self.GetTopLevelParent().SetFocus()
elif event.KeyCode in ( wx.WXK_UP, wx.WXK_NUMPAD_UP, wx.WXK_DOWN, wx.WXK_NUMPAD_DOWN ) and self._text_ctrl.GetValue() == '' and len( self._dropdown_list ) == 0:
@ -385,7 +402,15 @@ class AutoCompleteDropdownMessageTerms( AutoCompleteDropdown ):
self._dropdown_window.SetSizer( vbox )
def _BroadcastChoice( self, predicate ): HydrusGlobals.pubsub.pub( 'add_predicate', self._page_key, predicate )
def _BroadcastChoice( self, predicate ):
if self._text_ctrl.GetValue() != '':
self._text_ctrl.SetValue( '' )
HydrusGlobals.pubsub.pub( 'add_predicate', self._page_key, predicate )
def _InitDropDownList( self ): return ListBoxMessagesActiveOnly( self._dropdown_window, self.BroadcastChoice )
@ -404,6 +429,8 @@ class AutoCompleteDropdownMessageTerms( AutoCompleteDropdown ):
def _UpdateList( self ):
self._last_search_text = self._text_ctrl.GetValue()
matches = self._GenerateMatches()
self._dropdown_list.SetTerms( matches )
@ -467,6 +494,8 @@ class AutoCompleteDropdownTags( AutoCompleteDropdown ):
def _UpdateList( self ):
self._last_search_text = self._text_ctrl.GetValue()
matches = self._GenerateMatches()
self._dropdown_list.SetPredicates( matches )
@ -583,7 +612,22 @@ class AutoCompleteDropdownTagsRead( AutoCompleteDropdownTags ):
HydrusGlobals.pubsub.sub( self, 'IncludePending', 'notify_include_pending' )
def _BroadcastChoice( self, predicate ): HydrusGlobals.pubsub.pub( 'add_predicate', self._page_key, predicate )
def _BroadcastChoice( self, predicate ):
if self._text_ctrl.GetValue() != '':
self._text_ctrl.SetValue( '' )
HydrusGlobals.pubsub.pub( 'add_predicate', self._page_key, predicate )
def _BroadcastCurrentText( self ):
( inclusive, search_text, entry_predicate ) = self._ParseSearchText()
self._BroadcastChoice( entry_predicate )
def _ChangeFileRepository( self, file_service_key ):
@ -599,9 +643,7 @@ class AutoCompleteDropdownTagsRead( AutoCompleteDropdownTags ):
HydrusGlobals.pubsub.pub( 'change_tag_repository', self._page_key, self._tag_service_key )
def _GenerateMatches( self ):
num_autocomplete_chars = HC.options[ 'num_autocomplete_chars' ]
def _ParseSearchText( self ):
raw_entry = self._text_ctrl.GetValue()
@ -620,6 +662,17 @@ class AutoCompleteDropdownTagsRead( AutoCompleteDropdownTags ):
search_text = HydrusTags.CleanTag( search_text )
entry_predicate = HydrusData.Predicate( HC.PREDICATE_TYPE_TAG, search_text, inclusive = inclusive )
return ( inclusive, search_text, entry_predicate )
def _GenerateMatches( self ):
num_autocomplete_chars = HC.options[ 'num_autocomplete_chars' ]
( inclusive, search_text, entry_predicate ) = self._ParseSearchText()
if search_text == '':
self._cache_text = ''
@ -734,8 +787,6 @@ class AutoCompleteDropdownTagsRead( AutoCompleteDropdownTags ):
if self._current_namespace != '': matches.insert( 0, HydrusData.Predicate( HC.PREDICATE_TYPE_NAMESPACE, self._current_namespace, inclusive = inclusive ) )
if '*' in search_text: matches.insert( 0, HydrusData.Predicate( HC.PREDICATE_TYPE_WILDCARD, search_text, inclusive = inclusive ) )
entry_predicate = HydrusData.Predicate( HC.PREDICATE_TYPE_TAG, search_text, inclusive = inclusive )
try:
index = matches.index( entry_predicate )
@ -803,6 +854,11 @@ class AutoCompleteDropdownTagsWrite( AutoCompleteDropdownTags ):
def _BroadcastChoice( self, predicate ):
if self._text_ctrl.GetValue() != '':
self._text_ctrl.SetValue( '' )
if predicate is None: self._chosen_tag_callable( None )
else:
@ -825,14 +881,50 @@ class AutoCompleteDropdownTagsWrite( AutoCompleteDropdownTags ):
def _GenerateMatches( self ):
num_autocomplete_chars = HC.options[ 'num_autocomplete_chars' ]
def _ParseSearchText( self ):
raw_entry = self._text_ctrl.GetValue()
search_text = HydrusTags.CleanTag( raw_entry )
entry_predicate = HydrusData.Predicate( HC.PREDICATE_TYPE_TAG, search_text )
siblings_manager = wx.GetApp().GetManager( 'tag_siblings' )
sibling = siblings_manager.GetSibling( search_text )
if sibling is not None:
sibling_predicate = HydrusData.Predicate( HC.PREDICATE_TYPE_TAG, sibling )
else:
sibling_predicate = None
return ( search_text, entry_predicate, sibling_predicate )
def _BroadcastCurrentText( self ):
( search_text, entry_predicate, sibling_predicate ) = self._ParseSearchText()
if sibling_predicate is not None:
self._BroadcastChoice( sibling_predicate )
else:
self._BroadcastChoice( entry_predicate )
def _GenerateMatches( self ):
num_autocomplete_chars = HC.options[ 'num_autocomplete_chars' ]
( search_text, entry_predicate, sibling_predicate ) = self._ParseSearchText()
if search_text == '':
self._cache_text = ''
@ -886,13 +978,12 @@ class AutoCompleteDropdownTagsWrite( AutoCompleteDropdownTags ):
top_predicates = []
top_predicates.append( HydrusData.Predicate( HC.PREDICATE_TYPE_TAG, search_text ) )
top_predicates.append( entry_predicate )
siblings_manager = wx.GetApp().GetManager( 'tag_siblings' )
sibling = siblings_manager.GetSibling( search_text )
if sibling is not None: top_predicates.append( HydrusData.Predicate( HC.PREDICATE_TYPE_TAG, sibling ) )
if sibling_predicate is not None:
top_predicates.append( sibling_predicate )
for predicate in top_predicates:
@ -3967,7 +4058,7 @@ class RatingLikeDialog( RatingLike ):
( pen_colour, brush_colour ) = ClientRatings.GetPenAndBrushColours( self._service_key, self._rating_state )
ClientRatings.DrawLike( dc, 0, 0, pen_colour, brush_colour )
ClientRatings.DrawLike( dc, 0, 0, self._service_key, self._rating_state )
self._dirty = False
@ -4038,9 +4129,7 @@ class RatingLikeCanvas( RatingLike ):
self._rating_state = ClientRatings.GetLikeStateFromMedia( ( self._current_media, ), self._service_key )
( pen_colour, brush_colour ) = ClientRatings.GetPenAndBrushColours( self._service_key, self._rating_state )
ClientRatings.DrawLike( dc, 0, 0, pen_colour, brush_colour )
ClientRatings.DrawLike( dc, 0, 0, self._service_key, self._rating_state )
self._dirty = False
@ -4125,6 +4214,7 @@ class RatingNumerical( wx.Window ):
self._service = wx.GetApp().GetManager( 'services' ).GetService( self._service_key )
self._num_stars = self._service.GetInfo( 'num_stars' )
self._allow_zero = self._service.GetInfo( 'allow_zero' )
my_width = ClientRatings.GetNumericalWidth( self._service_key )
@ -4166,10 +4256,17 @@ class RatingNumerical( wx.Window ):
if 0 <= y and y <= my_active_height:
if 0 <= x and x <= my_active_width:
proportion_filled = float( x_adjusted ) / my_active_width
rating = round( proportion_filled * self._num_stars ) / self._num_stars
if self._allow_zero:
rating = round( proportion_filled * self._num_stars ) / self._num_stars
else:
rating = float( int( proportion_filled * self._num_stars ) ) / ( self._num_stars - 1 )
return rating
@ -4220,9 +4317,7 @@ class RatingNumericalDialog( RatingNumerical ):
dc.Clear()
stars = ClientRatings.GetStars( self._service_key, self._rating_state, self._rating )
ClientRatings.DrawNumerical( dc, 0, 0, stars )
ClientRatings.DrawNumerical( dc, 0, 0, self._service_key, self._rating_state, self._rating )
self._dirty = False
@ -4313,9 +4408,7 @@ class RatingNumericalCanvas( RatingNumerical ):
( self._rating_state, self._rating ) = ClientRatings.GetNumericalStateFromMedia( ( self._current_media, ), self._service_key )
stars = ClientRatings.GetStars( self._service_key, self._rating_state, self._rating )
ClientRatings.DrawNumerical( dc, 0, 0, stars )
ClientRatings.DrawNumerical( dc, 0, 0, self._service_key, self._rating_state, self._rating )
self._dirty = False

View File

@ -1130,7 +1130,18 @@ class DialogInputCustomFilterAction( Dialog ):
num_stars = service.GetInfo( 'num_stars' )
self._ratings_numerical_slider.SetRange( 0, num_stars )
allow_zero = service.GetInfo( 'allow_zero' )
if allow_zero:
min = 0
else:
min = 1
self._ratings_numerical_slider.SetRange( min, num_stars )
@ -1188,11 +1199,21 @@ class DialogInputCustomFilterAction( Dialog ):
else:
self._pretty_action = HydrusData.ToString( self._ratings_numerical_slider.GetValue() )
value = self._ratings_numerical_slider.GetValue()
self._pretty_action = HydrusData.ToString( value )
num_stars = self._current_ratings_numerical_service.GetInfo( 'num_stars' )
allow_zero = self._current_ratings_numerical_service.GetInfo( 'allow_zero' )
self._action = float( self._pretty_action ) / num_stars
if allow_zero:
self._action = float( value ) / num_stars
else:
self._action = float( value - 1 ) / ( num_stars - 1 )
self.EndModal( wx.ID_OK )
@ -1848,7 +1869,7 @@ class DialogInputLocalFiles( Dialog ):
if i % 500 == 0: gc.collect()
wx.CallAfter( self.SetGaugeInfo, num_file_paths, i, u'Done ' + HydrusData.ToString( i ) + '/' + HydrusData.ToString( num_file_paths ) )
wx.CallAfter( self.SetGaugeInfo, num_file_paths, i, u'Done ' + HydrusData.ConvertValueRangeToPrettyString( i, num_file_paths ) )
job_key.WaitOnPause()

View File

@ -544,6 +544,8 @@ class DialogManageBoorus( ClientGUIDialogs.Dialog ):
self._boorus.AddPage( name, page, select = True )
self._boorus.Select( name )
page = self._boorus.GetNamesToActivePages()[ name ]
page.Update( booru )
@ -2797,6 +2799,21 @@ class DialogManageOptions( ClientGUIDialogs.Dialog ):
self._listbook = ClientGUICommon.ListBook( self )
# connection
self._connection_page = wx.Panel( self._listbook )
self._connection_page.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) )
self._proxy_type = ClientGUICommon.BetterChoice( self._connection_page )
self._proxy_address = wx.TextCtrl( self._connection_page )
self._proxy_port = wx.SpinCtrl( self._connection_page, min = 0, max = 65535 )
self._proxy_username = wx.TextCtrl( self._connection_page )
self._proxy_password = wx.TextCtrl( self._connection_page )
self._listbook.AddPage( 'connection', self._connection_page )
# files and thumbnails
self._file_page = wx.Panel( self._listbook )
@ -3039,6 +3056,36 @@ class DialogManageOptions( ClientGUIDialogs.Dialog ):
def PopulateControls():
self._proxy_type.Append( 'http', 'http' )
self._proxy_type.Append( 'socks4', 'socks4' )
self._proxy_type.Append( 'socks5', 'socks5' )
if HC.options[ 'proxy' ] is not None:
( proxytype, host, port, username, password ) = HC.options[ 'proxy' ]
self._proxy_type.SelectClientData( proxytype )
self._proxy_address.SetValue( host )
self._proxy_port.SetValue( port )
if username is not None:
self._proxy_username.SetValue( username )
if password is not None:
self._proxy_password.SetValue( password )
else:
self._proxy_type.Select( 0 )
#
if HC.options[ 'export_path' ] is not None:
abs_path = HydrusData.ConvertPortablePathToAbsPath( HC.options[ 'export_path' ] )
@ -3179,6 +3226,40 @@ class DialogManageOptions( ClientGUIDialogs.Dialog ):
gridbox.AddGrowableCol( 1, 1 )
gridbox.AddF( wx.StaticText( self._connection_page, label = 'Proxy type: ' ), CC.FLAGS_MIXED )
gridbox.AddF( self._proxy_type, CC.FLAGS_MIXED )
gridbox.AddF( wx.StaticText( self._connection_page, label = 'Address: ' ), CC.FLAGS_MIXED )
gridbox.AddF( self._proxy_address, CC.FLAGS_MIXED )
gridbox.AddF( wx.StaticText( self._connection_page, label = 'Port: ' ), CC.FLAGS_MIXED )
gridbox.AddF( self._proxy_port, CC.FLAGS_MIXED )
gridbox.AddF( wx.StaticText( self._connection_page, label = 'Username (optional): ' ), CC.FLAGS_MIXED )
gridbox.AddF( self._proxy_username, CC.FLAGS_MIXED )
gridbox.AddF( wx.StaticText( self._connection_page, label = 'Password (optional): ' ), CC.FLAGS_MIXED )
gridbox.AddF( self._proxy_password, CC.FLAGS_MIXED )
text = 'You have to restart the client for proxy settings to take effect.'
text += os.linesep
text += 'This is in a buggy prototype stage right now, pending a rewrite of the networking engine.'
text += os.linesep
text += 'Please send me your feedback.'
vbox.AddF( wx.StaticText( self._connection_page, label = text ), CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.AddF( gridbox, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
self._connection_page.SetSizer( vbox )
#
vbox = wx.BoxSizer( wx.VERTICAL )
gridbox = wx.FlexGridSizer( 0, 2 )
gridbox.AddGrowableCol( 1, 1 )
gridbox.AddF( wx.StaticText( self._file_page, label = 'Default export directory: ' ), CC.FLAGS_MIXED )
gridbox.AddF( self._export_location, CC.FLAGS_EXPAND_BOTH_WAYS )
@ -3649,6 +3730,26 @@ class DialogManageOptions( ClientGUIDialogs.Dialog ):
def EventOK( self, event ):
if self._proxy_address.GetValue() == '':
HC.options[ 'proxy' ] = None
else:
proxytype = self._proxy_type.GetChoice()
address = self._proxy_address.GetValue()
port = self._proxy_port.GetValue()
username = self._proxy_username.GetValue()
password = self._proxy_password.GetValue()
if username == '': username = None
if password == '': password = None
HC.options[ 'proxy' ] = ( proxytype, address, port, username, password )
#
HC.options[ 'play_dumper_noises' ] = self._play_dumper_noises.GetValue()
HC.options[ 'default_gui_session' ] = self._default_gui_session.GetStringSelection()
@ -4790,6 +4891,8 @@ class DialogManageServices( ClientGUIDialogs.Dialog ):
info[ 'colours' ] = ClientRatings.default_numerical_colours
info[ 'allow_zero' ] = True
else:
info[ 'colours' ] = ClientRatings.default_like_colours
@ -5065,6 +5168,30 @@ class DialogManageServices( ClientGUIDialogs.Dialog ):
self._num_stars = wx.SpinCtrl( self._local_rating_panel, min = 1, max = 20 )
self._num_stars.SetValue( num_stars )
allow_zero = info[ 'allow_zero' ]
self._allow_zero = wx.CheckBox( self._local_rating_panel )
self._allow_zero.SetValue( allow_zero )
self._shape = ClientGUICommon.BetterChoice( self._local_rating_panel )
self._shape.Append( 'circle', ClientRatings.CIRCLE )
self._shape.Append( 'square', ClientRatings.SQUARE )
self._shape.Append( 'star', ClientRatings.STAR )
self._colour_ctrls = {}
for colour_type in [ ClientRatings.LIKE, ClientRatings.DISLIKE, ClientRatings.NULL, ClientRatings.MIXED ]:
border_ctrl = wx.ColourPickerCtrl( self._local_rating_panel )
fill_ctrl = wx.ColourPickerCtrl( self._local_rating_panel )
border_ctrl.SetMaxSize( ( 20, -1 ) )
fill_ctrl.SetMaxSize( ( 20, -1 ) )
self._colour_ctrls[ colour_type ] = ( border_ctrl, fill_ctrl )
if service_type in HC.TAG_SERVICES:
@ -5084,7 +5211,6 @@ class DialogManageServices( ClientGUIDialogs.Dialog ):
self._archive_sync_remove = wx.Button( self._archive_panel, label = 'remove' )
self._archive_sync_remove.Bind( wx.EVT_BUTTON, self.EventArchiveRemove )
if service_type == HC.LOCAL_BOORU:
@ -5122,6 +5248,23 @@ class DialogManageServices( ClientGUIDialogs.Dialog ):
self._UpdateArchiveButtons()
if service_type in HC.RATINGS_SERVICES:
self._shape.SelectClientData( info[ 'shape' ] )
colours = info[ 'colours' ]
for colour_type in colours:
( border_rgb, fill_rgb ) = colours[ colour_type ]
( border_ctrl, fill_ctrl ) = self._colour_ctrls[ colour_type ]
border_ctrl.SetColour( wx.Colour( *border_rgb ) )
fill_ctrl.SetColour( wx.Colour( *fill_rgb ) )
if service_type == HC.LOCAL_BOORU:
self._port.SetValue( info[ 'port' ] )
@ -5178,12 +5321,30 @@ class DialogManageServices( ClientGUIDialogs.Dialog ):
gridbox.AddF( wx.StaticText( self._local_rating_panel, label = 'number of \'stars\'' ), CC.FLAGS_MIXED )
gridbox.AddF( self._num_stars, CC.FLAGS_EXPAND_BOTH_WAYS )
gridbox.AddF( wx.StaticText( self._local_rating_panel, label = 'allow a zero rating' ), CC.FLAGS_MIXED )
gridbox.AddF( self._allow_zero, CC.FLAGS_EXPAND_BOTH_WAYS )
gridbox.AddF( wx.StaticText( self._local_rating_panel, label = 'shape options will go here soon' ), CC.FLAGS_MIXED )
gridbox.AddF( wx.StaticText( self._local_rating_panel, label = ':D' ), CC.FLAGS_EXPAND_BOTH_WAYS )
gridbox.AddF( wx.StaticText( self._local_rating_panel, label = 'shape' ), CC.FLAGS_MIXED )
gridbox.AddF( self._shape, CC.FLAGS_EXPAND_BOTH_WAYS )
gridbox.AddF( wx.StaticText( self._local_rating_panel, label = 'colour options will go here soon' ), CC.FLAGS_MIXED )
gridbox.AddF( wx.StaticText( self._local_rating_panel, label = ':D' ), CC.FLAGS_EXPAND_BOTH_WAYS )
for colour_type in [ ClientRatings.LIKE, ClientRatings.DISLIKE, ClientRatings.NULL, ClientRatings.MIXED ]:
( border_ctrl, fill_ctrl ) = self._colour_ctrls[ colour_type ]
hbox = wx.BoxSizer( wx.HORIZONTAL )
hbox.AddF( border_ctrl, CC.FLAGS_MIXED )
hbox.AddF( fill_ctrl, CC.FLAGS_MIXED )
if colour_type == ClientRatings.LIKE: colour_text = 'liked'
elif colour_type == ClientRatings.DISLIKE: colour_text = 'disliked'
elif colour_type == ClientRatings.NULL: colour_text = 'not rated'
elif colour_type == ClientRatings.MIXED: colour_text = 'a mixture of ratings'
gridbox.AddF( wx.StaticText( self._local_rating_panel, label = 'border/fill for ' + colour_text ), CC.FLAGS_MIXED )
gridbox.AddF( hbox, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
self._local_rating_panel.AddF( gridbox, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
@ -5435,9 +5596,34 @@ class DialogManageServices( ClientGUIDialogs.Dialog ):
info[ 'paused' ] = self._pause_synchronisation.GetValue()
if service_type == HC.LOCAL_RATING_NUMERICAL:
if service_type in HC.RATINGS_SERVICES:
info[ 'num_stars' ] = self._num_stars.GetValue()
if service_type == HC.LOCAL_RATING_NUMERICAL:
info[ 'num_stars' ] = self._num_stars.GetValue()
info[ 'allow_zero' ] = self._allow_zero.GetValue()
info[ 'shape' ] = self._shape.GetChoice()
colours = {}
for colour_type in self._colour_ctrls:
( border_ctrl, fill_ctrl ) = self._colour_ctrls[ colour_type ]
border_colour = border_ctrl.GetColour()
border_rgb = ( border_colour.Red(), border_colour.Green(), border_colour.Blue() )
fill_colour = fill_ctrl.GetColour()
fill_rgb = ( fill_colour.Red(), fill_colour.Green(), fill_colour.Blue() )
colours[ colour_type ] = ( border_rgb, fill_rgb )
info[ 'colours' ] = colours
if service_type in HC.TAG_SERVICES:

View File

@ -633,7 +633,7 @@ class ManagementPanelDumper( ManagementPanel ):
else: initial = ''
initial += HydrusData.ToString( index + 1 ) + '/' + HydrusData.ToString( num_files )
initial += HydrusData.ConvertValueRangeToPrettyString( index + 1, num_files )
advanced_tag_options = self._advanced_tag_options.GetInfo()
@ -686,7 +686,7 @@ class ManagementPanelDumper( ManagementPanel ):
index = self._sorted_media_hashes.index( self._current_hash )
self._post_info.SetLabel( HydrusData.ToString( index + 1 ) + '/' + HydrusData.ToString( num_files ) + ': ' + dump_status_string )
self._post_info.SetLabel( HydrusData.ConvertValueRangeToPrettyString( index + 1, num_files ) + ': ' + dump_status_string )
for ( name, field_type, value ) in post_field_info:
@ -1981,7 +1981,7 @@ class ManagementPanelImportThreadWatcher( ManagementPanelImport ):
self._thread_times_to_check.SetValue( times_to_check )
self._thread_times_to_check.Bind( wx.EVT_SPINCTRL, self.EventThreadVariable )
self._thread_check_period = wx.SpinCtrl( self._thread_panel, size = ( 100, -1 ), min = 30, max = 86400 )
self._thread_check_period = wx.SpinCtrl( self._thread_panel, size = ( 60, -1 ), min = 30, max = 86400 )
self._thread_check_period.SetValue( check_period )
self._thread_check_period.Bind( wx.EVT_SPINCTRL, self.EventThreadVariable )

View File

@ -1469,7 +1469,7 @@ class MediaPanelThumbnails( MediaPanel ):
if page_index not in self._clean_canvas_pages:
if len( self._dirty_canvas_pages ) > 0: bmp = self._dirty_canvas_pages.pop()
if len( self._dirty_canvas_pages ) > 0: bmp = self._dirty_canvas_pages.pop( 0 )
else:
index_to_steal = potential_clean_indices_to_steal.pop()

View File

@ -25,16 +25,46 @@ default_numerical_colours[ DISLIKE ] = ( ( 0, 0, 0 ), ( 255, 255, 255 ) )
default_numerical_colours[ NULL ] = ( ( 0, 0, 0 ), ( 191, 191, 191 ) )
default_numerical_colours[ MIXED ] = ( ( 0, 0, 0 ), ( 95, 95, 95 ) )
def DrawLike( dc, x, y, pen_colour, brush_colour ):
STAR_COORDS = []
STAR_COORDS.append( wx.Point( 6, 0 ) ) # top
STAR_COORDS.append( wx.Point( 9, 4 ) )
STAR_COORDS.append( wx.Point( 12, 4 ) ) # right
STAR_COORDS.append( wx.Point( 9, 8 ) )
STAR_COORDS.append( wx.Point( 10, 12 ) ) # bottom right
STAR_COORDS.append( wx.Point( 6, 10 ) )
STAR_COORDS.append( wx.Point( 2, 12 ) ) # bottom left
STAR_COORDS.append( wx.Point( 3, 8 ) )
STAR_COORDS.append( wx.Point( 0, 4 ) ) # left
STAR_COORDS.append( wx.Point( 3, 4 ) )
def DrawLike( dc, x, y, service_key, rating_state ):
shape = GetShape( service_key )
( pen_colour, brush_colour ) = GetPenAndBrushColours( service_key, rating_state )
dc.SetPen( wx.Pen( pen_colour ) )
dc.SetBrush( wx.Brush( brush_colour ) )
if shape == CIRCLE:
dc.DrawCircle( x + 7, y + 7, 6 )
elif shape == SQUARE:
dc.DrawRectangle( x + 2, y + 2, 12, 12 )
elif shape == STAR:
dc.DrawPolygon( STAR_COORDS, x + 1, y + 1 )
dc.DrawCircle( x + 7, y + 7, 6 )
def DrawNumerical( dc, x, y, service_key, rating_state, rating ):
def DrawNumerical( dc, x, y, stars ):
( shape, stars ) = GetStars( service_key, rating_state, rating )
x_delta = 7
x_delta = 0
x_step = 12
for ( num_stars, pen_colour, brush_colour ) in stars:
@ -44,7 +74,18 @@ def DrawNumerical( dc, x, y, stars ):
for i in range( num_stars ):
dc.DrawCircle( x + x_delta, y + 7, 6 )
if shape == CIRCLE:
dc.DrawCircle( x + 7 + x_delta, y + 7, 6 )
elif shape == SQUARE:
dc.DrawRectangle( x + 2 + x_delta, y + 2, 12, 12 )
elif shape == STAR:
dc.DrawPolygon( STAR_COORDS, x + 1 + x_delta, y + 1 )
x_delta += x_step
@ -156,10 +197,22 @@ def GetPenAndBrushColours( service_key, rating_state ):
return ( pen_colour, brush_colour )
def GetShape( service_key ):
service = wx.GetApp().GetManager( 'services' ).GetService( service_key )
shape = service.GetInfo( 'shape' )
return shape
def GetStars( service_key, rating_state, rating ):
service = wx.GetApp().GetManager( 'services' ).GetService( service_key )
allow_zero = service.GetInfo( 'allow_zero' )
shape = service.GetInfo( 'shape' )
num_stars = service.GetInfo( 'num_stars' )
stars = []
@ -172,20 +225,27 @@ def GetStars( service_key, rating_state, rating ):
else:
num_stars_on = int( round( rating * num_stars ) )
if allow_zero:
num_stars_on = int( round( rating * num_stars ) )
else:
num_stars_on = int( round( rating * ( num_stars - 1 ) ) ) + 1
num_stars_off = num_stars - num_stars_on
( pen_colour, brush_colour ) = GetPenAndBrushColours( service_key, LIKE )
stars.append( ( num_stars_on, pen_colour, brush_colour ) )
num_stars_off = num_stars - num_stars_on
( pen_colour, brush_colour ) = GetPenAndBrushColours( service_key, DISLIKE )
stars.append( ( num_stars_off, pen_colour, brush_colour ) )
return stars
return ( shape, stars )
class CPRemoteRatingsServiceKeys( object ):

View File

@ -49,7 +49,7 @@ options = {}
# Misc
NETWORK_VERSION = 16
SOFTWARE_VERSION = 159
SOFTWARE_VERSION = 160
UNSCALED_THUMBNAIL_DIMENSIONS = ( 200, 200 )

View File

@ -488,6 +488,10 @@ def ConvertUnitToInt( unit ):
elif unit == 'MB': return 1048576
elif unit == 'GB': return 1073741824
def ConvertValueRangeToPrettyString( value, range ):
return ConvertIntToPrettyString( value ) + '/' + ConvertIntToPrettyString( range )
def ConvertZoomToPercentage( zoom ):
zoom = zoom * 100.0
@ -748,7 +752,7 @@ class Account( HydrusYAMLBase ):
used_requests = self._info[ 'used_requests' ]
if max_num_requests is None: return ConvertIntToPrettyString( used_requests ) + ' requests used this month'
else: return ConvertIntToPrettyString( used_requests ) + '/' + ConvertIntToPrettyString( max_num_requests ) + ' requests used this month'
else: return ConvertValueRangeToPrettyString( used_requests, max_num_requests ) + ' requests used this month'
def GetUsedBytes( self ): return self._info[ 'used_bytes' ]
@ -1528,6 +1532,30 @@ class ServerToClientContentUpdatePackage( HydrusSerialisable.SerialisableBase ):
return num
def GetNumRows( self ):
num = 0
for data_type in self._content_data:
for action in self._content_data[ data_type ]:
data = self._content_data[ data_type ][ action ]
if data_type == HC.CONTENT_DATA_TYPE_MAPPINGS:
for ( tag, hash_ids ) in data:
num += len( hash_ids )
else: num += len( data )
return num
def IterateContentUpdates( self, as_if_pending = False ):
data_types = [ HC.CONTENT_DATA_TYPE_FILES, HC.CONTENT_DATA_TYPE_MAPPINGS, HC.CONTENT_DATA_TYPE_TAG_SIBLINGS, HC.CONTENT_DATA_TYPE_TAG_PARENTS ]

View File

@ -5,6 +5,8 @@ import HydrusSerialisable
import httplib
import multipart
import os
import socket
import socks
import threading
import time
import urllib
@ -138,6 +140,25 @@ def GenerateMultipartFormDataCTAndBodyFromDict( fields ):
return m.get()
def GetLocalConnection( port ):
old_socket = httplib.socket.socket
httplib.socket.socket = socket._socketobject
try:
connection = httplib.HTTPConnection( '127.0.0.1', port, timeout = 8 )
connection.connect()
finally:
httplib.socket.socket = old_socket
return connection
def ParseURL( url ):
try:
@ -167,6 +188,16 @@ def ParseURL( url ):
return ( location, path, query )
def SetProxy( proxytype, host, port, username = None, password = None ):
if proxytype == 'http': proxytype = socks.PROXY_TYPE_HTTP
elif proxytype == 'socks4': proxytype = socks.PROXY_TYPE_SOCKS4
elif proxytype == 'socks5': proxytype = socks.PROXY_TYPE_SOCKS5
socks.setdefaultproxy( proxytype = proxytype, addr = host, port = port, username = username, password = password )
socks.wrapmodule( httplib )
class HTTPConnectionManager( object ):
def __init__( self ):
@ -328,6 +359,17 @@ class HTTPConnection( object ):
def _ParseResponse( self, response, report_hooks ):
server_header = response.getheader( 'Server' )
if server_header is not None and 'hydrus' in server_header:
hydrus_service = True
else:
hydrus_service = False
content_length = response.getheader( 'Content-Length' )
@ -381,7 +423,14 @@ class HTTPConnection( object ):
elif content_type == 'application/json':
parsed_response = HydrusSerialisable.CreateFromNetworkString( data )
if hydrus_service:
parsed_response = HydrusSerialisable.CreateFromNetworkString( data )
else:
parsed_response = data
elif content_type == 'text/html':
@ -399,8 +448,18 @@ class HTTPConnection( object ):
if self._scheme == 'http': self._connection = httplib.HTTPConnection( self._host, self._port, timeout = self._timeout )
elif self._scheme == 'https': self._connection = httplib.HTTPSConnection( self._host, self._port, timeout = self._timeout )
try: self._connection.connect()
except: raise Exception( 'Could not connect to ' + HydrusData.ToString( self._host ) + '!' )
try:
self._connection.connect()
except Exception as e:
text = 'Could not connect to ' + HydrusData.ToString( self._host ) + ':'
text += os.linesep * 2
text += HydrusData.ToString( e )
raise Exception( text )
def _WriteResponseToPath( self, response, temp_path, report_hooks ):

View File

@ -3,6 +3,7 @@ import HydrusConstants as HC
import HydrusController
import HydrusData
import HydrusGlobals
import HydrusNetworking
import HydrusServer
import HydrusSessions
import HydrusThreading
@ -24,11 +25,9 @@ class Controller( HydrusController.HydrusController ):
def _AlreadyRunning( self, port ):
connection = httplib.HTTPConnection( '127.0.0.1', port, timeout = 20 )
try:
connection.connect()
connection = HydrusNetworking.GetLocalConnection( port )
connection.close()
return True
@ -50,11 +49,9 @@ class Controller( HydrusController.HydrusController ):
port = options[ 'port' ]
connection = httplib.HTTPConnection( '127.0.0.1', port, timeout = 10 )
try:
connection.connect()
connection = HydrusNetworking.GetLocalConnection( port )
connection.close()
raise Exception( 'Something was already bound to port ' + HydrusData.ToString( port ) )
@ -70,11 +67,9 @@ class Controller( HydrusController.HydrusController ):
self._services[ service_key ] = reactor.listenTCP( port, service_object )
connection = httplib.HTTPConnection( '127.0.0.1', port, timeout = 10 )
try:
connection.connect()
connection = HydrusNetworking.GetLocalConnection( port )
connection.close()
except:
@ -142,11 +137,9 @@ class Controller( HydrusController.HydrusController ):
port = options[ 'port' ]
connection = httplib.HTTPConnection( '127.0.0.1', port, timeout = 10 )
try:
connection.connect()
connection = HydrusNetworking.GetLocalConnection( port )
connection.close()
message = 'Something was already bound to port ' + HydrusData.ToString( port )