hydrus/include/ClientGUITagSuggestions.py

620 lines
18 KiB
Python
Raw Normal View History

2019-01-09 22:59:03 +00:00
from . import ClientConstants as CC
from . import ClientData
from . import ClientGUICommon
from . import ClientGUIDialogs
from . import ClientGUIListBoxes
from . import ClientGUIParsing
from . import ClientParsing
from . import ClientSearch
from . import ClientThreading
2016-08-03 22:15:54 +00:00
import collections
2019-01-09 22:59:03 +00:00
from . import HydrusConstants as HC
from . import HydrusData
from . import HydrusGlobals as HG
from . import HydrusSerialisable
2016-08-03 22:15:54 +00:00
import wx
2017-02-01 21:11:17 +00:00
class ListBoxTagsSuggestionsFavourites( ClientGUIListBoxes.ListBoxTagsStrings ):
2016-08-03 22:15:54 +00:00
2016-09-21 19:54:04 +00:00
def __init__( self, parent, activate_callable, sort_tags = True ):
2016-08-03 22:15:54 +00:00
2017-02-01 21:11:17 +00:00
ClientGUIListBoxes.ListBoxTagsStrings.__init__( self, parent, sort_tags = sort_tags )
2016-08-03 22:15:54 +00:00
self._activate_callable = activate_callable
2017-12-06 22:06:56 +00:00
width = HG.client_controller.new_options.GetInteger( 'suggested_tags_width' )
2016-11-09 23:13:22 +00:00
if width is not None:
self.SetMinSize( ( width, -1 ) )
2016-08-03 22:15:54 +00:00
def _Activate( self ):
if len( self._selected_terms ) > 0:
tags = set( self._selected_terms )
self._activate_callable( tags )
2016-11-16 20:21:43 +00:00
def ActivateAll( self ):
2016-11-23 20:37:53 +00:00
self._activate_callable( self.GetTags(), only_add = True )
2016-11-16 20:21:43 +00:00
2017-05-24 20:28:24 +00:00
2019-06-05 19:42:39 +00:00
def TakeFocusForUser( self ):
if len( self._selected_terms ) == 0 and len( self._terms ) > 0:
self._Hit( False, False, 0 )
self.SetFocus()
2017-03-22 22:38:15 +00:00
class ListBoxTagsSuggestionsRelated( ClientGUIListBoxes.ListBoxTagsPredicates ):
2016-08-03 22:15:54 +00:00
def __init__( self, parent, activate_callable ):
2017-02-01 21:11:17 +00:00
ClientGUIListBoxes.ListBoxTags.__init__( self, parent )
2016-08-03 22:15:54 +00:00
self._activate_callable = activate_callable
2017-12-06 22:06:56 +00:00
width = HG.client_controller.new_options.GetInteger( 'suggested_tags_width' )
2016-08-03 22:15:54 +00:00
2016-11-09 23:13:22 +00:00
self.SetMinSize( ( width, -1 ) )
2016-08-03 22:15:54 +00:00
def _Activate( self ):
if len( self._selected_terms ) > 0:
tags = { predicate.GetValue() for predicate in self._selected_terms }
self._activate_callable( tags )
2017-03-29 19:39:34 +00:00
def _GetTextFromTerm( self, term ):
predicate = term
2019-01-09 22:59:03 +00:00
return predicate.ToString( with_count = False )
2017-03-29 19:39:34 +00:00
2016-08-03 22:15:54 +00:00
def SetPredicates( self, predicates ):
2017-03-22 22:38:15 +00:00
self._Clear()
2016-08-03 22:15:54 +00:00
for predicate in predicates:
2017-03-22 22:38:15 +00:00
self._AppendTerm( predicate )
2016-08-03 22:15:54 +00:00
2017-03-22 22:38:15 +00:00
self._DataHasChanged()
2016-08-03 22:15:54 +00:00
2019-06-05 19:42:39 +00:00
def TakeFocusForUser( self ):
if len( self._selected_terms ) == 0 and len( self._terms ) > 0:
self._Hit( False, False, 0 )
self.SetFocus()
2016-08-31 19:55:14 +00:00
class RecentTagsPanel( wx.Panel ):
def __init__( self, parent, service_key, activate_callable, canvas_key = None ):
wx.Panel.__init__( self, parent )
self._service_key = service_key
self._canvas_key = canvas_key
2017-12-06 22:06:56 +00:00
self._new_options = HG.client_controller.new_options
2016-08-31 19:55:14 +00:00
vbox = wx.BoxSizer( wx.VERTICAL )
clear_button = wx.Button( self, label = 'clear' )
clear_button.Bind( wx.EVT_BUTTON, self.EventClear )
2016-09-21 19:54:04 +00:00
self._recent_tags = ListBoxTagsSuggestionsFavourites( self, activate_callable, sort_tags = False )
2016-08-31 19:55:14 +00:00
2018-01-03 22:37:30 +00:00
vbox.Add( clear_button, CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.Add( self._recent_tags, CC.FLAGS_EXPAND_BOTH_WAYS )
2016-08-31 19:55:14 +00:00
self.SetSizer( vbox )
self._RefreshRecentTags()
if self._canvas_key is not None:
2017-05-10 21:33:58 +00:00
HG.client_controller.sub( self, 'CanvasHasNewMedia', 'canvas_new_display_media' )
2016-08-31 19:55:14 +00:00
def _RefreshRecentTags( self ):
2018-01-31 22:58:15 +00:00
def do_it( service_key ):
def wx_code():
if not self:
return
self._recent_tags.SetTags( recent_tags )
recent_tags = HG.client_controller.Read( 'recent_tags', service_key )
wx.CallAfter( wx_code )
2016-08-31 19:55:14 +00:00
2018-01-31 22:58:15 +00:00
HG.client_controller.CallToThread( do_it, self._service_key )
2016-08-31 19:55:14 +00:00
def CanvasHasNewMedia( self, canvas_key, new_media_singleton ):
if canvas_key == self._canvas_key:
self._RefreshRecentTags()
def EventClear( self, event ):
2018-01-31 22:58:15 +00:00
HG.client_controller.Write( 'push_recent_tags', self._service_key, None )
2016-08-31 19:55:14 +00:00
self._RefreshRecentTags()
2019-06-05 19:42:39 +00:00
def TakeFocusForUser( self ):
self._recent_tags.TakeFocusForUser()
2016-08-03 22:15:54 +00:00
class RelatedTagsPanel( wx.Panel ):
2016-08-10 19:04:08 +00:00
def __init__( self, parent, service_key, media, activate_callable, canvas_key = None ):
2016-08-03 22:15:54 +00:00
wx.Panel.__init__( self, parent )
self._service_key = service_key
self._media = media
2016-08-10 19:04:08 +00:00
self._canvas_key = canvas_key
2016-08-03 22:15:54 +00:00
2019-06-05 19:42:39 +00:00
self._have_fetched = False
2017-12-06 22:06:56 +00:00
self._new_options = HG.client_controller.new_options
2016-08-03 22:15:54 +00:00
vbox = wx.BoxSizer( wx.VERTICAL )
2019-06-05 19:42:39 +00:00
self._button_2 = wx.Button( self, label = 'medium' )
self._button_2.Bind( wx.EVT_BUTTON, self.EventSuggestedRelatedTags2 )
self._button_2.SetMinSize( ( 30, -1 ) )
2016-08-03 22:15:54 +00:00
2019-06-05 19:42:39 +00:00
self._button_3 = wx.Button( self, label = 'thorough' )
self._button_3.Bind( wx.EVT_BUTTON, self.EventSuggestedRelatedTags3 )
self._button_3.SetMinSize( ( 30, -1 ) )
2016-08-03 22:15:54 +00:00
self._related_tags = ListBoxTagsSuggestionsRelated( self, activate_callable )
button_hbox = wx.BoxSizer( wx.HORIZONTAL )
2019-06-05 19:42:39 +00:00
button_hbox.Add( self._button_2, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
button_hbox.Add( self._button_3, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
2016-08-03 22:15:54 +00:00
2018-01-03 22:37:30 +00:00
vbox.Add( button_hbox, CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.Add( self._related_tags, CC.FLAGS_EXPAND_BOTH_WAYS )
2016-08-03 22:15:54 +00:00
self.SetSizer( vbox )
2016-08-10 19:04:08 +00:00
if self._canvas_key is not None:
2017-05-10 21:33:58 +00:00
HG.client_controller.sub( self, 'CanvasHasNewMedia', 'canvas_new_display_media' )
2016-08-10 19:04:08 +00:00
self._QuickSuggestedRelatedTags()
2016-08-03 22:15:54 +00:00
def _FetchRelatedTags( self, max_time_to_take ):
2018-01-31 22:58:15 +00:00
def do_it( service_key ):
def wx_code():
if not self:
return
self._related_tags.SetPredicates( predicates )
2019-06-05 19:42:39 +00:00
self._have_fetched = True
2018-01-31 22:58:15 +00:00
predicates = HG.client_controller.Read( 'related_tags', service_key, hash, search_tags, max_results, max_time_to_take )
predicates = ClientSearch.SortPredicates( predicates )
wx.CallAfter( wx_code )
2016-08-03 22:15:54 +00:00
( m, ) = self._media
hash = m.GetHash()
( current_tags_to_count, deleted_tags_to_count, pending_tags_to_count, petitioned_tags_to_count ) = ClientData.GetMediasTagCount( self._media, tag_service_key = self._service_key, collapse_siblings = False )
tags_to_count = collections.Counter()
tags_to_count.update( current_tags_to_count )
tags_to_count.update( pending_tags_to_count )
search_tags = set( tags_to_count.keys() )
max_results = 100
2018-01-31 22:58:15 +00:00
HG.client_controller.CallToThread( do_it, self._service_key )
2016-08-03 22:15:54 +00:00
2016-08-10 19:04:08 +00:00
def _QuickSuggestedRelatedTags( self ):
2016-08-03 22:15:54 +00:00
max_time_to_take = self._new_options.GetInteger( 'related_tags_search_1_duration_ms' ) / 1000.0
self._FetchRelatedTags( max_time_to_take )
2016-08-10 19:04:08 +00:00
def CanvasHasNewMedia( self, canvas_key, new_media_singleton ):
if canvas_key == self._canvas_key:
2018-08-29 20:20:41 +00:00
if new_media_singleton is not None:
self._media = ( new_media_singleton.Duplicate(), )
self._QuickSuggestedRelatedTags()
2016-08-10 19:04:08 +00:00
2016-08-03 22:15:54 +00:00
def EventSuggestedRelatedTags2( self, event ):
max_time_to_take = self._new_options.GetInteger( 'related_tags_search_2_duration_ms' ) / 1000.0
self._FetchRelatedTags( max_time_to_take )
def EventSuggestedRelatedTags3( self, event ):
max_time_to_take = self._new_options.GetInteger( 'related_tags_search_3_duration_ms' ) / 1000.0
self._FetchRelatedTags( max_time_to_take )
2019-06-05 19:42:39 +00:00
def TakeFocusForUser( self ):
self._related_tags.TakeFocusForUser()
2016-11-09 23:13:22 +00:00
class FileLookupScriptTagsPanel( wx.Panel ):
2016-11-16 20:21:43 +00:00
def __init__( self, parent, service_key, media, activate_callable, canvas_key = None ):
2016-11-09 23:13:22 +00:00
wx.Panel.__init__( self, parent )
self._service_key = service_key
self._media = media
2016-11-16 20:21:43 +00:00
self._canvas_key = canvas_key
2016-11-09 23:13:22 +00:00
self._script_choice = ClientGUICommon.BetterChoice( self )
2018-01-31 22:58:15 +00:00
self._script_choice.Disable()
2016-11-09 23:13:22 +00:00
2019-06-05 19:42:39 +00:00
self._have_fetched = False
2018-01-31 22:58:15 +00:00
self._fetch_button = ClientGUICommon.BetterButton( self, 'fetch tags', self.FetchTags )
2016-11-09 23:13:22 +00:00
2018-01-31 22:58:15 +00:00
self._fetch_button.Disable()
2016-11-09 23:13:22 +00:00
2016-11-16 20:21:43 +00:00
self._script_management = ClientGUIParsing.ScriptManagementControl( self )
2016-11-09 23:13:22 +00:00
self._tags = ListBoxTagsSuggestionsFavourites( self, activate_callable, sort_tags = True )
2016-11-16 20:21:43 +00:00
self._add_all = ClientGUICommon.BetterButton( self, 'add all', self._tags.ActivateAll )
2016-11-09 23:13:22 +00:00
vbox = wx.BoxSizer( wx.VERTICAL )
2018-01-03 22:37:30 +00:00
vbox.Add( self._script_choice, CC.FLAGS_EXPAND_PERPENDICULAR )
2018-01-31 22:58:15 +00:00
vbox.Add( self._fetch_button, CC.FLAGS_EXPAND_PERPENDICULAR )
2018-01-03 22:37:30 +00:00
vbox.Add( self._script_management, CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.Add( self._add_all, CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.Add( self._tags, CC.FLAGS_EXPAND_BOTH_WAYS )
2016-11-09 23:13:22 +00:00
2016-11-16 20:21:43 +00:00
self._SetTags( [] )
2016-11-09 23:13:22 +00:00
self.SetSizer( vbox )
2016-11-16 20:21:43 +00:00
if self._canvas_key is not None:
2017-05-10 21:33:58 +00:00
HG.client_controller.sub( self, 'CanvasHasNewMedia', 'canvas_new_display_media' )
2016-11-16 20:21:43 +00:00
2018-01-31 22:58:15 +00:00
self._FetchScripts()
def _FetchScripts( self ):
def do_it():
def wx_code():
if not self:
return
script_names_to_scripts = { script.GetName() : script for script in scripts }
2019-01-09 22:59:03 +00:00
for ( name, script ) in list(script_names_to_scripts.items()):
2018-01-31 22:58:15 +00:00
self._script_choice.Append( script.GetName(), script )
new_options = HG.client_controller.new_options
favourite_file_lookup_script = new_options.GetNoneableString( 'favourite_file_lookup_script' )
if favourite_file_lookup_script in script_names_to_scripts:
self._script_choice.SelectClientData( script_names_to_scripts[ favourite_file_lookup_script ] )
else:
self._script_choice.Select( 0 )
self._script_choice.Enable()
self._fetch_button.Enable()
scripts = HG.client_controller.Read( 'serialisable_named', HydrusSerialisable.SERIALISABLE_TYPE_PARSE_ROOT_FILE_LOOKUP )
wx.CallAfter( wx_code )
HG.client_controller.CallToThread( do_it )
2016-11-16 20:21:43 +00:00
def _SetTags( self, tags ):
self._tags.SetTags( tags )
if len( tags ) == 0:
self._add_all.Disable()
else:
self._add_all.Enable()
def CanvasHasNewMedia( self, canvas_key, new_media_singleton ):
if canvas_key == self._canvas_key:
2018-08-29 20:20:41 +00:00
if new_media_singleton is not None:
self._media = ( new_media_singleton.Duplicate(), )
self._SetTags( [] )
2016-11-16 20:21:43 +00:00
2016-11-09 23:13:22 +00:00
def FetchTags( self ):
script = self._script_choice.GetChoice()
if script.UsesUserInput():
message = 'Enter the custom input for the file lookup script.'
with ClientGUIDialogs.DialogTextEntry( self, message ) as dlg:
if dlg.ShowModal() != wx.ID_OK:
return
file_identifier = dlg.GetValue()
else:
( m, ) = self._media
file_identifier = script.ConvertMediaToFileIdentifier( m )
2016-11-16 20:21:43 +00:00
stop_time = HydrusData.GetNow() + 30
job_key = ClientThreading.JobKey( cancellable = True, stop_time = stop_time )
self._script_management.SetJobKey( job_key )
2017-12-13 22:33:07 +00:00
HG.client_controller.CallToThread( self.THREADFetchTags, script, job_key, file_identifier )
2016-11-16 20:21:43 +00:00
2019-06-05 19:42:39 +00:00
def TakeFocusForUser( self ):
if self._have_fetched:
self._tags.TakeFocusForUser()
else:
self._fetch_button.SetFocus()
2017-12-13 22:33:07 +00:00
def THREADFetchTags( self, script, job_key, file_identifier ):
2016-11-16 20:21:43 +00:00
2018-01-24 23:09:42 +00:00
def wx_code( tags ):
if not self:
return
self._SetTags( tags )
2019-06-05 19:42:39 +00:00
self._have_fetched = True
2018-01-24 23:09:42 +00:00
2018-02-07 23:40:33 +00:00
parse_results = script.DoQuery( job_key, file_identifier )
2016-11-09 23:13:22 +00:00
2018-02-07 23:40:33 +00:00
tags = ClientParsing.GetTagsFromParseResults( parse_results )
2016-11-09 23:13:22 +00:00
2018-01-24 23:09:42 +00:00
wx.CallAfter( wx_code, tags )
2016-11-09 23:13:22 +00:00
2016-08-03 22:15:54 +00:00
class SuggestedTagsPanel( wx.Panel ):
2016-08-10 19:04:08 +00:00
def __init__( self, parent, service_key, media, activate_callable, canvas_key = None ):
2016-08-03 22:15:54 +00:00
wx.Panel.__init__( self, parent )
self._service_key = service_key
self._media = media
2016-08-10 19:04:08 +00:00
self._canvas_key = canvas_key
2016-08-03 22:15:54 +00:00
2017-12-06 22:06:56 +00:00
self._new_options = HG.client_controller.new_options
2016-08-03 22:15:54 +00:00
2016-11-09 23:13:22 +00:00
layout_mode = self._new_options.GetNoneableString( 'suggested_tags_layout' )
2019-06-05 19:42:39 +00:00
self._notebook = None
2016-11-09 23:13:22 +00:00
if layout_mode == 'notebook':
2019-06-05 19:42:39 +00:00
self._notebook = ClientGUICommon.BetterNotebook( self )
2016-11-09 23:13:22 +00:00
2019-06-05 19:42:39 +00:00
panel_parent = self._notebook
2016-11-09 23:13:22 +00:00
else:
panel_parent = self
2016-08-03 22:15:54 +00:00
2016-11-09 23:13:22 +00:00
panels = []
2016-08-03 22:15:54 +00:00
favourites = self._new_options.GetSuggestedTagsFavourites( service_key )
2019-06-05 19:42:39 +00:00
self._favourite_tags = None
2016-08-03 22:15:54 +00:00
if len( favourites ) > 0:
2019-06-05 19:42:39 +00:00
self._favourite_tags = ListBoxTagsSuggestionsFavourites( panel_parent, activate_callable )
2016-08-03 22:15:54 +00:00
2019-06-05 19:42:39 +00:00
self._favourite_tags.SetTags( favourites )
2016-08-03 22:15:54 +00:00
2019-06-05 19:42:39 +00:00
panels.append( ( 'favourites', self._favourite_tags ) )
2016-08-03 22:15:54 +00:00
2019-06-05 19:42:39 +00:00
self._related_tags = None
2016-08-03 22:15:54 +00:00
if self._new_options.GetBoolean( 'show_related_tags' ) and len( media ) == 1:
2019-06-05 19:42:39 +00:00
self._related_tags = RelatedTagsPanel( panel_parent, service_key, media, activate_callable, canvas_key = self._canvas_key )
2016-11-09 23:13:22 +00:00
2019-06-05 19:42:39 +00:00
panels.append( ( 'related', self._related_tags ) )
2016-08-03 22:15:54 +00:00
2016-11-09 23:13:22 +00:00
2019-06-05 19:42:39 +00:00
self._file_lookup_script_tags = None
2016-11-09 23:13:22 +00:00
if self._new_options.GetBoolean( 'show_file_lookup_script_tags' ) and len( media ) == 1:
2016-08-03 22:15:54 +00:00
2019-06-05 19:42:39 +00:00
self._file_lookup_script_tags = FileLookupScriptTagsPanel( panel_parent, service_key, media, activate_callable, canvas_key = self._canvas_key )
2016-11-09 23:13:22 +00:00
2019-06-05 19:42:39 +00:00
panels.append( ( 'file lookup scripts', self._file_lookup_script_tags ) )
2016-08-03 22:15:54 +00:00
2019-06-05 19:42:39 +00:00
self._recent_tags = None
2016-08-31 19:55:14 +00:00
if self._new_options.GetNoneableInteger( 'num_recent_tags' ) is not None:
2019-06-05 19:42:39 +00:00
self._recent_tags = RecentTagsPanel( panel_parent, service_key, activate_callable, canvas_key = self._canvas_key )
2016-08-31 19:55:14 +00:00
2019-06-05 19:42:39 +00:00
panels.append( ( 'recent', self._recent_tags ) )
2016-08-31 19:55:14 +00:00
2016-11-09 23:13:22 +00:00
if layout_mode == 'notebook':
hbox = wx.BoxSizer( wx.HORIZONTAL )
for ( name, panel ) in panels:
2019-06-05 19:42:39 +00:00
self._notebook.AddPage( panel, name )
2016-11-09 23:13:22 +00:00
2019-06-05 19:42:39 +00:00
hbox.Add( self._notebook, CC.FLAGS_EXPAND_BOTH_WAYS )
2016-11-09 23:13:22 +00:00
self.SetSizer( hbox )
elif layout_mode == 'columns':
hbox = wx.BoxSizer( wx.HORIZONTAL )
for ( name, panel ) in panels:
2018-01-03 22:37:30 +00:00
hbox.Add( panel, CC.FLAGS_EXPAND_PERPENDICULAR )
2016-11-09 23:13:22 +00:00
self.SetSizer( hbox )
2016-08-03 22:15:54 +00:00
2016-11-09 23:13:22 +00:00
if len( panels ) == 0:
2016-08-03 22:15:54 +00:00
self.Hide()
2017-02-01 21:11:17 +00:00
2019-06-05 19:42:39 +00:00
def TakeFocusForUser( self, command ):
if command == 'show_and_focus_manage_tags_favourite_tags':
panel = self._favourite_tags
elif command == 'show_and_focus_manage_tags_related_tags':
panel = self._related_tags
elif command == 'show_and_focus_manage_tags_file_lookup_script_tags':
panel = self._file_lookup_script_tags
elif command == 'show_and_focus_manage_tags_recent_tags':
panel = self._recent_tags
if panel is not None:
if self._notebook is not None:
self._notebook.SelectPage( panel )
panel.TakeFocusForUser()