hydrus/include/ClientGUIPages.py

3117 lines
96 KiB
Python
Raw Normal View History

2019-01-09 22:59:03 +00:00
from . import HydrusConstants as HC
from . import ClientConstants as CC
2020-02-12 22:50:37 +00:00
from . import ClientGUICanvas
2020-03-04 22:12:53 +00:00
from . import ClientGUICore as CGC
2019-01-09 22:59:03 +00:00
from . import ClientGUIDialogs
2019-09-05 00:05:32 +00:00
from . import ClientGUIDialogsQuick
2019-06-26 21:27:18 +00:00
from . import ClientGUIFunctions
2019-01-09 22:59:03 +00:00
from . import ClientGUIManagement
from . import ClientGUIMenus
2020-02-12 22:50:37 +00:00
from . import ClientGUIResults
2019-01-09 22:59:03 +00:00
from . import ClientSearch
from . import ClientGUIShortcuts
from . import ClientThreading
2018-05-02 20:45:20 +00:00
import collections
2019-01-09 22:59:03 +00:00
from . import HydrusData
from . import HydrusExceptions
2020-03-04 22:12:53 +00:00
from . import HydrusGlobals as HG
2019-01-09 22:59:03 +00:00
from . import HydrusSerialisable
2020-01-02 03:05:35 +00:00
from . import HydrusText
2013-02-19 00:11:43 +00:00
import os
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
from . 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
file_search_context = ClientSearch.FileSearchContext( file_service_key = file_service_key, tag_service_key = tag_service_key )
self._result = ( 'page', ClientGUIManagement.CreateManagementControllerQuery( page_name, file_service_key, file_search_context, search_enabled ) )
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
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
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.SetupSplits()
2015-11-04 22:30:28 +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
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()
self._preview_canvas.SetMedia( None )
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
2019-08-21 21:34:01 +00:00
sort_by = self._management_panel.GetMediaSort()
2019-05-22 22:35:06 +00:00
new_panel.Sort( self._page_key, sort_by )
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
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()
self._controller.pub( 'set_focus', self._page_key, None )
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
2015-11-25 22:00:57 +00:00
self._controller.pub( 'set_focus', self._page_key, 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
2015-11-25 22:00:57 +00:00
self._controller.pub( 'set_focus', self._page_key, 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 }
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()
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 ):
2017-09-27 21:52:54 +00:00
self._management_panel.PageShown()
self._media_panel.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:
self._controller.pub( 'refresh_query', self._page_key )
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 ):
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' ] )
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
2015-11-25 22:00:57 +00:00
self._controller.pub( 'set_focus', self._page_key, 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
2015-11-25 22:00:57 +00:00
def SetSynchronisedWait( self ):
self._controller.pub( 'synchronised_wait_switch', self._page_key )
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-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() )
self.currentChanged.connect( self.EventPageChanged )
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() )
if hasattr( source_widget.parentWidget(), 'GetPageKey' ):
self._controller.pub( 'refresh_page_name', source_widget.parentWidget().GetPageKey() )
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 )
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
2018-04-05 01:22:26 +00:00
def _GetTopNotebook( self ):
top_notebook = self
2019-11-14 03:56:30 +00:00
parent = top_notebook.parentWidget()
2018-04-05 01:22:26 +00:00
while isinstance( parent, PagesNotebook ):
top_notebook = parent
2019-11-14 03:56:30 +00:00
parent = top_notebook.parentWidget()
2018-04-05 01:22:26 +00:00
return top_notebook
2017-10-04 17:51:58 +00:00
def _MovePage( self, page, dest_notebook, insertion_tab_index, follow_dropped_page = False ):
2019-11-14 03:56:30 +00:00
source_notebook = page.parentWidget().parentWidget() # page.parentWidget() is a QStackedWidget
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() )
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:
2019-11-14 03:56:30 +00:00
if page.parentWidget() != 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
2019-11-14 03:56:30 +00:00
safe_page_name = QP.EscapeMnemonics( page_name )
2018-02-07 23:40:33 +00:00
2019-11-14 03:56:30 +00:00
existing_page_name = self.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
2019-11-14 03:56:30 +00:00
self.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
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
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
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-11-14 03:56:30 +00:00
def EventPageChanged( self, index ):
2017-08-16 21:58:06 +00:00
2019-11-14 03:56:30 +00:00
old_selection = self._previous_page_index
selection = index
2017-08-16 21:58:06 +00:00
2019-11-14 03:56:30 +00:00
if old_selection != -1 and old_selection < self.count():
2017-08-16 21:58:06 +00:00
2019-11-14 03:56:30 +00:00
self.widget( old_selection ).PageHidden()
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
self.widget( selection ).PageShown()
2017-08-16 21:58:06 +00:00
2019-11-14 03:56:30 +00:00
self._controller.gui.RefreshStatusBar()
2017-08-16 21:58:06 +00:00
2019-11-14 03:56:30 +00:00
self._previous_page_index = index
2017-08-16 21:58:06 +00:00
2018-06-27 19:27:05 +00:00
self._controller.pub( 'notify_page_change' )
2017-08-16 21:58:06 +00:00
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
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():
page_is_focused = is_selected and page == current_page
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:
total_problems = sum( count.values() )
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:
( page_type, page_data ) = page_tuple
if page_type == 'pages':
( name, subpage_tuples ) = page_data
try:
page = self.NewPagesNotebook( name, forced_insertion_index = forced_insertion_index, give_it_a_blank_page = False, select_page = False )
page.AppendSessionPageTuples( subpage_tuples )
except Exception as e:
HydrusData.ShowException( e )
elif page_type == 'page':
( management_controller, initial_hashes ) = page_data
try:
select_page = not done_first_page
self.NewPage( management_controller, initial_hashes = initial_hashes, forced_insertion_index = forced_insertion_index, select_page = select_page )
done_first_page = True
except Exception as e:
HydrusData.ShowException( e )
forced_insertion_index += 1
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
2019-11-14 03:56:30 +00:00
self.LayoutPages()
page.SetupSplits()
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
file_search_context = ClientSearch.FileSearchContext( file_service_key = file_service_key, tag_service_key = tag_service_key, predicates = initial_predicates )
management_controller = ClientGUIManagement.CreateManagementControllerQuery( page_name, file_service_key, file_search_context, search_enabled )
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 )
if select_page: self.setCurrentIndex( insertion_index )
self.LayoutPages()
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()
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