hydrus/hydrus/client/gui/ClientGUIPages.py

3162 lines
98 KiB
Python
Raw Normal View History

2018-05-02 20:45:20 +00:00
import collections
2013-02-19 00:11:43 +00:00
import os
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
from qtpy import QtGui as QG
2020-04-22 21:00:35 +00:00
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.core import HydrusSerialisable
from hydrus.core import HydrusText
from hydrus.client import ClientConstants as CC
from hydrus.client import ClientSearch
from hydrus.client import ClientThreading
from hydrus.client.gui import ClientGUICanvas
from hydrus.client.gui import ClientGUICore as CGC
from hydrus.client.gui import ClientGUIDialogs
from hydrus.client.gui import ClientGUIDialogsQuick
from hydrus.client.gui import ClientGUIFunctions
from hydrus.client.gui import ClientGUIManagement
from hydrus.client.gui import ClientGUIMenus
from hydrus.client.gui import ClientGUIResults
from hydrus.client.gui import ClientGUIShortcuts
from hydrus.client.gui import QtPorting as QP
2013-02-19 00:11:43 +00:00
2018-11-28 22:31:04 +00:00
RESERVED_SESSION_NAMES = { '', 'just a blank page', 'last session', 'exit session' }
2017-10-25 21:45:15 +00:00
2017-08-16 21:58:06 +00:00
class DialogPageChooser( ClientGUIDialogs.Dialog ):
def __init__( self, parent, controller ):
ClientGUIDialogs.Dialog.__init__( self, parent, 'new page', position = 'center' )
self._controller = controller
2020-01-16 02:08:23 +00:00
self._action_picked = False
2017-08-16 21:58:06 +00:00
self._result = None
2019-11-14 03:56:30 +00:00
# spawn and add to layout in this order, so focus precipitates from the graphical top
self._button_7 = QW.QPushButton( '', self )
self._button_8 = QW.QPushButton( '', self )
self._button_9 = QW.QPushButton( '', self )
self._button_4 = QW.QPushButton( '', self )
self._button_5 = QW.QPushButton( '', self )
self._button_6 = QW.QPushButton( '', self )
self._button_1 = QW.QPushButton( '', self )
self._button_2 = QW.QPushButton( '', self )
self._button_3 = QW.QPushButton( '', self )
size_policy = self._button_1.sizePolicy()
size_policy.setVerticalPolicy( QW.QSizePolicy.Expanding )
size_policy.setRetainSizeWhenHidden( True )
self._button_7.setSizePolicy( size_policy )
self._button_8.setSizePolicy( size_policy )
self._button_9.setSizePolicy( size_policy )
self._button_4.setSizePolicy( size_policy )
self._button_5.setSizePolicy( size_policy )
self._button_6.setSizePolicy( size_policy )
self._button_1.setSizePolicy( size_policy )
self._button_2.setSizePolicy( size_policy )
self._button_3.setSizePolicy( size_policy )
self._button_7.setObjectName('7')
self._button_8.setObjectName('8')
self._button_9.setObjectName('9')
self._button_4.setObjectName('4')
self._button_5.setObjectName('5')
self._button_6.setObjectName('6')
self._button_1.setObjectName('1')
self._button_2.setObjectName('2')
self._button_3.setObjectName('3')
# this ensures these buttons won't get focus and receive key events, letting dialog handle arrow/number shortcuts
self._button_7.setFocusPolicy( QC.Qt.NoFocus )
self._button_8.setFocusPolicy( QC.Qt.NoFocus )
self._button_9.setFocusPolicy( QC.Qt.NoFocus )
self._button_4.setFocusPolicy( QC.Qt.NoFocus )
self._button_5.setFocusPolicy( QC.Qt.NoFocus )
self._button_6.setFocusPolicy( QC.Qt.NoFocus )
self._button_1.setFocusPolicy( QC.Qt.NoFocus )
self._button_2.setFocusPolicy( QC.Qt.NoFocus )
self._button_3.setFocusPolicy( QC.Qt.NoFocus )
gridbox = QP.GridLayout( cols = 3 )
QP.AddToLayout( gridbox, self._button_7 )
QP.AddToLayout( gridbox, self._button_8 )
QP.AddToLayout( gridbox, self._button_9 )
QP.AddToLayout( gridbox, self._button_4 )
QP.AddToLayout( gridbox, self._button_5 )
QP.AddToLayout( gridbox, self._button_6 )
QP.AddToLayout( gridbox, self._button_1 )
QP.AddToLayout( gridbox, self._button_2 )
QP.AddToLayout( gridbox, self._button_3 )
self.setLayout( gridbox )
( width, height ) = ClientGUIFunctions.ConvertTextToPixels( self, ( 64, 14 ) )
self.setMinimumWidth( width )
self.setMinimumHeight( height )
2017-08-16 21:58:06 +00:00
self._services = HG.client_controller.services_manager.GetServices()
repository_petition_permissions = [ ( content_type, HC.PERMISSION_ACTION_OVERRULE ) for content_type in HC.REPOSITORY_CONTENT_TYPES ]
self._petition_service_keys = [ service.GetServiceKey() for service in self._services if service.GetServiceType() in HC.REPOSITORIES and True in ( service.HasPermission( content_type, action ) for ( content_type, action ) in repository_petition_permissions ) ]
self._InitButtons( 'home' )
2019-11-14 03:56:30 +00:00
self._button_7.clicked.connect( lambda: self._HitButton( 7 ) )
self._button_8.clicked.connect( lambda: self._HitButton( 8 ) )
self._button_9.clicked.connect( lambda: self._HitButton( 9 ) )
self._button_4.clicked.connect( lambda: self._HitButton( 4 ) )
self._button_5.clicked.connect( lambda: self._HitButton( 5 ) )
self._button_6.clicked.connect( lambda: self._HitButton( 6 ) )
self._button_1.clicked.connect( lambda: self._HitButton( 1 ) )
self._button_2.clicked.connect( lambda: self._HitButton( 2 ) )
self._button_3.clicked.connect( lambda: self._HitButton( 3 ) )
2017-08-16 21:58:06 +00:00
def _AddEntry( self, button, entry ):
2019-11-14 03:56:30 +00:00
id = int( button.objectName() )
2017-08-16 21:58:06 +00:00
self._command_dict[ id ] = entry
( entry_type, obj ) = entry
if entry_type == 'menu':
2019-11-14 03:56:30 +00:00
button.setText( obj )
2017-08-16 21:58:06 +00:00
elif entry_type == 'page_duplicate_filter':
2019-11-14 03:56:30 +00:00
button.setText( 'duplicates processing' )
2017-08-16 21:58:06 +00:00
elif entry_type == 'pages_notebook':
2019-11-14 03:56:30 +00:00
button.setText( 'page of pages' )
2017-08-16 21:58:06 +00:00
elif entry_type in ( 'page_query', 'page_petitions' ):
name = HG.client_controller.services_manager.GetService( obj ).GetName()
2019-11-14 03:56:30 +00:00
button.setText( name )
2017-08-16 21:58:06 +00:00
elif entry_type == 'page_import_gallery':
2019-11-14 03:56:30 +00:00
button.setText( 'gallery' )
2017-08-16 21:58:06 +00:00
2018-04-05 01:22:26 +00:00
elif entry_type == 'page_import_simple_downloader':
2017-08-16 21:58:06 +00:00
2019-11-14 03:56:30 +00:00
button.setText( 'simple downloader' )
2017-08-16 21:58:06 +00:00
2018-05-23 21:05:06 +00:00
elif entry_type == 'page_import_watcher':
2017-08-16 21:58:06 +00:00
2019-11-14 03:56:30 +00:00
button.setText( 'watcher' )
2017-08-16 21:58:06 +00:00
elif entry_type == 'page_import_urls':
2019-11-14 03:56:30 +00:00
button.setText( 'urls' )
2017-08-16 21:58:06 +00:00
2019-11-14 03:56:30 +00:00
button.show()
2017-08-16 21:58:06 +00:00
def _HitButton( self, id ):
if id in self._command_dict:
( entry_type, obj ) = self._command_dict[ id ]
if entry_type == 'menu':
self._InitButtons( obj )
else:
if entry_type == 'page_query':
file_service_key = obj
page_name = 'files'
search_enabled = True
2017-12-06 22:06:56 +00:00
new_options = self._controller.new_options
2017-08-16 21:58:06 +00:00
tag_service_key = new_options.GetKey( 'default_tag_service_search_page' )
if not self._controller.services_manager.ServiceExists( tag_service_key ):
tag_service_key = CC.COMBINED_TAG_SERVICE_KEY
2020-03-11 21:52:11 +00:00
tag_search_context = ClientSearch.TagSearchContext( service_key = tag_service_key )
file_search_context = ClientSearch.FileSearchContext( file_service_key = file_service_key, tag_search_context = tag_search_context )
2017-08-16 21:58:06 +00:00
2020-04-01 21:51:42 +00:00
self._result = ( 'page', ClientGUIManagement.CreateManagementControllerQuery( page_name, file_search_context, search_enabled ) )
2017-08-16 21:58:06 +00:00
elif entry_type == 'page_duplicate_filter':
self._result = ( 'page', ClientGUIManagement.CreateManagementControllerDuplicateFilter() )
elif entry_type == 'pages_notebook':
self._result = ( 'pages', None )
elif entry_type == 'page_import_gallery':
2018-08-01 20:44:57 +00:00
self._result = ( 'page', ClientGUIManagement.CreateManagementControllerImportGallery() )
2017-08-16 21:58:06 +00:00
2018-04-05 01:22:26 +00:00
elif entry_type == 'page_import_simple_downloader':
2017-08-16 21:58:06 +00:00
2018-04-05 01:22:26 +00:00
self._result = ( 'page', ClientGUIManagement.CreateManagementControllerImportSimpleDownloader() )
2017-08-16 21:58:06 +00:00
2018-05-23 21:05:06 +00:00
elif entry_type == 'page_import_watcher':
2017-08-16 21:58:06 +00:00
2018-08-01 20:44:57 +00:00
self._result = ( 'page', ClientGUIManagement.CreateManagementControllerImportMultipleWatcher() )
2017-08-16 21:58:06 +00:00
elif entry_type == 'page_import_urls':
self._result = ( 'page', ClientGUIManagement.CreateManagementControllerImportURLs() )
elif entry_type == 'page_petitions':
petition_service_key = obj
self._result = ( 'page', ClientGUIManagement.CreateManagementControllerPetitions( petition_service_key ) )
2020-01-16 02:08:23 +00:00
self._action_picked = True
2019-11-14 03:56:30 +00:00
self.done( QW.QDialog.Accepted )
2017-08-16 21:58:06 +00:00
def _InitButtons( self, menu_keyword ):
self._command_dict = {}
entries = []
if menu_keyword == 'home':
entries.append( ( 'menu', 'files' ) )
entries.append( ( 'menu', 'download' ) )
if len( self._petition_service_keys ) > 0:
entries.append( ( 'menu', 'petitions' ) )
entries.append( ( 'menu', 'special' ) )
elif menu_keyword == 'files':
entries.append( ( 'page_query', CC.LOCAL_FILE_SERVICE_KEY ) )
entries.append( ( 'page_query', CC.TRASH_SERVICE_KEY ) )
2019-05-22 22:35:06 +00:00
if HG.client_controller.new_options.GetBoolean( 'advanced_mode' ):
entries.append( ( 'page_query', CC.COMBINED_LOCAL_FILE_SERVICE_KEY ) )
2017-08-16 21:58:06 +00:00
for service in self._services:
if service.GetServiceType() == HC.FILE_REPOSITORY:
entries.append( ( 'page_query', service.GetServiceKey() ) )
elif menu_keyword == 'download':
entries.append( ( 'page_import_urls', None ) )
2018-05-23 21:05:06 +00:00
entries.append( ( 'page_import_watcher', None ) )
2018-08-01 20:44:57 +00:00
entries.append( ( 'page_import_gallery', None ) )
2018-04-05 01:22:26 +00:00
entries.append( ( 'page_import_simple_downloader', None ) )
2017-08-16 21:58:06 +00:00
elif menu_keyword == 'petitions':
entries = [ ( 'page_petitions', service_key ) for service_key in self._petition_service_keys ]
elif menu_keyword == 'special':
entries.append( ( 'pages_notebook', None ) )
entries.append( ( 'page_duplicate_filter', None ) )
if len( entries ) <= 4:
2019-11-14 03:56:30 +00:00
self._button_1.setVisible( False )
self._button_3.setVisible( False )
self._button_5.setVisible( False )
self._button_7.setVisible( False )
self._button_9.setVisible( False )
2017-08-16 21:58:06 +00:00
potential_buttons = [ self._button_8, self._button_4, self._button_6, self._button_2 ]
elif len( entries ) <= 9:
potential_buttons = [ self._button_7, self._button_8, self._button_9, self._button_4, self._button_5, self._button_6, self._button_1, self._button_2, self._button_3 ]
else:
# sort out a multi-page solution? maybe only if this becomes a big thing; the person can always select from the menus, yeah?
potential_buttons = [ self._button_7, self._button_8, self._button_9, self._button_4, self._button_5, self._button_6, self._button_1, self._button_2, self._button_3 ]
entries = entries[:9]
2018-04-18 22:10:15 +00:00
for entry in entries:
self._AddEntry( potential_buttons.pop( 0 ), entry )
2017-08-16 21:58:06 +00:00
unused_buttons = potential_buttons
2018-08-01 20:44:57 +00:00
for button in unused_buttons:
2019-11-14 03:56:30 +00:00
button.setVisible( False )
2018-08-01 20:44:57 +00:00
2017-08-16 21:58:06 +00:00
2020-01-16 02:08:23 +00:00
def event( self, event ):
if event.type() == QC.QEvent.WindowDeactivate and not self._action_picked:
self.done( QW.QDialog.Rejected )
return True
else:
return ClientGUIDialogs.Dialog.event( self, event )
2019-11-14 03:56:30 +00:00
def keyPressEvent( self, event ):
2017-08-16 21:58:06 +00:00
id = None
2018-05-16 20:09:50 +00:00
( modifier, key ) = ClientGUIShortcuts.ConvertKeyEventToSimpleTuple( event )
2017-08-16 21:58:06 +00:00
2019-11-14 03:56:30 +00:00
if key == QC.Qt.Key_Up: id = 8
elif key == QC.Qt.Key_Left: id = 4
elif key == QC.Qt.Key_Right: id = 6
elif key == QC.Qt.Key_Down: id = 2
elif key == QC.Qt.Key_1 and modifier == QC.Qt.KeypadModifier: id = 1
elif key == QC.Qt.Key_2 and modifier == QC.Qt.KeypadModifier: id = 2
elif key == QC.Qt.Key_3 and modifier == QC.Qt.KeypadModifier: id = 3
elif key == QC.Qt.Key_4 and modifier == QC.Qt.KeypadModifier: id = 4
elif key == QC.Qt.Key_5 and modifier == QC.Qt.KeypadModifier: id = 5
elif key == QC.Qt.Key_6 and modifier == QC.Qt.KeypadModifier: id = 6
elif key == QC.Qt.Key_7 and modifier == QC.Qt.KeypadModifier: id = 7
elif key == QC.Qt.Key_8 and modifier == QC.Qt.KeypadModifier: id = 8
elif key == QC.Qt.Key_9 and modifier == QC.Qt.KeypadModifier: id = 9
2020-01-16 02:08:23 +00:00
elif key in ( QC.Qt.Key_Enter, QC.Qt.Key_Return ):
# get the 'first', scanning from top-left
for possible_id in ( 7, 8, 9, 4, 5, 6, 1, 2, 3 ):
if possible_id in self._command_dict:
id = possible_id
break
2019-11-14 03:56:30 +00:00
elif key == QC.Qt.Key_Escape:
self.done( QW.QDialog.Rejected )
2017-08-16 21:58:06 +00:00
return
else:
2019-11-14 03:56:30 +00:00
event.ignore()
2017-08-16 21:58:06 +00:00
if id is not None:
self._HitButton( id )
def GetValue( self ):
return self._result
2019-11-14 03:56:30 +00:00
class Page( QW.QSplitter ):
2013-02-19 00:11:43 +00:00
2017-07-05 21:09:28 +00:00
def __init__( self, parent, controller, management_controller, initial_hashes ):
2015-06-24 22:10:14 +00:00
2019-11-14 03:56:30 +00:00
QW.QSplitter.__init__( self, parent )
2013-02-19 00:11:43 +00:00
2020-04-08 21:10:11 +00:00
self._parent_notebook = parent
2015-11-25 22:00:57 +00:00
self._controller = controller
2018-05-23 21:05:06 +00:00
self._page_key = self._controller.AcquirePageKey()
2015-06-24 22:10:14 +00:00
self._management_controller = management_controller
2017-07-05 21:09:28 +00:00
self._initial_hashes = initial_hashes
2015-06-24 22:10:14 +00:00
self._management_controller.SetKey( 'page', self._page_key )
2015-03-04 22:44:32 +00:00
2017-08-16 21:58:06 +00:00
self._initialised = False
2013-02-19 00:11:43 +00:00
self._pretty_status = ''
2019-11-14 03:56:30 +00:00
self._search_preview_split = QW.QSplitter( self )
2013-02-19 00:11:43 +00:00
2020-05-13 19:03:16 +00:00
self._done_split_setups = False
2019-11-14 03:56:30 +00:00
self._management_panel = ClientGUIManagement.CreateManagementPanel( self._search_preview_split, self, self._controller, self._management_controller )
2013-02-19 00:11:43 +00:00
2019-11-14 03:56:30 +00:00
file_service_key = self._management_controller.GetKey( 'file_service' )
2013-02-19 00:11:43 +00:00
2019-11-14 03:56:30 +00:00
self._preview_panel = QW.QFrame( self._search_preview_split )
2019-11-20 23:10:46 +00:00
self._preview_panel.setFrameStyle( QW.QFrame.Panel | QW.QFrame.Sunken )
self._preview_panel.setLineWidth( 2 )
2013-02-19 00:11:43 +00:00
2019-11-14 03:56:30 +00:00
self._preview_canvas = ClientGUICanvas.CanvasPanel( self._preview_panel, self._page_key )
2013-02-19 00:11:43 +00:00
2020-02-12 22:50:37 +00:00
self._media_panel = ClientGUIResults.MediaPanelThumbnails( self, self._page_key, file_service_key, [] )
2013-09-11 21:28:19 +00:00
2019-11-14 03:56:30 +00:00
vbox = QP.VBoxLayout( margin = 0 )
2013-09-11 21:28:19 +00:00
2019-11-14 03:56:30 +00:00
QP.AddToLayout( vbox, self._preview_canvas, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
2013-02-19 00:11:43 +00:00
2019-11-14 03:56:30 +00:00
self._preview_panel.setLayout( vbox )
2015-06-24 22:10:14 +00:00
2019-11-14 03:56:30 +00:00
self.widget( 0 ).setMinimumWidth( 120 )
self.widget( 1 ).setMinimumWidth( 120 )
self.setStretchFactor( 0, 0 )
self.setStretchFactor( 1, 1 )
self._handle_event_filter = QP.WidgetEventFilter( self.handle( 1 ) )
self._handle_event_filter.EVT_LEFT_DCLICK( self.EventUnsplit )
self._search_preview_split.widget( 0 ).setMinimumHeight( 180 )
self._search_preview_split.widget( 1 ).setMinimumHeight( 180 )
self._search_preview_split.setStretchFactor( 0, 1 )
self._search_preview_split.setStretchFactor( 1, 0 )
2019-11-20 23:10:46 +00:00
2019-11-14 03:56:30 +00:00
self._search_preview_split._handle_event_filter = QP.WidgetEventFilter( self._search_preview_split.handle( 1 ) )
self._search_preview_split._handle_event_filter.EVT_LEFT_DCLICK( self.EventPreviewUnsplit )
2015-06-24 22:10:14 +00:00
2015-11-04 22:30:28 +00:00
if HC.options[ 'hide_preview' ]:
2019-11-14 03:56:30 +00:00
QP.CallAfter( QP.Unsplit, self._search_preview_split, self._preview_panel )
2015-11-04 22:30:28 +00:00
2015-11-25 22:00:57 +00:00
self._controller.sub( self, 'SetPrettyStatus', 'new_page_status' )
2018-03-07 22:48:29 +00:00
self._controller.sub( self, 'SetSplitterPositions', 'set_splitter_positions' )
2013-02-19 00:11:43 +00:00
2020-03-25 21:15:57 +00:00
self._ConnectMediaPanelSignals()
def _ConnectMediaPanelSignals( self ):
self._media_panel.refreshQuery.connect( self.RefreshQuery )
self._media_panel.focusMediaChanged.connect( self._preview_canvas.SetMedia )
2020-04-01 21:51:42 +00:00
self._media_panel.focusMediaCleared.connect( self._preview_canvas.ClearMedia )
2020-03-25 21:15:57 +00:00
self._management_panel.ConnectMediaPanelSignals( self._media_panel )
2017-07-05 21:09:28 +00:00
def _SetPrettyStatus( self, status ):
self._pretty_status = status
2018-01-03 22:37:30 +00:00
self._controller.gui.SetStatusBarDirty()
2017-07-05 21:09:28 +00:00
def _SwapMediaPanel( self, new_panel ):
2018-02-21 21:59:37 +00:00
# if a new media page comes in while its menu is open, we can enter program instability.
# so let's just put it off.
2019-11-14 03:56:30 +00:00
previous_sizes = self.sizes()
2020-03-25 21:15:57 +00:00
self._preview_canvas.ClearMedia()
2017-07-05 21:09:28 +00:00
self._media_panel.ClearPageKey()
2019-08-21 21:34:01 +00:00
media_collect = self._management_panel.GetMediaCollect()
2019-05-15 20:35:00 +00:00
2019-08-21 21:34:01 +00:00
if media_collect.DoesACollect():
2019-05-15 20:35:00 +00:00
2019-08-21 21:34:01 +00:00
new_panel.Collect( self._page_key, media_collect )
2019-05-15 20:35:00 +00:00
2020-04-01 21:51:42 +00:00
media_sort = self._management_panel.GetMediaSort()
2019-05-22 22:35:06 +00:00
2020-04-01 21:51:42 +00:00
new_panel.Sort( media_sort )
2019-05-22 22:35:06 +00:00
2019-05-15 20:35:00 +00:00
2019-11-14 03:56:30 +00:00
self._media_panel.setParent( None )
2019-11-20 23:10:46 +00:00
old_panel = self._media_panel
2019-11-14 03:56:30 +00:00
self.addWidget( new_panel )
self.setSizes( previous_sizes )
2017-07-05 21:09:28 +00:00
2019-11-20 23:10:46 +00:00
self.setStretchFactor( 1, 1 )
2018-05-16 20:09:50 +00:00
2017-07-05 21:09:28 +00:00
self._media_panel = new_panel
2020-03-25 21:15:57 +00:00
self._ConnectMediaPanelSignals()
2018-02-21 21:59:37 +00:00
self._controller.pub( 'refresh_page_name', self._page_key )
2019-11-20 23:10:46 +00:00
def clean_up_old_panel():
2020-03-04 22:12:53 +00:00
if CGC.core().MenuIsOpen():
2019-11-20 23:10:46 +00:00
self._controller.CallLaterQtSafe( self, 0.5, clean_up_old_panel )
return
old_panel.deleteLater()
clean_up_old_panel()
2013-02-19 00:11:43 +00:00
2018-05-02 20:45:20 +00:00
def CheckAbleToClose( self ):
self._management_panel.CheckAbleToClose()
2019-06-19 22:08:48 +00:00
def CleanBeforeClose( self ):
self._management_panel.CleanBeforeClose()
2020-03-25 21:15:57 +00:00
self._media_panel.SetFocusedMedia( None )
2019-06-19 22:08:48 +00:00
2017-07-05 21:09:28 +00:00
def CleanBeforeDestroy( self ):
self._management_panel.CleanBeforeDestroy()
2019-11-14 03:56:30 +00:00
self._preview_canvas.CleanBeforeDestroy()
2019-03-06 23:06:22 +00:00
2018-05-23 21:05:06 +00:00
self._controller.ReleasePageKey( self._page_key )
2013-02-19 00:11:43 +00:00
2015-11-04 22:30:28 +00:00
def EventPreviewUnsplit( self, event ):
2019-11-14 03:56:30 +00:00
QP.Unsplit( self._search_preview_split, self._preview_panel )
2015-11-04 22:30:28 +00:00
2020-03-25 21:15:57 +00:00
self._media_panel.SetFocusedMedia( None )
2015-11-04 22:30:28 +00:00
2013-02-19 00:11:43 +00:00
2015-11-04 22:30:28 +00:00
def EventUnsplit( self, event ):
2019-11-14 03:56:30 +00:00
QP.Unsplit( self, self._search_preview_split )
2015-11-04 22:30:28 +00:00
2020-03-25 21:15:57 +00:00
self._media_panel.SetFocusedMedia( None )
2015-11-04 22:30:28 +00:00
2013-02-19 00:11:43 +00:00
2019-08-21 21:34:01 +00:00
def GetAPIInfoDict( self, simple ):
d = {}
d[ 'name' ] = self._management_controller.GetPageName()
d[ 'page_key' ] = self._page_key.hex()
d[ 'page_type' ] = self._management_controller.GetType()
management_info = self._management_controller.GetAPIInfoDict( simple )
d[ 'management' ] = management_info
media_info = self._media_panel.GetAPIInfoDict( simple )
d[ 'media' ] = media_info
return d
2017-07-05 21:09:28 +00:00
def GetHashes( self ):
if self._initialised:
2018-05-30 20:13:21 +00:00
return self._media_panel.GetHashes( ordered = True )
2017-07-05 21:09:28 +00:00
else:
return self._initial_hashes
2015-06-24 22:10:14 +00:00
def GetManagementController( self ):
2014-01-22 21:11:22 +00:00
2015-06-24 22:10:14 +00:00
return self._management_controller
2014-01-22 21:11:22 +00:00
2013-02-19 00:11:43 +00:00
2019-02-27 23:03:30 +00:00
def GetManagementPanel( self ):
return self._management_panel
2015-06-24 22:10:14 +00:00
# used by autocomplete
def GetMedia( self ):
2013-02-19 00:11:43 +00:00
2015-06-24 22:10:14 +00:00
return self._media_panel.GetSortedMedia()
2013-02-19 00:11:43 +00:00
2015-06-24 22:10:14 +00:00
2017-12-20 22:55:48 +00:00
def GetMediaPanel( self ):
return self._media_panel
2017-08-16 21:58:06 +00:00
def GetName( self ):
return self._management_controller.GetPageName()
2018-05-02 20:45:20 +00:00
def GetNumFileSummary( self ):
2017-08-02 21:32:54 +00:00
if self._initialised:
2018-05-02 20:45:20 +00:00
num_files = self._media_panel.GetNumFiles()
2017-08-02 21:32:54 +00:00
else:
2018-05-02 20:45:20 +00:00
num_files = len( self._initial_hashes )
2017-08-02 21:32:54 +00:00
2018-05-02 20:45:20 +00:00
( num_value, num_range ) = self._management_controller.GetValueRange()
if num_value == num_range:
( num_value, num_range ) = ( 0, 0 )
return ( num_files, ( num_value, num_range ) )
2017-08-02 21:32:54 +00:00
2015-09-16 18:11:00 +00:00
def GetPageKey( self ):
return self._page_key
2018-05-23 21:05:06 +00:00
def GetPageKeys( self ):
return { self._page_key }
2020-04-08 21:10:11 +00:00
def GetParentNotebook( self ):
return self._parent_notebook
2019-08-21 21:34:01 +00:00
def GetSessionAPIInfoDict( self, is_selected = False ):
2019-06-05 19:42:39 +00:00
root = {}
root[ 'name' ] = self.GetName()
2019-06-26 21:27:18 +00:00
root[ 'page_key' ] = self._page_key.hex()
2019-06-05 19:42:39 +00:00
root[ 'page_type' ] = self._management_controller.GetType()
root[ 'focused' ] = is_selected
return root
2015-06-24 22:10:14 +00:00
def GetPrettyStatus( self ):
2013-02-19 00:11:43 +00:00
2015-06-24 22:10:14 +00:00
return self._pretty_status
2013-02-19 00:11:43 +00:00
def GetSashPositions( self ):
2019-11-14 03:56:30 +00:00
if QP.SplitterVisibleCount( self ) > 1:
2015-11-04 22:30:28 +00:00
2019-11-14 03:56:30 +00:00
x = self.widget( 0 ).width()
2015-11-04 22:30:28 +00:00
2016-05-25 21:54:03 +00:00
else:
x = HC.options[ 'hpos' ]
2013-02-19 00:11:43 +00:00
2019-11-14 03:56:30 +00:00
if QP.SplitterVisibleCount( self._search_preview_split ) > 1:
2015-11-04 22:30:28 +00:00
2019-11-14 03:56:30 +00:00
y = self._search_preview_split.widget( 0 ).height()
2015-11-04 22:30:28 +00:00
2016-05-25 21:54:03 +00:00
else:
y = HC.options[ 'vpos' ]
2013-02-19 00:11:43 +00:00
return ( x, y )
2019-10-16 20:47:55 +00:00
def GetTotalWeight( self ):
num_hashes = len( self.GetHashes() )
num_seeds = self._management_controller.GetNumSeeds()
# hashes are smaller, but seeds tend to need more cpu, so we'll just say 1:1 for now
return num_hashes + num_seeds
2018-05-16 20:09:50 +00:00
def IsMultipleWatcherPage( self ):
return self._management_controller.GetType() == ClientGUIManagement.MANAGEMENT_TYPE_IMPORT_MULTIPLE_WATCHER
2017-08-16 21:58:06 +00:00
def IsImporter( self ):
return self._management_controller.IsImporter()
2017-05-17 21:53:02 +00:00
def IsURLImportPage( self ):
return self._management_controller.GetType() == ClientGUIManagement.MANAGEMENT_TYPE_IMPORT_URLS
2015-11-25 22:00:57 +00:00
def PageHidden( self ):
2017-09-27 21:52:54 +00:00
self._management_panel.PageHidden()
self._media_panel.PageHidden()
2020-03-25 21:15:57 +00:00
self._preview_canvas.PageHidden()
2015-11-25 22:00:57 +00:00
2013-02-19 00:11:43 +00:00
2015-11-25 22:00:57 +00:00
def PageShown( self ):
2020-05-13 19:03:16 +00:00
if self.isVisible() and not self._done_split_setups:
self.SetupSplits()
self._done_split_setups = True
2017-09-27 21:52:54 +00:00
self._management_panel.PageShown()
self._media_panel.PageShown()
2020-03-25 21:15:57 +00:00
self._preview_canvas.PageShown()
2015-11-25 22:00:57 +00:00
2013-02-19 00:11:43 +00:00
2015-11-25 22:00:57 +00:00
def RefreshQuery( self ):
2017-07-05 21:09:28 +00:00
if self._initialised:
2020-03-25 21:15:57 +00:00
self._management_panel.RefreshQuery()
2017-07-05 21:09:28 +00:00
2015-11-25 22:00:57 +00:00
2013-02-19 00:11:43 +00:00
2019-11-14 03:56:30 +00:00
def SetupSplits( self ):
2020-04-01 21:51:42 +00:00
2019-11-14 03:56:30 +00:00
QP.SplitVertically( self, self._search_preview_split, self._media_panel, HC.options[ 'hpos' ] )
2019-11-20 23:10:46 +00:00
2019-11-14 03:56:30 +00:00
QP.SplitHorizontally( self._search_preview_split, self._management_panel, self._preview_panel, HC.options[ 'vpos' ] )
2020-03-25 21:15:57 +00:00
2013-02-19 00:11:43 +00:00
def ShowHideSplit( self ):
2019-11-14 03:56:30 +00:00
if QP.SplitterVisibleCount( self ) > 1:
2013-02-19 00:11:43 +00:00
2019-11-14 03:56:30 +00:00
QP.Unsplit( self, self._search_preview_split )
2013-02-19 00:11:43 +00:00
2020-03-25 21:15:57 +00:00
self._media_panel.SetFocusedMedia( None )
2015-11-04 22:30:28 +00:00
2013-02-19 00:11:43 +00:00
else:
2019-11-14 03:56:30 +00:00
self.SetupSplits()
2013-02-19 00:11:43 +00:00
2017-07-05 21:09:28 +00:00
def SetMediaFocus( self ):
2019-11-14 03:56:30 +00:00
self._media_panel.setFocus( QC.Qt.OtherFocusReason )
2017-07-05 21:09:28 +00:00
def SetMediaResults( self, media_results ):
2019-12-18 22:06:34 +00:00
if self._management_controller.IsImporter():
file_service_key = CC.LOCAL_FILE_SERVICE_KEY
else:
file_service_key = self._management_controller.GetKey( 'file_service' )
2017-07-05 21:09:28 +00:00
2020-02-12 22:50:37 +00:00
media_panel = ClientGUIResults.MediaPanelThumbnails( self, self._page_key, file_service_key, media_results )
2017-07-05 21:09:28 +00:00
self._SwapMediaPanel( media_panel )
self._initialised = True
self._initial_hashes = []
2019-11-14 03:56:30 +00:00
QP.CallAfter( self._management_panel.Start ) # importand this is callafter, so it happens after a heavy session load is done
2017-07-19 21:21:41 +00:00
2013-02-19 00:11:43 +00:00
2019-04-10 22:50:53 +00:00
def SetName( self, name ):
2017-08-16 21:58:06 +00:00
return self._management_controller.SetPageName( name )
2015-06-24 22:10:14 +00:00
def SetPrettyStatus( self, page_key, status ):
if page_key == self._page_key:
2017-07-05 21:09:28 +00:00
if self._initialised:
self._SetPrettyStatus( status )
2015-06-24 22:10:14 +00:00
2015-11-25 22:00:57 +00:00
def SetSearchFocus( self ):
2018-03-28 21:55:58 +00:00
self._management_panel.SetSearchFocus()
2015-11-25 22:00:57 +00:00
2015-06-24 22:10:14 +00:00
2018-03-07 22:48:29 +00:00
def SetSplitterPositions( self, hpos, vpos ):
2019-11-28 01:11:46 +00:00
QP.SplitHorizontally( self._search_preview_split, self._management_panel, self._preview_panel, vpos )
2018-03-07 22:48:29 +00:00
2019-11-28 01:11:46 +00:00
QP.SplitVertically( self, self._search_preview_split, self._media_panel, hpos )
2018-03-07 22:48:29 +00:00
if HC.options[ 'hide_preview' ]:
2019-11-14 03:56:30 +00:00
QP.CallAfter( QP.Unsplit, self._search_preview_split, self._preview_panel )
2018-03-07 22:48:29 +00:00
2020-03-25 21:15:57 +00:00
def SynchronisedWaitSwitch( self ):
2015-11-25 22:00:57 +00:00
2020-03-25 21:15:57 +00:00
self._management_panel.SynchronisedWaitSwitch()
2015-11-25 22:00:57 +00:00
2015-06-24 22:10:14 +00:00
2017-08-16 21:58:06 +00:00
def Start( self ):
if self._initial_hashes is not None and len( self._initial_hashes ) > 0:
2018-01-24 23:09:42 +00:00
self._controller.CallToThread( self.THREADLoadInitialMediaResults, self._controller, self._initial_hashes )
2017-08-16 21:58:06 +00:00
else:
self._initialised = True
2019-11-14 03:56:30 +00:00
QP.CallAfter( self._management_panel.Start ) # importand this is callafter, so it happens after a heavy session load is done
2017-08-16 21:58:06 +00:00
2018-02-21 21:59:37 +00:00
def SwapMediaPanel( self, new_panel ):
2013-02-19 00:11:43 +00:00
2018-02-21 21:59:37 +00:00
self._SwapMediaPanel( new_panel )
2017-07-05 21:09:28 +00:00
def TestAbleToClose( self ):
2018-05-02 20:45:20 +00:00
try:
self._management_panel.CheckAbleToClose()
except HydrusExceptions.VetoException as e:
2019-01-09 22:59:03 +00:00
reason = str( e )
2018-05-02 20:45:20 +00:00
2019-09-05 00:05:32 +00:00
message = '{} Are you sure you want to close it?'.format( str( e ) )
result = ClientGUIDialogsQuick.GetYesNo( self, message )
2019-11-14 03:56:30 +00:00
if result == QW.QDialog.Rejected:
2018-05-02 20:45:20 +00:00
2019-09-05 00:05:32 +00:00
raise HydrusExceptions.VetoException()
2018-05-02 20:45:20 +00:00
2017-07-05 21:09:28 +00:00
2018-01-24 23:09:42 +00:00
def THREADLoadInitialMediaResults( self, controller, initial_hashes ):
2019-11-14 03:56:30 +00:00
def qt_code_status( status ):
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._SetPrettyStatus( status )
2019-11-14 03:56:30 +00:00
def qt_code_publish( media_results ):
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.SetMediaResults( media_results )
2017-07-05 21:09:28 +00:00
initial_media_results = []
2018-01-24 23:09:42 +00:00
for group_of_initial_hashes in HydrusData.SplitListIntoChunks( initial_hashes, 256 ):
2013-02-19 00:11:43 +00:00
2018-01-24 23:09:42 +00:00
more_media_results = controller.Read( 'media_results', group_of_initial_hashes )
2015-05-20 21:31:40 +00:00
2017-07-05 21:09:28 +00:00
initial_media_results.extend( more_media_results )
2013-02-19 00:11:43 +00:00
2019-01-09 22:59:03 +00:00
status = 'Loading initial files\u2026 ' + HydrusData.ConvertValueRangeToPrettyString( len( initial_media_results ), len( initial_hashes ) )
2017-07-05 21:09:28 +00:00
2019-11-14 03:56:30 +00:00
QP.CallAfter( qt_code_status, status )
2013-02-19 00:11:43 +00:00
2017-07-05 21:09:28 +00:00
hashes_to_media_results = { media_result.GetHash() : media_result for media_result in initial_media_results }
2015-09-02 23:16:09 +00:00
2019-06-26 21:27:18 +00:00
sorted_initial_media_results = [ hashes_to_media_results[ hash ] for hash in initial_hashes if hash in hashes_to_media_results ]
2017-07-05 21:09:28 +00:00
2019-11-14 03:56:30 +00:00
QP.CallAfter( qt_code_publish, sorted_initial_media_results )
2015-09-02 23:16:09 +00:00
2013-02-19 00:11:43 +00:00
2018-05-30 20:13:21 +00:00
def REPEATINGPageUpdate( self ):
2017-12-13 22:33:07 +00:00
2018-05-30 20:13:21 +00:00
self._management_panel.REPEATINGPageUpdate()
2017-12-13 22:33:07 +00:00
2019-11-14 03:56:30 +00:00
class PagesNotebook( QP.TabWidgetWithDnD ):
2017-08-09 21:33:51 +00:00
2017-08-16 21:58:06 +00:00
def __init__( self, parent, controller, name ):
2017-08-09 21:33:51 +00:00
2019-11-14 03:56:30 +00:00
QP.TabWidgetWithDnD.__init__( self, parent )
2020-05-13 19:03:16 +00:00
if HG.client_controller.new_options.GetBoolean( 'elide_page_tab_names' ):
self.tabBar().setElideMode( QC.Qt.ElideMiddle )
2020-04-08 21:10:11 +00:00
self._parent_notebook = parent
2020-01-16 02:08:23 +00:00
# this is disabled for now because it seems borked in Qt
2018-06-06 21:27:02 +00:00
if controller.new_options.GetBoolean( 'notebook_tabs_on_left' ):
2019-11-14 03:56:30 +00:00
self.setTabPosition( QW.QTabWidget.West )
2018-06-06 21:27:02 +00:00
else:
2019-11-14 03:56:30 +00:00
self.setTabPosition( QW.QTabWidget.North )
2017-08-09 21:33:51 +00:00
self._controller = controller
2018-05-23 21:05:06 +00:00
self._page_key = self._controller.AcquirePageKey()
2017-08-16 21:58:06 +00:00
self._name = name
2017-08-09 21:33:51 +00:00
2017-08-16 21:58:06 +00:00
self._next_new_page_index = None
2017-08-09 21:33:51 +00:00
2017-08-23 21:34:25 +00:00
self._potential_drag_page = None
2017-08-16 21:58:06 +00:00
self._closed_pages = []
2017-08-09 21:33:51 +00:00
2017-08-16 21:58:06 +00:00
self._controller.sub( self, 'RefreshPageName', 'refresh_page_name' )
self._controller.sub( self, 'NotifyPageUnclosed', 'notify_page_unclosed' )
2017-08-09 21:33:51 +00:00
2019-11-14 03:56:30 +00:00
self._widget_event_filter = QP.WidgetEventFilter( self )
self._widget_event_filter.EVT_LEFT_DCLICK( self.EventLeftDoubleClick )
self._widget_event_filter.EVT_MIDDLE_DOWN( self.EventMiddleClick )
self._widget_event_filter.EVT_LEFT_DOWN( lambda ev: ev.accept() )
self._widget_event_filter.EVT_LEFT_DOWN( lambda ev: ev.accept() )
2020-05-13 19:03:16 +00:00
self.currentChanged.connect( self.pageJustChanged )
2019-11-14 03:56:30 +00:00
self.pageDragAndDropped.connect( self._RefreshPageNamesAfterDnD )
self._previous_page_index = -1
2017-08-09 21:33:51 +00:00
2019-11-14 03:56:30 +00:00
def _RefreshPageNamesAfterDnD( self, page_widget, source_widget ):
if hasattr( page_widget, 'GetPageKey' ):
self._controller.pub( 'refresh_page_name', page_widget.GetPageKey() )
2020-04-08 21:10:11 +00:00
source_notebook = source_widget.parentWidget()
if hasattr( source_notebook, 'GetPageKey' ):
2019-11-14 03:56:30 +00:00
2020-04-08 21:10:11 +00:00
self._controller.pub( 'refresh_page_name', source_notebook.GetPageKey() )
2019-11-14 03:56:30 +00:00
2020-04-08 21:10:11 +00:00
2019-11-14 03:56:30 +00:00
def _UpdatePreviousPageIndex( self ):
self._previous_page_index = self.currentIndex()
2017-08-16 21:58:06 +00:00
def _ChooseNewPage( self, insertion_index = None ):
2017-08-09 21:33:51 +00:00
2017-08-16 21:58:06 +00:00
self._next_new_page_index = insertion_index
with DialogPageChooser( self, self._controller ) as dlg:
2017-08-09 21:33:51 +00:00
2019-11-14 03:56:30 +00:00
if dlg.exec() == QW.QDialog.Accepted:
2017-08-16 21:58:06 +00:00
( page_type, page_data ) = dlg.GetValue()
if page_type == 'pages':
self.NewPagesNotebook()
elif page_type == 'page':
management_controller = page_data
self.NewPage( management_controller )
2017-08-09 21:33:51 +00:00
2018-05-16 20:09:50 +00:00
def _CloseAllPages( self, polite = True, delete_pages = False ):
2017-08-09 21:33:51 +00:00
2019-11-14 03:56:30 +00:00
closees = [ index for index in range( self.count() ) ]
2017-08-09 21:33:51 +00:00
2018-05-16 20:09:50 +00:00
self._ClosePages( closees, polite, delete_pages = delete_pages )
2017-08-09 21:33:51 +00:00
2017-08-16 21:58:06 +00:00
def _CloseLeftPages( self, from_index ):
2017-08-09 21:33:51 +00:00
2017-08-16 21:58:06 +00:00
message = 'Close all pages to the left?'
2019-09-05 00:05:32 +00:00
result = ClientGUIDialogsQuick.GetYesNo( self, message )
2019-11-14 03:56:30 +00:00
if result == QW.QDialog.Accepted:
2017-08-16 21:58:06 +00:00
2019-11-14 03:56:30 +00:00
closees = [ index for index in range( self.count() ) if index < from_index ]
2019-09-05 00:05:32 +00:00
self._ClosePages( closees )
2017-08-16 21:58:06 +00:00
2017-08-09 21:33:51 +00:00
2017-08-16 21:58:06 +00:00
def _CloseOtherPages( self, except_index ):
2017-08-09 21:33:51 +00:00
2017-08-16 21:58:06 +00:00
message = 'Close all other pages?'
2017-08-09 21:33:51 +00:00
2019-09-05 00:05:32 +00:00
result = ClientGUIDialogsQuick.GetYesNo( self, message )
2019-11-14 03:56:30 +00:00
if result == QW.QDialog.Accepted:
2017-08-09 21:33:51 +00:00
2019-11-14 03:56:30 +00:00
closees = [ index for index in range( self.count() ) if index != except_index ]
2019-09-05 00:05:32 +00:00
self._ClosePages( closees )
2017-08-09 21:33:51 +00:00
2018-05-16 20:09:50 +00:00
def _ClosePage( self, index, polite = True, delete_page = False ):
2017-08-09 21:33:51 +00:00
2017-08-16 21:58:06 +00:00
self._controller.ResetIdleTimer()
self._controller.ResetPageChangeTimer()
2017-08-09 21:33:51 +00:00
2019-11-14 03:56:30 +00:00
if index == -1 or index > self.count() - 1:
2017-08-09 21:33:51 +00:00
2017-08-16 21:58:06 +00:00
return False
2017-08-09 21:33:51 +00:00
2019-11-14 03:56:30 +00:00
page = self.widget( index )
2017-08-09 21:33:51 +00:00
2017-08-16 21:58:06 +00:00
if polite:
2017-08-09 21:33:51 +00:00
2017-08-16 21:58:06 +00:00
try:
2017-08-09 21:33:51 +00:00
2017-08-16 21:58:06 +00:00
page.TestAbleToClose()
2017-08-09 21:33:51 +00:00
2018-05-02 20:45:20 +00:00
except HydrusExceptions.VetoException:
2017-08-09 21:33:51 +00:00
2017-08-16 21:58:06 +00:00
return False
2017-08-09 21:33:51 +00:00
2019-06-19 22:08:48 +00:00
page.CleanBeforeClose()
2017-08-09 21:33:51 +00:00
2017-08-23 21:34:25 +00:00
page_key = page.GetPageKey()
self._closed_pages.append( ( index, page_key ) )
2017-08-09 21:33:51 +00:00
2019-11-14 03:56:30 +00:00
self.removeTab( index )
self._UpdatePreviousPageIndex()
2013-12-11 22:09:25 +00:00
2017-08-23 21:34:25 +00:00
self._controller.pub( 'refresh_page_name', self._page_key )
2018-05-16 20:09:50 +00:00
if delete_page:
self._controller.pub( 'notify_deleted_page', page )
else:
self._controller.pub( 'notify_closed_page', page )
self._controller.pub( 'notify_new_undo' )
2013-12-11 22:09:25 +00:00
2017-08-16 21:58:06 +00:00
return True
2013-12-11 22:09:25 +00:00
2013-02-19 00:11:43 +00:00
2018-05-16 20:09:50 +00:00
def _ClosePages( self, indices, polite = True, delete_pages = False ):
2015-03-25 22:04:19 +00:00
2017-08-16 21:58:06 +00:00
indices = list( indices )
2013-02-19 00:11:43 +00:00
2017-08-16 21:58:06 +00:00
indices.sort( reverse = True ) # so we are closing from the end first
for index in indices:
2015-06-24 22:10:14 +00:00
2018-05-16 20:09:50 +00:00
successful = self._ClosePage( index, polite, delete_page = delete_pages )
2015-06-24 22:10:14 +00:00
2017-08-16 21:58:06 +00:00
if not successful:
break
2015-06-24 22:10:14 +00:00
2013-09-04 16:48:44 +00:00
2013-02-19 00:11:43 +00:00
2017-08-16 21:58:06 +00:00
def _CloseRightPages( self, from_index ):
2013-03-27 20:02:51 +00:00
2017-08-16 21:58:06 +00:00
message = 'Close all pages to the right?'
2019-09-05 00:05:32 +00:00
result = ClientGUIDialogsQuick.GetYesNo( self, message )
2019-11-14 03:56:30 +00:00
if result == QW.QDialog.Accepted:
2014-01-22 21:11:22 +00:00
2019-11-14 03:56:30 +00:00
closees = [ index for index in range( self.count() ) if index > from_index ]
2019-09-05 00:05:32 +00:00
self._ClosePages( closees )
2017-08-16 21:58:06 +00:00
2020-03-04 22:12:53 +00:00
def _DuplicatePage( self, index ):
if index == -1 or index > self.count() - 1:
return False
page = self.widget( index )
session = GUISession( 'dupe page session' )
session.AddPageTuple( page )
2020-03-18 21:35:57 +00:00
session = session.Duplicate() # this ensures we are using fresh new objects
2020-03-04 22:12:53 +00:00
self.InsertSessionPageTuples( index + 1, session.GetPageTuples() )
2017-08-16 21:58:06 +00:00
def _GetDefaultPageInsertionIndex( self ):
2017-12-06 22:06:56 +00:00
new_options = self._controller.new_options
2017-08-16 21:58:06 +00:00
new_page_goes = new_options.GetInteger( 'default_new_page_goes' )
2019-11-14 03:56:30 +00:00
current_index = self.currentIndex()
2017-08-16 21:58:06 +00:00
2019-11-14 03:56:30 +00:00
if current_index == -1:
2017-08-16 21:58:06 +00:00
new_page_goes = CC.NEW_PAGE_GOES_FAR_LEFT
if new_page_goes == CC.NEW_PAGE_GOES_FAR_LEFT:
insertion_index = 0
elif new_page_goes == CC.NEW_PAGE_GOES_LEFT_OF_CURRENT:
insertion_index = current_index
elif new_page_goes == CC.NEW_PAGE_GOES_RIGHT_OF_CURRENT:
insertion_index = current_index + 1
elif new_page_goes == CC.NEW_PAGE_GOES_FAR_RIGHT:
2019-11-14 03:56:30 +00:00
insertion_index = self.count()
2017-08-16 21:58:06 +00:00
return insertion_index
def _GetMediaPages( self, only_my_level ):
results = []
for page in self._GetPages():
if isinstance( page, PagesNotebook ):
if not only_my_level:
results.extend( page.GetMediaPages() )
else:
results.append( page )
return results
2017-08-23 21:34:25 +00:00
def _GetIndex( self, page_key ):
2019-11-14 03:56:30 +00:00
for ( page, index ) in ( ( self.widget( index ), index ) for index in range( self.count() ) ):
2017-08-23 21:34:25 +00:00
if page.GetPageKey() == page_key:
return index
raise HydrusExceptions.DataMissing()
def _GetNotebookFromScreenPosition( self, screen_position ):
2017-08-16 21:58:06 +00:00
2019-11-14 03:56:30 +00:00
current_page = self.currentWidget()
2017-08-16 21:58:06 +00:00
if current_page is None or not isinstance( current_page, PagesNotebook ):
2017-08-23 21:34:25 +00:00
return self
2017-08-16 21:58:06 +00:00
else:
2019-11-14 03:56:30 +00:00
tab_index = ClientGUIFunctions.NotebookScreenToHitTest( self, screen_position )
2017-08-16 21:58:06 +00:00
2019-11-14 03:56:30 +00:00
if tab_index != -1:
2017-08-16 21:58:06 +00:00
2017-08-23 21:34:25 +00:00
return self
2017-08-16 21:58:06 +00:00
2020-02-26 22:28:52 +00:00
on_child_notebook_somewhere = screen_position.y() > current_page.pos().y()
2017-08-30 20:27:47 +00:00
2017-12-20 22:55:48 +00:00
if on_child_notebook_somewhere:
2017-08-16 21:58:06 +00:00
2017-08-23 21:34:25 +00:00
return current_page._GetNotebookFromScreenPosition( screen_position )
2017-08-16 21:58:06 +00:00
2017-08-23 21:34:25 +00:00
return self
2017-08-16 21:58:06 +00:00
2017-08-23 21:34:25 +00:00
def _GetPages( self ):
2017-08-16 21:58:06 +00:00
2019-11-14 03:56:30 +00:00
return [ self.widget( i ) for i in range( self.count() ) ]
2017-08-23 21:34:25 +00:00
2018-02-14 21:47:18 +00:00
def _GetPageFromName( self, page_name ):
for page in self._GetPages():
2019-04-10 22:50:53 +00:00
if page.GetName() == page_name:
2018-02-14 21:47:18 +00:00
return page
if isinstance( page, PagesNotebook ):
result = page._GetPageFromName( page_name )
if result is not None:
return result
2017-08-23 21:34:25 +00:00
return None
2017-08-16 21:58:06 +00:00
2017-10-04 17:51:58 +00:00
def _MovePage( self, page, dest_notebook, insertion_tab_index, follow_dropped_page = False ):
2020-04-08 21:10:11 +00:00
source_notebook = page.GetParentNotebook()
2017-10-04 17:51:58 +00:00
for ( index, p ) in enumerate( source_notebook._GetPages() ):
if p == page:
2019-11-14 03:56:30 +00:00
source_notebook.removeTab( index )
source_notebook._UpdatePreviousPageIndex()
2017-10-04 17:51:58 +00:00
break
if source_notebook != dest_notebook:
2019-11-14 03:56:30 +00:00
page.setParent( dest_notebook )
2017-10-04 17:51:58 +00:00
self._controller.pub( 'refresh_page_name', source_notebook.GetPageKey() )
2019-11-14 03:56:30 +00:00
insertion_tab_index = min( insertion_tab_index, dest_notebook.count() )
2017-10-04 17:51:58 +00:00
2019-11-14 03:56:30 +00:00
dest_notebook.insertTab( insertion_tab_index, page, page.GetName() )
2020-04-08 21:10:11 +00:00
2019-11-14 03:56:30 +00:00
if follow_dropped_page: dest_notebook.setCurrentIndex( insertion_tab_index )
2017-10-04 17:51:58 +00:00
if follow_dropped_page:
self.ShowPage( page )
self._controller.pub( 'refresh_page_name', page.GetPageKey() )
2018-04-05 01:22:26 +00:00
def _MovePages( self, pages, dest_notebook ):
insertion_tab_index = dest_notebook.GetNumPages( only_my_level = True )
for page in pages:
2020-04-08 21:10:11 +00:00
if page.GetParentNotebook() != dest_notebook:
2018-04-05 01:22:26 +00:00
self._MovePage( page, dest_notebook, insertion_tab_index )
insertion_tab_index += 1
2017-08-16 21:58:06 +00:00
def _RefreshPageName( self, index ):
2019-11-14 03:56:30 +00:00
if index == -1 or index > self.count() - 1:
2017-08-16 21:58:06 +00:00
return
2017-12-06 22:06:56 +00:00
new_options = self._controller.new_options
2017-08-16 21:58:06 +00:00
max_page_name_chars = new_options.GetInteger( 'max_page_name_chars' )
page_file_count_display = new_options.GetInteger( 'page_file_count_display' )
2018-05-16 20:09:50 +00:00
import_page_progress_display = new_options.GetBoolean( 'import_page_progress_display' )
2019-11-14 03:56:30 +00:00
page = self.widget( index )
2017-08-16 21:58:06 +00:00
2019-04-10 22:50:53 +00:00
page_name = page.GetName()
2017-10-25 21:45:15 +00:00
2018-02-07 23:40:33 +00:00
page_name = page_name.replace( os.linesep, '' )
2020-01-02 03:05:35 +00:00
page_name = HydrusText.ElideText( page_name, max_page_name_chars )
2017-08-16 21:58:06 +00:00
2018-05-16 20:09:50 +00:00
num_string = ''
( num_files, ( num_value, num_range ) ) = page.GetNumFileSummary()
2017-08-16 21:58:06 +00:00
if page_file_count_display == CC.PAGE_FILE_COUNT_DISPLAY_ALL or ( page_file_count_display == CC.PAGE_FILE_COUNT_DISPLAY_ONLY_IMPORTERS and page.IsImporter() ):
2018-07-04 20:48:28 +00:00
num_string += HydrusData.ToHumanInt( num_files )
2018-05-02 20:45:20 +00:00
2018-05-16 20:09:50 +00:00
if import_page_progress_display:
2018-05-02 20:45:20 +00:00
if num_range > 0 and num_value != num_range:
2018-05-16 20:09:50 +00:00
if len( num_string ) > 0:
num_string += ', '
num_string += HydrusData.ConvertValueRangeToPrettyString( num_value, num_range )
2018-05-02 20:45:20 +00:00
2017-08-16 21:58:06 +00:00
2018-05-16 20:09:50 +00:00
if len( num_string ) > 0:
2018-05-02 20:45:20 +00:00
page_name += ' (' + num_string + ')'
2017-08-16 21:58:06 +00:00
2020-04-22 21:00:35 +00:00
safe_page_name = ClientGUIFunctions.EscapeMnemonics( page_name )
2018-02-07 23:40:33 +00:00
2020-05-13 19:03:16 +00:00
tab_bar = self.tabBar()
existing_page_name = tab_bar.tabText( index )
2018-02-07 23:40:33 +00:00
if existing_page_name not in ( safe_page_name, page_name ):
2017-08-16 21:58:06 +00:00
2020-05-13 19:03:16 +00:00
tab_bar.setTabText( index, safe_page_name )
2017-08-16 21:58:06 +00:00
def _RenamePage( self, index ):
2019-11-14 03:56:30 +00:00
if index == -1 or index > self.count() - 1:
2017-08-16 21:58:06 +00:00
return
2019-11-14 03:56:30 +00:00
page = self.widget( index )
2017-08-16 21:58:06 +00:00
2019-04-10 22:50:53 +00:00
current_name = page.GetName()
2017-10-25 21:45:15 +00:00
2017-08-16 21:58:06 +00:00
with ClientGUIDialogs.DialogTextEntry( self, 'Enter the new name.', default = current_name, allow_blank = False ) as dlg:
2019-11-14 03:56:30 +00:00
if dlg.exec() == QW.QDialog.Accepted:
2017-08-16 21:58:06 +00:00
new_name = dlg.GetValue()
2019-04-10 22:50:53 +00:00
page.SetName( new_name )
2017-08-16 21:58:06 +00:00
self._controller.pub( 'refresh_page_name', page.GetPageKey() )
2017-10-04 17:51:58 +00:00
def _SendPageToNewNotebook( self, index ):
2019-11-14 03:56:30 +00:00
if 0 <= index and index <= self.count() - 1:
2018-04-25 22:07:52 +00:00
2019-11-14 03:56:30 +00:00
page = self.widget( index )
2018-04-25 22:07:52 +00:00
dest_notebook = self.NewPagesNotebook( forced_insertion_index = index, give_it_a_blank_page = False )
self._MovePage( page, dest_notebook, 0 )
2017-10-04 17:51:58 +00:00
def _SendRightPagesToNewNotebook( self, from_index ):
message = 'Send all pages to the right to a new page of pages?'
2019-09-05 00:05:32 +00:00
result = ClientGUIDialogsQuick.GetYesNo( self, message )
2019-11-14 03:56:30 +00:00
if result == QW.QDialog.Accepted:
2017-10-04 17:51:58 +00:00
2019-11-14 03:56:30 +00:00
pages_index = self.count()
2019-09-05 00:05:32 +00:00
dest_notebook = self.NewPagesNotebook( forced_insertion_index = pages_index, give_it_a_blank_page = False )
movees = list( range( from_index + 1, pages_index ) )
movees.reverse()
for index in movees:
2017-10-04 17:51:58 +00:00
2019-11-14 03:56:30 +00:00
page = self.widget( index )
2017-10-04 17:51:58 +00:00
2019-09-05 00:05:32 +00:00
self._MovePage( page, dest_notebook, 0 )
2017-10-04 17:51:58 +00:00
2019-07-10 22:38:30 +00:00
def _ShiftPage( self, page_index, delta = None, new_index = None ):
new_page_index = page_index
if delta is not None:
new_page_index = page_index + delta
if new_index is not None:
new_page_index = new_index
if new_page_index == page_index:
return
2019-11-14 03:56:30 +00:00
if 0 <= new_page_index and new_page_index <= self.count() - 1:
page_is_selected = self.currentIndex() == page_index
2019-07-10 22:38:30 +00:00
2019-11-14 03:56:30 +00:00
page = self.widget( page_index )
name = self.tabText( page_index )
2019-07-10 22:38:30 +00:00
2019-11-14 03:56:30 +00:00
self.removeTab( page_index )
2019-07-10 22:38:30 +00:00
2019-11-14 03:56:30 +00:00
self._UpdatePreviousPageIndex()
2019-07-10 22:38:30 +00:00
2019-11-14 03:56:30 +00:00
self.insertTab( new_page_index, page, name )
if page_is_selected: self.setCurrentIndex( new_page_index )
2019-07-10 22:38:30 +00:00
2017-08-23 21:34:25 +00:00
def _ShowMenu( self, screen_position ):
2019-11-14 03:56:30 +00:00
tab_index = ClientGUIFunctions.NotebookScreenToHitTest( self, screen_position )
2017-08-16 21:58:06 +00:00
2019-11-14 03:56:30 +00:00
num_pages = self.count()
2017-08-16 21:58:06 +00:00
2018-04-05 01:22:26 +00:00
end_index = num_pages - 1
2017-12-13 22:33:07 +00:00
more_than_one_tab = num_pages > 1
2017-08-16 21:58:06 +00:00
click_over_tab = tab_index != -1
2018-04-05 01:22:26 +00:00
can_go_left = tab_index > 0
can_go_right = tab_index < end_index
2017-12-13 22:33:07 +00:00
2018-04-05 01:22:26 +00:00
click_over_page_of_pages = False
2017-08-16 21:58:06 +00:00
2019-11-14 03:56:30 +00:00
menu = QW.QMenu()
2017-08-16 21:58:06 +00:00
2017-10-04 17:51:58 +00:00
if click_over_tab:
2017-08-16 21:58:06 +00:00
2019-11-14 03:56:30 +00:00
page = self.widget( tab_index )
2017-12-13 22:33:07 +00:00
click_over_page_of_pages = isinstance( page, PagesNotebook )
2019-11-14 03:56:30 +00:00
ClientGUIMenus.AppendMenuItem( menu, 'close page', 'Close this page.', self._ClosePage, tab_index )
2017-08-16 21:58:06 +00:00
if num_pages > 1:
2019-11-14 03:56:30 +00:00
ClientGUIMenus.AppendMenuItem( menu, 'close other pages', 'Close all pages but this one.', self._CloseOtherPages, tab_index )
2017-08-16 21:58:06 +00:00
2017-10-04 17:51:58 +00:00
if can_go_left:
2020-03-04 22:12:53 +00:00
2019-11-14 03:56:30 +00:00
ClientGUIMenus.AppendMenuItem( menu, 'close pages to the left', 'Close all pages to the left of this one.', self._CloseLeftPages, tab_index )
2017-08-16 21:58:06 +00:00
2017-10-04 17:51:58 +00:00
if can_go_right:
2020-03-04 22:12:53 +00:00
2019-11-14 03:56:30 +00:00
ClientGUIMenus.AppendMenuItem( menu, 'close pages to the right', 'Close all pages to the right of this one.', self._CloseRightPages, tab_index )
2017-08-16 21:58:06 +00:00
ClientGUIMenus.AppendSeparator( menu )
2019-11-14 03:56:30 +00:00
ClientGUIMenus.AppendMenuItem( menu, 'rename page', 'Rename this page.', self._RenamePage, tab_index )
2017-08-16 21:58:06 +00:00
2019-12-11 23:18:37 +00:00
2019-11-14 03:56:30 +00:00
ClientGUIMenus.AppendMenuItem( menu, 'new page', 'Choose a new page.', self._ChooseNewPage )
2017-12-13 22:33:07 +00:00
2017-08-16 21:58:06 +00:00
if click_over_tab:
2019-11-14 03:56:30 +00:00
ClientGUIMenus.AppendMenuItem( menu, 'new page here', 'Choose a new page.', self._ChooseNewPage, tab_index )
2017-12-13 22:33:07 +00:00
2020-03-04 22:12:53 +00:00
ClientGUIMenus.AppendSeparator( menu )
ClientGUIMenus.AppendMenuItem( menu, 'duplicate page', 'Duplicate this page.', self._DuplicatePage, tab_index )
2017-08-16 21:58:06 +00:00
if more_than_one_tab:
2017-12-13 22:33:07 +00:00
ClientGUIMenus.AppendSeparator( menu )
2017-08-16 21:58:06 +00:00
can_home = tab_index > 1
can_move_left = tab_index > 0
can_move_right = tab_index < end_index
can_end = tab_index < end_index - 1
if can_home:
2019-11-14 03:56:30 +00:00
ClientGUIMenus.AppendMenuItem( menu, 'move to left end', 'Move this page all the way to the left.', self._ShiftPage, tab_index, new_index=0 )
2017-08-16 21:58:06 +00:00
if can_move_left:
2020-03-04 22:12:53 +00:00
2019-11-14 03:56:30 +00:00
ClientGUIMenus.AppendMenuItem( menu, 'move left', 'Move this page one to the left.', self._ShiftPage, tab_index, delta=-1 )
2017-08-16 21:58:06 +00:00
if can_move_right:
2020-03-04 22:12:53 +00:00
2019-11-14 03:56:30 +00:00
ClientGUIMenus.AppendMenuItem( menu, 'move right', 'Move this page one to the right.', self._ShiftPage, tab_index, 1 )
2017-08-16 21:58:06 +00:00
if can_end:
2019-11-14 03:56:30 +00:00
ClientGUIMenus.AppendMenuItem( menu, 'move to right end', 'Move this page all the way to the right.', self._ShiftPage, tab_index, new_index=end_index )
2017-08-16 21:58:06 +00:00
2019-07-10 22:38:30 +00:00
ClientGUIMenus.AppendSeparator( menu )
2019-11-14 03:56:30 +00:00
ClientGUIMenus.AppendMenuItem( menu, 'sort pages by most files first', 'Sort these pages according to how many files they appear to have.', self._SortPagesByFileCount, 'desc' )
ClientGUIMenus.AppendMenuItem( menu, 'sort pages by fewest files first', 'Sort these pages according to how few files they appear to have.', self._SortPagesByFileCount, 'asc' )
2019-07-10 22:38:30 +00:00
2017-08-16 21:58:06 +00:00
2018-04-05 01:22:26 +00:00
ClientGUIMenus.AppendSeparator( menu )
2019-11-14 03:56:30 +00:00
ClientGUIMenus.AppendMenuItem( menu, 'send this page down to a new page of pages', 'Make a new page of pages and put this page in it.', self._SendPageToNewNotebook, tab_index )
2018-04-05 01:22:26 +00:00
if can_go_right:
2019-12-11 23:18:37 +00:00
ClientGUIMenus.AppendMenuItem( menu, 'send pages to the right to a new page of pages', 'Make a new page of pages and put all the pages to the right into it.', self._SendRightPagesToNewNotebook, tab_index )
2018-04-05 01:22:26 +00:00
2020-04-08 21:10:11 +00:00
2019-11-14 03:56:30 +00:00
if click_over_page_of_pages and page.count() > 0:
2017-10-04 17:51:58 +00:00
ClientGUIMenus.AppendSeparator( menu )
2019-11-14 03:56:30 +00:00
ClientGUIMenus.AppendMenuItem( menu, 'refresh all this page\'s pages', 'Command every page below this one to refresh.', page.RefreshAllPages )
2017-10-04 17:51:58 +00:00
2017-08-16 21:58:06 +00:00
2018-11-28 22:31:04 +00:00
existing_session_names = self._controller.Read( 'serialisable_names', HydrusSerialisable.SERIALISABLE_TYPE_GUI_SESSION )
2018-04-05 01:22:26 +00:00
if len( existing_session_names ) > 0 or click_over_page_of_pages:
ClientGUIMenus.AppendSeparator( menu )
if len( existing_session_names ) > 0:
2019-11-14 03:56:30 +00:00
submenu = QW.QMenu( menu )
2018-04-05 01:22:26 +00:00
for name in existing_session_names:
2019-12-11 23:18:37 +00:00
2019-11-14 03:56:30 +00:00
ClientGUIMenus.AppendMenuItem( submenu, name, 'Load this session here.', self.AppendGUISession, name )
2018-04-05 01:22:26 +00:00
ClientGUIMenus.AppendMenu( menu, submenu, 'append session' )
if click_over_page_of_pages:
2019-11-14 03:56:30 +00:00
submenu = QW.QMenu( menu )
2018-04-05 01:22:26 +00:00
for name in existing_session_names:
2018-11-28 22:31:04 +00:00
if name in RESERVED_SESSION_NAMES:
2018-04-05 01:22:26 +00:00
continue
2019-12-11 23:18:37 +00:00
ClientGUIMenus.AppendMenuItem( submenu, name, 'Save this page of pages to the session.', self._controller.gui.ProposeSaveGUISession, notebook = page, name = name )
ClientGUIMenus.AppendMenuItem( submenu, 'create a new session', 'Save this page of pages to the session.', self._controller.gui.ProposeSaveGUISession, notebook = page, suggested_name = page.GetName() )
2018-04-05 01:22:26 +00:00
ClientGUIMenus.AppendMenu( menu, submenu, 'save this page of pages to a session' )
2020-03-04 22:12:53 +00:00
CGC.core().PopupMenu( self, menu )
2017-08-16 21:58:06 +00:00
2019-07-10 22:38:30 +00:00
def _SortPagesByFileCount( self, order ):
ordered_pages = list( self.GetPages() )
def key( page ):
( total_num_files, ( total_num_value, total_num_range ) ) = page.GetNumFileSummary()
return ( total_num_files, total_num_range, total_num_value )
ordered_pages.sort( key = key )
if order == 'desc':
ordered_pages.reverse()
2019-11-14 03:56:30 +00:00
selected_page = self.currentWidget()
2019-07-10 22:38:30 +00:00
pages_to_names = {}
2019-11-14 03:56:30 +00:00
for i in range( self.count() ):
2019-07-10 22:38:30 +00:00
2019-11-14 03:56:30 +00:00
page = self.widget( 0 )
2019-07-10 22:38:30 +00:00
2019-11-14 03:56:30 +00:00
name = self.tabText( 0 )
2019-07-10 22:38:30 +00:00
pages_to_names[ page ] = name
2019-11-14 03:56:30 +00:00
self.removeTab( 0 )
self._UpdatePreviousPageIndex()
2019-07-10 22:38:30 +00:00
for page in ordered_pages:
is_selected = page == selected_page
name = pages_to_names[ page ]
2019-11-14 03:56:30 +00:00
self.addTab( page, name )
if is_selected: self.setCurrentIndex( self.count() - 1 )
2019-07-10 22:38:30 +00:00
2017-12-13 22:33:07 +00:00
def AppendGUISession( self, name, load_in_a_page_of_pages = True ):
2017-08-16 21:58:06 +00:00
2020-02-19 21:48:36 +00:00
job_key = ClientThreading.JobKey()
job_key.SetVariable( 'popup_text_1', 'loading session "{}"\u2026'.format( name ) )
HG.client_controller.pub( 'message', job_key )
# get that message showing before we do the work of loading session
HG.client_controller.app.processEvents()
2017-08-16 21:58:06 +00:00
try:
session = self._controller.Read( 'serialisable_named', HydrusSerialisable.SERIALISABLE_TYPE_GUI_SESSION, name )
except Exception as e:
HydrusData.ShowText( 'While trying to load session ' + name + ', this error happened:' )
HydrusData.ShowException( e )
self.NewPageQuery( CC.LOCAL_FILE_SERVICE_KEY )
return
2020-04-08 21:10:11 +00:00
HG.client_controller.app.processEvents()
2017-12-13 22:33:07 +00:00
if load_in_a_page_of_pages:
destination = self.NewPagesNotebook( name = name, give_it_a_blank_page = False)
else:
destination = self
2019-02-13 22:26:43 +00:00
page_tuples = session.GetPageTuples()
2017-08-16 21:58:06 +00:00
2020-04-08 21:10:11 +00:00
HG.client_controller.app.processEvents()
2017-12-13 22:33:07 +00:00
destination.AppendSessionPageTuples( page_tuples )
2017-08-16 21:58:06 +00:00
2020-02-19 21:48:36 +00:00
job_key.Delete()
2017-08-16 21:58:06 +00:00
2018-11-28 22:31:04 +00:00
def AppendGUISessionBackup( self, name, timestamp, load_in_a_page_of_pages = True ):
try:
session = self._controller.Read( 'serialisable_named', HydrusSerialisable.SERIALISABLE_TYPE_GUI_SESSION, name, timestamp )
except Exception as e:
HydrusData.ShowText( 'While trying to load session ' + name + ' (ts ' + str( timestamp ) + ', this error happened:' )
HydrusData.ShowException( e )
self.NewPageQuery( CC.LOCAL_FILE_SERVICE_KEY )
return
if load_in_a_page_of_pages:
destination = self.NewPagesNotebook( name = name, give_it_a_blank_page = False)
else:
destination = self
2019-02-13 22:26:43 +00:00
page_tuples = session.GetPageTuples()
2018-11-28 22:31:04 +00:00
destination.AppendSessionPageTuples( page_tuples )
2017-08-16 21:58:06 +00:00
def AppendSessionPageTuples( self, page_tuples ):
starting_index = self._GetDefaultPageInsertionIndex()
forced_insertion_index = starting_index
2020-03-04 22:12:53 +00:00
self.InsertSessionPageTuples( forced_insertion_index, page_tuples )
2017-08-16 21:58:06 +00:00
def ChooseNewPage( self ):
self._ChooseNewPage()
def ChooseNewPageForDeepestNotebook( self ):
2019-11-14 03:56:30 +00:00
current_page = self.currentWidget()
2017-08-16 21:58:06 +00:00
if isinstance( current_page, PagesNotebook ):
current_page.ChooseNewPageForDeepestNotebook()
else:
self._ChooseNewPage()
2019-06-19 22:08:48 +00:00
def CleanBeforeClose( self ):
for page in self._GetPages():
page.CleanBeforeClose()
2017-08-16 21:58:06 +00:00
def CleanBeforeDestroy( self ):
for page in self._GetPages():
page.CleanBeforeDestroy()
2018-05-23 21:05:06 +00:00
self._controller.ReleasePageKey( self._page_key )
2017-08-16 21:58:06 +00:00
def CloseCurrentPage( self, polite = True ):
2019-11-14 03:56:30 +00:00
selection = self.currentIndex()
2017-08-16 21:58:06 +00:00
2019-11-14 03:56:30 +00:00
if selection != -1:
2017-08-16 21:58:06 +00:00
2019-11-14 03:56:30 +00:00
page = self.widget( selection )
2017-08-16 21:58:06 +00:00
if isinstance( page, PagesNotebook ):
if page.GetNumPages() > 0:
page.CloseCurrentPage( polite )
else:
self._ClosePage( selection, polite = polite )
else:
self._ClosePage( selection, polite = polite )
2017-08-23 21:34:25 +00:00
2017-08-16 21:58:06 +00:00
def EventLeftDoubleClick( self, event ):
2019-11-14 03:56:30 +00:00
position = event.pos()
2017-08-16 21:58:06 +00:00
2019-12-05 05:29:32 +00:00
screen_pos = self.mapToGlobal( position )
tab_pos = self.tabBar().mapFromGlobal( screen_pos )
tab_index = self.tabBar().tabAt( tab_pos )
2017-08-16 21:58:06 +00:00
2019-11-14 03:56:30 +00:00
if tab_index == -1:
2017-08-16 21:58:06 +00:00
2019-11-14 03:56:30 +00:00
self.ChooseNewPage()
2019-12-05 05:29:32 +00:00
2017-09-06 20:18:20 +00:00
else:
2019-11-14 03:56:30 +00:00
return True # was: event.ignore()
2020-02-12 22:50:37 +00:00
2017-08-16 21:58:06 +00:00
2019-12-11 23:18:37 +00:00
def mouseReleaseEvent( self, event ):
if event.button() != QC.Qt.RightButton:
QP.TabWidgetWithDnD.mouseReleaseEvent( self, event )
return
2017-08-16 21:58:06 +00:00
2020-02-12 22:50:37 +00:00
mouse_position = QG.QCursor.pos()
2017-08-23 21:34:25 +00:00
2020-02-12 22:50:37 +00:00
self._ShowMenu( mouse_position )
2017-08-16 21:58:06 +00:00
2019-12-11 23:18:37 +00:00
def ShowMenuFromScreenPosition( self, position ):
2017-08-16 21:58:06 +00:00
2017-08-23 21:34:25 +00:00
notebook = self._GetNotebookFromScreenPosition( position )
2017-08-16 21:58:06 +00:00
notebook._ShowMenu( position )
def EventMiddleClick( self, event ):
2020-03-04 22:12:53 +00:00
if CGC.core().MenuIsOpen():
2017-08-30 20:27:47 +00:00
return
2019-11-14 03:56:30 +00:00
position = event.pos()
2017-08-23 21:34:25 +00:00
2019-12-05 05:29:32 +00:00
screen_pos = self.mapToGlobal( position )
tab_pos = self.tabBar().mapFromGlobal( screen_pos )
tab_index = self.tabBar().tabAt( tab_pos )
2017-08-16 21:58:06 +00:00
2019-11-14 03:56:30 +00:00
if tab_index == -1:
2017-08-16 21:58:06 +00:00
2019-11-14 03:56:30 +00:00
self.ChooseNewPage()
2017-08-16 21:58:06 +00:00
else:
self._ClosePage( tab_index )
2017-08-23 21:34:25 +00:00
def EventNewPageFromScreenPosition( self, position ):
2017-08-16 21:58:06 +00:00
2017-08-23 21:34:25 +00:00
notebook = self._GetNotebookFromScreenPosition( position )
2017-08-16 21:58:06 +00:00
notebook._ChooseNewPage()
2019-08-21 21:34:01 +00:00
def GetAPIInfoDict( self, simple ):
return {}
2019-12-11 23:18:37 +00:00
def GetCurrentGUISession( self, name ):
session = GUISession( name )
for page in self._GetPages():
session.AddPageTuple( page )
return session
2017-08-16 21:58:06 +00:00
def GetCurrentMediaPage( self ):
2019-11-14 03:56:30 +00:00
page = self.currentWidget()
2017-08-16 21:58:06 +00:00
if isinstance( page, PagesNotebook ):
return page.GetCurrentMediaPage()
else:
return page # this can be None
def GetMediaPages( self, only_my_level = False ):
return self._GetMediaPages( only_my_level )
def GetName( self ):
return self._name
2018-05-02 20:45:20 +00:00
def GetNumFileSummary( self ):
total_num_files = 0
total_num_value = 0
total_num_range = 0
for page in self._GetPages():
( num_files, ( num_value, num_range ) ) = page.GetNumFileSummary()
total_num_files += num_files
total_num_value += num_value
total_num_range += num_range
2017-08-16 21:58:06 +00:00
2018-05-02 20:45:20 +00:00
return ( total_num_files, ( total_num_value, total_num_range ) )
2017-08-16 21:58:06 +00:00
def GetNumPages( self, only_my_level = False ):
if only_my_level:
2019-11-14 03:56:30 +00:00
return self.count()
2017-08-16 21:58:06 +00:00
else:
total = 0
for page in self._GetPages():
if isinstance( page, PagesNotebook ):
total += page.GetNumPages( False )
else:
total += 1
return total
2019-06-26 21:27:18 +00:00
def GetOrMakeMultipleWatcherPage( self, desired_page_name = None, desired_page_key = None, select_page = True ):
2018-05-16 20:09:50 +00:00
2019-03-20 21:22:10 +00:00
potential_watcher_pages = [ page for page in self._GetMediaPages( False ) if page.IsMultipleWatcherPage() ]
2018-05-30 20:13:21 +00:00
2019-06-26 21:27:18 +00:00
if desired_page_key is not None and desired_page_key in ( page.GetPageKey() for page in potential_watcher_pages ):
potential_watcher_pages = [ page for page in potential_watcher_pages if page.GetPageKey() == desired_page_key ]
elif desired_page_name is not None:
2018-05-30 20:13:21 +00:00
2019-04-10 22:50:53 +00:00
potential_watcher_pages = [ page for page in potential_watcher_pages if page.GetName() == desired_page_name ]
2018-05-30 20:13:21 +00:00
2019-02-27 23:03:30 +00:00
2019-03-20 21:22:10 +00:00
if len( potential_watcher_pages ) > 0:
2019-02-27 23:03:30 +00:00
2019-03-20 21:22:10 +00:00
# ok, we can use an existing one. should we use the current?
2019-02-27 23:03:30 +00:00
2019-03-20 21:22:10 +00:00
current_media_page = self.GetCurrentMediaPage()
2018-05-16 20:09:50 +00:00
2019-03-20 21:22:10 +00:00
if current_media_page is not None and current_media_page in potential_watcher_pages:
2018-05-16 20:09:50 +00:00
2019-03-20 21:22:10 +00:00
return current_media_page
2018-05-16 20:09:50 +00:00
2019-03-20 21:22:10 +00:00
else:
2018-05-16 20:09:50 +00:00
2019-03-20 21:22:10 +00:00
return potential_watcher_pages[0]
2018-05-16 20:09:50 +00:00
2019-03-20 21:22:10 +00:00
else:
return self.NewPageImportMultipleWatcher( page_name = desired_page_name, on_deepest_notebook = True, select_page = select_page )
2018-05-16 20:09:50 +00:00
2019-06-26 21:27:18 +00:00
def GetOrMakeURLImportPage( self, desired_page_name = None, desired_page_key = None, select_page = True ):
2019-02-27 23:03:30 +00:00
2019-03-20 21:22:10 +00:00
potential_url_import_pages = [ page for page in self._GetMediaPages( False ) if page.IsURLImportPage() ]
2019-02-27 23:03:30 +00:00
2019-06-26 21:27:18 +00:00
if desired_page_key is not None and desired_page_key in ( page.GetPageKey() for page in potential_url_import_pages ):
potential_url_import_pages = [ page for page in potential_url_import_pages if page.GetPageKey() == desired_page_key ]
elif desired_page_name is not None:
2019-02-27 23:03:30 +00:00
2019-04-10 22:50:53 +00:00
potential_url_import_pages = [ page for page in potential_url_import_pages if page.GetName() == desired_page_name ]
2019-02-27 23:03:30 +00:00
2019-03-20 21:22:10 +00:00
if len( potential_url_import_pages ) > 0:
2019-02-27 23:03:30 +00:00
2019-03-20 21:22:10 +00:00
# ok, we can use an existing one. should we use the current?
2019-02-27 23:03:30 +00:00
2019-03-20 21:22:10 +00:00
current_media_page = self.GetCurrentMediaPage()
2017-08-16 21:58:06 +00:00
2019-03-20 21:22:10 +00:00
if current_media_page is not None and current_media_page in potential_url_import_pages:
2017-08-16 21:58:06 +00:00
2019-03-20 21:22:10 +00:00
return current_media_page
2017-08-16 21:58:06 +00:00
2019-03-20 21:22:10 +00:00
else:
2017-08-16 21:58:06 +00:00
2019-03-20 21:22:10 +00:00
return potential_url_import_pages[0]
2017-08-16 21:58:06 +00:00
2019-03-20 21:22:10 +00:00
else:
return self.NewPageImportURLs( page_name = desired_page_name, on_deepest_notebook = True, select_page = select_page )
2017-08-16 21:58:06 +00:00
2019-07-17 22:10:19 +00:00
def GetPageFromPageKey( self, page_key ):
2019-08-21 21:34:01 +00:00
if self._page_key == page_key:
return self
2019-07-17 22:10:19 +00:00
for page in self._GetPages():
if page.GetPageKey() == page_key:
return page
if isinstance( page, PagesNotebook ):
if page.HasPageKey( page_key ):
return page.GetPageFromPageKey( page_key )
return None
2017-08-16 21:58:06 +00:00
def GetPageKey( self ):
return self._page_key
2018-05-23 21:05:06 +00:00
def GetPageKeys( self ):
page_keys = { self._page_key }
for page in self._GetPages():
page_keys.update( page.GetPageKeys() )
return page_keys
2020-04-08 21:10:11 +00:00
def GetParentNotebook( self ):
return self._parent_notebook
2019-08-21 21:34:01 +00:00
def GetSessionAPIInfoDict( self, is_selected = True ):
2019-06-05 19:42:39 +00:00
2019-11-14 03:56:30 +00:00
current_page = self.currentWidget()
2019-06-05 19:42:39 +00:00
my_pages_list = []
for page in self._GetPages():
2019-08-21 21:34:01 +00:00
page_info_dict = page.GetSessionAPIInfoDict( is_selected = is_selected )
2019-06-05 19:42:39 +00:00
my_pages_list.append( page_info_dict )
root = {}
root[ 'name' ] = self.GetName()
2019-06-26 21:27:18 +00:00
root[ 'page_key' ] = self._page_key.hex()
2019-06-05 19:42:39 +00:00
root[ 'page_type' ] = ClientGUIManagement.MANAGEMENT_TYPE_PAGE_OF_PAGES
root[ 'selected' ] = is_selected
root[ 'pages' ] = my_pages_list
return root
2017-08-16 21:58:06 +00:00
def GetPages( self ):
return self._GetPages()
def GetPrettyStatus( self ):
2018-05-02 20:45:20 +00:00
( num_files, ( num_value, num_range ) ) = self.GetNumFileSummary()
2018-07-04 20:48:28 +00:00
num_string = HydrusData.ToHumanInt( num_files )
2018-05-02 20:45:20 +00:00
if num_range > 0 and num_value != num_range:
num_string += ', ' + HydrusData.ConvertValueRangeToPrettyString( num_value, num_range )
2019-11-14 03:56:30 +00:00
return HydrusData.ToHumanInt( self.count() ) + ' pages, ' + num_string + ' files'
2017-08-16 21:58:06 +00:00
2019-02-06 22:41:35 +00:00
def GetTestAbleToCloseStatement( self ):
count = collections.Counter()
for page in self._GetMediaPages( False ):
try:
page.CheckAbleToClose()
except HydrusExceptions.VetoException as e:
reason = str( e )
count[ reason ] += 1
if len( count ) > 0:
message = ''
for ( reason, c ) in list(count.items()):
if c == 1:
message = '1 page says: ' + reason
else:
message = HydrusData.ToHumanInt( c ) + ' pages say:' + reason
message += os.linesep
return message
else:
return None
2019-10-16 20:47:55 +00:00
def GetTotalWeight( self ):
total_weight = sum( ( page.GetTotalWeight() for page in self._GetPages() ) )
return total_weight
2018-05-16 20:09:50 +00:00
def HasMediaPageName( self, page_name, only_my_level = False ):
media_pages = self._GetMediaPages( only_my_level )
for page in media_pages:
if page.GetName() == page_name:
return True
return False
2017-08-16 21:58:06 +00:00
def HasPage( self, page ):
return self.HasPageKey( page.GetPageKey() )
def HasPageKey( self, page_key ):
for page in self._GetPages():
if page.GetPageKey() == page_key:
return True
elif isinstance( page, PagesNotebook ) and page.HasPageKey( page_key ):
return True
2018-05-16 20:09:50 +00:00
return False
def HasMultipleWatcherPage( self ):
for page in self._GetPages():
if isinstance( page, PagesNotebook ):
if page.HasMultipleWatcherPage():
return True
else:
if page.IsMultipleWatcherPage():
return True
2017-08-16 21:58:06 +00:00
return False
def HasURLImportPage( self ):
for page in self._GetPages():
if isinstance( page, PagesNotebook ):
if page.HasURLImportPage():
return True
else:
if page.IsURLImportPage():
return True
return False
2020-03-04 22:12:53 +00:00
def InsertSessionPageTuples( self, forced_insertion_index, page_tuples ):
done_first_page = False
for page_tuple in page_tuples:
2020-05-13 19:03:16 +00:00
select_page = not done_first_page
2020-03-04 22:12:53 +00:00
( page_type, page_data ) = page_tuple
if page_type == 'pages':
( name, subpage_tuples ) = page_data
try:
2020-05-13 19:03:16 +00:00
page = self.NewPagesNotebook( name, forced_insertion_index = forced_insertion_index, give_it_a_blank_page = False, select_page = select_page )
2020-03-04 22:12:53 +00:00
page.AppendSessionPageTuples( subpage_tuples )
except Exception as e:
HydrusData.ShowException( e )
elif page_type == 'page':
( management_controller, initial_hashes ) = page_data
try:
self.NewPage( management_controller, initial_hashes = initial_hashes, forced_insertion_index = forced_insertion_index, select_page = select_page )
except Exception as e:
HydrusData.ShowException( e )
forced_insertion_index += 1
2020-05-13 19:03:16 +00:00
done_first_page = True
2020-03-04 22:12:53 +00:00
2019-02-27 23:03:30 +00:00
def IsMultipleWatcherPage( self ):
return False
2018-12-05 22:35:30 +00:00
def IsImporter( self ):
return False
2019-02-27 23:03:30 +00:00
def IsURLImportPage( self ):
return False
2017-08-16 21:58:06 +00:00
def LoadGUISession( self, name ):
2019-11-14 03:56:30 +00:00
if self.count() > 0:
2017-08-16 21:58:06 +00:00
2019-09-05 00:05:32 +00:00
message = 'Close the current pages and load session "{}"?'.format( name )
result = ClientGUIDialogsQuick.GetYesNo( self, message, title = 'Clear and load session?' )
2017-08-16 21:58:06 +00:00
2019-11-14 03:56:30 +00:00
if result != QW.QDialog.Accepted:
2017-12-13 22:33:07 +00:00
2019-09-05 00:05:32 +00:00
return
2017-12-13 22:33:07 +00:00
2017-08-16 21:58:06 +00:00
2017-12-13 22:33:07 +00:00
try:
self.TestAbleToClose()
2018-05-02 20:45:20 +00:00
except HydrusExceptions.VetoException:
2017-12-13 22:33:07 +00:00
return
2018-05-16 20:09:50 +00:00
self._CloseAllPages( polite = False, delete_pages = True )
2019-11-14 03:56:30 +00:00
self._controller.CallLaterQtSafe(self, 1.0, self.AppendGUISession, name, load_in_a_page_of_pages = False)
2018-05-16 20:09:50 +00:00
else:
self.AppendGUISession( name, load_in_a_page_of_pages = False )
2017-08-16 21:58:06 +00:00
2017-12-20 22:55:48 +00:00
def MediaDragAndDropDropped( self, source_page_key, hashes ):
2019-07-17 22:10:19 +00:00
source_page = self.GetPageFromPageKey( source_page_key )
2017-12-20 22:55:48 +00:00
if source_page is None:
return
2019-11-14 03:56:30 +00:00
screen_position = QG.QCursor.pos()
2017-12-20 22:55:48 +00:00
dest_notebook = self._GetNotebookFromScreenPosition( screen_position )
2019-11-14 03:56:30 +00:00
tab_index = ClientGUIFunctions.NotebookScreenToHitTest( dest_notebook, screen_position )
2017-12-20 22:55:48 +00:00
do_add = True
# do chase - if we need to chase to an existing dest page on which we dropped files
# do return - if we need to return to source page if we created a new one
2019-11-14 03:56:30 +00:00
if tab_index == -1 and dest_notebook.currentWidget() and dest_notebook.currentWidget().rect().contains( dest_notebook.currentWidget().mapFromGlobal( screen_position ) ):
2017-12-20 22:55:48 +00:00
2019-11-14 03:56:30 +00:00
dest_page = dest_notebook.currentWidget()
2017-12-20 22:55:48 +00:00
2019-11-14 03:56:30 +00:00
elif tab_index == -1:
2017-12-20 22:55:48 +00:00
dest_page = dest_notebook.NewPageQuery( CC.LOCAL_FILE_SERVICE_KEY, initial_hashes = hashes )
do_add = False
else:
2019-11-14 03:56:30 +00:00
dest_page = dest_notebook.widget( tab_index )
2017-12-20 22:55:48 +00:00
if isinstance( dest_page, PagesNotebook ):
result = dest_page.GetCurrentMediaPage()
if result is None:
dest_page = dest_page.NewPageQuery( CC.LOCAL_FILE_SERVICE_KEY, initial_hashes = hashes )
do_add = False
else:
dest_page = result
if dest_page is None:
return # we somehow dropped onto a new notebook that has no pages
if dest_page.GetPageKey() == source_page_key:
return # we dropped onto the same page we picked up on
if do_add:
2019-05-01 21:24:42 +00:00
media_results = self._controller.Read( 'media_results', hashes, sorted = True )
2017-12-20 22:55:48 +00:00
2019-05-01 21:24:42 +00:00
dest_page.GetMediaPanel().AddMediaResults( dest_page.GetPageKey(), media_results )
2017-12-20 22:55:48 +00:00
else:
self.ShowPage( source_page )
2019-11-14 03:56:30 +00:00
# queryKBM here for instant check, not waiting for event processing to catch up u wot mate
ctrl_down = QW.QApplication.queryKeyboardModifiers() & QC.Qt.ControlModifier
2017-12-20 22:55:48 +00:00
if not ctrl_down:
source_page.GetMediaPanel().RemoveMedia( source_page.GetPageKey(), hashes )
2018-02-14 21:47:18 +00:00
def NewPage( self, management_controller, initial_hashes = None, forced_insertion_index = None, on_deepest_notebook = False, select_page = True ):
2017-08-16 21:58:06 +00:00
2019-11-14 03:56:30 +00:00
if self.window().isMinimized():
2019-06-05 19:42:39 +00:00
return None
2019-11-14 03:56:30 +00:00
current_page = self.currentWidget()
2017-08-16 21:58:06 +00:00
2017-08-23 21:34:25 +00:00
if on_deepest_notebook and isinstance( current_page, PagesNotebook ):
2017-08-16 21:58:06 +00:00
2017-09-13 20:50:41 +00:00
return current_page.NewPage( management_controller, initial_hashes = initial_hashes, forced_insertion_index = forced_insertion_index, on_deepest_notebook = on_deepest_notebook )
2017-08-16 21:58:06 +00:00
2017-12-13 22:33:07 +00:00
WARNING_TOTAL_PAGES = self._controller.new_options.GetInteger( 'total_pages_warning' )
2017-12-06 22:06:56 +00:00
MAX_TOTAL_PAGES = 200
2019-10-16 20:47:55 +00:00
( total_active_page_count, total_closed_page_count, total_active_weight, total_closed_weight ) = self._controller.gui.GetTotalPageCounts()
2017-12-06 22:06:56 +00:00
if total_active_page_count + total_closed_page_count >= WARNING_TOTAL_PAGES:
2017-08-16 21:58:06 +00:00
2017-12-06 22:06:56 +00:00
self._controller.gui.DeleteAllClosedPages()
2017-08-16 21:58:06 +00:00
2017-12-06 22:06:56 +00:00
if not HG.no_page_limit_mode:
2017-08-16 21:58:06 +00:00
2017-08-23 21:34:25 +00:00
if total_active_page_count >= MAX_TOTAL_PAGES:
2017-12-06 22:06:56 +00:00
message = 'The client should not have more than ' + str( MAX_TOTAL_PAGES ) + ' pages open, as it leads to program instability! Are you sure you want to open more pages?'
2017-08-23 21:34:25 +00:00
2019-09-05 00:05:32 +00:00
result = ClientGUIDialogsQuick.GetYesNo( self, message, title = 'Too many pages!', yes_label = 'yes, and do not tell me again', no_label = 'no' )
2019-11-14 03:56:30 +00:00
if result == QW.QDialog.Accepted:
2017-12-06 22:06:56 +00:00
2019-09-05 00:05:32 +00:00
HG.no_page_limit_mode = True
self._controller.pub( 'notify_new_options' )
else:
return None
2017-12-06 22:06:56 +00:00
2017-08-23 21:34:25 +00:00
2017-12-06 22:06:56 +00:00
if total_active_page_count == WARNING_TOTAL_PAGES:
2017-08-23 21:34:25 +00:00
2017-12-13 22:33:07 +00:00
HydrusData.ShowText( 'You have ' + str( total_active_page_count ) + ' pages open! You can only open a few more before program stability is affected! Please close some now!' )
2017-08-23 21:34:25 +00:00
2017-08-16 21:58:06 +00:00
self._controller.ResetIdleTimer()
self._controller.ResetPageChangeTimer()
if initial_hashes is None:
initial_hashes = []
page = Page( self, self._controller, management_controller, initial_hashes )
if forced_insertion_index is None:
if self._next_new_page_index is None:
insertion_index = self._GetDefaultPageInsertionIndex()
else:
insertion_index = self._next_new_page_index
self._next_new_page_index = None
else:
insertion_index = forced_insertion_index
2019-04-10 22:50:53 +00:00
page_name = page.GetName()
2017-08-16 21:58:06 +00:00
2017-10-18 19:41:25 +00:00
# in some unusual circumstances, this gets out of whack
2019-11-14 03:56:30 +00:00
insertion_index = min( insertion_index, self.count() )
self.insertTab( insertion_index, page, page_name )
2019-11-28 01:11:46 +00:00
if select_page:
self.setCurrentIndex( insertion_index )
2017-10-18 19:41:25 +00:00
2017-08-16 21:58:06 +00:00
self._controller.pub( 'refresh_page_name', page.GetPageKey() )
2017-10-25 21:45:15 +00:00
self._controller.pub( 'notify_new_pages' )
2017-08-16 21:58:06 +00:00
2019-11-14 03:56:30 +00:00
QP.CallAfter( page.Start )
2018-03-28 21:55:58 +00:00
if select_page:
2018-05-16 20:09:50 +00:00
page.SetSearchFocus()
# this is here for now due to the pagechooser having a double-layer dialog on a booru choice, which messes up some focus inheritance
2019-11-14 03:56:30 +00:00
self._controller.CallLaterQtSafe( self, 0.5, page.SetSearchFocus )
2018-03-28 21:55:58 +00:00
2017-08-16 21:58:06 +00:00
return page
2017-08-23 21:34:25 +00:00
def NewPageDuplicateFilter( self, on_deepest_notebook = False ):
2017-08-16 21:58:06 +00:00
management_controller = ClientGUIManagement.CreateManagementControllerDuplicateFilter()
2017-08-23 21:34:25 +00:00
return self.NewPage( management_controller, on_deepest_notebook = on_deepest_notebook )
2017-08-16 21:58:06 +00:00
2018-08-01 20:44:57 +00:00
def NewPageImportGallery( self, on_deepest_notebook = False ):
2017-08-16 21:58:06 +00:00
2018-08-01 20:44:57 +00:00
management_controller = ClientGUIManagement.CreateManagementControllerImportGallery()
2017-08-16 21:58:06 +00:00
2017-08-23 21:34:25 +00:00
return self.NewPage( management_controller, on_deepest_notebook = on_deepest_notebook )
2017-08-16 21:58:06 +00:00
2018-04-05 01:22:26 +00:00
def NewPageImportSimpleDownloader( self, on_deepest_notebook = False ):
2017-08-16 21:58:06 +00:00
2018-04-05 01:22:26 +00:00
management_controller = ClientGUIManagement.CreateManagementControllerImportSimpleDownloader()
2017-08-16 21:58:06 +00:00
2017-08-23 21:34:25 +00:00
return self.NewPage( management_controller, on_deepest_notebook = on_deepest_notebook )
2017-08-16 21:58:06 +00:00
2019-03-20 21:22:10 +00:00
def NewPageImportMultipleWatcher( self, page_name = None, url = None, on_deepest_notebook = False, select_page = True ):
2018-05-16 20:09:50 +00:00
2019-02-27 23:03:30 +00:00
management_controller = ClientGUIManagement.CreateManagementControllerImportMultipleWatcher( page_name = page_name, url = url )
2018-05-16 20:09:50 +00:00
2019-03-20 21:22:10 +00:00
return self.NewPage( management_controller, on_deepest_notebook = on_deepest_notebook, select_page = select_page )
2018-05-16 20:09:50 +00:00
2019-03-20 21:22:10 +00:00
def NewPageImportURLs( self, page_name = None, on_deepest_notebook = False, select_page = True ):
2017-08-16 21:58:06 +00:00
2019-02-27 23:03:30 +00:00
management_controller = ClientGUIManagement.CreateManagementControllerImportURLs( page_name = page_name )
2017-08-16 21:58:06 +00:00
2019-03-20 21:22:10 +00:00
return self.NewPage( management_controller, on_deepest_notebook = on_deepest_notebook, select_page = select_page )
2017-08-16 21:58:06 +00:00
2017-08-23 21:34:25 +00:00
def NewPagePetitions( self, service_key, on_deepest_notebook = False ):
2017-08-16 21:58:06 +00:00
management_controller = ClientGUIManagement.CreateManagementControllerPetitions( service_key )
2017-08-23 21:34:25 +00:00
return self.NewPage( management_controller, on_deepest_notebook = on_deepest_notebook )
2017-08-16 21:58:06 +00:00
2018-02-14 21:47:18 +00:00
def NewPageQuery( self, file_service_key, initial_hashes = None, initial_predicates = None, page_name = None, on_deepest_notebook = False, do_sort = False, select_page = True ):
2017-08-16 21:58:06 +00:00
if initial_hashes is None:
initial_hashes = []
if initial_predicates is None:
initial_predicates = []
if page_name is None:
page_name = 'files'
search_enabled = len( initial_hashes ) == 0
2017-12-06 22:06:56 +00:00
new_options = self._controller.new_options
2017-08-16 21:58:06 +00:00
tag_service_key = new_options.GetKey( 'default_tag_service_search_page' )
if not self._controller.services_manager.ServiceExists( tag_service_key ):
tag_service_key = CC.COMBINED_TAG_SERVICE_KEY
2020-03-18 21:35:57 +00:00
if file_service_key == CC.COMBINED_FILE_SERVICE_KEY and tag_service_key == CC.COMBINED_TAG_SERVICE_KEY:
2020-04-01 21:51:42 +00:00
file_service_key = CC.COMBINED_LOCAL_FILE_SERVICE_KEY
2020-03-18 21:35:57 +00:00
2020-03-11 21:52:11 +00:00
tag_search_context = ClientSearch.TagSearchContext( service_key = tag_service_key )
file_search_context = ClientSearch.FileSearchContext( file_service_key = file_service_key, tag_search_context = tag_search_context, predicates = initial_predicates )
2017-08-16 21:58:06 +00:00
2020-04-01 21:51:42 +00:00
management_controller = ClientGUIManagement.CreateManagementControllerQuery( page_name, file_search_context, search_enabled )
2017-08-16 21:58:06 +00:00
2018-02-14 21:47:18 +00:00
page = self.NewPage( management_controller, initial_hashes = initial_hashes, on_deepest_notebook = on_deepest_notebook, select_page = select_page )
2017-10-18 19:41:25 +00:00
if do_sort:
HG.client_controller.pub( 'do_page_sort', page.GetPageKey() )
return page
2017-08-16 21:58:06 +00:00
2018-05-16 20:09:50 +00:00
def NewPagesNotebook( self, name = 'pages', forced_insertion_index = None, on_deepest_notebook = False, give_it_a_blank_page = True, select_page = True ):
2017-08-23 21:34:25 +00:00
2019-11-14 03:56:30 +00:00
current_page = self.currentWidget()
2017-08-23 21:34:25 +00:00
if on_deepest_notebook and isinstance( current_page, PagesNotebook ):
2019-02-13 22:26:43 +00:00
return current_page.NewPagesNotebook( name = name, forced_insertion_index = forced_insertion_index, on_deepest_notebook = on_deepest_notebook, give_it_a_blank_page = give_it_a_blank_page )
2017-08-23 21:34:25 +00:00
2017-08-16 21:58:06 +00:00
self._controller.ResetIdleTimer()
self._controller.ResetPageChangeTimer()
page = PagesNotebook( self, self._controller, name )
if forced_insertion_index is None:
if self._next_new_page_index is None:
insertion_index = self._GetDefaultPageInsertionIndex()
else:
insertion_index = self._next_new_page_index
self._next_new_page_index = None
else:
insertion_index = forced_insertion_index
2019-04-10 22:50:53 +00:00
page_name = page.GetName()
2017-08-16 21:58:06 +00:00
2019-11-14 03:56:30 +00:00
self.insertTab( insertion_index, page, page_name )
2020-05-13 19:03:16 +00:00
if select_page:
self.setCurrentIndex( insertion_index )
2017-08-16 21:58:06 +00:00
self._controller.pub( 'refresh_page_name', page.GetPageKey() )
2017-08-30 20:27:47 +00:00
if give_it_a_blank_page:
page.NewPageQuery( CC.LOCAL_FILE_SERVICE_KEY )
2017-08-16 21:58:06 +00:00
return page
def NotifyPageUnclosed( self, page ):
page_key = page.GetPageKey()
for ( index, closed_page_key ) in self._closed_pages:
if page_key == closed_page_key:
2019-11-14 03:56:30 +00:00
page.show()
2017-08-16 21:58:06 +00:00
2019-11-14 03:56:30 +00:00
insert_index = min( index, self.count() )
2017-08-16 21:58:06 +00:00
2019-04-10 22:50:53 +00:00
name = page.GetName()
2017-08-16 21:58:06 +00:00
2019-11-14 03:56:30 +00:00
self.insertTab( insert_index, page, name )
self.setCurrentIndex( insert_index )
2017-08-16 21:58:06 +00:00
self._controller.pub( 'refresh_page_name', page.GetPageKey() )
self._closed_pages.remove( ( index, closed_page_key ) )
break
def PageHidden( self ):
2019-11-14 03:56:30 +00:00
result = self.currentWidget()
2017-08-16 21:58:06 +00:00
if result is not None:
result.PageHidden()
2020-05-13 19:03:16 +00:00
def pageJustChanged( self, index ):
old_selection = self._previous_page_index
selection = index
if old_selection != -1 and old_selection < self.count():
self.widget( old_selection ).PageHidden()
if selection != -1:
new_page = self.widget( selection )
new_page.PageShown()
self._controller.gui.RefreshStatusBar()
self._previous_page_index = index
self._controller.pub( 'notify_page_change' )
2017-08-16 21:58:06 +00:00
def PageShown( self ):
2019-11-14 03:56:30 +00:00
result = self.currentWidget()
2017-08-16 21:58:06 +00:00
if result is not None:
result.PageShown()
2018-02-14 21:47:18 +00:00
def PresentImportedFilesToPage( self, hashes, page_name ):
page = self._GetPageFromName( page_name )
if page is None:
page = self.NewPageQuery( CC.LOCAL_FILE_SERVICE_KEY, initial_hashes = hashes, page_name = page_name, on_deepest_notebook = True, select_page = False )
else:
2019-11-14 03:56:30 +00:00
def qt_finish( page, media_results ):
2019-10-16 20:47:55 +00:00
if not page:
return
page.GetMediaPanel().AddMediaResults( page.GetPageKey(), media_results )
def do_it( page, hashes ):
media_results = self._controller.Read( 'media_results', hashes, sorted = True )
2019-11-14 03:56:30 +00:00
QP.CallAfter( qt_finish, page, media_results )
2019-10-16 20:47:55 +00:00
2018-02-14 21:47:18 +00:00
2019-10-16 20:47:55 +00:00
HG.client_controller.CallToThread( do_it, page, hashes )
2018-02-14 21:47:18 +00:00
return page
2017-10-04 17:51:58 +00:00
def RefreshAllPages( self ):
2017-08-16 21:58:06 +00:00
for page in self._GetPages():
2017-10-04 17:51:58 +00:00
if isinstance( page, PagesNotebook ):
page.RefreshAllPages()
else:
page.RefreshQuery()
2017-08-16 21:58:06 +00:00
def RefreshPageName( self, page_key = None ):
if page_key is None:
2019-11-14 03:56:30 +00:00
for index in range( self.count() ):
2017-08-16 21:58:06 +00:00
self._RefreshPageName( index )
else:
for ( index, page ) in enumerate( self._GetPages() ):
do_it = False
if page.GetPageKey() == page_key:
do_it = True
elif isinstance( page, PagesNotebook ) and page.HasPageKey( page_key ):
do_it = True
if do_it:
self._RefreshPageName( index )
break
2019-04-10 22:50:53 +00:00
def SetName( self, name ):
2017-08-16 21:58:06 +00:00
self._name = name
def ShowPage( self, showee ):
for ( i, page ) in enumerate( self._GetPages() ):
2019-11-14 03:56:30 +00:00
if isinstance( page, QW.QTabWidget ) and page.HasPage( showee ):
2017-08-16 21:58:06 +00:00
2019-11-14 03:56:30 +00:00
self.setCurrentIndex( i )
2017-08-16 21:58:06 +00:00
page.ShowPage( showee )
break
elif page == showee:
2019-11-14 03:56:30 +00:00
self.setCurrentIndex( i )
2017-08-16 21:58:06 +00:00
break
2019-02-13 22:26:43 +00:00
def TestAbleToClose( self ):
statement = self.GetTestAbleToCloseStatement()
if statement is not None:
message = 'Are you sure you want to close this page of pages?'
message += os.linesep * 2
message += statement
2019-09-05 00:05:32 +00:00
result = ClientGUIDialogsQuick.GetYesNo( self, message )
2019-11-14 03:56:30 +00:00
if result == QW.QDialog.Rejected:
2019-02-13 22:26:43 +00:00
2019-09-05 00:05:32 +00:00
raise HydrusExceptions.VetoException()
2019-02-13 22:26:43 +00:00
2018-05-30 20:13:21 +00:00
def REPEATINGPageUpdate( self ):
2017-12-13 22:33:07 +00:00
pass
2017-08-16 21:58:06 +00:00
class GUISession( HydrusSerialisable.SerialisableBaseNamed ):
SERIALISABLE_TYPE = HydrusSerialisable.SERIALISABLE_TYPE_GUI_SESSION
2017-11-29 21:48:23 +00:00
SERIALISABLE_NAME = 'GUI Session'
2019-04-10 22:50:53 +00:00
SERIALISABLE_VERSION = 4
2017-08-16 21:58:06 +00:00
def __init__( self, name ):
HydrusSerialisable.SerialisableBaseNamed.__init__( self, name )
2019-02-13 22:26:43 +00:00
self._page_tuples = []
2017-08-16 21:58:06 +00:00
def _GetPageTuple( self, page ):
if isinstance( page, PagesNotebook ):
name = page.GetName()
page_tuples = [ self._GetPageTuple( subpage ) for subpage in page.GetPages() ]
return ( 'pages', ( name, page_tuples ) )
else:
management_controller = page.GetManagementController()
hashes = list( page.GetHashes() )
return ( 'page', ( management_controller, hashes ) )
def _GetSerialisableInfo( self ):
2020-03-04 22:12:53 +00:00
def handle_e( page_tuple, e ):
2018-05-09 20:23:00 +00:00
HydrusData.ShowText( 'Attempting to save a page to the session failed! Its data tuple and error follows! Please close it or see if you can clear any potentially invalid data from it!' )
HydrusData.ShowText( page_tuple )
HydrusData.ShowException( e )
2017-08-16 21:58:06 +00:00
def GetSerialisablePageTuple( page_tuple ):
( page_type, page_data ) = page_tuple
if page_type == 'pages':
( name, page_tuples ) = page_data
2018-05-09 20:23:00 +00:00
serialisable_page_tuples = []
for pt in page_tuples:
try:
serialisable_page_tuples.append( GetSerialisablePageTuple( pt ) )
except Exception as e:
2020-03-04 22:12:53 +00:00
handle_e( page_tuple, e )
2018-05-09 20:23:00 +00:00
2017-08-16 21:58:06 +00:00
serialisable_page_data = ( name, serialisable_page_tuples )
elif page_type == 'page':
( management_controller, hashes ) = page_data
serialisable_management_controller = management_controller.GetSerialisableTuple()
2019-01-09 22:59:03 +00:00
serialisable_hashes = [ hash.hex() for hash in hashes ]
2017-08-16 21:58:06 +00:00
serialisable_page_data = ( serialisable_management_controller, serialisable_hashes )
serialisable_tuple = ( page_type, serialisable_page_data )
return serialisable_tuple
serialisable_info = []
2019-02-13 22:26:43 +00:00
for page_tuple in self._page_tuples:
2017-08-16 21:58:06 +00:00
2018-05-09 20:23:00 +00:00
try:
serialisable_page_tuple = GetSerialisablePageTuple( page_tuple )
serialisable_info.append( serialisable_page_tuple )
except Exception as e:
2020-03-04 22:12:53 +00:00
handle_e( page_tuple, e )
2018-05-09 20:23:00 +00:00
2017-08-16 21:58:06 +00:00
return serialisable_info
def _InitialiseFromSerialisableInfo( self, serialisable_info ):
2020-03-04 22:12:53 +00:00
def handle_e( serialisable_page_tuple, e ):
2018-05-09 20:23:00 +00:00
HydrusData.ShowText( 'A page failed to load! Its serialised data and error follows!' )
HydrusData.ShowText( serialisable_page_tuple )
HydrusData.ShowException( e )
2017-08-16 21:58:06 +00:00
def GetPageTuple( serialisable_page_tuple ):
( page_type, serialisable_page_data ) = serialisable_page_tuple
if page_type == 'pages':
( name, serialisable_page_tuples ) = serialisable_page_data
2018-05-09 20:23:00 +00:00
page_tuples = []
for spt in serialisable_page_tuples:
try:
page_tuples.append( GetPageTuple( spt ) )
except Exception as e:
2020-03-04 22:12:53 +00:00
handle_e( spt, e )
2018-05-09 20:23:00 +00:00
2017-08-16 21:58:06 +00:00
page_data = ( name, page_tuples )
elif page_type == 'page':
( serialisable_management_controller, serialisable_hashes ) = serialisable_page_data
management_controller = HydrusSerialisable.CreateFromSerialisableTuple( serialisable_management_controller )
2019-01-09 22:59:03 +00:00
hashes = [ bytes.fromhex( hash ) for hash in serialisable_hashes ]
2017-08-16 21:58:06 +00:00
page_data = ( management_controller, hashes )
page_tuple = ( page_type, page_data )
return page_tuple
for serialisable_page_tuple in serialisable_info:
2018-05-09 20:23:00 +00:00
try:
page_tuple = GetPageTuple( serialisable_page_tuple )
2019-02-13 22:26:43 +00:00
self._page_tuples.append( page_tuple )
2018-05-09 20:23:00 +00:00
except Exception as e:
2020-03-04 22:12:53 +00:00
handle_e( serialisable_page_tuple, e )
2018-05-09 20:23:00 +00:00
2017-08-02 21:32:54 +00:00
def _UpdateSerialisableInfo( self, version, old_serialisable_info ):
if version == 1:
new_serialisable_info = []
for ( page_name, serialisable_management_controller, serialisable_hashes ) in old_serialisable_info:
management_controller = HydrusSerialisable.CreateFromSerialisableTuple( serialisable_management_controller )
management_controller.SetPageName( page_name )
serialisable_management_controller = management_controller.GetSerialisableTuple()
new_serialisable_info.append( ( serialisable_management_controller, serialisable_hashes ) )
return ( 2, new_serialisable_info )
2014-01-22 21:11:22 +00:00
2013-04-24 21:23:53 +00:00
2017-08-16 21:58:06 +00:00
if version == 2:
new_serialisable_info = []
for ( serialisable_management_controller, serialisable_hashes ) in old_serialisable_info:
new_serialisable_info.append( ( 'page', ( serialisable_management_controller, serialisable_hashes ) ) )
return ( 3, new_serialisable_info )
2019-04-10 22:50:53 +00:00
if version == 3:
def clean_tuple( spt ):
( page_type, serialisable_page_data ) = spt
if page_type == 'pages':
( name, pages_serialisable_page_tuples ) = serialisable_page_data
if name.startswith( '[USER]' ) and len( name ) > 6:
name = name[6:]
pages_serialisable_page_tuples = [ clean_tuple( pages_spt ) for pages_spt in pages_serialisable_page_tuples ]
return ( 'pages', ( name, pages_serialisable_page_tuples ) )
else:
return spt
new_serialisable_info = []
serialisable_page_tuples = old_serialisable_info
for serialisable_page_tuple in serialisable_page_tuples:
serialisable_page_tuple = clean_tuple( serialisable_page_tuple )
new_serialisable_info.append( serialisable_page_tuple )
return ( 4, new_serialisable_info )
2013-02-19 00:11:43 +00:00
2019-02-13 22:26:43 +00:00
def AddPageTuple( self, page ):
2017-08-16 21:58:06 +00:00
page_tuple = self._GetPageTuple( page )
2013-11-27 18:27:11 +00:00
2019-02-13 22:26:43 +00:00
self._page_tuples.append( page_tuple )
2013-11-27 18:27:11 +00:00
2019-02-13 22:26:43 +00:00
def GetPageTuples( self ):
2013-02-19 00:11:43 +00:00
2019-02-13 22:26:43 +00:00
return self._page_tuples
2013-02-19 00:11:43 +00:00
2015-06-24 22:10:14 +00:00
HydrusSerialisable.SERIALISABLE_TYPES_TO_OBJECT_TYPES[ HydrusSerialisable.SERIALISABLE_TYPE_GUI_SESSION ] = GUISession