960 lines
30 KiB
Python
960 lines
30 KiB
Python
import typing
|
|
|
|
from qtpy import QtCore as QC
|
|
from qtpy import QtGui as QG
|
|
from qtpy import QtWidgets as QW
|
|
|
|
from hydrus.core import HydrusConstants as HC
|
|
from hydrus.core import HydrusData
|
|
from hydrus.core import HydrusExceptions
|
|
from hydrus.core import HydrusGlobals as HG
|
|
|
|
from hydrus.client import ClientConstants as CC
|
|
from hydrus.client import ClientSearch
|
|
from hydrus.client.gui import ClientGUICore as CGC
|
|
from hydrus.client.gui import ClientGUIFunctions
|
|
from hydrus.client.gui import ClientGUIMenus
|
|
from hydrus.client.gui import ClientGUITags
|
|
from hydrus.client.gui import QtPorting as QP
|
|
from hydrus.client.gui.search import ClientGUISearch
|
|
from hydrus.client.gui.widgets import ClientGUICommon
|
|
from hydrus.client.gui.widgets import ClientGUIMenuButton
|
|
from hydrus.client.media import ClientMedia
|
|
from hydrus.client.metadata import ClientTags
|
|
|
|
# wew lad
|
|
# https://stackoverflow.com/questions/46456238/checkbox-not-visible-inside-combobox
|
|
class CheckBoxDelegate( QW.QStyledItemDelegate ):
|
|
|
|
def __init__( self, parent = None ):
|
|
|
|
super( CheckBoxDelegate, self ).__init__( parent )
|
|
|
|
|
|
def createEditor( self, parent, op, idx ):
|
|
|
|
self.editor = QW.QCheckBox( parent )
|
|
|
|
|
|
|
|
class CollectComboCtrl( QW.QComboBox ):
|
|
|
|
itemChanged = QC.Signal()
|
|
|
|
def __init__( self, parent, media_collect ):
|
|
|
|
QW.QComboBox.__init__( self, parent )
|
|
|
|
self.view().pressed.connect( self._HandleItemPressed )
|
|
|
|
# this was previously 'if Fusion style only', but as it works for normal styles too, it is more helpful to have it always on
|
|
self.setItemDelegate( CheckBoxDelegate() )
|
|
|
|
self.setModel( QG.QStandardItemModel( self ) )
|
|
|
|
self._ReinitialiseChoices()
|
|
|
|
# Trick to display custom text
|
|
|
|
self._cached_text = ''
|
|
|
|
if media_collect.DoesACollect():
|
|
|
|
QP.CallAfter( self.SetCollectByValue, media_collect )
|
|
|
|
|
|
|
|
def _HandleItemPressed( self, index ):
|
|
|
|
item = self.model().itemFromIndex( index )
|
|
|
|
if item.checkState() == QC.Qt.Checked:
|
|
|
|
item.setCheckState( QC.Qt.Unchecked )
|
|
|
|
else:
|
|
|
|
item.setCheckState( QC.Qt.Checked )
|
|
|
|
|
|
self.SetValue( self._cached_text )
|
|
|
|
self.itemChanged.emit()
|
|
|
|
|
|
def _ReinitialiseChoices( self ):
|
|
|
|
text_and_data_tuples = set()
|
|
|
|
for media_sort in HG.client_controller.new_options.GetDefaultNamespaceSorts():
|
|
|
|
namespaces = media_sort.GetNamespaces()
|
|
|
|
try:
|
|
|
|
text_and_data_tuples.update( namespaces )
|
|
|
|
except:
|
|
|
|
HydrusData.DebugPrint( 'Bad namespaces: {}'.format( namespaces ) )
|
|
|
|
HydrusData.ShowText( 'Hey, your namespace-based sorts are likely damaged. Details have been written to the log, please let hydev know!' )
|
|
|
|
|
|
|
|
text_and_data_tuples = sorted( ( ( namespace, ( 'namespace', namespace ) ) for namespace in text_and_data_tuples ) )
|
|
|
|
ratings_services = HG.client_controller.services_manager.GetServices( ( HC.LOCAL_RATING_LIKE, HC.LOCAL_RATING_NUMERICAL ) )
|
|
|
|
for ratings_service in ratings_services:
|
|
|
|
text_and_data_tuples.append( ( ratings_service.GetName(), ('rating', ratings_service.GetServiceKey() ) ) )
|
|
|
|
|
|
current_text_and_data_tuples = []
|
|
|
|
for i in range( self.count() ):
|
|
|
|
item = self.model().item( i, 0 )
|
|
|
|
t = item.text()
|
|
d = self.itemData( i, QC.Qt.UserRole )
|
|
|
|
current_text_and_data_tuples.append( ( t, d ) )
|
|
|
|
|
|
made_changes = False
|
|
|
|
if current_text_and_data_tuples != text_and_data_tuples:
|
|
|
|
if self.count() > 0:
|
|
|
|
# PRO TIP 4 U: if you say self.clear() here, the program has a ~15% chance to crash instantly if you have previously done a clear/add cycle!
|
|
# this affects PyQt and PySide, 5 and 6, running from source, so must be something in Qt core. some argument between the model and widget
|
|
self.model().clear()
|
|
|
|
|
|
for ( text, data ) in text_and_data_tuples:
|
|
|
|
self.addItem( text, userData = data )
|
|
|
|
item = self.model().item( self.count() - 1, 0 )
|
|
|
|
item.setCheckState( QC.Qt.Unchecked )
|
|
|
|
|
|
made_changes = True
|
|
|
|
|
|
return made_changes
|
|
|
|
|
|
def GetCheckedIndices( self ):
|
|
|
|
indices = []
|
|
|
|
for idx in range( self.count() ):
|
|
|
|
item = self.model().item( idx )
|
|
|
|
if item.checkState() == QC.Qt.Checked:
|
|
|
|
indices.append( idx )
|
|
|
|
|
|
|
|
return indices
|
|
|
|
|
|
def GetCheckedStrings( self ):
|
|
|
|
strings = [ ]
|
|
|
|
for idx in range( self.count() ):
|
|
|
|
item = self.model().item( idx )
|
|
|
|
if item.checkState() == QC.Qt.Checked:
|
|
|
|
strings.append( item.text() )
|
|
|
|
|
|
|
|
return strings
|
|
|
|
|
|
def GetValues( self ):
|
|
|
|
namespaces = []
|
|
rating_service_keys = []
|
|
|
|
for index in self.GetCheckedIndices():
|
|
|
|
( collect_type, collect_data ) = self.itemData( index, QC.Qt.UserRole )
|
|
|
|
if collect_type == 'namespace':
|
|
|
|
namespaces.append( collect_data )
|
|
|
|
elif collect_type == 'rating':
|
|
|
|
rating_service_keys.append( collect_data )
|
|
|
|
|
|
|
|
collect_strings = self.GetCheckedStrings()
|
|
|
|
if len( collect_strings ) > 0:
|
|
|
|
description = 'collect by ' + '-'.join( collect_strings )
|
|
|
|
else:
|
|
|
|
description = 'no collections'
|
|
|
|
|
|
return ( namespaces, rating_service_keys, description )
|
|
|
|
|
|
def hidePopup(self):
|
|
|
|
if not self.view().underMouse():
|
|
|
|
QW.QComboBox.hidePopup( self )
|
|
|
|
|
|
|
|
|
|
def paintEvent( self, e ):
|
|
|
|
painter = QW.QStylePainter( self )
|
|
painter.setPen( self.palette().color( QG.QPalette.Text ) )
|
|
|
|
opt = QW.QStyleOptionComboBox()
|
|
self.initStyleOption( opt )
|
|
|
|
opt.currentText = self._cached_text
|
|
|
|
painter.drawComplexControl( QW.QStyle.CC_ComboBox, opt )
|
|
|
|
painter.drawControl( QW.QStyle.CE_ComboBoxLabel, opt )
|
|
|
|
|
|
def ReinitialiseChoices( self ):
|
|
|
|
return self._ReinitialiseChoices()
|
|
|
|
|
|
def SetValue( self, text ):
|
|
|
|
self._cached_text = text
|
|
|
|
self.setCurrentText( text )
|
|
|
|
|
|
|
|
def SetCollectByValue( self, media_collect ):
|
|
|
|
try:
|
|
|
|
indices_to_check = []
|
|
|
|
for index in range( self.count() ):
|
|
|
|
( collect_type, collect_data ) = self.itemData( index, QC.Qt.UserRole )
|
|
|
|
p1 = collect_type == 'namespace' and collect_data in media_collect.namespaces
|
|
p2 = collect_type == 'rating' and collect_data in media_collect.rating_service_keys
|
|
|
|
if p1 or p2:
|
|
|
|
indices_to_check.append( index )
|
|
|
|
|
|
|
|
self.SetCheckedIndices( indices_to_check )
|
|
|
|
self.itemChanged.emit()
|
|
|
|
except Exception as e:
|
|
|
|
HydrusData.ShowText( 'Failed to set a collect-by value!' )
|
|
|
|
HydrusData.ShowException( e )
|
|
|
|
|
|
|
|
def SetCheckedIndices( self, indices_to_check ):
|
|
|
|
for idx in range( self.count() ):
|
|
|
|
item = self.model().item( idx )
|
|
|
|
if idx in indices_to_check:
|
|
|
|
item.setCheckState( QC.Qt.Checked )
|
|
|
|
else:
|
|
|
|
item.setCheckState( QC.Qt.Unchecked )
|
|
|
|
|
|
|
|
|
|
|
|
class MediaCollectControl( QW.QWidget ):
|
|
|
|
def __init__( self, parent, management_controller = None, silent = False ):
|
|
|
|
QW.QWidget.__init__( self, parent )
|
|
|
|
# this is trash, rewrite it to deal with the media_collect object, not the management controller
|
|
|
|
self._management_controller = management_controller
|
|
|
|
if self._management_controller is not None and self._management_controller.HasVariable( 'media_collect' ):
|
|
|
|
self._media_collect = self._management_controller.GetVariable( 'media_collect' )
|
|
|
|
else:
|
|
|
|
self._media_collect = HG.client_controller.new_options.GetDefaultCollect()
|
|
|
|
|
|
self._silent = silent
|
|
|
|
self._collect_comboctrl = CollectComboCtrl( self, self._media_collect )
|
|
|
|
choice_tuples = [
|
|
( 'collect unmatched', True ),
|
|
( 'leave unmatched', False )
|
|
]
|
|
|
|
self._collect_unmatched = ClientGUIMenuButton.MenuChoiceButton( self, choice_tuples )
|
|
|
|
width = ClientGUIFunctions.ConvertTextToPixelWidth( self._collect_unmatched, 19 )
|
|
|
|
self._collect_unmatched.setMinimumWidth( width )
|
|
|
|
self._tag_context_button = ClientGUISearch.TagContextButton( self, self._media_collect.tag_context, use_short_label = True )
|
|
|
|
#
|
|
|
|
self._collect_unmatched.SetValue( self._media_collect.collect_unmatched )
|
|
|
|
#
|
|
|
|
hbox = QP.HBoxLayout( margin = 0 )
|
|
|
|
QP.AddToLayout( hbox, self._collect_comboctrl, CC.FLAGS_EXPAND_BOTH_WAYS )
|
|
QP.AddToLayout( hbox, self._collect_unmatched, CC.FLAGS_CENTER_PERPENDICULAR )
|
|
QP.AddToLayout( hbox, self._tag_context_button, CC.FLAGS_CENTER_PERPENDICULAR )
|
|
|
|
self.setLayout( hbox )
|
|
|
|
#
|
|
|
|
self._UpdateButtonsVisible()
|
|
self._UpdateLabel()
|
|
|
|
self._collect_unmatched.valueChanged.connect( self.CollectValuesChanged )
|
|
self._collect_comboctrl.itemChanged.connect( self.CollectValuesChanged )
|
|
self._tag_context_button.valueChanged.connect( self.CollectValuesChanged )
|
|
|
|
self._collect_comboctrl.installEventFilter( self )
|
|
|
|
HG.client_controller.sub( self, 'NotifyAdvancedMode', 'notify_advanced_mode' )
|
|
HG.client_controller.sub( self, 'SetCollectFromPage', 'set_page_collect' )
|
|
|
|
|
|
def _BroadcastCollect( self ):
|
|
|
|
if not self._silent and self._management_controller is not None:
|
|
|
|
self._management_controller.SetVariable( 'media_collect', self._media_collect )
|
|
|
|
page_key = self._management_controller.GetVariable( 'page_key' )
|
|
|
|
HG.client_controller.pub( 'collect_media', page_key, self._media_collect )
|
|
HG.client_controller.pub( 'a_collect_happened', page_key )
|
|
|
|
|
|
|
|
def _UpdateButtonsVisible( self ):
|
|
|
|
self._tag_context_button.setVisible( HG.client_controller.new_options.GetBoolean( 'advanced_mode' ) )
|
|
|
|
|
|
def _UpdateLabel( self ):
|
|
|
|
( namespaces, rating_service_keys, description ) = self._collect_comboctrl.GetValues()
|
|
|
|
self._collect_comboctrl.SetValue( description )
|
|
|
|
|
|
def CollectValuesChanged( self ):
|
|
|
|
( namespaces, rating_service_keys, description ) = self._collect_comboctrl.GetValues()
|
|
|
|
self._UpdateLabel()
|
|
|
|
collect_unmatched = self._collect_unmatched.GetValue()
|
|
|
|
tag_context = self._tag_context_button.GetValue()
|
|
|
|
self._media_collect = ClientMedia.MediaCollect( namespaces = namespaces, rating_service_keys = rating_service_keys, collect_unmatched = collect_unmatched, tag_context = tag_context )
|
|
|
|
self._BroadcastCollect()
|
|
|
|
|
|
def eventFilter( self, watched, event ):
|
|
|
|
if watched == self._collect_comboctrl:
|
|
|
|
if event.type() == QC.QEvent.MouseButtonPress and event.button() == QC.Qt.MiddleButton:
|
|
|
|
self.SetCollect( ClientMedia.MediaCollect( collect_unmatched = self._media_collect.collect_unmatched ) )
|
|
|
|
return True
|
|
|
|
|
|
|
|
return False
|
|
|
|
|
|
def GetValue( self ):
|
|
|
|
return self._media_collect
|
|
|
|
|
|
def ListenForNewOptions( self ):
|
|
|
|
HG.client_controller.sub( self, 'NotifyNewOptions', 'notify_new_options' )
|
|
|
|
|
|
def NotifyAdvancedMode( self ):
|
|
|
|
self._UpdateButtonsVisible()
|
|
|
|
|
|
def NotifyNewOptions( self ):
|
|
|
|
media_collect = self._media_collect.Duplicate()
|
|
|
|
made_changes = self._collect_comboctrl.ReinitialiseChoices()
|
|
|
|
if made_changes:
|
|
|
|
self.SetCollect( media_collect, do_broadcast = False )
|
|
|
|
|
|
|
|
def SetCollect( self, media_collect: ClientMedia.MediaCollect, do_broadcast = True ):
|
|
|
|
self._media_collect = media_collect
|
|
|
|
self._collect_comboctrl.blockSignals( True )
|
|
self._collect_unmatched.blockSignals( True )
|
|
|
|
self._collect_comboctrl.SetCollectByValue( self._media_collect )
|
|
self._collect_unmatched.SetValue( self._media_collect.collect_unmatched )
|
|
|
|
self._UpdateLabel()
|
|
|
|
self._collect_comboctrl.blockSignals( False )
|
|
self._collect_unmatched.blockSignals( False )
|
|
|
|
if do_broadcast:
|
|
|
|
self._BroadcastCollect()
|
|
|
|
|
|
|
|
def SetCollectFromPage( self, page_key, media_collect ):
|
|
|
|
if page_key == self._management_controller.GetVariable( 'page_key' ):
|
|
|
|
self.SetCollect( media_collect )
|
|
|
|
self._BroadcastCollect()
|
|
|
|
|
|
|
|
class MediaSortControl( QW.QWidget ):
|
|
|
|
sortChanged = QC.Signal( ClientMedia.MediaSort )
|
|
|
|
def __init__( self, parent, management_controller = None ):
|
|
|
|
QW.QWidget.__init__( self, parent )
|
|
|
|
self._management_controller = management_controller
|
|
|
|
self._sort_type = ( 'system', CC.SORT_FILES_BY_FILESIZE )
|
|
|
|
self._sort_type_button = ClientGUICommon.BetterButton( self, 'sort', self._SortTypeButtonClick )
|
|
self._sort_tag_display_type_button = ClientGUIMenuButton.MenuChoiceButton( self, [] )
|
|
self._sort_order_choice = ClientGUIMenuButton.MenuChoiceButton( self, [] )
|
|
|
|
tag_context = ClientSearch.TagContext( service_key = CC.COMBINED_TAG_SERVICE_KEY )
|
|
|
|
self._tag_context_button = ClientGUISearch.TagContextButton( self, tag_context, use_short_label = True )
|
|
|
|
type_width = ClientGUIFunctions.ConvertTextToPixelWidth( self._sort_type_button, 14 )
|
|
|
|
self._sort_type_button.setMinimumWidth( type_width )
|
|
|
|
tdt_width = ClientGUIFunctions.ConvertTextToPixelWidth( self._sort_tag_display_type_button, 8 )
|
|
|
|
self._sort_tag_display_type_button.setMinimumWidth( tdt_width )
|
|
|
|
asc_width = ClientGUIFunctions.ConvertTextToPixelWidth( self._sort_order_choice, 14 )
|
|
|
|
self._sort_order_choice.setMinimumWidth( asc_width )
|
|
|
|
self._UpdateSortTypeLabel()
|
|
self._UpdateButtonsVisible()
|
|
self._UpdateAscDescLabelsAndDefault()
|
|
|
|
#
|
|
|
|
hbox = QP.HBoxLayout( margin = 0 )
|
|
|
|
QP.AddToLayout( hbox, self._sort_type_button, CC.FLAGS_EXPAND_BOTH_WAYS )
|
|
QP.AddToLayout( hbox, self._sort_tag_display_type_button, CC.FLAGS_CENTER_PERPENDICULAR )
|
|
QP.AddToLayout( hbox, self._sort_order_choice, CC.FLAGS_CENTER_PERPENDICULAR )
|
|
QP.AddToLayout( hbox, self._tag_context_button, CC.FLAGS_CENTER_PERPENDICULAR )
|
|
|
|
self.setLayout( hbox )
|
|
|
|
HG.client_controller.sub( self, 'ACollectHappened', 'a_collect_happened' )
|
|
HG.client_controller.sub( self, 'BroadcastSort', 'do_page_sort' )
|
|
|
|
if self._management_controller is not None and self._management_controller.HasVariable( 'media_sort' ):
|
|
|
|
media_sort = self._management_controller.GetVariable( 'media_sort' )
|
|
|
|
try:
|
|
|
|
self.SetSort( media_sort )
|
|
|
|
except:
|
|
|
|
default_sort = ClientMedia.MediaSort( ( 'system', CC.SORT_FILES_BY_FILESIZE ), CC.SORT_ASC )
|
|
|
|
self.SetSort( default_sort )
|
|
|
|
|
|
|
|
self._sort_tag_display_type_button.valueChanged.connect( self.EventTagDisplayTypeChoice )
|
|
self._sort_order_choice.valueChanged.connect( self.EventSortAscChoice )
|
|
self._tag_context_button.valueChanged.connect( self.EventTagContextChanged )
|
|
|
|
|
|
def _BroadcastSort( self ):
|
|
|
|
media_sort = self._GetCurrentSort()
|
|
|
|
if self._management_controller is not None:
|
|
|
|
self._management_controller.SetVariable( 'media_sort', media_sort )
|
|
|
|
|
|
self.sortChanged.emit( media_sort )
|
|
|
|
|
|
def _GetCurrentSort( self ) -> ClientMedia.MediaSort:
|
|
|
|
sort_order = self._sort_order_choice.GetValue()
|
|
|
|
if sort_order is None:
|
|
|
|
sort_order = CC.SORT_ASC
|
|
|
|
|
|
tag_context = self._tag_context_button.GetValue()
|
|
|
|
media_sort = ClientMedia.MediaSort( sort_type = self._sort_type, sort_order = sort_order, tag_context = tag_context )
|
|
|
|
return media_sort
|
|
|
|
|
|
def _PopulateSortMenuOrList( self, menu = None ):
|
|
|
|
sort_types = []
|
|
|
|
menu_items_and_sort_types = []
|
|
|
|
submetatypes_to_menus = {}
|
|
|
|
for system_sort_type in CC.SYSTEM_SORT_TYPES_SORT_CONTROL_SORTED:
|
|
|
|
sort_type = ( 'system', system_sort_type )
|
|
|
|
sort_types.append( sort_type )
|
|
|
|
if menu is not None:
|
|
|
|
submetatype = CC.system_sort_type_submetatype_string_lookup[ system_sort_type ]
|
|
|
|
if submetatype is None:
|
|
|
|
menu_to_add_to = menu
|
|
|
|
else:
|
|
|
|
if submetatype not in submetatypes_to_menus:
|
|
|
|
submenu = QW.QMenu( menu )
|
|
|
|
submetatypes_to_menus[ submetatype ] = submenu
|
|
|
|
ClientGUIMenus.AppendMenu( menu, submenu, submetatype )
|
|
|
|
|
|
menu_to_add_to = submetatypes_to_menus[ submetatype ]
|
|
|
|
|
|
label = CC.sort_type_basic_string_lookup[ system_sort_type ]
|
|
|
|
menu_item = ClientGUIMenus.AppendMenuItem( menu_to_add_to, label, 'Select this sort type.', self._SetSortTypeFromUser, sort_type )
|
|
|
|
menu_items_and_sort_types.append( ( menu_item, sort_type ) )
|
|
|
|
|
|
|
|
default_namespace_sorts = HG.client_controller.new_options.GetDefaultNamespaceSorts()
|
|
|
|
if menu is not None:
|
|
|
|
submenu = QW.QMenu( menu )
|
|
|
|
ClientGUIMenus.AppendMenu( menu, submenu, 'namespaces' )
|
|
|
|
|
|
for namespace_sort in default_namespace_sorts:
|
|
|
|
sort_type = namespace_sort.sort_type
|
|
|
|
sort_types.append( sort_type )
|
|
|
|
if menu is not None:
|
|
|
|
example_sort = ClientMedia.MediaSort( sort_type, CC.SORT_ASC )
|
|
|
|
label = example_sort.GetSortTypeString()
|
|
|
|
menu_item = ClientGUIMenus.AppendMenuItem( submenu, label, 'Select this sort type.', self._SetSortTypeFromUser, sort_type )
|
|
|
|
menu_items_and_sort_types.append( ( menu_item, sort_type ) )
|
|
|
|
|
|
|
|
if menu is not None:
|
|
|
|
ClientGUIMenus.AppendMenuItem( submenu, 'custom', 'Set a custom namespace sort', self._SetCustomNamespaceSortFromUser )
|
|
|
|
|
|
rating_service_keys = HG.client_controller.services_manager.GetServiceKeys( ( HC.LOCAL_RATING_LIKE, HC.LOCAL_RATING_NUMERICAL ) )
|
|
|
|
if len( rating_service_keys ) > 0:
|
|
|
|
if menu is not None:
|
|
|
|
submenu = QW.QMenu( menu )
|
|
|
|
ClientGUIMenus.AppendMenu( menu, submenu, 'ratings' )
|
|
|
|
|
|
for service_key in rating_service_keys:
|
|
|
|
sort_type = ( 'rating', service_key )
|
|
|
|
sort_types.append( sort_type )
|
|
|
|
if menu is not None:
|
|
|
|
example_sort = ClientMedia.MediaSort( sort_type, CC.SORT_ASC )
|
|
|
|
label = example_sort.GetSortTypeString()
|
|
|
|
menu_item = ClientGUIMenus.AppendMenuItem( submenu, label, 'Select this sort type.', self._SetSortTypeFromUser, sort_type )
|
|
|
|
menu_items_and_sort_types.append( ( menu_item, sort_type ) )
|
|
|
|
|
|
|
|
|
|
if menu is not None:
|
|
|
|
for ( menu_item, sort_choice ) in menu_items_and_sort_types:
|
|
|
|
if sort_choice == self._sort_type:
|
|
|
|
menu_item.setCheckable( True )
|
|
menu_item.setChecked( True )
|
|
|
|
|
|
|
|
|
|
return sort_types
|
|
|
|
|
|
def _SetCustomNamespaceSortFromUser( self ):
|
|
|
|
if self._sort_type[0] == 'namespaces':
|
|
|
|
sort_data = self._sort_type[1]
|
|
|
|
else:
|
|
|
|
sort_data = ( [ 'series' ], ClientTags.TAG_DISPLAY_ACTUAL )
|
|
|
|
|
|
try:
|
|
|
|
sort_data = ClientGUITags.EditNamespaceSort( self, sort_data )
|
|
|
|
sort_type = ( 'namespaces', sort_data )
|
|
|
|
self._SetSortTypeFromUser( sort_type )
|
|
|
|
except HydrusExceptions.VetoException:
|
|
|
|
return
|
|
|
|
|
|
|
|
def _SortTypeButtonClick( self ):
|
|
|
|
menu = QW.QMenu()
|
|
|
|
self._PopulateSortMenuOrList( menu = menu )
|
|
|
|
CGC.core().PopupMenu( self, menu )
|
|
|
|
|
|
def _SetSortType( self, sort_type ):
|
|
|
|
self._sort_type = sort_type
|
|
|
|
self._UpdateSortTypeLabel()
|
|
self._UpdateButtonsVisible()
|
|
self._UpdateAscDescLabelsAndDefault()
|
|
|
|
|
|
def _SetSortTypeFromUser( self, sort_type ):
|
|
|
|
self._SetSortType( sort_type )
|
|
|
|
self._UserChoseASort()
|
|
|
|
self._BroadcastSort()
|
|
|
|
|
|
def _UpdateAscDescLabelsAndDefault( self ):
|
|
|
|
media_sort = self._GetCurrentSort()
|
|
|
|
self._sort_order_choice.blockSignals( True )
|
|
|
|
if media_sort.CanAsc():
|
|
|
|
( asc_str, desc_str, default_sort_order ) = media_sort.GetSortOrderStrings()
|
|
|
|
choice_tuples = [
|
|
( asc_str, CC.SORT_ASC ),
|
|
( desc_str, CC.SORT_DESC )
|
|
]
|
|
|
|
# if there are no changes to asc/desc texts, then we'll keep the previous value
|
|
|
|
if choice_tuples != self._sort_order_choice.GetChoiceTuples():
|
|
|
|
self._sort_order_choice.SetChoiceTuples( choice_tuples )
|
|
|
|
self._sort_order_choice.SetValue( default_sort_order )
|
|
|
|
|
|
self._sort_order_choice.setVisible( True )
|
|
|
|
else:
|
|
|
|
self._sort_order_choice.setVisible( False )
|
|
#self._sort_order_choice.SetChoiceTuples( [] )
|
|
|
|
|
|
self._sort_order_choice.blockSignals( False )
|
|
|
|
|
|
def _UpdateButtonsVisible( self ):
|
|
|
|
( sort_metatype, sort_data ) = self._sort_type
|
|
|
|
show_tag_button = sort_metatype == 'namespaces' and HG.client_controller.new_options.GetBoolean( 'advanced_mode' )
|
|
|
|
self._tag_context_button.setVisible( show_tag_button )
|
|
|
|
self._sort_tag_display_type_button.setVisible( show_tag_button )
|
|
|
|
|
|
def _UpdateSortTypeLabel( self ):
|
|
|
|
example_sort = ClientMedia.MediaSort( self._sort_type, CC.SORT_ASC )
|
|
|
|
self._sort_type_button.setText( example_sort.GetSortTypeString() )
|
|
|
|
( sort_metatype, sort_data ) = self._sort_type
|
|
|
|
show_tdt = sort_metatype == 'namespaces' and HG.client_controller.new_options.GetBoolean( 'advanced_mode' )
|
|
|
|
if show_tdt:
|
|
|
|
if sort_metatype == 'namespaces':
|
|
|
|
( namespaces, current_tag_display_type ) = sort_data
|
|
|
|
tag_display_types = [
|
|
ClientTags.TAG_DISPLAY_ACTUAL,
|
|
ClientTags.TAG_DISPLAY_SELECTION_LIST,
|
|
ClientTags.TAG_DISPLAY_SINGLE_MEDIA
|
|
]
|
|
|
|
choice_tuples = [ ( ClientTags.tag_display_str_lookup[ tag_display_type ], tag_display_type ) for tag_display_type in tag_display_types ]
|
|
|
|
self._sort_tag_display_type_button.blockSignals( True )
|
|
|
|
self._sort_tag_display_type_button.SetChoiceTuples( choice_tuples )
|
|
|
|
self._sort_tag_display_type_button.SetValue( current_tag_display_type )
|
|
|
|
self._sort_tag_display_type_button.blockSignals( False )
|
|
|
|
|
|
|
|
|
|
def _UserChoseASort( self ):
|
|
|
|
if HG.client_controller.new_options.GetBoolean( 'save_page_sort_on_change' ):
|
|
|
|
media_sort = self._GetCurrentSort()
|
|
|
|
HG.client_controller.new_options.SetDefaultSort( media_sort )
|
|
|
|
|
|
|
|
def ACollectHappened( self, page_key ):
|
|
|
|
if self._management_controller is not None:
|
|
|
|
my_page_key = self._management_controller.GetVariable( 'page_key' )
|
|
|
|
if page_key == my_page_key:
|
|
|
|
self._BroadcastSort()
|
|
|
|
|
|
|
|
|
|
def BroadcastSort( self, page_key = None ):
|
|
|
|
if page_key is not None and page_key != self._management_controller.GetVariable( 'page_key' ):
|
|
|
|
return
|
|
|
|
|
|
self._BroadcastSort()
|
|
|
|
|
|
def EventSortAscChoice( self ):
|
|
|
|
self._UserChoseASort()
|
|
|
|
self._BroadcastSort()
|
|
|
|
|
|
def EventTagContextChanged( self, tag_context: ClientSearch.TagContext ):
|
|
|
|
self._UserChoseASort()
|
|
|
|
self._BroadcastSort()
|
|
|
|
|
|
def EventTagDisplayTypeChoice( self ):
|
|
|
|
( sort_metatype, sort_data ) = self._sort_type
|
|
|
|
if sort_metatype == 'namespaces':
|
|
|
|
( namespaces, current_tag_display_type ) = sort_data
|
|
|
|
tag_display_type = self._sort_tag_display_type_button.GetValue()
|
|
|
|
sort_data = ( namespaces, tag_display_type )
|
|
|
|
self._SetSortType( ( sort_metatype, sort_data ) )
|
|
|
|
self._UserChoseASort()
|
|
|
|
self._BroadcastSort()
|
|
|
|
|
|
|
|
def GetSort( self ) -> ClientMedia.MediaSort:
|
|
|
|
return self._GetCurrentSort()
|
|
|
|
|
|
def NotifyAdvancedMode( self ):
|
|
|
|
self._UpdateButtonsVisible()
|
|
|
|
|
|
def SetSort( self, media_sort: ClientMedia.MediaSort ):
|
|
|
|
self._SetSortType( media_sort.sort_type )
|
|
|
|
# put this after 'asclabels', since we may transition from one-state to two-state
|
|
self._sort_order_choice.SetValue( media_sort.sort_order )
|
|
|
|
self._tag_context_button.SetValue( media_sort.tag_context )
|
|
|
|
|
|
def wheelEvent( self, event ):
|
|
|
|
if HG.client_controller.new_options.GetBoolean( 'menu_choice_buttons_can_mouse_scroll' ):
|
|
|
|
if self._sort_type_button.rect().contains( self._sort_type_button.mapFromGlobal( QG.QCursor.pos() ) ):
|
|
|
|
if event.angleDelta().y() > 0:
|
|
|
|
index_delta = -1
|
|
|
|
else:
|
|
|
|
index_delta = 1
|
|
|
|
|
|
sort_types = self._PopulateSortMenuOrList()
|
|
|
|
if self._sort_type in sort_types:
|
|
|
|
index = sort_types.index( self._sort_type )
|
|
|
|
new_index = ( index + index_delta ) % len( sort_types )
|
|
|
|
new_sort_type = sort_types[ new_index ]
|
|
|
|
self._SetSortTypeFromUser( new_sort_type )
|
|
|
|
|
|
|
|
event.accept()
|
|
|
|
else:
|
|
|
|
event.ignore()
|
|
|
|
|
|
|