2023-01-25 22:59:39 +00:00
import os
2020-05-06 21:31:41 +00:00
import typing
2020-04-22 21:00:35 +00:00
2019-11-14 03:56:30 +00:00
from qtpy import QtCore as QC
from qtpy import QtWidgets as QW
2020-04-22 21:00:35 +00:00
from hydrus . core import HydrusConstants as HC
from hydrus . core import HydrusData
from hydrus . core import HydrusGlobals as HG
from hydrus . core import HydrusSerialisable
2020-07-29 20:52:44 +00:00
2020-07-08 22:00:33 +00:00
from hydrus . client import ClientApplicationCommand as CAC
2020-04-22 21:00:35 +00:00
from hydrus . client import ClientConstants as CC
from hydrus . client import ClientParsing
from hydrus . client import ClientSearch
from hydrus . client import ClientThreading
from hydrus . client . gui import ClientGUIDialogs
from hydrus . client . gui import QtPorting as QP
2020-07-15 20:52:09 +00:00
from hydrus . client . gui . lists import ClientGUIListBoxes
2021-02-11 01:59:52 +00:00
from hydrus . client . gui . lists import ClientGUIListBoxesData
2022-08-24 21:06:25 +00:00
from hydrus . client . gui . parsing import ClientGUIParsingLegacy
2021-03-17 21:59:28 +00:00
from hydrus . client . gui . widgets import ClientGUICommon
2022-12-21 22:00:27 +00:00
from hydrus . client . media import ClientMedia
2020-08-05 20:10:36 +00:00
from hydrus . client . metadata import ClientTags
2021-02-24 22:35:18 +00:00
from hydrus . client . metadata import ClientTagSorting
2016-08-03 22:15:54 +00:00
2020-08-27 01:00:42 +00:00
def FilterSuggestedPredicatesForMedia ( predicates : typing . Sequence [ ClientSearch . Predicate ] , medias : typing . Collection [ ClientMedia . Media ] , service_key : bytes ) - > typing . List [ ClientSearch . Predicate ] :
2020-04-29 21:44:12 +00:00
2020-05-06 21:31:41 +00:00
tags = [ predicate . GetValue ( ) for predicate in predicates ]
2020-04-29 21:44:12 +00:00
2020-07-08 22:00:33 +00:00
filtered_tags = FilterSuggestedTagsForMedia ( tags , medias , service_key )
2020-04-29 21:44:12 +00:00
predicates = [ predicate for predicate in predicates if predicate . GetValue ( ) in filtered_tags ]
return predicates
2023-02-01 21:20:47 +00:00
2020-08-27 01:00:42 +00:00
def FilterSuggestedTagsForMedia ( tags : typing . Sequence [ str ] , medias : typing . Collection [ ClientMedia . Media ] , service_key : bytes ) - > typing . List [ str ] :
2020-04-29 21:44:12 +00:00
2023-01-25 22:59:39 +00:00
num_media = len ( medias )
2023-02-01 21:20:47 +00:00
useful_tags_set = set ( tags )
2020-04-29 21:44:12 +00:00
2020-07-08 22:00:33 +00:00
( current_tags_to_count , deleted_tags_to_count , pending_tags_to_count , petitioned_tags_to_count ) = ClientMedia . GetMediasTagCount ( medias , service_key , ClientTags . TAG_DISPLAY_STORAGE )
2020-04-29 21:44:12 +00:00
current_tags_to_count . update ( pending_tags_to_count )
2023-02-01 21:20:47 +00:00
# TODO: figure out a nicer way to filter out siblings and parents here
# maybe have to wait for when tags always know their siblings
# then we could also filter out worse/better siblings of the same count
# this is a sync way for now:
# db_tags_to_ideals_and_parents = HG.client_controller.Read( 'tag_display_decorators', service_key, tags_to_lookup )
2020-04-29 21:44:12 +00:00
for ( tag , count ) in current_tags_to_count . items ( ) :
if count == num_media :
2023-02-01 21:20:47 +00:00
useful_tags_set . discard ( tag )
2020-04-29 21:44:12 +00:00
2023-02-01 21:20:47 +00:00
tags_filtered = [ tag for tag in tags if tag in useful_tags_set ]
2020-05-06 21:31:41 +00:00
return tags_filtered
2020-04-29 21:44:12 +00:00
2017-02-01 21:11:17 +00:00
class ListBoxTagsSuggestionsFavourites ( ClientGUIListBoxes . ListBoxTagsStrings ) :
2016-08-03 22:15:54 +00:00
2020-09-09 20:59:19 +00:00
def __init__ ( self , parent , service_key , activate_callable , sort_tags = True ) :
2016-08-03 22:15:54 +00:00
2021-02-24 22:35:18 +00:00
ClientGUIListBoxes . ListBoxTagsStrings . __init__ ( self , parent , service_key = service_key , sort_tags = sort_tags , tag_display_type = ClientTags . TAG_DISPLAY_STORAGE )
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 :
2019-11-14 03:56:30 +00:00
self . setMinimumWidth ( width )
2016-11-09 23:13:22 +00:00
2016-08-03 22:15:54 +00:00
2021-11-10 21:53:57 +00:00
def _Activate ( self , ctrl_down , shift_down ) - > bool :
2016-08-03 22:15:54 +00:00
if len ( self . _selected_terms ) > 0 :
2021-02-11 01:59:52 +00:00
tags = set ( self . _GetTagsFromTerms ( self . _selected_terms ) )
2016-08-03 22:15:54 +00:00
2020-04-01 21:51:42 +00:00
self . _activate_callable ( tags , only_add = True )
self . _RemoveSelectedTerms ( )
self . _DataHasChanged ( )
2016-08-03 22:15:54 +00:00
2020-11-18 22:15:21 +00:00
return True
return False
2016-08-03 22:15:54 +00:00
2016-11-16 20:21:43 +00:00
2021-03-03 22:23:35 +00:00
def _Sort ( self ) :
self . _RegenTermsToIndices ( )
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 ) :
2021-02-11 01:59:52 +00:00
self . SelectTopItem ( )
2019-06-05 19:42:39 +00:00
2019-11-14 03:56:30 +00:00
self . setFocus ( QC . Qt . OtherFocusReason )
2019-06-05 19:42:39 +00:00
2017-03-22 22:38:15 +00:00
class ListBoxTagsSuggestionsRelated ( ClientGUIListBoxes . ListBoxTagsPredicates ) :
2016-08-03 22:15:54 +00:00
2020-09-09 20:59:19 +00:00
def __init__ ( self , parent , service_key , activate_callable ) :
2016-08-03 22:15:54 +00:00
2021-02-24 22:35:18 +00:00
ClientGUIListBoxes . ListBoxTagsPredicates . __init__ ( self , parent , tag_display_type = ClientTags . TAG_DISPLAY_STORAGE )
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
2019-11-14 03:56:30 +00:00
self . setMinimumWidth ( width )
2016-08-03 22:15:54 +00:00
2021-11-10 21:53:57 +00:00
def _Activate ( self , ctrl_down , shift_down ) - > bool :
2016-08-03 22:15:54 +00:00
if len ( self . _selected_terms ) > 0 :
2021-02-11 01:59:52 +00:00
tags = set ( self . _GetTagsFromTerms ( self . _selected_terms ) )
2016-08-03 22:15:54 +00:00
2020-04-29 21:44:12 +00:00
self . _activate_callable ( tags , only_add = True )
2016-08-03 22:15:54 +00:00
2020-04-01 21:51:42 +00:00
self . _RemoveSelectedTerms ( )
self . _DataHasChanged ( )
2020-11-18 22:15:21 +00:00
return True
return False
2016-08-03 22:15:54 +00:00
2021-02-24 22:35:18 +00:00
def _GenerateTermFromPredicate ( self , predicate : ClientSearch . Predicate ) - > ClientGUIListBoxesData . ListBoxItemPredicate :
2021-02-11 01:59:52 +00:00
2022-01-12 22:14:50 +00:00
predicate = predicate . GetCountlessCopy ( )
2017-03-29 19:39:34 +00:00
2021-02-24 22:35:18 +00:00
return ClientGUIListBoxesData . ListBoxItemPredicate ( predicate )
2017-03-29 19:39:34 +00:00
2021-03-03 22:23:35 +00:00
def _Sort ( self ) :
self . _RegenTermsToIndices ( )
2019-06-05 19:42:39 +00:00
def TakeFocusForUser ( self ) :
2021-02-11 01:59:52 +00:00
self . SelectTopItem ( )
2019-06-05 19:42:39 +00:00
2019-11-14 03:56:30 +00:00
self . setFocus ( QC . Qt . OtherFocusReason )
2019-06-05 19:42:39 +00:00
2020-04-29 21:44:12 +00:00
class FavouritesTagsPanel ( QW . QWidget ) :
2020-09-23 21:02:02 +00:00
mouseActivationOccurred = QC . Signal ( )
2020-04-29 21:44:12 +00:00
def __init__ ( self , parent , service_key , media , activate_callable ) :
QW . QWidget . __init__ ( self , parent )
self . _service_key = service_key
self . _media = media
vbox = QP . VBoxLayout ( )
2020-09-09 20:59:19 +00:00
self . _favourite_tags = ListBoxTagsSuggestionsFavourites ( self , self . _service_key , activate_callable , sort_tags = False )
2020-04-29 21:44:12 +00:00
QP . AddToLayout ( vbox , self . _favourite_tags , CC . FLAGS_EXPAND_BOTH_WAYS )
self . setLayout ( vbox )
self . _UpdateTagDisplay ( )
2020-09-23 21:02:02 +00:00
self . _favourite_tags . mouseActivationOccurred . connect ( self . mouseActivationOccurred )
2020-04-29 21:44:12 +00:00
def _UpdateTagDisplay ( self ) :
2020-05-13 19:03:16 +00:00
favourites = list ( HG . client_controller . new_options . GetSuggestedTagsFavourites ( self . _service_key ) )
2021-03-10 23:10:11 +00:00
ClientTagSorting . SortTags ( HG . client_controller . new_options . GetDefaultTagSort ( ) , favourites )
2020-04-29 21:44:12 +00:00
tags = FilterSuggestedTagsForMedia ( favourites , self . _media , self . _service_key )
self . _favourite_tags . SetTags ( tags )
def MediaUpdated ( self ) :
self . _UpdateTagDisplay ( )
def SetMedia ( self , media ) :
self . _media = media
self . _UpdateTagDisplay ( )
def TakeFocusForUser ( self ) :
self . _favourite_tags . TakeFocusForUser ( )
2019-11-14 03:56:30 +00:00
class RecentTagsPanel ( QW . QWidget ) :
2016-08-31 19:55:14 +00:00
2020-09-23 21:02:02 +00:00
mouseActivationOccurred = QC . Signal ( )
2020-04-29 21:44:12 +00:00
def __init__ ( self , parent , service_key , media , activate_callable ) :
2016-08-31 19:55:14 +00:00
2019-11-14 03:56:30 +00:00
QW . QWidget . __init__ ( self , parent )
2016-08-31 19:55:14 +00:00
self . _service_key = service_key
2020-04-29 21:44:12 +00:00
self . _media = media
2020-05-06 21:31:41 +00:00
self . _last_fetched_tags = [ ]
2016-08-31 19:55:14 +00:00
2017-12-06 22:06:56 +00:00
self . _new_options = HG . client_controller . new_options
2016-08-31 19:55:14 +00:00
2019-11-14 03:56:30 +00:00
vbox = QP . VBoxLayout ( )
2016-08-31 19:55:14 +00:00
2019-11-14 03:56:30 +00:00
clear_button = QW . QPushButton ( ' clear ' , self )
clear_button . clicked . connect ( self . EventClear )
2016-08-31 19:55:14 +00:00
2020-09-09 20:59:19 +00:00
self . _recent_tags = ListBoxTagsSuggestionsFavourites ( self , self . _service_key , activate_callable , sort_tags = False )
2016-08-31 19:55:14 +00:00
2019-11-14 03:56:30 +00:00
QP . AddToLayout ( vbox , clear_button , CC . FLAGS_EXPAND_PERPENDICULAR )
QP . AddToLayout ( vbox , self . _recent_tags , CC . FLAGS_EXPAND_BOTH_WAYS )
2016-08-31 19:55:14 +00:00
2019-11-14 03:56:30 +00:00
self . setLayout ( vbox )
2016-08-31 19:55:14 +00:00
self . _RefreshRecentTags ( )
2020-09-23 21:02:02 +00:00
self . _recent_tags . mouseActivationOccurred . connect ( self . mouseActivationOccurred )
2016-08-31 19:55:14 +00:00
def _RefreshRecentTags ( self ) :
2018-01-31 22:58:15 +00:00
def do_it ( service_key ) :
2020-04-29 21:44:12 +00:00
def qt_code ( recent_tags ) :
2018-01-31 22:58:15 +00:00
2019-11-14 03:56:30 +00:00
if not self or not QP . isValid ( self ) :
2018-01-31 22:58:15 +00:00
return
2020-04-29 21:44:12 +00:00
self . _last_fetched_tags = recent_tags
self . _UpdateTagDisplay ( )
2018-01-31 22:58:15 +00:00
2020-06-11 12:01:08 +00:00
if len ( self . _recent_tags . GetTags ( ) ) > 0 :
self . _recent_tags . SelectTopItem ( )
2018-01-31 22:58:15 +00:00
recent_tags = HG . client_controller . Read ( ' recent_tags ' , service_key )
2020-04-29 21:44:12 +00:00
QP . CallAfter ( qt_code , recent_tags )
2018-01-31 22:58:15 +00:00
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
2020-04-29 21:44:12 +00:00
def _UpdateTagDisplay ( self ) :
tags = FilterSuggestedTagsForMedia ( self . _last_fetched_tags , self . _media , self . _service_key )
self . _recent_tags . SetTags ( tags )
2019-11-14 03:56:30 +00:00
def EventClear ( self ) :
2016-08-31 19:55:14 +00:00
2020-04-22 21:00:35 +00:00
from hydrus . client . gui import ClientGUIDialogsQuick
2016-08-31 19:55:14 +00:00
2020-04-16 00:09:42 +00:00
result = ClientGUIDialogsQuick . GetYesNo ( self , ' Clear recent tags? ' )
if result == QW . QDialog . Accepted :
HG . client_controller . Write ( ' push_recent_tags ' , self . _service_key , None )
2020-05-06 21:31:41 +00:00
self . _last_fetched_tags = [ ]
2020-04-29 21:44:12 +00:00
self . _UpdateTagDisplay ( )
2020-04-16 00:09:42 +00:00
2016-08-31 19:55:14 +00:00
2020-04-01 21:51:42 +00:00
def RefreshRecentTags ( self ) :
self . _RefreshRecentTags ( )
2020-04-29 21:44:12 +00:00
def MediaUpdated ( self ) :
self . _UpdateTagDisplay ( )
def SetMedia ( self , media ) :
self . _media = media
self . _UpdateTagDisplay ( )
self . _RefreshRecentTags ( )
2019-06-05 19:42:39 +00:00
def TakeFocusForUser ( self ) :
self . _recent_tags . TakeFocusForUser ( )
2019-11-14 03:56:30 +00:00
class RelatedTagsPanel ( QW . QWidget ) :
2016-08-03 22:15:54 +00:00
2020-09-23 21:02:02 +00:00
mouseActivationOccurred = QC . Signal ( )
2020-04-29 21:44:12 +00:00
def __init__ ( self , parent , service_key , media , activate_callable ) :
2016-08-03 22:15:54 +00:00
2019-11-14 03:56:30 +00:00
QW . QWidget . __init__ ( self , parent )
2016-08-03 22:15:54 +00:00
self . _service_key = service_key
self . _media = media
2020-04-29 21:44:12 +00:00
self . _last_fetched_predicates = [ ]
2016-08-03 22:15:54 +00:00
2023-02-01 21:20:47 +00:00
self . _have_done_search_with_this_media = False
2019-06-05 19:42:39 +00:00
2023-01-25 22:59:39 +00:00
self . _selected_tags = set ( )
2017-12-06 22:06:56 +00:00
self . _new_options = HG . client_controller . new_options
2016-08-03 22:15:54 +00:00
2019-11-14 03:56:30 +00:00
vbox = QP . VBoxLayout ( )
2016-08-03 22:15:54 +00:00
2023-02-01 21:20:47 +00:00
self . _status_label = ClientGUICommon . BetterStaticText ( self , label = ' ready ' )
self . _just_do_local_files = ClientGUICommon . OnOffButton ( self , on_label = ' just for my files ' , off_label = ' for all known files ' , start_on = True )
self . _just_do_local_files . setToolTip ( ' Select how big the search is. Searching across all known files on a repository produces high quality results but takes a long time. ' )
2023-01-25 22:59:39 +00:00
tt = ' If you select some tags, this will search using only those as reference! '
2023-02-01 21:20:47 +00:00
self . _button_1 = QW . QPushButton ( ' quick ' , self )
self . _button_1 . clicked . connect ( self . RefreshQuick )
self . _button_1 . setMinimumWidth ( 30 )
self . _button_1 . setToolTip ( tt )
2019-11-14 03:56:30 +00:00
self . _button_2 = QW . QPushButton ( ' medium ' , self )
2021-01-07 01:10:01 +00:00
self . _button_2 . clicked . connect ( self . RefreshMedium )
2019-11-14 03:56:30 +00:00
self . _button_2 . setMinimumWidth ( 30 )
2023-01-25 22:59:39 +00:00
self . _button_2 . setToolTip ( tt )
2016-08-03 22:15:54 +00:00
2019-11-14 03:56:30 +00:00
self . _button_3 = QW . QPushButton ( ' thorough ' , self )
2021-01-07 01:10:01 +00:00
self . _button_3 . clicked . connect ( self . RefreshThorough )
2019-11-14 03:56:30 +00:00
self . _button_3 . setMinimumWidth ( 30 )
2023-01-25 22:59:39 +00:00
self . _button_3 . setToolTip ( tt )
if HG . client_controller . services_manager . GetServiceType ( self . _service_key ) == HC . LOCAL_TAG :
2023-02-01 21:20:47 +00:00
self . _just_do_local_files . setVisible ( False )
2023-01-25 22:59:39 +00:00
2016-08-03 22:15:54 +00:00
2020-09-09 20:59:19 +00:00
self . _related_tags = ListBoxTagsSuggestionsRelated ( self , service_key , activate_callable )
2016-08-03 22:15:54 +00:00
2019-11-14 03:56:30 +00:00
button_hbox = QP . HBoxLayout ( )
2016-08-03 22:15:54 +00:00
2023-02-01 21:20:47 +00:00
QP . AddToLayout ( button_hbox , self . _button_1 , CC . FLAGS_EXPAND_SIZER_BOTH_WAYS )
2019-11-14 03:56:30 +00:00
QP . AddToLayout ( button_hbox , self . _button_2 , CC . FLAGS_EXPAND_SIZER_BOTH_WAYS )
QP . AddToLayout ( button_hbox , self . _button_3 , CC . FLAGS_EXPAND_SIZER_BOTH_WAYS )
2016-08-03 22:15:54 +00:00
2023-02-01 21:20:47 +00:00
QP . AddToLayout ( vbox , self . _status_label , CC . FLAGS_EXPAND_PERPENDICULAR )
QP . AddToLayout ( vbox , self . _just_do_local_files , CC . FLAGS_EXPAND_PERPENDICULAR )
2019-11-14 03:56:30 +00:00
QP . AddToLayout ( vbox , button_hbox , CC . FLAGS_EXPAND_PERPENDICULAR )
QP . AddToLayout ( vbox , self . _related_tags , CC . FLAGS_EXPAND_BOTH_WAYS )
2016-08-03 22:15:54 +00:00
2019-11-14 03:56:30 +00:00
self . setLayout ( vbox )
2016-08-03 22:15:54 +00:00
2020-09-23 21:02:02 +00:00
self . _related_tags . mouseActivationOccurred . connect ( self . mouseActivationOccurred )
2016-08-03 22:15:54 +00:00
2023-02-01 21:20:47 +00:00
def _FetchRelatedTagsNew ( self , max_time_to_take ) :
2016-08-03 22:15:54 +00:00
2023-02-01 21:20:47 +00:00
def do_it ( file_service_key , tag_service_key , search_tags ) :
2018-01-31 22:58:15 +00:00
2023-02-01 21:20:47 +00:00
def qt_code ( predicates , num_done , num_to_do , total_time_took ) :
2018-01-31 22:58:15 +00:00
2019-11-14 03:56:30 +00:00
if not self or not QP . isValid ( self ) :
2018-01-31 22:58:15 +00:00
return
2023-02-01 21:20:47 +00:00
if num_to_do == len ( search_tags ) :
tags_s = ' tags '
else :
tags_s = ' tags ( {} had no relations) ' . format ( HydrusData . ToHumanInt ( len ( search_tags ) - num_to_do ) )
if num_done == len ( search_tags ) :
num_done_s = ' Searched all {} {} in ' . format ( HydrusData . ToHumanInt ( num_done ) , tags_s )
elif num_done == num_to_do :
num_done_s = ' Searched {} {} in ' . format ( HydrusData . ToHumanInt ( num_done ) , tags_s )
else :
num_done_s = ' {} {} searched fully in ' . format ( HydrusData . ConvertValueRangeToPrettyString ( num_done , num_to_do ) , tags_s )
label = ' {} {} . ' . format ( num_done_s , HydrusData . TimeDeltaToPrettyTimeDelta ( total_time_took ) )
self . _status_label . setText ( label )
2020-04-29 21:44:12 +00:00
self . _last_fetched_predicates = predicates
self . _UpdateTagDisplay ( )
2018-01-31 22:58:15 +00:00
2023-02-01 21:20:47 +00:00
self . _have_done_search_with_this_media = True
2019-06-05 19:42:39 +00:00
2018-01-31 22:58:15 +00:00
2023-02-01 21:20:47 +00:00
start_time = HydrusData . GetNowPrecise ( )
2018-01-31 22:58:15 +00:00
2023-02-01 21:20:47 +00:00
( num_done , num_to_do , predicates ) = HG . client_controller . Read ( ' related_tags ' , file_service_key , tag_service_key , search_tags , max_time_to_take = max_time_to_take )
2018-01-31 22:58:15 +00:00
2023-02-01 21:20:47 +00:00
total_time_took = HydrusData . GetNowPrecise ( ) - start_time
2018-01-31 22:58:15 +00:00
2023-02-01 21:20:47 +00:00
predicates = ClientSearch . SortPredicates ( predicates )
2023-01-25 22:59:39 +00:00
2023-02-01 21:20:47 +00:00
QP . CallAfter ( qt_code , predicates , num_done , num_to_do , total_time_took )
2023-01-25 22:59:39 +00:00
2023-02-01 21:20:47 +00:00
self . _related_tags . SetPredicates ( [ ] )
2023-01-25 22:59:39 +00:00
if len ( self . _selected_tags ) == 0 :
search_tags = ClientMedia . GetMediasTags ( self . _media , self . _service_key , ClientTags . TAG_DISPLAY_STORAGE , ( HC . CONTENT_STATUS_CURRENT , HC . CONTENT_STATUS_PENDING ) )
else :
search_tags = self . _selected_tags
2016-08-03 22:15:54 +00:00
2023-02-01 21:20:47 +00:00
if len ( search_tags ) == 0 :
2023-01-25 22:59:39 +00:00
2023-02-01 21:20:47 +00:00
self . _status_label . setVisible ( False )
2023-01-25 22:59:39 +00:00
2023-02-01 21:20:47 +00:00
return
2023-01-25 22:59:39 +00:00
2023-02-01 21:20:47 +00:00
self . _status_label . setVisible ( True )
2023-01-25 22:59:39 +00:00
2023-02-01 21:20:47 +00:00
self . _status_label . setText ( ' searching \u2026 ' )
if self . _just_do_local_files . IsOn ( ) :
2023-01-25 22:59:39 +00:00
2023-02-01 21:20:47 +00:00
file_service_key = CC . COMBINED_LOCAL_MEDIA_SERVICE_KEY
2023-01-25 22:59:39 +00:00
else :
2023-02-01 21:20:47 +00:00
file_service_key = CC . COMBINED_FILE_SERVICE_KEY
2023-01-25 22:59:39 +00:00
tag_service_key = self . _service_key
HG . client_controller . CallToThread ( do_it , file_service_key , tag_service_key , search_tags )
2023-02-01 21:20:47 +00:00
def _UpdateTagDisplay ( self ) :
2016-08-03 22:15:54 +00:00
2023-02-01 21:20:47 +00:00
predicates = FilterSuggestedPredicatesForMedia ( self . _last_fetched_predicates , self . _media , self . _service_key )
2016-08-03 22:15:54 +00:00
2023-02-01 21:20:47 +00:00
self . _related_tags . SetPredicates ( predicates )
2016-08-03 22:15:54 +00:00
2023-02-01 21:20:47 +00:00
def RefreshQuick ( self ) :
2020-04-29 21:44:12 +00:00
2023-02-01 21:20:47 +00:00
max_time_to_take = self . _new_options . GetInteger ( ' related_tags_search_1_duration_ms ' ) / 1000.0
2020-04-29 21:44:12 +00:00
2023-02-01 21:20:47 +00:00
self . _FetchRelatedTagsNew ( max_time_to_take )
2020-04-29 21:44:12 +00:00
2021-01-07 01:10:01 +00:00
def RefreshMedium ( self ) :
2016-08-03 22:15:54 +00:00
max_time_to_take = self . _new_options . GetInteger ( ' related_tags_search_2_duration_ms ' ) / 1000.0
2023-02-01 21:20:47 +00:00
self . _FetchRelatedTagsNew ( max_time_to_take )
2016-08-03 22:15:54 +00:00
2021-01-07 01:10:01 +00:00
def RefreshThorough ( self ) :
2016-08-03 22:15:54 +00:00
max_time_to_take = self . _new_options . GetInteger ( ' related_tags_search_3_duration_ms ' ) / 1000.0
2023-02-01 21:20:47 +00:00
self . _FetchRelatedTagsNew ( max_time_to_take )
2016-08-03 22:15:54 +00:00
2023-02-01 21:20:47 +00:00
def MediaUpdated ( self ) :
2023-01-25 22:59:39 +00:00
2023-02-01 21:20:47 +00:00
self . _UpdateTagDisplay ( )
2023-01-25 22:59:39 +00:00
2023-02-01 21:20:47 +00:00
def NotifyUserLooking ( self ) :
2020-04-29 21:44:12 +00:00
2023-02-01 21:20:47 +00:00
if not self . _have_done_search_with_this_media :
self . RefreshQuick ( )
2020-04-29 21:44:12 +00:00
2020-04-01 21:51:42 +00:00
def SetMedia ( self , media ) :
self . _media = media
2023-02-01 21:20:47 +00:00
self . _status_label . setText ( ' ready ' )
self . _related_tags . SetPredicates ( [ ] )
self . _have_done_search_with_this_media = False
2023-01-25 22:59:39 +00:00
def SetSelectedTags ( self , tags ) :
self . _selected_tags = tags
2020-04-01 21:51:42 +00:00
2019-06-05 19:42:39 +00:00
def TakeFocusForUser ( self ) :
self . _related_tags . TakeFocusForUser ( )
2019-11-14 03:56:30 +00:00
class FileLookupScriptTagsPanel ( QW . QWidget ) :
2016-11-09 23:13:22 +00:00
2020-09-23 21:02:02 +00:00
mouseActivationOccurred = QC . Signal ( )
2020-04-29 21:44:12 +00:00
def __init__ ( self , parent , service_key , media , activate_callable ) :
2016-11-09 23:13:22 +00:00
2019-11-14 03:56:30 +00:00
QW . QWidget . __init__ ( self , parent )
2016-11-09 23:13:22 +00:00
self . _service_key = service_key
self . _media = media
2020-05-06 21:31:41 +00:00
self . _last_fetched_tags = [ ]
2016-11-09 23:13:22 +00:00
self . _script_choice = ClientGUICommon . BetterChoice ( self )
2019-11-14 03:56:30 +00:00
self . _script_choice . setEnabled ( False )
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
2019-11-14 03:56:30 +00:00
self . _fetch_button . setEnabled ( False )
2016-11-09 23:13:22 +00:00
2022-08-24 21:06:25 +00:00
self . _script_management = ClientGUIParsingLegacy . ScriptManagementControl ( self )
2016-11-16 20:21:43 +00:00
2020-09-09 20:59:19 +00:00
self . _tags = ListBoxTagsSuggestionsFavourites ( self , self . _service_key , activate_callable , sort_tags = True )
2016-11-09 23:13:22 +00:00
2016-11-16 20:21:43 +00:00
self . _add_all = ClientGUICommon . BetterButton ( self , ' add all ' , self . _tags . ActivateAll )
2019-11-14 03:56:30 +00:00
vbox = QP . VBoxLayout ( )
2016-11-09 23:13:22 +00:00
2019-11-14 03:56:30 +00:00
QP . AddToLayout ( vbox , self . _script_choice , CC . FLAGS_EXPAND_PERPENDICULAR )
QP . AddToLayout ( vbox , self . _fetch_button , CC . FLAGS_EXPAND_PERPENDICULAR )
QP . AddToLayout ( vbox , self . _script_management , CC . FLAGS_EXPAND_PERPENDICULAR )
QP . AddToLayout ( vbox , self . _add_all , CC . FLAGS_EXPAND_PERPENDICULAR )
QP . AddToLayout ( vbox , 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 ( [ ] )
2019-11-14 03:56:30 +00:00
self . setLayout ( vbox )
2016-11-09 23:13:22 +00:00
2018-01-31 22:58:15 +00:00
self . _FetchScripts ( )
2020-09-23 21:02:02 +00:00
self . _tags . mouseActivationOccurred . connect ( self . mouseActivationOccurred )
2018-01-31 22:58:15 +00:00
def _FetchScripts ( self ) :
def do_it ( ) :
2019-11-14 03:56:30 +00:00
def qt_code ( ) :
2018-01-31 22:58:15 +00:00
2019-11-14 03:56:30 +00:00
if not self or not QP . isValid ( self ) :
2018-01-31 22:58:15 +00:00
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
2019-11-14 03:56:30 +00:00
self . _script_choice . addItem ( script . GetName ( ) , script )
2018-01-31 22:58:15 +00:00
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 :
2019-07-24 21:39:02 +00:00
self . _script_choice . SetValue ( script_names_to_scripts [ favourite_file_lookup_script ] )
2018-01-31 22:58:15 +00:00
else :
2019-11-14 03:56:30 +00:00
self . _script_choice . setCurrentIndex ( 0 )
2018-01-31 22:58:15 +00:00
2019-11-14 03:56:30 +00:00
self . _script_choice . setEnabled ( True )
self . _fetch_button . setEnabled ( True )
2018-01-31 22:58:15 +00:00
scripts = HG . client_controller . Read ( ' serialisable_named ' , HydrusSerialisable . SERIALISABLE_TYPE_PARSE_ROOT_FILE_LOOKUP )
2019-11-14 03:56:30 +00:00
QP . CallAfter ( qt_code )
2018-01-31 22:58:15 +00:00
HG . client_controller . CallToThread ( do_it )
2016-11-16 20:21:43 +00:00
def _SetTags ( self , tags ) :
2020-04-29 21:44:12 +00:00
self . _last_fetched_tags = tags
self . _UpdateTagDisplay ( )
def _UpdateTagDisplay ( self ) :
tags = FilterSuggestedTagsForMedia ( self . _last_fetched_tags , self . _media , self . _service_key )
2016-11-16 20:21:43 +00:00
self . _tags . SetTags ( tags )
if len ( tags ) == 0 :
2019-11-14 03:56:30 +00:00
self . _add_all . setEnabled ( False )
2016-11-16 20:21:43 +00:00
else :
2019-11-14 03:56:30 +00:00
self . _add_all . setEnabled ( True )
2016-11-16 20:21:43 +00:00
2016-11-09 23:13:22 +00:00
def FetchTags ( self ) :
2019-07-24 21:39:02 +00:00
script = self . _script_choice . GetValue ( )
2016-11-09 23:13:22 +00:00
if script . UsesUserInput ( ) :
message = ' Enter the custom input for the file lookup script. '
with ClientGUIDialogs . DialogTextEntry ( self , message ) as dlg :
2019-11-14 03:56:30 +00:00
if dlg . exec ( ) != QW . QDialog . Accepted :
2016-11-09 23:13:22 +00:00
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 )
2020-05-06 21:31:41 +00:00
self . _SetTags ( [ ] )
2020-04-01 21:51:42 +00:00
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
2020-04-29 21:44:12 +00:00
def MediaUpdated ( self ) :
self . _UpdateTagDisplay ( )
2020-04-01 21:51:42 +00:00
def SetMedia ( self , media ) :
self . _media = media
2020-04-29 21:44:12 +00:00
self . _UpdateTagDisplay ( )
2020-04-01 21:51:42 +00:00
2019-06-05 19:42:39 +00:00
def TakeFocusForUser ( self ) :
if self . _have_fetched :
self . _tags . TakeFocusForUser ( )
else :
2019-11-14 03:56:30 +00:00
self . _fetch_button . setFocus ( QC . Qt . OtherFocusReason )
2019-06-05 19:42:39 +00:00
2017-12-13 22:33:07 +00:00
def THREADFetchTags ( self , script , job_key , file_identifier ) :
2016-11-16 20:21:43 +00:00
2019-11-14 03:56:30 +00:00
def qt_code ( tags ) :
2018-01-24 23:09:42 +00:00
2019-11-14 03:56:30 +00:00
if not self or not QP . isValid ( self ) :
2018-01-24 23:09:42 +00:00
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
2022-12-21 22:00:27 +00:00
tags = list ( ClientParsing . GetTagsFromParseResults ( parse_results ) )
tag_sort = ClientTagSorting . TagSort ( ClientTagSorting . SORT_BY_HUMAN_TAG , sort_order = CC . SORT_ASC )
ClientTagSorting . SortTags ( tag_sort , tags )
2016-11-09 23:13:22 +00:00
2019-11-14 03:56:30 +00:00
QP . CallAfter ( qt_code , tags )
2016-11-09 23:13:22 +00:00
2019-11-14 03:56:30 +00:00
class SuggestedTagsPanel ( QW . QWidget ) :
2016-08-03 22:15:54 +00:00
2020-09-23 21:02:02 +00:00
mouseActivationOccurred = QC . Signal ( )
2020-04-29 21:44:12 +00:00
def __init__ ( self , parent , service_key , media , activate_callable ) :
2016-08-03 22:15:54 +00:00
2019-11-14 03:56:30 +00:00
QW . QWidget . __init__ ( self , parent )
2016-08-03 22:15:54 +00:00
self . _service_key = service_key
self . _media = media
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
2019-06-05 19:42:39 +00:00
self . _favourite_tags = None
2020-04-29 21:44:12 +00:00
favourites = HG . client_controller . new_options . GetSuggestedTagsFavourites ( self . _service_key )
2016-08-03 22:15:54 +00:00
if len ( favourites ) > 0 :
2020-04-29 21:44:12 +00:00
self . _favourite_tags = FavouritesTagsPanel ( panel_parent , service_key , media , activate_callable )
2016-08-03 22:15:54 +00:00
2020-09-23 21:02:02 +00:00
self . _favourite_tags . mouseActivationOccurred . connect ( self . mouseActivationOccurred )
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
2023-01-25 22:59:39 +00:00
if self . _new_options . GetBoolean ( ' show_related_tags ' ) :
2016-08-03 22:15:54 +00:00
2020-04-29 21:44:12 +00:00
self . _related_tags = RelatedTagsPanel ( panel_parent , service_key , media , activate_callable )
2016-11-09 23:13:22 +00:00
2020-09-23 21:02:02 +00:00
self . _related_tags . mouseActivationOccurred . connect ( self . mouseActivationOccurred )
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
2020-04-29 21:44:12 +00:00
self . _file_lookup_script_tags = FileLookupScriptTagsPanel ( panel_parent , service_key , media , activate_callable )
2016-11-09 23:13:22 +00:00
2020-09-23 21:02:02 +00:00
self . _file_lookup_script_tags . mouseActivationOccurred . connect ( self . mouseActivationOccurred )
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 :
2020-04-29 21:44:12 +00:00
self . _recent_tags = RecentTagsPanel ( panel_parent , service_key , media , activate_callable )
2016-08-31 19:55:14 +00:00
2020-09-23 21:02:02 +00:00
self . _recent_tags . mouseActivationOccurred . connect ( self . mouseActivationOccurred )
2019-06-05 19:42:39 +00:00
panels . append ( ( ' recent ' , self . _recent_tags ) )
2016-08-31 19:55:14 +00:00
2020-04-01 21:51:42 +00:00
hbox = QP . HBoxLayout ( )
2016-11-09 23:13:22 +00:00
if layout_mode == ' notebook ' :
for ( name , panel ) in panels :
2019-11-14 03:56:30 +00:00
self . _notebook . addTab ( panel , name )
2016-11-09 23:13:22 +00:00
2019-11-14 03:56:30 +00:00
QP . AddToLayout ( hbox , self . _notebook , CC . FLAGS_EXPAND_BOTH_WAYS )
2016-11-09 23:13:22 +00:00
2023-02-01 21:20:47 +00:00
name_to_page_dict = {
' favourites ' : self . _favourite_tags ,
' related ' : self . _related_tags ,
' file_lookup_scripts ' : self . _file_lookup_script_tags ,
' recent ' : self . _recent_tags
}
default_suggested_tags_notebook_page = self . _new_options . GetString ( ' default_suggested_tags_notebook_page ' )
choice = name_to_page_dict . get ( default_suggested_tags_notebook_page , None )
if choice is not None :
self . _notebook . setCurrentWidget ( choice )
self . _notebook . currentChanged . connect ( self . _PageChanged )
2016-11-09 23:13:22 +00:00
elif layout_mode == ' columns ' :
for ( name , panel ) in panels :
2023-02-01 21:20:47 +00:00
box_panel = ClientGUICommon . StaticBox ( self , name )
box_panel . Add ( panel , CC . FLAGS_EXPAND_BOTH_WAYS )
QP . AddToLayout ( hbox , box_panel , CC . FLAGS_EXPAND_PERPENDICULAR )
2016-11-09 23:13:22 +00:00
2020-04-01 21:51:42 +00:00
self . setLayout ( 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
2019-11-14 03:56:30 +00:00
self . hide ( )
2016-08-03 22:15:54 +00:00
2023-02-01 21:20:47 +00:00
else :
self . _PageChanged ( )
def _PageChanged ( self ) :
if self . _notebook is None :
self . _related_tags . NotifyUserLooking ( )
return
current_page = self . _notebook . currentWidget ( )
if current_page == self . _related_tags :
self . _related_tags . NotifyUserLooking ( )
2016-08-03 22:15:54 +00:00
2017-02-01 21:11:17 +00:00
2020-04-29 21:44:12 +00:00
def MediaUpdated ( self ) :
if self . _favourite_tags is not None :
self . _favourite_tags . MediaUpdated ( )
if self . _recent_tags is not None :
self . _recent_tags . MediaUpdated ( )
if self . _file_lookup_script_tags is not None :
self . _file_lookup_script_tags . MediaUpdated ( )
if self . _related_tags is not None :
self . _related_tags . MediaUpdated ( )
2021-01-07 01:10:01 +00:00
def RefreshRelatedThorough ( self ) :
if self . _related_tags is not None :
self . _related_tags . RefreshThorough ( )
2020-04-01 21:51:42 +00:00
def SetMedia ( self , media ) :
self . _media = media
2020-04-29 21:44:12 +00:00
if self . _favourite_tags is not None :
self . _favourite_tags . SetMedia ( media )
2020-04-01 22:52:48 +00:00
if self . _recent_tags is not None :
2020-04-01 21:51:42 +00:00
2020-04-29 21:44:12 +00:00
self . _recent_tags . SetMedia ( media )
2020-04-01 22:52:48 +00:00
if self . _file_lookup_script_tags is not None :
self . _file_lookup_script_tags . SetMedia ( media )
if self . _related_tags is not None :
self . _related_tags . SetMedia ( media )
2020-04-01 21:51:42 +00:00
2023-02-01 21:20:47 +00:00
self . _PageChanged ( )
2020-04-01 21:51:42 +00:00
2023-01-25 22:59:39 +00:00
def SetSelectedTags ( self , tags ) :
if self . _related_tags is not None :
self . _related_tags . SetSelectedTags ( tags )
2019-06-05 19:42:39 +00:00
def TakeFocusForUser ( self , command ) :
2020-07-08 22:00:33 +00:00
if command == CAC . SIMPLE_SHOW_AND_FOCUS_MANAGE_TAGS_FAVOURITE_TAGS :
2019-06-05 19:42:39 +00:00
panel = self . _favourite_tags
2020-07-08 22:00:33 +00:00
elif command == CAC . SIMPLE_SHOW_AND_FOCUS_MANAGE_TAGS_RELATED_TAGS :
2019-06-05 19:42:39 +00:00
panel = self . _related_tags
2020-07-08 22:00:33 +00:00
elif command == CAC . SIMPLE_SHOW_AND_FOCUS_MANAGE_TAGS_FILE_LOOKUP_SCRIPT_TAGS :
2019-06-05 19:42:39 +00:00
panel = self . _file_lookup_script_tags
2020-07-08 22:00:33 +00:00
elif command == CAC . SIMPLE_SHOW_AND_FOCUS_MANAGE_TAGS_RECENT_TAGS :
2019-06-05 19:42:39 +00:00
panel = self . _recent_tags
if panel is not None :
if self . _notebook is not None :
self . _notebook . SelectPage ( panel )
panel . TakeFocusForUser ( )