2019-01-09 22:59:03 +00:00
from . import ClientCaches
from . import ClientConstants as CC
from . import ClientData
from . import ClientGUICommon
2019-06-26 21:27:18 +00:00
from . import ClientGUIFunctions
2019-01-09 22:59:03 +00:00
from . import ClientGUIListBoxes
from . import ClientGUIMenus
from . import ClientGUIShortcuts
from . import ClientSearch
2019-01-30 22:14:54 +00:00
from . import ClientThreading
2016-09-21 19:54:04 +00:00
import collections
2019-01-09 22:59:03 +00:00
from . import HydrusConstants as HC
from . import HydrusData
from . import HydrusExceptions
from . import HydrusGlobals as HG
from . import HydrusTags
2019-06-26 21:27:18 +00:00
from . import HydrusText
2016-09-21 19:54:04 +00:00
import itertools
import wx
2019-04-03 22:45:57 +00:00
import wx . lib . scrolledpanel
2016-09-21 19:54:04 +00:00
ID_TIMER_DROPDOWN_HIDE = wx . NewId ( )
ID_TIMER_AC_LAG = wx . NewId ( )
2018-01-31 22:58:15 +00:00
( SelectUpEvent , EVT_SELECT_UP ) = wx . lib . newevent . NewCommandEvent ( )
( SelectDownEvent , EVT_SELECT_DOWN ) = wx . lib . newevent . NewCommandEvent ( )
( ShowPreviousEvent , EVT_SHOW_PREVIOUS ) = wx . lib . newevent . NewCommandEvent ( )
( ShowNextEvent , EVT_SHOW_NEXT ) = wx . lib . newevent . NewCommandEvent ( )
2019-04-10 22:50:53 +00:00
def ReadFetch ( win , job_key , results_callable , parsed_search_text , wx_media_callable , file_search_context , synchronised , include_unusual_predicate_types , initial_matches_fetched , search_text_for_current_cache , cached_results , under_construction_or_predicate ) :
2019-01-30 22:14:54 +00:00
next_search_is_probably_fast = False
include_current = file_search_context . IncludeCurrentTags ( )
include_pending = file_search_context . IncludePendingTags ( )
file_service_key = file_search_context . GetFileServiceKey ( )
tag_service_key = file_search_context . GetTagServiceKey ( )
num_autocomplete_chars = HC . options [ ' num_autocomplete_chars ' ]
( raw_entry , inclusive , search_text , explicit_wildcard , cache_text , entry_predicate ) = parsed_search_text
if search_text in ( ' ' , ' : ' , ' * ' ) :
# if the user inputs '-' or similar, let's go to an empty list
if raw_entry == ' ' :
input_just_changed = search_text_for_current_cache is not None
db_not_going_to_hang_if_we_hit_it = not HG . client_controller . DBCurrentlyDoingJob ( )
if input_just_changed or db_not_going_to_hang_if_we_hit_it or not initial_matches_fetched :
if file_service_key == CC . COMBINED_FILE_SERVICE_KEY :
search_service_key = tag_service_key
else :
search_service_key = file_service_key
search_text_for_current_cache = None
cached_results = HG . client_controller . Read ( ' file_system_predicates ' , search_service_key )
matches = cached_results
else :
matches = [ ]
else :
( namespace , half_complete_subtag ) = HydrusTags . SplitTag ( search_text )
2019-04-17 21:51:50 +00:00
siblings_manager = HG . client_controller . tag_siblings_manager
2019-01-30 22:14:54 +00:00
if False and half_complete_subtag == ' ' :
search_text_for_current_cache = None
matches = [ ] # a query like 'namespace:'
else :
fetch_from_db = True
if synchronised and wx_media_callable is not None :
try :
media = HG . client_controller . CallBlockingToWX ( win , wx_media_callable )
except HydrusExceptions . WXDeadWindowException :
return
can_fetch_from_media = media is not None and len ( media ) > 0
if can_fetch_from_media :
fetch_from_db = False
if fetch_from_db :
# if user searches 'blah', then we include 'blah (23)' for 'series:blah (10)', 'blah (13)'
# if they search for 'series:blah', then we don't!
add_namespaceless = ' : ' not in namespace
small_and_specific_search = cache_text is not None and len ( cache_text ) < num_autocomplete_chars
if small_and_specific_search :
predicates = HG . client_controller . Read ( ' autocomplete_predicates ' , file_service_key = file_service_key , tag_service_key = tag_service_key , search_text = cache_text , exact_match = True , inclusive = inclusive , include_current = include_current , include_pending = include_pending , add_namespaceless = add_namespaceless , job_key = job_key , collapse_siblings = True )
else :
cache_invalid_for_this_search = cache_text is None or search_text_for_current_cache is None or not cache_text . startswith ( search_text_for_current_cache )
if cache_invalid_for_this_search :
new_search_text_for_current_cache = cache_text
cached_results = HG . client_controller . Read ( ' autocomplete_predicates ' , file_service_key = file_service_key , tag_service_key = tag_service_key , search_text = search_text , inclusive = inclusive , include_current = include_current , include_pending = include_pending , add_namespaceless = add_namespaceless , job_key = job_key , collapse_siblings = True )
predicates = cached_results
next_search_is_probably_fast = True
else :
# it is possible that media will change between calls to this, so don't cache it
# it's also quick as hell, so who cares
tags_managers = [ ]
for m in media :
if m . IsCollection ( ) :
tags_managers . extend ( m . GetSingletonsTagsManagers ( ) )
else :
tags_managers . append ( m . GetTagsManager ( ) )
tags_to_do = set ( )
current_tags_to_count = collections . Counter ( )
pending_tags_to_count = collections . Counter ( )
if include_current :
lists_of_current_tags = [ list ( tags_manager . GetCurrent ( tag_service_key ) ) for tags_manager in tags_managers ]
current_tags_flat_iterable = itertools . chain . from_iterable ( lists_of_current_tags )
current_tags_flat = ClientSearch . FilterTagsBySearchText ( tag_service_key , search_text , current_tags_flat_iterable )
current_tags_to_count . update ( current_tags_flat )
tags_to_do . update ( list ( current_tags_to_count . keys ( ) ) )
if include_pending :
lists_of_pending_tags = [ list ( tags_manager . GetPending ( tag_service_key ) ) for tags_manager in tags_managers ]
pending_tags_flat_iterable = itertools . chain . from_iterable ( lists_of_pending_tags )
pending_tags_flat = ClientSearch . FilterTagsBySearchText ( tag_service_key , search_text , pending_tags_flat_iterable )
pending_tags_to_count . update ( pending_tags_flat )
tags_to_do . update ( list ( pending_tags_to_count . keys ( ) ) )
predicates = [ ClientSearch . Predicate ( HC . PREDICATE_TYPE_TAG , tag , inclusive , current_tags_to_count [ tag ] , pending_tags_to_count [ tag ] ) for tag in tags_to_do ]
if tag_service_key != CC . COMBINED_TAG_SERVICE_KEY :
predicates = siblings_manager . CollapsePredicates ( tag_service_key , predicates )
if namespace == ' ' :
predicates = ClientData . MergePredicates ( predicates , add_namespaceless = True )
next_search_is_probably_fast = True
matches = ClientSearch . FilterPredicatesBySearchText ( tag_service_key , search_text , predicates )
matches = ClientSearch . SortPredicates ( matches )
if include_unusual_predicate_types :
if explicit_wildcard :
matches . insert ( 0 , ClientSearch . Predicate ( HC . PREDICATE_TYPE_WILDCARD , search_text , inclusive ) )
else :
if namespace != ' ' and half_complete_subtag in ( ' ' , ' * ' ) :
matches . insert ( 0 , ClientSearch . Predicate ( HC . PREDICATE_TYPE_NAMESPACE , namespace , inclusive ) )
for match in matches :
if match . GetInclusive ( ) != inclusive :
match . SetInclusive ( inclusive )
try :
index = matches . index ( entry_predicate )
predicate = matches [ index ]
del matches [ index ]
matches . insert ( 0 , predicate )
except :
pass
2019-04-10 22:50:53 +00:00
if under_construction_or_predicate is not None :
matches . insert ( 0 , under_construction_or_predicate )
2019-01-30 22:14:54 +00:00
if job_key . IsCancelled ( ) :
return
HG . client_controller . CallLaterWXSafe ( win , 0.0 , results_callable , job_key , search_text , search_text_for_current_cache , cached_results , matches , next_search_is_probably_fast )
def PutAtTopOfMatches ( matches , predicate ) :
try :
index = matches . index ( predicate )
predicate = matches [ index ]
matches . remove ( predicate )
except ValueError :
pass
matches . insert ( 0 , predicate )
def WriteFetch ( win , job_key , results_callable , parsed_search_text , file_service_key , tag_service_key , expand_parents , search_text_for_current_cache , cached_results ) :
next_search_is_probably_fast = False
num_autocomplete_chars = HC . options [ ' num_autocomplete_chars ' ]
( raw_entry , search_text , cache_text , entry_predicate , sibling_predicate ) = parsed_search_text
if search_text in ( ' ' , ' : ' , ' * ' ) :
search_text_for_current_cache = None
matches = [ ]
else :
must_do_a_search = False
small_and_specific_search = cache_text is not None and len ( cache_text ) < num_autocomplete_chars
if small_and_specific_search :
predicates = HG . client_controller . Read ( ' autocomplete_predicates ' , file_service_key = file_service_key , tag_service_key = tag_service_key , search_text = cache_text , exact_match = True , add_namespaceless = False , job_key = job_key , collapse_siblings = False )
else :
cache_invalid_for_this_search = cache_text is None or search_text_for_current_cache is None or not cache_text . startswith ( search_text_for_current_cache )
if must_do_a_search or cache_invalid_for_this_search :
search_text_for_current_cache = cache_text
cached_results = HG . client_controller . Read ( ' autocomplete_predicates ' , file_service_key = file_service_key , tag_service_key = tag_service_key , search_text = search_text , add_namespaceless = False , job_key = job_key , collapse_siblings = False )
predicates = cached_results
next_search_is_probably_fast = True
matches = ClientSearch . FilterPredicatesBySearchText ( tag_service_key , search_text , predicates )
matches = ClientSearch . SortPredicates ( matches )
PutAtTopOfMatches ( matches , entry_predicate )
if sibling_predicate is not None :
PutAtTopOfMatches ( matches , sibling_predicate )
if expand_parents :
2019-04-17 21:51:50 +00:00
parents_manager = HG . client_controller . tag_parents_manager
2019-01-30 22:14:54 +00:00
matches = parents_manager . ExpandPredicates ( tag_service_key , matches )
HG . client_controller . CallLaterWXSafe ( win , 0.0 , results_callable , job_key , search_text , search_text_for_current_cache , cached_results , matches , next_search_is_probably_fast )
2016-09-21 19:54:04 +00:00
# much of this is based on the excellent TexCtrlAutoComplete class by Edward Flick, Michele Petrazzo and Will Sadkin, just with plenty of simplification and integration into hydrus
class AutoCompleteDropdown ( wx . Panel ) :
def __init__ ( self , parent ) :
wx . Panel . __init__ ( self , parent )
self . _intercept_key_events = True
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
# I think it is something to do with the initialisation order; if the frame is init'ed before the ShowModal call, but whatever.
# This turned out to be ugly when I added the manage tags frame, so I've set it to if the tlp has a parent, which basically means "not the main gui"
2018-02-21 21:59:37 +00:00
not_main_gui = tlp . GetParent ( ) is not None
2019-02-27 23:03:30 +00:00
if not_main_gui or HC . options [ ' always_embed_autocompletes ' ] or not HC . PLATFORM_WINDOWS :
2016-09-21 19:54:04 +00:00
self . _float_mode = False
else :
self . _float_mode = True
2019-05-15 20:35:00 +00:00
self . _text_ctrl = wx . TextCtrl ( self , style = wx . TE_PROCESS_ENTER )
2016-09-21 19:54:04 +00:00
2017-09-20 19:47:31 +00:00
self . _UpdateBackgroundColour ( )
2016-09-21 19:54:04 +00:00
self . _last_attempted_dropdown_width = 0
self . _last_attempted_dropdown_position = ( None , None )
2018-02-21 21:59:37 +00:00
self . _last_move_event_started = 0.0
self . _last_move_event_occurred = 0.0
2016-09-21 19:54:04 +00:00
if self . _float_mode :
self . _text_ctrl . Bind ( wx . EVT_SET_FOCUS , self . EventSetFocus )
self . _text_ctrl . Bind ( wx . EVT_KILL_FOCUS , self . EventKillFocus )
self . _text_ctrl . Bind ( wx . EVT_TEXT , self . EventText )
2017-04-19 20:58:30 +00:00
self . _text_ctrl . Bind ( wx . EVT_CHAR_HOOK , self . EventCharHook )
2016-09-21 19:54:04 +00:00
self . _text_ctrl . Bind ( wx . EVT_MOUSEWHEEL , self . EventMouseWheel )
vbox = wx . BoxSizer ( wx . VERTICAL )
2019-06-26 21:27:18 +00:00
self . _text_input_hbox = wx . BoxSizer ( wx . HORIZONTAL )
self . _text_input_hbox . Add ( self . _text_ctrl , CC . FLAGS_VCENTER_EXPAND_DEPTH_ONLY )
vbox . Add ( self . _text_input_hbox , CC . FLAGS_EXPAND_SIZER_PERPENDICULAR )
2016-09-21 19:54:04 +00:00
#self._dropdown_window = wx.PopupWindow( self, flags = wx.BORDER_RAISED )
#self._dropdown_window = wx.PopupTransientWindow( self, style = wx.BORDER_RAISED )
#self._dropdown_window = wx.Window( self, style = wx.BORDER_RAISED )
#self._dropdown_window = wx.Panel( self )
if self . _float_mode :
self . _dropdown_window = wx . Frame ( self , style = wx . FRAME_TOOL_WINDOW | wx . FRAME_NO_TASKBAR | wx . FRAME_FLOAT_ON_PARENT | wx . BORDER_RAISED )
self . _dropdown_window . SetBackgroundColour ( wx . SystemSettings . GetColour ( wx . SYS_COLOUR_FRAMEBK ) )
2019-06-26 21:27:18 +00:00
self . _dropdown_window . SetPosition ( ClientGUIFunctions . ClientToScreen ( self . _text_ctrl , ( 0 , 0 ) ) )
2016-09-21 19:54:04 +00:00
self . _dropdown_window . Bind ( wx . EVT_CLOSE , self . EventCloseDropdown )
self . _dropdown_hidden = True
2018-05-23 21:05:06 +00:00
self . _list_height_num_chars = 19
2016-09-21 19:54:04 +00:00
else :
self . _dropdown_window = wx . Panel ( self )
2018-10-31 21:41:14 +00:00
self . _list_height_num_chars = 8
2016-09-21 19:54:04 +00:00
2018-03-28 21:55:58 +00:00
self . _dropdown_notebook = wx . Notebook ( self . _dropdown_window )
#
self . _search_results_list = self . _InitSearchResultsList ( )
self . _dropdown_notebook . AddPage ( self . _search_results_list , ' results ' , True )
#
2016-09-21 19:54:04 +00:00
2018-02-07 23:40:33 +00:00
if not self . _float_mode :
vbox . Add ( self . _dropdown_window , CC . FLAGS_EXPAND_BOTH_WAYS )
2016-09-21 19:54:04 +00:00
self . SetSizer ( vbox )
2019-01-30 22:14:54 +00:00
self . _last_fetched_search_text = ' '
self . _next_search_is_probably_fast = False
self . _search_text_for_current_cache = None
2016-09-21 19:54:04 +00:00
self . _cached_results = [ ]
2019-01-30 22:14:54 +00:00
self . _current_fetch_job_key = None
2016-09-21 19:54:04 +00:00
self . _initial_matches_fetched = False
2018-02-14 21:47:18 +00:00
self . _move_hide_job = None
2019-01-30 22:14:54 +00:00
self . _refresh_list_job = None
2018-01-03 22:37:30 +00:00
2016-09-21 19:54:04 +00:00
if self . _float_mode :
self . Bind ( wx . EVT_MOVE , self . EventMove )
self . Bind ( wx . EVT_SIZE , self . EventMove )
2018-02-21 21:59:37 +00:00
HG . client_controller . sub ( self , ' _ParentMovedOrResized ' , ' main_gui_move_event ' )
2016-09-21 19:54:04 +00:00
parent = self
while True :
try :
parent = parent . GetParent ( )
if isinstance ( parent , wx . ScrolledWindow ) :
parent . Bind ( wx . EVT_SCROLLWIN , self . EventMove )
except :
break
2017-09-20 19:47:31 +00:00
HG . client_controller . sub ( self , ' _UpdateBackgroundColour ' , ' notify_new_colourset ' )
2018-06-27 19:27:05 +00:00
HG . client_controller . sub ( self , ' DoDropdownHideShow ' , ' notify_page_change ' )
2017-09-20 19:47:31 +00:00
2018-02-14 21:47:18 +00:00
self . _ScheduleListRefresh ( 0.0 )
2016-09-21 19:54:04 +00:00
2019-04-03 22:45:57 +00:00
def _BroadcastChoices ( self , predicates , shift_down ) :
2016-09-21 19:54:04 +00:00
raise NotImplementedError ( )
2019-04-03 22:45:57 +00:00
def _BroadcastCurrentText ( self , shift_down ) :
2016-09-21 19:54:04 +00:00
text = self . _text_ctrl . GetValue ( )
2019-04-03 22:45:57 +00:00
self . _BroadcastChoices ( { text } , shift_down )
2016-09-21 19:54:04 +00:00
2019-06-19 22:08:48 +00:00
def _CancelCurrentResultsFetchJob ( self ) :
if self . _current_fetch_job_key is not None :
self . _current_fetch_job_key . Cancel ( )
2018-02-14 21:47:18 +00:00
def _CancelScheduledListRefresh ( self ) :
if self . _refresh_list_job is not None :
self . _refresh_list_job . Cancel ( )
2018-05-23 21:05:06 +00:00
def _ClearInput ( self ) :
self . _text_ctrl . SetValue ( ' ' )
2019-04-10 22:50:53 +00:00
self . _SetResultsToList ( [ ] )
2018-05-23 21:05:06 +00:00
self . _ScheduleListRefresh ( 0.0 )
2018-02-28 22:30:36 +00:00
def _DropdownHideShow ( self ) :
if not self . _float_mode :
return
try :
if self . _ShouldShow ( ) :
self . _ShowDropdown ( )
if self . _move_hide_job is not None :
self . _move_hide_job . Cancel ( )
self . _move_hide_job = None
else :
self . _HideDropdown ( )
except :
if self . _move_hide_job is not None :
self . _move_hide_job . Cancel ( )
self . _move_hide_job = None
raise
2019-04-10 22:50:53 +00:00
def _HandleEscape ( self ) :
if self . _float_mode :
self . GetTopLevelParent ( ) . SetFocus ( )
return True
else :
return False
2016-09-21 19:54:04 +00:00
def _HideDropdown ( self ) :
if not self . _dropdown_hidden :
2018-03-28 21:55:58 +00:00
self . _dropdown_window . Hide ( )
2016-09-21 19:54:04 +00:00
self . _dropdown_hidden = True
2018-03-28 21:55:58 +00:00
def _InitSearchResultsList ( self ) :
raise NotImplementedError ( )
2018-02-21 21:59:37 +00:00
def _ParentMovedOrResized ( self ) :
if self . _float_mode :
if HydrusData . TimeHasPassedFloat ( self . _last_move_event_occurred + 1.0 ) :
self . _last_move_event_started = HydrusData . GetNowFloat ( )
self . _last_move_event_occurred = HydrusData . GetNowFloat ( )
# we'll do smoother move updates for a little bit to stop flickeryness, but after that we'll just hide
NICE_ANIMATION_GRACE_PERIOD = 0.25
time_to_delay_these_calls = HydrusData . TimeHasPassedFloat ( self . _last_move_event_started + NICE_ANIMATION_GRACE_PERIOD )
if time_to_delay_these_calls :
self . _HideDropdown ( )
if self . _ShouldShow ( ) :
if self . _move_hide_job is None :
2018-05-16 20:09:50 +00:00
self . _move_hide_job = HG . client_controller . CallRepeatingWXSafe ( self . _dropdown_window , 0.0 , 0.25 , self . _DropdownHideShow )
2018-02-21 21:59:37 +00:00
self . _move_hide_job . Delay ( 0.25 )
else :
2018-02-28 22:30:36 +00:00
self . _DropdownHideShow ( )
2018-02-21 21:59:37 +00:00
2018-02-14 21:47:18 +00:00
def _ScheduleListRefresh ( self , delay ) :
if self . _refresh_list_job is not None and delay == 0.0 :
2018-05-16 20:09:50 +00:00
self . _refresh_list_job . Wake ( )
2018-02-14 21:47:18 +00:00
else :
self . _CancelScheduledListRefresh ( )
2018-03-28 21:55:58 +00:00
self . _refresh_list_job = HG . client_controller . CallLaterWXSafe ( self , delay , self . _UpdateSearchResultsList )
2018-02-14 21:47:18 +00:00
def _SetListDirty ( self ) :
2019-01-30 22:14:54 +00:00
self . _search_text_for_current_cache = None
2018-02-14 21:47:18 +00:00
self . _ScheduleListRefresh ( 0.0 )
2019-01-30 22:14:54 +00:00
def _SetResultsToList ( self , results ) :
raise NotImplementedError ( )
2016-09-21 19:54:04 +00:00
def _ShouldShow ( self ) :
tlp_active = self . GetTopLevelParent ( ) . IsActive ( ) or self . _dropdown_window . IsActive ( )
if HC . PLATFORM_LINUX :
tlp = self . GetTopLevelParent ( )
if isinstance ( tlp , wx . Dialog ) :
visible = True
else :
# notebook on linux doesn't 'hide' things apparently, so isshownonscreen, which recursively tests parents' hide status, doesn't work!
2017-05-10 21:33:58 +00:00
gui = HG . client_controller . GetGUI ( )
2016-09-21 19:54:04 +00:00
current_page = gui . GetCurrentPage ( )
2019-06-26 21:27:18 +00:00
visible = ClientGUIFunctions . IsWXAncestor ( self , current_page )
2016-09-21 19:54:04 +00:00
else :
visible = self . _text_ctrl . IsShownOnScreen ( )
2019-06-26 21:27:18 +00:00
focus_remains_on_self_or_children = ClientGUIFunctions . WindowOrAnyTLPChildHasFocus ( self )
2016-09-21 19:54:04 +00:00
return tlp_active and visible and focus_remains_on_self_or_children
def _ShouldTakeResponsibilityForEnter ( self ) :
raise NotImplementedError ( )
def _ShowDropdown ( self ) :
( text_width , text_height ) = self . _text_ctrl . GetSize ( )
2017-05-31 21:50:53 +00:00
if self . _text_ctrl . IsShown ( ) :
2016-09-21 19:54:04 +00:00
2019-06-26 21:27:18 +00:00
desired_dropdown_position = ClientGUIFunctions . ClientToScreen ( self . _text_ctrl , ( - 2 , text_height - 2 ) )
2016-09-21 19:54:04 +00:00
2017-05-31 21:50:53 +00:00
if self . _last_attempted_dropdown_position != desired_dropdown_position :
self . _dropdown_window . SetPosition ( desired_dropdown_position )
self . _last_attempted_dropdown_position = desired_dropdown_position
2016-09-21 19:54:04 +00:00
#
show_and_fit_needed = False
if self . _dropdown_hidden :
2018-03-28 21:55:58 +00:00
self . _dropdown_window . Show ( )
2016-09-21 19:54:04 +00:00
2018-03-28 21:55:58 +00:00
self . _dropdown_hidden = False
2016-09-21 19:54:04 +00:00
2018-03-28 21:55:58 +00:00
if text_width != self . _last_attempted_dropdown_width :
show_and_fit_needed = True
2016-09-21 19:54:04 +00:00
self . _dropdown_window . Fit ( )
self . _dropdown_window . SetSize ( ( text_width , - 1 ) )
self . _dropdown_window . Layout ( )
self . _last_attempted_dropdown_width = text_width
2019-01-30 22:14:54 +00:00
def _StartResultsFetchJob ( self , job_key ) :
raise NotImplementedError ( )
2019-04-03 22:45:57 +00:00
def _TakeResponsibilityForEnter ( self , shift_down ) :
2016-09-21 19:54:04 +00:00
raise NotImplementedError ( )
2017-09-20 19:47:31 +00:00
def _UpdateBackgroundColour ( self ) :
2017-12-06 22:06:56 +00:00
colour = HG . client_controller . new_options . GetColour ( CC . COLOUR_AUTOCOMPLETE_BACKGROUND )
2017-09-20 19:47:31 +00:00
if not self . _intercept_key_events :
colour = ClientData . GetLighterDarkerColour ( colour )
self . _text_ctrl . SetBackgroundColour ( colour )
self . _text_ctrl . Refresh ( )
2018-03-28 21:55:58 +00:00
def _UpdateSearchResultsList ( self ) :
2016-09-21 19:54:04 +00:00
2019-01-30 22:14:54 +00:00
self . _refresh_list_job = None
2019-06-19 22:08:48 +00:00
self . _CancelCurrentResultsFetchJob ( )
2019-01-30 22:14:54 +00:00
self . _current_fetch_job_key = ClientThreading . JobKey ( cancellable = True )
self . _StartResultsFetchJob ( self . _current_fetch_job_key )
2016-09-21 19:54:04 +00:00
2019-04-10 22:50:53 +00:00
def BroadcastChoices ( self , predicates , shift_down = False ) :
2019-04-03 22:45:57 +00:00
self . _BroadcastChoices ( predicates , shift_down )
2016-09-21 19:54:04 +00:00
2019-06-19 22:08:48 +00:00
def CancelCurrentResultsFetchJob ( self ) :
self . _CancelCurrentResultsFetchJob ( )
2018-06-27 19:27:05 +00:00
def DoDropdownHideShow ( self ) :
self . _DropdownHideShow ( )
2017-04-19 20:58:30 +00:00
def EventCharHook ( self , event ) :
2016-09-21 19:54:04 +00:00
2017-05-10 21:33:58 +00:00
HG . client_controller . ResetIdleTimer ( )
2016-09-21 19:54:04 +00:00
2018-05-16 20:09:50 +00:00
( modifier , key ) = ClientGUIShortcuts . ConvertKeyEventToSimpleTuple ( event )
2017-04-05 21:16:40 +00:00
if key in ( wx . WXK_INSERT , wx . WXK_NUMPAD_INSERT ) :
2016-09-21 19:54:04 +00:00
2017-09-20 19:47:31 +00:00
self . _intercept_key_events = not self . _intercept_key_events
2017-09-13 20:50:41 +00:00
2017-09-20 19:47:31 +00:00
self . _UpdateBackgroundColour ( )
2016-09-21 19:54:04 +00:00
2017-04-05 21:16:40 +00:00
elif key == wx . WXK_SPACE and event . RawControlDown ( ) : # this is control, not command on os x, for which command+space does some os stuff
2016-09-21 19:54:04 +00:00
2018-02-14 21:47:18 +00:00
self . _ScheduleListRefresh ( 0.0 )
2016-09-21 19:54:04 +00:00
elif self . _intercept_key_events :
2018-03-28 21:55:58 +00:00
send_input_to_current_list = False
current_results_list = self . _dropdown_notebook . GetCurrentPage ( )
current_list_is_empty = len ( current_results_list ) == 0
input_is_empty = self . _text_ctrl . GetValue ( ) == ' '
2017-04-05 21:16:40 +00:00
if key in ( ord ( ' A ' ) , ord ( ' a ' ) ) and modifier == wx . ACCEL_CTRL :
2016-09-21 19:54:04 +00:00
event . Skip ( )
2017-04-05 21:16:40 +00:00
elif key in ( wx . WXK_RETURN , wx . WXK_NUMPAD_ENTER ) and self . _ShouldTakeResponsibilityForEnter ( ) :
2016-09-21 19:54:04 +00:00
2019-04-03 22:45:57 +00:00
shift_down = modifier == wx . ACCEL_SHIFT
self . _TakeResponsibilityForEnter ( shift_down )
2016-09-21 19:54:04 +00:00
2018-03-28 21:55:58 +00:00
elif input_is_empty : # maybe we should be sending a 'move' event to a different place
2016-09-21 19:54:04 +00:00
2018-03-28 21:55:58 +00:00
if key in ( wx . WXK_UP , wx . WXK_NUMPAD_UP , wx . WXK_DOWN , wx . WXK_NUMPAD_DOWN ) and current_list_is_empty :
2017-09-20 19:47:31 +00:00
2018-03-28 21:55:58 +00:00
if key in ( wx . WXK_UP , wx . WXK_NUMPAD_UP ) :
new_event = SelectUpEvent ( - 1 )
elif key in ( wx . WXK_DOWN , wx . WXK_NUMPAD_DOWN ) :
new_event = SelectDownEvent ( - 1 )
2017-09-20 19:47:31 +00:00
2018-03-28 21:55:58 +00:00
wx . QueueEvent ( self . GetEventHandler ( ) , new_event )
2017-09-20 19:47:31 +00:00
2018-03-28 21:55:58 +00:00
elif key in ( wx . WXK_PAGEDOWN , wx . WXK_NUMPAD_PAGEDOWN , wx . WXK_PAGEUP , wx . WXK_NUMPAD_PAGEUP ) and current_list_is_empty :
2017-09-20 19:47:31 +00:00
2018-03-28 21:55:58 +00:00
if key in ( wx . WXK_PAGEUP , wx . WXK_NUMPAD_PAGEUP ) :
new_event = ShowPreviousEvent ( - 1 )
elif key in ( wx . WXK_PAGEDOWN , wx . WXK_NUMPAD_PAGEDOWN ) :
new_event = ShowNextEvent ( - 1 )
2016-09-21 19:54:04 +00:00
2018-03-28 21:55:58 +00:00
wx . QueueEvent ( self . GetEventHandler ( ) , new_event )
2016-09-21 19:54:04 +00:00
2018-03-28 21:55:58 +00:00
elif key in ( wx . WXK_LEFT , wx . WXK_NUMPAD_LEFT , wx . WXK_RIGHT , wx . WXK_NUMPAD_RIGHT ) :
2016-09-21 19:54:04 +00:00
2018-03-28 21:55:58 +00:00
if key in ( wx . WXK_LEFT , wx . WXK_NUMPAD_LEFT ) :
direction = - 1
elif key in ( wx . WXK_RIGHT , wx . WXK_NUMPAD_RIGHT ) :
direction = 1
self . MoveNotebookPageFocus ( direction = direction )
2019-04-10 22:50:53 +00:00
elif key == wx . WXK_ESCAPE :
escape_caught = self . _HandleEscape ( )
if not escape_caught :
send_input_to_current_list = True
2018-03-28 21:55:58 +00:00
else :
send_input_to_current_list = True
2016-09-21 19:54:04 +00:00
else :
2018-03-28 21:55:58 +00:00
send_input_to_current_list = True
if send_input_to_current_list :
2018-02-21 21:59:37 +00:00
# Don't say QueueEvent here--it duplicates the event processing at higher levels, leading to 2 x F9, for instance
2018-03-28 21:55:58 +00:00
current_results_list . EventCharHook ( event ) # ultimately, this typically skips the event, letting the text ctrl take it
2016-09-21 19:54:04 +00:00
else :
event . Skip ( )
2017-04-19 20:58:30 +00:00
def EventCloseDropdown ( self , event ) :
2017-05-10 21:33:58 +00:00
HG . client_controller . GetGUI ( ) . Close ( )
2017-04-19 20:58:30 +00:00
2016-09-21 19:54:04 +00:00
def EventKillFocus ( self , event ) :
2018-02-14 21:47:18 +00:00
if self . _float_mode :
2018-01-03 22:37:30 +00:00
2018-02-28 22:30:36 +00:00
self . _DropdownHideShow ( )
2018-01-03 22:37:30 +00:00
2016-09-21 19:54:04 +00:00
event . Skip ( )
def EventMouseWheel ( self , event ) :
2018-03-28 21:55:58 +00:00
current_results_list = self . _dropdown_notebook . GetCurrentPage ( )
if self . _text_ctrl . GetValue ( ) == ' ' and len ( current_results_list ) == 0 :
2016-09-21 19:54:04 +00:00
2018-01-31 22:58:15 +00:00
if event . GetWheelRotation ( ) > 0 :
new_event = SelectUpEvent ( - 1 )
else :
new_event = SelectDownEvent ( - 1 )
2016-09-21 19:54:04 +00:00
2018-02-21 21:59:37 +00:00
wx . QueueEvent ( self . GetEventHandler ( ) , new_event )
2016-09-21 19:54:04 +00:00
else :
if event . CmdDown ( ) :
2017-04-19 20:58:30 +00:00
if event . GetWheelRotation ( ) > 0 :
2018-03-28 21:55:58 +00:00
current_results_list . MoveSelectionUp ( )
2017-04-19 20:58:30 +00:00
else :
2018-03-28 21:55:58 +00:00
current_results_list . MoveSelectionDown ( )
2017-04-19 20:58:30 +00:00
2016-09-21 19:54:04 +00:00
else :
# for some reason, the scrolledwindow list doesn't process scroll events properly when in a popupwindow
# so let's just tell it to scroll manually
2018-03-28 21:55:58 +00:00
( start_x , start_y ) = current_results_list . GetViewStart ( )
2016-09-21 19:54:04 +00:00
2018-03-28 21:55:58 +00:00
if event . GetWheelRotation ( ) > 0 :
current_results_list . Scroll ( - 1 , start_y - 3 )
else :
current_results_list . Scroll ( - 1 , start_y + 3 )
2016-09-21 19:54:04 +00:00
2018-03-28 21:55:58 +00:00
if event . GetWheelRotation ( ) > 0 :
command_type = wx . wxEVT_SCROLLWIN_LINEUP
else :
command_type = wx . wxEVT_SCROLLWIN_LINEDOWN
2016-09-21 19:54:04 +00:00
2018-03-28 21:55:58 +00:00
wx . QueueEvent ( current_results_list . GetEventHandler ( ) , wx . ScrollWinEvent ( command_type ) )
2016-09-21 19:54:04 +00:00
def EventMove ( self , event ) :
2018-02-21 21:59:37 +00:00
self . _ParentMovedOrResized ( )
2016-09-21 19:54:04 +00:00
event . Skip ( )
def EventSetFocus ( self , event ) :
2018-02-14 21:47:18 +00:00
if self . _float_mode :
2018-01-03 22:37:30 +00:00
2018-02-28 22:30:36 +00:00
self . _DropdownHideShow ( )
2018-01-03 22:37:30 +00:00
2016-09-21 19:54:04 +00:00
event . Skip ( )
def EventText ( self , event ) :
num_chars = len ( self . _text_ctrl . GetValue ( ) )
if num_chars == 0 :
2018-02-14 21:47:18 +00:00
self . _ScheduleListRefresh ( 0.0 )
2016-09-21 19:54:04 +00:00
2018-03-28 21:55:58 +00:00
else :
2016-09-21 19:54:04 +00:00
2018-03-28 21:55:58 +00:00
if HC . options [ ' fetch_ac_results_automatically ' ] :
2018-02-07 23:40:33 +00:00
2018-03-28 21:55:58 +00:00
( char_limit , long_wait , short_wait ) = HC . options [ ' ac_timings ' ]
2018-02-07 23:40:33 +00:00
2019-01-30 22:14:54 +00:00
self . _next_search_is_probably_fast = self . _next_search_is_probably_fast and num_chars > len ( self . _last_fetched_search_text )
2016-09-21 19:54:04 +00:00
2018-03-28 21:55:58 +00:00
if self . _next_search_is_probably_fast :
self . _ScheduleListRefresh ( 0.0 )
elif num_chars < char_limit :
self . _ScheduleListRefresh ( long_wait / 1000.0 )
else :
self . _ScheduleListRefresh ( short_wait / 1000.0 )
2016-09-21 19:54:04 +00:00
2018-03-28 21:55:58 +00:00
if self . _dropdown_notebook . GetCurrentPage ( ) != self . _search_results_list :
2016-09-21 19:54:04 +00:00
2018-03-28 21:55:58 +00:00
self . MoveNotebookPageFocus ( index = 0 )
2018-01-03 22:37:30 +00:00
2016-09-21 19:54:04 +00:00
2018-02-21 21:59:37 +00:00
def ForceSizeCalcNow ( self ) :
2018-02-28 22:30:36 +00:00
if self . _float_mode :
self . _DropdownHideShow ( )
2018-02-21 21:59:37 +00:00
2018-03-28 21:55:58 +00:00
def MoveNotebookPageFocus ( self , index = None , direction = None ) :
new_index = None
if index is not None :
new_index = index
elif direction is not None :
current_index = self . _dropdown_notebook . GetSelection ( )
if current_index is not None and current_index != wx . NOT_FOUND :
number_of_pages = self . _dropdown_notebook . GetPageCount ( )
new_index = ( current_index + direction ) % number_of_pages # does wraparound
if new_index is not None :
self . _dropdown_notebook . ChangeSelection ( new_index )
self . _text_ctrl . SetFocus ( )
2019-01-30 22:14:54 +00:00
def SetFetchedResults ( self , job_key , search_text , search_text_for_cache , cached_results , results ) :
2018-03-28 21:55:58 +00:00
2019-01-30 22:14:54 +00:00
if self . _current_fetch_job_key is not None and self . _current_fetch_job_key . GetKey ( ) == job_key . GetKey ( ) :
self . _last_fetched_search_text = search_text
self . _search_text_for_current_cache = search_text_for_cache
self . _cached_results = cached_results
self . _current_fetch_job_key = None
self . _initial_matches_fetched = True
self . _SetResultsToList ( results )
2018-03-28 21:55:58 +00:00
2018-05-16 20:09:50 +00:00
def SetFocus ( self ) :
if HC . PLATFORM_OSX :
wx . CallAfter ( self . _text_ctrl . SetFocus )
else :
self . _text_ctrl . SetFocus ( )
2016-09-21 19:54:04 +00:00
class AutoCompleteDropdownTags ( AutoCompleteDropdown ) :
def __init__ ( self , parent , file_service_key , tag_service_key ) :
self . _file_service_key = file_service_key
self . _tag_service_key = tag_service_key
AutoCompleteDropdown . __init__ ( self , parent )
2019-04-24 22:18:50 +00:00
self . _allow_all_known_files = True
2017-06-28 20:23:21 +00:00
file_service = HG . client_controller . services_manager . GetService ( self . _file_service_key )
2016-12-21 22:30:54 +00:00
2017-06-28 20:23:21 +00:00
tag_service = HG . client_controller . services_manager . GetService ( self . _tag_service_key )
2016-09-21 19:54:04 +00:00
2016-10-26 20:45:34 +00:00
self . _file_repo_button = ClientGUICommon . BetterButton ( self . _dropdown_window , file_service . GetName ( ) , self . FileButtonHit )
2016-09-21 19:54:04 +00:00
self . _file_repo_button . SetMinSize ( ( 20 , - 1 ) )
2016-10-26 20:45:34 +00:00
self . _tag_repo_button = ClientGUICommon . BetterButton ( self . _dropdown_window , tag_service . GetName ( ) , self . TagButtonHit )
2016-09-21 19:54:04 +00:00
self . _tag_repo_button . SetMinSize ( ( 20 , - 1 ) )
2019-01-30 22:14:54 +00:00
self . _favourites_list = self . _InitFavouritesList ( )
self . RefreshFavouriteTags ( )
self . _dropdown_notebook . AddPage ( self . _favourites_list , ' favourites ' , False )
#
HG . client_controller . sub ( self , ' RefreshFavouriteTags ' , ' notify_new_favourite_tags ' )
2016-09-21 19:54:04 +00:00
def _ChangeFileService ( self , file_service_key ) :
if file_service_key == CC . COMBINED_FILE_SERVICE_KEY and self . _tag_service_key == CC . COMBINED_TAG_SERVICE_KEY :
self . _ChangeTagService ( CC . LOCAL_TAG_SERVICE_KEY )
self . _file_service_key = file_service_key
2017-06-28 20:23:21 +00:00
file_service = HG . client_controller . services_manager . GetService ( self . _file_service_key )
2016-09-21 19:54:04 +00:00
name = file_service . GetName ( )
self . _file_repo_button . SetLabelText ( name )
2018-02-14 21:47:18 +00:00
self . _SetListDirty ( )
2016-09-21 19:54:04 +00:00
def _ChangeTagService ( self , tag_service_key ) :
if tag_service_key == CC . COMBINED_TAG_SERVICE_KEY and self . _file_service_key == CC . COMBINED_FILE_SERVICE_KEY :
self . _ChangeFileService ( CC . LOCAL_FILE_SERVICE_KEY )
self . _tag_service_key = tag_service_key
2018-03-28 21:55:58 +00:00
self . _search_results_list . SetTagService ( self . _tag_service_key )
2016-09-21 19:54:04 +00:00
2017-06-28 20:23:21 +00:00
tag_service = tag_service = HG . client_controller . services_manager . GetService ( self . _tag_service_key )
2016-09-21 19:54:04 +00:00
name = tag_service . GetName ( )
self . _tag_repo_button . SetLabelText ( name )
2019-01-30 22:14:54 +00:00
self . _search_text_for_current_cache = None
2016-09-21 19:54:04 +00:00
2018-02-14 21:47:18 +00:00
self . _SetListDirty ( )
2016-09-21 19:54:04 +00:00
2019-01-30 22:14:54 +00:00
def _InitFavouritesList ( self ) :
2016-09-21 19:54:04 +00:00
2019-01-30 22:14:54 +00:00
raise NotImplementedError ( )
2016-09-21 19:54:04 +00:00
2019-01-30 22:14:54 +00:00
def _SetResultsToList ( self , results ) :
2016-09-21 19:54:04 +00:00
2019-01-30 22:14:54 +00:00
self . _search_results_list . SetPredicates ( results )
2016-09-21 19:54:04 +00:00
2016-10-26 20:45:34 +00:00
def FileButtonHit ( self ) :
2017-06-28 20:23:21 +00:00
services_manager = HG . client_controller . services_manager
2016-10-26 20:45:34 +00:00
services = [ ]
2016-12-21 22:30:54 +00:00
2016-10-26 20:45:34 +00:00
services . append ( services_manager . GetService ( CC . LOCAL_FILE_SERVICE_KEY ) )
services . append ( services_manager . GetService ( CC . TRASH_SERVICE_KEY ) )
2019-05-22 22:35:06 +00:00
if HG . client_controller . new_options . GetBoolean ( ' advanced_mode ' ) :
services . append ( services_manager . GetService ( CC . COMBINED_LOCAL_FILE_SERVICE_KEY ) )
2016-10-26 20:45:34 +00:00
services . extend ( services_manager . GetServices ( ( HC . FILE_REPOSITORY , ) ) )
2017-11-22 21:03:07 +00:00
advanced_mode = HG . client_controller . new_options . GetBoolean ( ' advanced_mode ' )
2019-04-24 22:18:50 +00:00
if advanced_mode and self . _allow_all_known_files :
2017-11-22 21:03:07 +00:00
services . append ( services_manager . GetService ( CC . COMBINED_FILE_SERVICE_KEY ) )
2016-10-26 20:45:34 +00:00
menu = wx . Menu ( )
2016-12-21 22:30:54 +00:00
for service in services :
2017-03-29 19:39:34 +00:00
ClientGUIMenus . AppendMenuItem ( self , menu , service . GetName ( ) , ' Change the current file domain to ' + service . GetName ( ) + ' . ' , self . _ChangeFileService , service . GetServiceKey ( ) )
2016-12-21 22:30:54 +00:00
2016-10-26 20:45:34 +00:00
2017-05-10 21:33:58 +00:00
HG . client_controller . PopupMenu ( self . _file_repo_button , menu )
2016-10-26 20:45:34 +00:00
2019-01-30 22:14:54 +00:00
def RefreshFavouriteTags ( self ) :
favourite_tags = list ( HG . client_controller . new_options . GetStringList ( ' favourite_tags ' ) )
favourite_tags . sort ( )
predicates = [ ClientSearch . Predicate ( HC . PREDICATE_TYPE_TAG , tag ) for tag in favourite_tags ]
self . _favourites_list . SetPredicates ( predicates )
2016-10-26 20:45:34 +00:00
def SetFileService ( self , file_service_key ) :
self . _ChangeFileService ( file_service_key )
def SetTagService ( self , tag_service_key ) :
self . _ChangeTagService ( tag_service_key )
def TagButtonHit ( self ) :
2016-09-21 19:54:04 +00:00
2017-06-28 20:23:21 +00:00
services_manager = HG . client_controller . services_manager
2016-09-21 19:54:04 +00:00
services = [ ]
2016-12-21 22:30:54 +00:00
2016-09-21 19:54:04 +00:00
services . append ( services_manager . GetService ( CC . LOCAL_TAG_SERVICE_KEY ) )
services . extend ( services_manager . GetServices ( ( HC . TAG_REPOSITORY , ) ) )
2016-12-21 22:30:54 +00:00
services . append ( services_manager . GetService ( CC . COMBINED_TAG_SERVICE_KEY ) )
2016-09-21 19:54:04 +00:00
menu = wx . Menu ( )
2016-12-21 22:30:54 +00:00
for service in services :
2017-03-29 19:39:34 +00:00
ClientGUIMenus . AppendMenuItem ( self , menu , service . GetName ( ) , ' Change the current tag domain to ' + service . GetName ( ) + ' . ' , self . _ChangeTagService , service . GetServiceKey ( ) )
2016-12-21 22:30:54 +00:00
2016-09-21 19:54:04 +00:00
2017-05-10 21:33:58 +00:00
HG . client_controller . PopupMenu ( self . _tag_repo_button , menu )
2016-09-21 19:54:04 +00:00
class AutoCompleteDropdownTagsRead ( AutoCompleteDropdownTags ) :
2019-04-24 22:18:50 +00:00
def __init__ ( self , parent , page_key , file_search_context , media_callable = None , synchronised = True , include_unusual_predicate_types = True , allow_all_known_files = True ) :
2016-09-21 19:54:04 +00:00
file_service_key = file_search_context . GetFileServiceKey ( )
tag_service_key = file_search_context . GetTagServiceKey ( )
AutoCompleteDropdownTags . __init__ ( self , parent , file_service_key , tag_service_key )
2019-04-24 22:18:50 +00:00
self . _allow_all_known_files = allow_all_known_files
2016-09-21 19:54:04 +00:00
self . _media_callable = media_callable
self . _page_key = page_key
2019-04-03 22:45:57 +00:00
self . _under_construction_or_predicate = None
2016-09-21 19:54:04 +00:00
self . _file_search_context = file_search_context
self . _include_current_tags = ClientGUICommon . OnOffButton ( self . _dropdown_window , self . _page_key , ' notify_include_current ' , on_label = ' include current tags ' , off_label = ' exclude current tags ' , start_on = file_search_context . IncludeCurrentTags ( ) )
2018-01-03 22:37:30 +00:00
self . _include_current_tags . SetToolTip ( ' select whether to include current tags in the search ' )
2016-09-21 19:54:04 +00:00
self . _include_pending_tags = ClientGUICommon . OnOffButton ( self . _dropdown_window , self . _page_key , ' notify_include_pending ' , on_label = ' include pending tags ' , off_label = ' exclude pending tags ' , start_on = file_search_context . IncludePendingTags ( ) )
2018-01-03 22:37:30 +00:00
self . _include_pending_tags . SetToolTip ( ' select whether to include pending tags in the search ' )
2016-09-21 19:54:04 +00:00
self . _synchronised = ClientGUICommon . OnOffButton ( self . _dropdown_window , self . _page_key , ' notify_search_immediately ' , on_label = ' searching immediately ' , off_label = ' waiting -- tag counts may be inaccurate ' , start_on = synchronised )
2018-01-03 22:37:30 +00:00
self . _synchronised . SetToolTip ( ' select whether to renew the search as soon as a new predicate is entered ' )
2016-09-21 19:54:04 +00:00
2019-04-10 22:50:53 +00:00
self . _or_cancel = ClientGUICommon . BetterBitmapButton ( self . _dropdown_window , CC . GlobalBMPs . delete , self . _CancelORConstruction )
self . _or_cancel . SetToolTip ( ' Cancel OR Predicate construction. ' )
self . _or_cancel . Hide ( )
2016-09-21 19:54:04 +00:00
2019-04-10 22:50:53 +00:00
self . _or_rewind = ClientGUICommon . BetterBitmapButton ( self . _dropdown_window , CC . GlobalBMPs . previous , self . _RewindORConstruction )
self . _or_rewind . SetToolTip ( ' Rewind OR Predicate construction. ' )
self . _or_rewind . Hide ( )
2019-04-03 22:45:57 +00:00
2019-04-10 22:50:53 +00:00
self . _include_unusual_predicate_types = include_unusual_predicate_types
2019-04-03 22:45:57 +00:00
2016-09-21 19:54:04 +00:00
button_hbox_1 = wx . BoxSizer ( wx . HORIZONTAL )
2018-01-03 22:37:30 +00:00
button_hbox_1 . Add ( self . _include_current_tags , CC . FLAGS_EXPAND_BOTH_WAYS )
button_hbox_1 . Add ( self . _include_pending_tags , CC . FLAGS_EXPAND_BOTH_WAYS )
2016-09-21 19:54:04 +00:00
2019-04-10 22:50:53 +00:00
sync_button_hbox = wx . BoxSizer ( wx . HORIZONTAL )
sync_button_hbox . Add ( self . _synchronised , CC . FLAGS_EXPAND_BOTH_WAYS )
2019-04-17 21:51:50 +00:00
sync_button_hbox . Add ( self . _or_cancel , CC . FLAGS_VCENTER )
sync_button_hbox . Add ( self . _or_rewind , CC . FLAGS_VCENTER )
2019-04-10 22:50:53 +00:00
2016-09-21 19:54:04 +00:00
button_hbox_2 = wx . BoxSizer ( wx . HORIZONTAL )
2018-01-03 22:37:30 +00:00
button_hbox_2 . Add ( self . _file_repo_button , CC . FLAGS_EXPAND_BOTH_WAYS )
button_hbox_2 . Add ( self . _tag_repo_button , CC . FLAGS_EXPAND_BOTH_WAYS )
2016-09-21 19:54:04 +00:00
vbox = wx . BoxSizer ( wx . VERTICAL )
2018-01-03 22:37:30 +00:00
vbox . Add ( button_hbox_1 , CC . FLAGS_EXPAND_SIZER_PERPENDICULAR )
2019-04-10 22:50:53 +00:00
vbox . Add ( sync_button_hbox , CC . FLAGS_EXPAND_SIZER_PERPENDICULAR )
2018-01-03 22:37:30 +00:00
vbox . Add ( button_hbox_2 , CC . FLAGS_EXPAND_SIZER_PERPENDICULAR )
2018-03-28 21:55:58 +00:00
vbox . Add ( self . _dropdown_notebook , CC . FLAGS_EXPAND_BOTH_WAYS )
2016-09-21 19:54:04 +00:00
self . _dropdown_window . SetSizer ( vbox )
2017-05-10 21:33:58 +00:00
HG . client_controller . sub ( self , ' SetSynchronisedWait ' , ' synchronised_wait_switch ' )
2016-09-21 19:54:04 +00:00
2017-05-10 21:33:58 +00:00
HG . client_controller . sub ( self , ' IncludeCurrent ' , ' notify_include_current ' )
HG . client_controller . sub ( self , ' IncludePending ' , ' notify_include_pending ' )
2016-09-21 19:54:04 +00:00
2019-04-03 22:45:57 +00:00
def _BroadcastChoices ( self , predicates , shift_down ) :
2016-09-21 19:54:04 +00:00
2019-04-10 22:50:53 +00:00
or_pred_in_broadcast = self . _under_construction_or_predicate is not None and self . _under_construction_or_predicate in predicates
2019-04-03 22:45:57 +00:00
if shift_down :
if self . _under_construction_or_predicate is None :
self . _under_construction_or_predicate = ClientSearch . Predicate ( HC . PREDICATE_TYPE_OR_CONTAINER , predicates )
else :
2019-04-10 22:50:53 +00:00
if or_pred_in_broadcast :
predicates . remove ( self . _under_construction_or_predicate )
2019-04-03 22:45:57 +00:00
or_preds = list ( self . _under_construction_or_predicate . GetValue ( ) )
or_preds . extend ( [ predicate for predicate in predicates if predicate not in or_preds ] )
self . _under_construction_or_predicate = ClientSearch . Predicate ( HC . PREDICATE_TYPE_OR_CONTAINER , or_preds )
else :
2019-04-10 22:50:53 +00:00
if self . _under_construction_or_predicate is not None and not or_pred_in_broadcast :
2019-04-03 22:45:57 +00:00
or_preds = list ( self . _under_construction_or_predicate . GetValue ( ) )
or_preds . extend ( [ predicate for predicate in predicates if predicate not in or_preds ] )
predicates = { ClientSearch . Predicate ( HC . PREDICATE_TYPE_OR_CONTAINER , or_preds ) }
2019-04-10 22:50:53 +00:00
if or_pred_in_broadcast :
2019-04-03 22:45:57 +00:00
2019-04-10 22:50:53 +00:00
or_preds = list ( self . _under_construction_or_predicate . GetValue ( ) )
if len ( or_preds ) == 1 :
predicates . remove ( self . _under_construction_or_predicate )
predicates . extend ( or_preds )
2019-04-03 22:45:57 +00:00
2019-04-10 22:50:53 +00:00
self . _under_construction_or_predicate = None
2019-04-03 22:45:57 +00:00
HG . client_controller . pub ( ' enter_predicates ' , self . _page_key , predicates )
2016-09-21 19:54:04 +00:00
2019-04-10 22:50:53 +00:00
self . _UpdateORButtons ( )
2018-05-23 21:05:06 +00:00
self . _ClearInput ( )
2016-09-21 19:54:04 +00:00
2019-04-03 22:45:57 +00:00
def _BroadcastCurrentText ( self , shift_down ) :
2016-09-21 19:54:04 +00:00
2018-04-25 22:07:52 +00:00
( raw_entry , inclusive , search_text , explicit_wildcard , cache_text , entry_predicate ) = self . _ParseSearchText ( )
2016-09-21 19:54:04 +00:00
2019-06-05 19:42:39 +00:00
( namespace , subtag ) = HydrusTags . SplitTag ( search_text )
if namespace != ' ' and subtag in ( ' ' , ' * ' ) :
2016-09-21 19:54:04 +00:00
2019-06-05 19:42:39 +00:00
entry_predicate = ClientSearch . Predicate ( HC . PREDICATE_TYPE_NAMESPACE , namespace , inclusive )
2016-09-21 19:54:04 +00:00
2019-06-05 19:42:39 +00:00
else :
2016-09-21 19:54:04 +00:00
2019-06-05 19:42:39 +00:00
try :
HydrusTags . CheckTagNotEmpty ( search_text )
except HydrusExceptions . SizeException :
return
2016-09-21 19:54:04 +00:00
2019-04-03 22:45:57 +00:00
self . _BroadcastChoices ( { entry_predicate } , shift_down )
2016-09-21 19:54:04 +00:00
2019-04-10 22:50:53 +00:00
def _CancelORConstruction ( self ) :
self . _under_construction_or_predicate = None
self . _UpdateORButtons ( )
self . _ClearInput ( )
2016-09-21 19:54:04 +00:00
def _ChangeFileService ( self , file_service_key ) :
AutoCompleteDropdownTags . _ChangeFileService ( self , file_service_key )
self . _file_search_context . SetFileServiceKey ( file_service_key )
2017-05-10 21:33:58 +00:00
HG . client_controller . pub ( ' change_file_service ' , self . _page_key , file_service_key )
2016-09-21 19:54:04 +00:00
2017-05-10 21:33:58 +00:00
HG . client_controller . pub ( ' refresh_query ' , self . _page_key )
2016-09-21 19:54:04 +00:00
def _ChangeTagService ( self , tag_service_key ) :
AutoCompleteDropdownTags . _ChangeTagService ( self , tag_service_key )
self . _file_search_context . SetTagServiceKey ( tag_service_key )
2017-05-10 21:33:58 +00:00
HG . client_controller . pub ( ' change_tag_service ' , self . _page_key , tag_service_key )
2016-09-21 19:54:04 +00:00
2017-05-10 21:33:58 +00:00
HG . client_controller . pub ( ' refresh_query ' , self . _page_key )
2016-09-21 19:54:04 +00:00
2019-04-10 22:50:53 +00:00
def _HandleEscape ( self ) :
if self . _under_construction_or_predicate is not None and self . _text_ctrl . GetValue ( ) == ' ' :
self . _CancelORConstruction ( )
return True
else :
return AutoCompleteDropdown . _HandleEscape ( self )
2018-03-28 21:55:58 +00:00
def _InitFavouritesList ( self ) :
2018-05-23 21:05:06 +00:00
favs_list = ClientGUIListBoxes . ListBoxTagsACRead ( self . _dropdown_notebook , self . BroadcastChoices , self . _tag_service_key , height_num_chars = self . _list_height_num_chars )
2016-09-21 19:54:04 +00:00
2018-03-28 21:55:58 +00:00
return favs_list
def _InitSearchResultsList ( self ) :
2018-05-23 21:05:06 +00:00
return ClientGUIListBoxes . ListBoxTagsACRead ( self . _dropdown_notebook , self . BroadcastChoices , self . _tag_service_key , height_num_chars = self . _list_height_num_chars )
2016-09-21 19:54:04 +00:00
def _ParseSearchText ( self ) :
raw_entry = self . _text_ctrl . GetValue ( )
if raw_entry . startswith ( ' - ' ) :
inclusive = False
2017-03-08 23:23:12 +00:00
entry_text = raw_entry [ 1 : ]
2016-09-21 19:54:04 +00:00
else :
inclusive = True
2017-03-08 23:23:12 +00:00
entry_text = raw_entry
2016-09-21 19:54:04 +00:00
2017-03-08 23:23:12 +00:00
tag = HydrusTags . CleanTag ( entry_text )
2017-02-01 21:11:17 +00:00
2017-03-08 23:23:12 +00:00
explicit_wildcard = ' * ' in entry_text
2016-09-21 19:54:04 +00:00
2017-03-08 23:23:12 +00:00
search_text = ClientSearch . ConvertEntryTextToSearchText ( entry_text )
2016-09-21 19:54:04 +00:00
2017-03-08 23:23:12 +00:00
if explicit_wildcard :
cache_text = None
2016-09-21 19:54:04 +00:00
2017-03-08 23:23:12 +00:00
entry_predicate = ClientSearch . Predicate ( HC . PREDICATE_TYPE_WILDCARD , search_text , inclusive )
2016-09-21 19:54:04 +00:00
else :
2017-03-08 23:23:12 +00:00
cache_text = search_text [ : - 1 ] # take off the trailing '*' for the cache text
2019-04-17 21:51:50 +00:00
siblings_manager = HG . client_controller . tag_siblings_manager
2017-03-08 23:23:12 +00:00
sibling = siblings_manager . GetSibling ( self . _tag_service_key , tag )
if sibling is None :
entry_predicate = ClientSearch . Predicate ( HC . PREDICATE_TYPE_TAG , tag , inclusive )
else :
entry_predicate = ClientSearch . Predicate ( HC . PREDICATE_TYPE_TAG , sibling , inclusive )
2016-09-21 19:54:04 +00:00
2018-04-25 22:07:52 +00:00
return ( raw_entry , inclusive , search_text , explicit_wildcard , cache_text , entry_predicate )
2016-09-21 19:54:04 +00:00
2019-04-10 22:50:53 +00:00
def _RewindORConstruction ( self ) :
2019-04-03 22:45:57 +00:00
2019-04-10 22:50:53 +00:00
if self . _under_construction_or_predicate is not None :
2019-04-03 22:45:57 +00:00
2019-04-10 22:50:53 +00:00
or_preds = self . _under_construction_or_predicate . GetValue ( )
2019-04-03 22:45:57 +00:00
2019-04-10 22:50:53 +00:00
if len ( or_preds ) < = 1 :
2019-04-03 22:45:57 +00:00
2019-04-10 22:50:53 +00:00
self . _CancelORConstruction ( )
2019-04-03 22:45:57 +00:00
2019-04-10 22:50:53 +00:00
return
2019-04-03 22:45:57 +00:00
2019-04-10 22:50:53 +00:00
or_preds = or_preds [ : - 1 ]
2019-04-03 22:45:57 +00:00
2019-04-10 22:50:53 +00:00
self . _under_construction_or_predicate = ClientSearch . Predicate ( HC . PREDICATE_TYPE_OR_CONTAINER , or_preds )
2019-04-03 22:45:57 +00:00
2019-04-10 22:50:53 +00:00
self . _UpdateORButtons ( )
self . _ClearInput ( )
2019-04-03 22:45:57 +00:00
2019-01-30 22:14:54 +00:00
def _StartResultsFetchJob ( self , job_key ) :
2016-09-21 19:54:04 +00:00
2019-01-30 22:14:54 +00:00
parsed_search_text = self . _ParseSearchText ( )
2016-09-21 19:54:04 +00:00
2019-04-10 22:50:53 +00:00
HG . client_controller . CallToThread ( ReadFetch , self , job_key , self . SetFetchedResults , parsed_search_text , self . _media_callable , self . _file_search_context , self . _synchronised . IsOn ( ) , self . _include_unusual_predicate_types , self . _initial_matches_fetched , self . _search_text_for_current_cache , self . _cached_results , self . _under_construction_or_predicate )
2016-09-21 19:54:04 +00:00
def _ShouldTakeResponsibilityForEnter ( self ) :
2019-01-30 22:14:54 +00:00
( raw_entry , inclusive , search_text , explicit_wildcard , cache_text , entry_predicate ) = self . _ParseSearchText ( )
sitting_on_empty = raw_entry == ' '
2016-09-21 19:54:04 +00:00
# when the user has quickly typed something in and the results are not yet in
2019-01-30 22:14:54 +00:00
p1 = not sitting_on_empty and self . _last_fetched_search_text != search_text
return p1
2016-09-21 19:54:04 +00:00
2019-04-03 22:45:57 +00:00
def _TakeResponsibilityForEnter ( self , shift_down ) :
2016-09-21 19:54:04 +00:00
2019-04-03 22:45:57 +00:00
self . _BroadcastCurrentText ( shift_down )
2016-09-21 19:54:04 +00:00
2019-04-10 22:50:53 +00:00
def _UpdateORButtons ( self ) :
layout_needed = False
if self . _under_construction_or_predicate is None :
if self . _or_cancel . IsShown ( ) :
self . _or_cancel . Hide ( )
layout_needed = True
if self . _or_rewind . IsShown ( ) :
self . _or_rewind . Hide ( )
layout_needed = True
else :
or_preds = self . _under_construction_or_predicate . GetValue ( )
if len ( or_preds ) > 1 :
if not self . _or_rewind . IsShown ( ) :
self . _or_rewind . Show ( )
layout_needed = True
else :
if self . _or_rewind . IsShown ( ) :
self . _or_rewind . Hide ( )
layout_needed = True
if not self . _or_cancel . IsShown ( ) :
self . _or_cancel . Show ( )
layout_needed = True
if layout_needed :
self . _dropdown_window . Layout ( )
2016-09-21 19:54:04 +00:00
def GetFileSearchContext ( self ) :
return self . _file_search_context
def IncludeCurrent ( self , page_key , value ) :
if page_key == self . _page_key :
self . _file_search_context . SetIncludeCurrentTags ( value )
2018-02-14 21:47:18 +00:00
self . _SetListDirty ( )
2017-01-18 22:52:39 +00:00
2017-05-10 21:33:58 +00:00
HG . client_controller . pub ( ' refresh_query ' , self . _page_key )
2017-01-18 22:52:39 +00:00
2016-09-21 19:54:04 +00:00
def IncludePending ( self , page_key , value ) :
if page_key == self . _page_key :
self . _file_search_context . SetIncludePendingTags ( value )
2018-02-14 21:47:18 +00:00
self . _SetListDirty ( )
2017-01-18 22:52:39 +00:00
2017-05-10 21:33:58 +00:00
HG . client_controller . pub ( ' refresh_query ' , self . _page_key )
2017-01-18 22:52:39 +00:00
2016-09-21 19:54:04 +00:00
2019-04-24 22:18:50 +00:00
def IsSynchronised ( self ) :
return self . _synchronised . IsOn ( )
2019-01-30 22:14:54 +00:00
def SetFetchedResults ( self , job_key , search_text , search_text_for_cache , cached_results , results , next_search_is_probably_fast ) :
if self . _current_fetch_job_key is not None and self . _current_fetch_job_key . GetKey ( ) == job_key . GetKey ( ) :
AutoCompleteDropdownTags . SetFetchedResults ( self , job_key , search_text , search_text_for_cache , cached_results , results )
self . _next_search_is_probably_fast = next_search_is_probably_fast
num_chars = len ( self . _text_ctrl . GetValue ( ) )
if num_chars == 0 :
# refresh system preds after five mins
self . _ScheduleListRefresh ( 300 )
2016-09-21 19:54:04 +00:00
def SetSynchronisedWait ( self , page_key ) :
2019-04-24 22:18:50 +00:00
if page_key == self . _page_key :
self . _synchronised . EventButton ( None )
2016-09-21 19:54:04 +00:00
class AutoCompleteDropdownTagsWrite ( AutoCompleteDropdownTags ) :
2019-06-26 21:27:18 +00:00
def __init__ ( self , parent , chosen_tag_callable , expand_parents , file_service_key , tag_service_key , null_entry_callable = None , tag_service_key_changed_callable = None , show_paste_button = False ) :
2016-09-21 19:54:04 +00:00
self . _chosen_tag_callable = chosen_tag_callable
self . _expand_parents = expand_parents
self . _null_entry_callable = null_entry_callable
2018-11-21 22:22:36 +00:00
self . _tag_service_key_changed_callable = tag_service_key_changed_callable
2016-09-21 19:54:04 +00:00
if tag_service_key != CC . COMBINED_TAG_SERVICE_KEY and HC . options [ ' show_all_tags_in_autocomplete ' ] :
file_service_key = CC . COMBINED_FILE_SERVICE_KEY
2017-05-10 21:33:58 +00:00
if tag_service_key == CC . LOCAL_TAG_SERVICE_KEY :
file_service_key = CC . LOCAL_FILE_SERVICE_KEY
2016-09-21 19:54:04 +00:00
AutoCompleteDropdownTags . __init__ ( self , parent , file_service_key , tag_service_key )
2019-06-26 21:27:18 +00:00
self . _paste_button = ClientGUICommon . BetterBitmapButton ( self , CC . GlobalBMPs . paste , self . _Paste )
self . _paste_button . SetToolTip ( ' Paste from the clipboard and quick-enter as if you had typed. This can take multiple newline-separated tags. ' )
if not show_paste_button :
self . _paste_button . Hide ( )
self . _text_input_hbox . Add ( self . _paste_button , CC . FLAGS_VCENTER )
2016-09-21 19:54:04 +00:00
vbox = wx . BoxSizer ( wx . VERTICAL )
hbox = wx . BoxSizer ( wx . HORIZONTAL )
2018-01-03 22:37:30 +00:00
hbox . Add ( self . _file_repo_button , CC . FLAGS_EXPAND_BOTH_WAYS )
hbox . Add ( self . _tag_repo_button , CC . FLAGS_EXPAND_BOTH_WAYS )
2016-09-21 19:54:04 +00:00
2018-01-03 22:37:30 +00:00
vbox . Add ( hbox , CC . FLAGS_EXPAND_SIZER_PERPENDICULAR )
2018-03-28 21:55:58 +00:00
vbox . Add ( self . _dropdown_notebook , CC . FLAGS_EXPAND_BOTH_WAYS )
2016-09-21 19:54:04 +00:00
self . _dropdown_window . SetSizer ( vbox )
2019-04-03 22:45:57 +00:00
def _BroadcastChoices ( self , predicates , shift_down ) :
2016-09-21 19:54:04 +00:00
tags = { predicate . GetValue ( ) for predicate in predicates }
if len ( tags ) > 0 :
self . _chosen_tag_callable ( tags )
2018-05-23 21:05:06 +00:00
self . _ClearInput ( )
2016-09-21 19:54:04 +00:00
def _ParseSearchText ( self ) :
raw_entry = self . _text_ctrl . GetValue ( )
2017-02-01 21:11:17 +00:00
tag = HydrusTags . CleanTag ( raw_entry )
2017-03-08 23:23:12 +00:00
search_text = ClientSearch . ConvertEntryTextToSearchText ( raw_entry )
if ClientSearch . IsComplexWildcard ( search_text ) :
cache_text = None
else :
cache_text = search_text [ : - 1 ] # take off the trailing '*' for the cache text
2016-09-21 19:54:04 +00:00
2017-02-01 21:11:17 +00:00
entry_predicate = ClientSearch . Predicate ( HC . PREDICATE_TYPE_TAG , tag )
2016-09-21 19:54:04 +00:00
2019-04-17 21:51:50 +00:00
siblings_manager = HG . client_controller . tag_siblings_manager
2016-09-21 19:54:04 +00:00
2017-02-01 21:11:17 +00:00
sibling = siblings_manager . GetSibling ( self . _tag_service_key , tag )
2016-09-21 19:54:04 +00:00
if sibling is not None :
sibling_predicate = ClientSearch . Predicate ( HC . PREDICATE_TYPE_TAG , sibling )
else :
sibling_predicate = None
2018-04-25 22:07:52 +00:00
return ( raw_entry , search_text , cache_text , entry_predicate , sibling_predicate )
2016-09-21 19:54:04 +00:00
2019-04-03 22:45:57 +00:00
def _BroadcastCurrentText ( self , shift_down ) :
2016-09-21 19:54:04 +00:00
2018-04-25 22:07:52 +00:00
( raw_entry , search_text , cache_text , entry_predicate , sibling_predicate ) = self . _ParseSearchText ( )
2016-09-21 19:54:04 +00:00
try :
HydrusTags . CheckTagNotEmpty ( search_text )
except HydrusExceptions . SizeException :
return
2019-04-03 22:45:57 +00:00
self . _BroadcastChoices ( { entry_predicate } , shift_down )
2016-09-21 19:54:04 +00:00
2018-11-21 22:22:36 +00:00
def _ChangeTagService ( self , tag_service_key ) :
AutoCompleteDropdownTags . _ChangeTagService ( self , tag_service_key )
if self . _tag_service_key_changed_callable is not None :
self . _tag_service_key_changed_callable ( tag_service_key )
2018-03-28 21:55:58 +00:00
def _InitFavouritesList ( self ) :
2018-05-23 21:05:06 +00:00
favs_list = ClientGUIListBoxes . ListBoxTagsACWrite ( self . _dropdown_notebook , self . BroadcastChoices , self . _tag_service_key , height_num_chars = self . _list_height_num_chars )
2018-03-28 21:55:58 +00:00
return favs_list
def _InitSearchResultsList ( self ) :
2016-09-21 19:54:04 +00:00
2018-05-23 21:05:06 +00:00
return ClientGUIListBoxes . ListBoxTagsACWrite ( self . _dropdown_notebook , self . BroadcastChoices , self . _tag_service_key , height_num_chars = self . _list_height_num_chars )
2016-09-21 19:54:04 +00:00
2019-06-26 21:27:18 +00:00
def _Paste ( self ) :
try :
raw_text = HG . client_controller . GetClipboardText ( )
except HydrusExceptions . DataMissing as e :
wx . MessageBox ( str ( e ) )
return
try :
tags = [ text for text in HydrusText . DeserialiseNewlinedTexts ( raw_text ) ]
tags = HydrusTags . CleanTags ( tags )
entry_predicates = [ ClientSearch . Predicate ( HC . PREDICATE_TYPE_TAG , tag ) for tag in tags ]
if len ( entry_predicates ) > 0 :
shift_down = False
self . _BroadcastChoices ( entry_predicates , shift_down )
except :
wx . MessageBox ( ' I could not understand what was in the clipboard ' )
raise
2019-01-30 22:14:54 +00:00
def _ShouldTakeResponsibilityForEnter ( self ) :
2016-09-21 19:54:04 +00:00
2019-01-30 22:14:54 +00:00
( raw_entry , search_text , cache_text , entry_predicate , sibling_predicate ) = self . _ParseSearchText ( )
2016-09-21 19:54:04 +00:00
2019-01-30 22:14:54 +00:00
sitting_on_empty = raw_entry == ' '
2016-09-21 19:54:04 +00:00
# when the user has quickly typed something in and the results are not yet in
2019-01-30 22:14:54 +00:00
p1 = not sitting_on_empty and self . _last_fetched_search_text != search_text
2016-09-21 19:54:04 +00:00
2018-03-28 21:55:58 +00:00
# when the text ctrl is empty, we are looking at search results, and we want to push a None to the parent dialog
2016-09-21 19:54:04 +00:00
2019-01-30 22:14:54 +00:00
p2 = sitting_on_empty and self . _dropdown_notebook . GetCurrentPage ( ) == self . _search_results_list
2016-09-21 19:54:04 +00:00
return p1 or p2
2019-01-30 22:14:54 +00:00
def _StartResultsFetchJob ( self , job_key ) :
parsed_search_text = self . _ParseSearchText ( )
HG . client_controller . CallToThread ( WriteFetch , self , job_key , self . SetFetchedResults , parsed_search_text , self . _file_service_key , self . _tag_service_key , self . _expand_parents , self . _search_text_for_current_cache , self . _cached_results )
2019-04-03 22:45:57 +00:00
def _TakeResponsibilityForEnter ( self , shift_down ) :
2016-09-21 19:54:04 +00:00
2018-03-28 21:55:58 +00:00
if self . _text_ctrl . GetValue ( ) == ' ' and self . _dropdown_notebook . GetCurrentPage ( ) == self . _search_results_list :
2016-09-21 19:54:04 +00:00
if self . _null_entry_callable is not None :
self . _null_entry_callable ( )
else :
2019-04-03 22:45:57 +00:00
self . _BroadcastCurrentText ( shift_down )
2016-09-21 19:54:04 +00:00
2016-12-21 22:30:54 +00:00
2018-04-05 01:22:26 +00:00
def RefreshFavouriteTags ( self ) :
favourite_tags = list ( HG . client_controller . new_options . GetStringList ( ' favourite_tags ' ) )
favourite_tags . sort ( )
predicates = [ ClientSearch . Predicate ( HC . PREDICATE_TYPE_TAG , tag ) for tag in favourite_tags ]
2019-04-17 21:51:50 +00:00
parents_manager = HG . client_controller . tag_parents_manager
2018-04-05 01:22:26 +00:00
predicates = parents_manager . ExpandPredicates ( CC . COMBINED_TAG_SERVICE_KEY , predicates )
self . _favourites_list . SetPredicates ( predicates )
2019-01-30 22:14:54 +00:00
def SetFetchedResults ( self , job_key , search_text , search_text_for_cache , cached_results , results , next_search_is_probably_fast ) :
if self . _current_fetch_job_key is not None and self . _current_fetch_job_key . GetKey ( ) == job_key . GetKey ( ) :
AutoCompleteDropdownTags . SetFetchedResults ( self , job_key , search_text , search_text_for_cache , cached_results , results )
self . _next_search_is_probably_fast = next_search_is_probably_fast