import collections import itertools import typing from qtpy import QtWidgets as QW from hydrus.core import HydrusData from hydrus.core import HydrusGlobals as HG from hydrus.client import ClientConstants as CC from hydrus.client import ClientSearch from hydrus.client.gui import ClientGUIFunctions from hydrus.client.gui import ClientGUIDialogsQuick from hydrus.client.gui import ClientGUIResultsSortCollect from hydrus.client.gui import ClientGUIScrolledPanels from hydrus.client.gui import ClientGUITopLevelWindowsPanels from hydrus.client.gui import QtPorting as QP from hydrus.client.gui.lists import ClientGUIListConstants as CGLC from hydrus.client.gui.lists import ClientGUIListCtrl from hydrus.client.gui.widgets import ClientGUICommon class EditFavouriteSearchPanel( ClientGUIScrolledPanels.EditPanel ): def __init__( self, parent, existing_folders_to_names, foldername, name, file_search_context, synchronised, media_sort, media_collect ): ClientGUIScrolledPanels.EditPanel.__init__( self, parent ) self._existing_folders_to_names = existing_folders_to_names self._original_folder_and_name = ( foldername, name ) self._foldername = QW.QLineEdit( self ) self._name = QW.QLineEdit( self ) self._media_sort = ClientGUIResultsSortCollect.MediaSortControl( self ) self._media_collect = ClientGUIResultsSortCollect.MediaCollectControl( self, silent = True ) page_key = HydrusData.GenerateKey() from hydrus.client.gui.search import ClientGUIACDropdown self._tag_autocomplete = ClientGUIACDropdown.AutoCompleteDropdownTagsRead( self, page_key, file_search_context, media_sort_widget = self._media_sort, media_collect_widget = self._media_collect, synchronised = synchronised, hide_favourites_edit_actions = True ) self._include_media_sort = QW.QCheckBox( self ) self._include_media_collect = QW.QCheckBox( self ) width = ClientGUIFunctions.ConvertTextToPixelWidth( self._include_media_collect, 48 ) self._include_media_collect.setMinimumWidth( width ) self._include_media_sort.stateChanged.connect( self._UpdateWidgets ) self._include_media_collect.stateChanged.connect( self._UpdateWidgets ) # if foldername is not None: self._foldername.setText( foldername ) self._name.setText( name ) if media_sort is not None: self._include_media_sort.setChecked( True ) self._media_sort.SetSort( media_sort ) if media_collect is not None: self._include_media_collect.setChecked( True ) self._media_collect.SetCollect( media_collect ) # rows = [] rows.append( ( 'folder (blank for none): ', self._foldername ) ) rows.append( ( 'name: ', self._name ) ) top_gridbox = ClientGUICommon.WrapInGrid( self, rows ) rows = [] rows.append( ( 'save sort: ', self._include_media_sort ) ) rows.append( ( 'sort: ', self._media_sort ) ) rows.append( ( 'save collect: ', self._include_media_collect ) ) rows.append( ( 'collect: ', self._media_collect ) ) bottom_gridbox = ClientGUICommon.WrapInGrid( self, rows ) vbox = QP.VBoxLayout() QP.AddToLayout( vbox, top_gridbox, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR ) QP.AddToLayout( vbox, self._tag_autocomplete, CC.FLAGS_EXPAND_BOTH_WAYS ) QP.AddToLayout( vbox, bottom_gridbox, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR ) self.widget().setLayout( vbox ) def _UpdateWidgets( self ): self._media_sort.setEnabled( self._include_media_sort.isChecked() ) self._media_collect.setEnabled( self._include_media_collect.isChecked() ) def UserIsOKToOK( self ): ( foldername, name, file_search_context, synchronised, media_sort, media_collect ) = self.GetValue() if ( foldername, name ) != self._original_folder_and_name: if foldername in self._existing_folders_to_names and name in self._existing_folders_to_names[ foldername ]: if foldername is None: folder_str = '' else: folder_str = ' under folder "{}"'.format( foldername ) message = 'The search "{}"{} already exists! Do you want to overwrite it?'.format( name, folder_str ) result = ClientGUIDialogsQuick.GetYesNo( self, message ) if result != QW.QDialog.Accepted: return False return True def GetValue( self ): foldername = self._foldername.text() if foldername == '': foldername = None name = self._name.text() file_search_context = self._tag_autocomplete.GetFileSearchContext() synchronised = self._tag_autocomplete.IsSynchronised() if self._include_media_sort.isChecked(): media_sort = self._media_sort.GetSort() else: media_sort = None if self._include_media_collect.isChecked(): media_collect = self._media_collect.GetValue() else: media_collect = None return ( foldername, name, file_search_context, synchronised, media_sort, media_collect ) class EditFavouriteSearchesPanel( ClientGUIScrolledPanels.EditPanel ): def __init__( self, parent, favourite_searches_rows, initial_search_row_to_edit = None ): ClientGUIScrolledPanels.EditPanel.__init__( self, parent ) self._favourite_searches_panel = ClientGUIListCtrl.BetterListCtrlPanel( self ) self._favourite_searches = ClientGUIListCtrl.BetterListCtrl( self._favourite_searches_panel, CGLC.COLUMN_LIST_FAVOURITE_SEARCHES.ID, 20, self._ConvertRowToListCtrlTuples, use_simple_delete = True, activation_callback = self._EditFavouriteSearch ) self._favourite_searches_panel.SetListCtrl( self._favourite_searches ) self._favourite_searches_panel.AddButton( 'add', self._AddNewFavouriteSearch ) self._favourite_searches_panel.AddButton( 'edit', self._EditFavouriteSearch, enabled_only_on_selection = True ) self._favourite_searches_panel.AddDeleteButton() # self._favourite_searches.AddDatas( favourite_searches_rows ) self._favourite_searches.Sort() # vbox = QP.VBoxLayout() QP.AddToLayout( vbox, self._favourite_searches_panel, CC.FLAGS_EXPAND_BOTH_WAYS ) self.widget().setLayout( vbox ) if initial_search_row_to_edit is not None: HG.client_controller.CallLaterQtSafe( self, 0.5, self._AddNewFavouriteSearch, initial_search_row_to_edit ) def _AddNewFavouriteSearch( self, search_row = None ): existing_folders_to_names = self._GetExistingFoldersToNames() existing_names = { name for name in itertools.chain.from_iterable( existing_folders_to_names.values() ) } if search_row is None: foldername = None name = 'new favourite search' file_search_context = ClientSearch.FileSearchContext( file_service_key = CC.LOCAL_FILE_SERVICE_KEY ) synchronised = True media_sort = None media_collect = None else: ( foldername, name, file_search_context, synchronised, media_sort, media_collect ) = search_row name = HydrusData.GetNonDupeName( name, existing_names ) with ClientGUITopLevelWindowsPanels.DialogEdit( self, 'edit favourite search' ) as dlg: panel = EditFavouriteSearchPanel( dlg, existing_folders_to_names, foldername, name, file_search_context, synchronised, media_sort, media_collect ) dlg.SetPanel( panel ) if dlg.exec() == QW.QDialog.Accepted: row = panel.GetValue() self._DeleteRow( row[0], row[1] ) self._favourite_searches.AddDatas( ( row, ) ) self._favourite_searches.Sort() def _ConvertRowToListCtrlTuples( self, row ): ( foldername, name, file_search_context, synchronised, media_sort, media_collect ) = row if foldername is None: pretty_foldername = '' else: pretty_foldername = foldername pretty_name = name pretty_file_search_context = ', '.join( predicate.ToString() for predicate in file_search_context.GetPredicates() ) if media_sort is None: pretty_media_sort = '' else: pretty_media_sort = media_sort.ToString() if media_collect is None: pretty_media_collect = '' else: pretty_media_collect = media_collect.ToString() display_tuple = ( pretty_foldername, pretty_name, pretty_file_search_context, pretty_media_sort, pretty_media_collect ) sort_tuple = ( pretty_foldername, pretty_name, pretty_file_search_context, pretty_media_sort, pretty_media_collect ) return ( display_tuple, sort_tuple ) def _DeleteRow( self, foldername, name ): for row in self._favourite_searches.GetData(): if foldername == row[0] and name == row[1]: self._favourite_searches.DeleteDatas( ( row, ) ) return def _EditFavouriteSearch( self ): for row in self._favourite_searches.GetData( only_selected = True ): ( foldername, name, file_search_context, synchronised, media_sort, media_collect ) = row existing_folders_to_names = self._GetExistingFoldersToNames() with ClientGUITopLevelWindowsPanels.DialogEdit( self, 'edit favourite search' ) as dlg: panel = EditFavouriteSearchPanel( dlg, existing_folders_to_names, foldername, name, file_search_context, synchronised, media_sort, media_collect ) dlg.SetPanel( panel ) if dlg.exec() == QW.QDialog.Accepted: self._DeleteRow( foldername, name ) edited_row = panel.GetValue() self._DeleteRow( edited_row[0], edited_row[1] ) self._favourite_searches.AddDatas( ( edited_row, ) ) else: break self._favourite_searches.Sort() def _GetExistingFoldersToNames( self ): existing_folders_to_names = collections.defaultdict( list ) for ( foldername, name, file_search_context, synchronised, media_sort, media_collect ) in self._favourite_searches.GetData(): existing_folders_to_names[ foldername ].append( name ) return existing_folders_to_names def GetValue( self ): favourite_searches_rows = self._favourite_searches.GetData() return favourite_searches_rows