hydrus/hydrus/client/gui/ClientGUIPopupMessages.py

1361 lines
40 KiB
Python
Raw Normal View History

2017-07-27 00:47:13 +00:00
import os
import sys
import traceback
2020-04-22 21:00:35 +00:00
2019-11-14 03:56:30 +00:00
from qtpy import QtCore as QC
from qtpy import QtWidgets as QW
2020-04-22 21:00:35 +00:00
2021-12-15 22:16:22 +00:00
from hydrus.core import HydrusConstants as HC
2020-04-22 21:00:35 +00:00
from hydrus.core import HydrusData
from hydrus.core import HydrusGlobals as HG
2023-04-19 20:38:13 +00:00
from hydrus.core import HydrusTime
2020-07-29 20:52:44 +00:00
2020-04-22 21:00:35 +00:00
from hydrus.client import ClientConstants as CC
from hydrus.client import ClientData
2022-01-19 21:28:59 +00:00
from hydrus.client import ClientLocation
2020-04-22 21:00:35 +00:00
from hydrus.client import ClientThreading
from hydrus.client.gui import ClientGUIDialogsQuick
from hydrus.client.gui import ClientGUIFunctions
from hydrus.client.gui import ClientGUITopLevelWindows
from hydrus.client.gui import QtPorting as QP
2021-04-07 21:26:45 +00:00
from hydrus.client.gui.networking import ClientGUINetworkJobControl
2021-03-17 21:59:28 +00:00
from hydrus.client.gui.widgets import ClientGUICommon
2017-07-27 00:47:13 +00:00
2019-11-14 03:56:30 +00:00
class PopupWindow( QW.QFrame ):
2017-07-27 00:47:13 +00:00
2022-10-05 21:00:47 +00:00
dismiss = QC.Signal( QW.QWidget )
iJustChangedSize = QC.Signal()
def __init__( self, parent ):
2017-07-27 00:47:13 +00:00
2019-11-14 03:56:30 +00:00
QW.QFrame.__init__( self, parent )
self.setFrameStyle( QW.QFrame.Box | QW.QFrame.Plain )
2017-07-27 00:47:13 +00:00
2019-11-14 03:56:30 +00:00
self._widget_event_filter = QP.WidgetEventFilter( self )
self._widget_event_filter.EVT_RIGHT_DOWN( self.EventDismiss )
2017-07-27 00:47:13 +00:00
def TryToDismiss( self ):
2022-10-05 21:00:47 +00:00
self.dismiss.emit( self )
2017-07-27 00:47:13 +00:00
def EventDismiss( self, event ):
self.TryToDismiss()
class PopupMessage( PopupWindow ):
TEXT_CUTOFF = 1024
2022-10-05 21:00:47 +00:00
def __init__( self, parent, job_key: ClientThreading.JobKey ):
2017-07-27 00:47:13 +00:00
2022-10-05 21:00:47 +00:00
PopupWindow.__init__( self, parent )
2019-11-28 01:11:46 +00:00
2017-07-27 00:47:13 +00:00
self._job_key = job_key
2022-10-05 21:00:47 +00:00
vbox_margin = 2
vbox = QP.VBoxLayout( vbox_margin )
2017-07-27 00:47:13 +00:00
2019-11-14 03:56:30 +00:00
self._title = ClientGUICommon.BetterStaticText( self )
self._title.setAlignment( QC.Qt.AlignHCenter | QC.Qt.AlignVCenter )
2019-11-28 01:11:46 +00:00
font = self._title.font()
font.setBold( True )
self._title.setFont( font )
2018-04-18 22:10:15 +00:00
popup_message_character_width = HG.client_controller.new_options.GetInteger( 'popup_message_character_width' )
2019-11-28 01:11:46 +00:00
popup_char_width = ClientGUIFunctions.ConvertTextToPixelWidth( self._title, popup_message_character_width )
2018-04-18 22:10:15 +00:00
2018-06-20 20:20:22 +00:00
if HG.client_controller.new_options.GetBoolean( 'popup_message_force_min_width' ):
2019-11-28 01:11:46 +00:00
self.setFixedWidth( popup_char_width )
else:
self.setMaximumWidth( popup_char_width )
2018-06-20 20:20:22 +00:00
2022-10-05 21:00:47 +00:00
popup_char_width_sub_widget = popup_char_width - ( vbox_margin * 2 )
# I discovered if I set the maxWidth to the static texts themselves, the sizehints here stop borking out and long multiline text paragraphs will happily size themselves
# if not set, they will be clipped by higher sizeHint somehow. 500x90 is told to fit in a 400x90 hole, the QWidget PopupWindow is not clever enough to propagate the max width down to (dynamic, height-for-width) children?
2019-11-20 23:10:46 +00:00
self._title.setWordWrap( True )
2022-10-05 21:00:47 +00:00
self._title.setMaximumWidth( popup_char_width_sub_widget )
2019-11-14 03:56:30 +00:00
self._title_ev = QP.WidgetEventFilter( self._title )
self._title_ev.EVT_RIGHT_DOWN( self.EventDismiss )
self._title.hide()
2017-07-27 00:47:13 +00:00
2019-11-20 23:10:46 +00:00
self._text_1 = ClientGUICommon.BetterStaticText( self )
self._text_1.setWordWrap( True )
2022-10-05 21:00:47 +00:00
self._text_1.setMaximumWidth( popup_char_width_sub_widget )
2019-11-14 03:56:30 +00:00
self._text_1_ev = QP.WidgetEventFilter( self._text_1 )
self._text_1_ev.EVT_RIGHT_DOWN( self.EventDismiss )
self._text_1.hide()
2017-07-27 00:47:13 +00:00
2019-11-14 03:56:30 +00:00
self._gauge_1 = ClientGUICommon.Gauge( self )
self._gauge_1_ev = QP.WidgetEventFilter( self._gauge_1 )
self._gauge_1_ev.EVT_RIGHT_DOWN( self.EventDismiss )
2019-11-28 01:11:46 +00:00
self._gauge_1.setMinimumWidth( int( popup_char_width * 0.9 ) )
2019-11-14 03:56:30 +00:00
self._gauge_1.hide()
2017-07-27 00:47:13 +00:00
2019-11-20 23:10:46 +00:00
self._text_2 = ClientGUICommon.BetterStaticText( self )
self._text_2.setWordWrap( True )
2022-10-05 21:00:47 +00:00
self._text_2.setMaximumWidth( popup_char_width_sub_widget )
2019-11-14 03:56:30 +00:00
self._text_2_ev = QP.WidgetEventFilter( self._text_2 )
self._text_2_ev.EVT_RIGHT_DOWN( self.EventDismiss )
self._text_2.hide()
2017-07-27 00:47:13 +00:00
2019-11-14 03:56:30 +00:00
self._gauge_2 = ClientGUICommon.Gauge( self )
self._gauge_2_ev = QP.WidgetEventFilter( self._gauge_2 )
self._gauge_2_ev.EVT_RIGHT_DOWN( self.EventDismiss )
2019-11-28 01:11:46 +00:00
self._gauge_2.setMinimumWidth( int( popup_char_width * 0.9 ) )
2019-11-14 03:56:30 +00:00
self._gauge_2.hide()
2017-07-27 00:47:13 +00:00
2018-06-06 21:27:02 +00:00
self._text_yes_no = ClientGUICommon.BetterStaticText( self )
2019-11-14 03:56:30 +00:00
self._text_yes_no_ev = QP.WidgetEventFilter( self._text_yes_no )
self._text_yes_no_ev.EVT_RIGHT_DOWN( self.EventDismiss )
self._text_yes_no.hide()
2017-10-04 17:51:58 +00:00
self._yes = ClientGUICommon.BetterButton( self, 'yes', self._YesButton )
2019-11-14 03:56:30 +00:00
self._yes.hide()
2017-10-04 17:51:58 +00:00
self._no = ClientGUICommon.BetterButton( self, 'no', self._NoButton )
2019-11-14 03:56:30 +00:00
self._no.hide()
2017-10-04 17:51:58 +00:00
2021-03-17 21:59:28 +00:00
self._network_job_ctrl = ClientGUINetworkJobControl.NetworkJobControl( self )
2023-06-28 20:29:14 +00:00
self._network_job_ctrl.SetShouldUpdateFreely( True )
2019-11-14 03:56:30 +00:00
self._network_job_ctrl.hide()
2022-04-20 20:18:56 +00:00
self._time_network_job_disappeared = 0
2017-07-27 00:47:13 +00:00
self._copy_to_clipboard_button = ClientGUICommon.BetterButton( self, 'copy to clipboard', self.CopyToClipboard )
2019-11-14 03:56:30 +00:00
self._copy_to_clipboard_button_ev = QP.WidgetEventFilter( self._copy_to_clipboard_button )
self._copy_to_clipboard_button_ev.EVT_RIGHT_DOWN( self.EventDismiss )
self._copy_to_clipboard_button.hide()
2017-07-27 00:47:13 +00:00
self._show_files_button = ClientGUICommon.BetterButton( self, 'show files', self.ShowFiles )
2019-11-14 03:56:30 +00:00
self._show_files_button_ev = QP.WidgetEventFilter( self._show_files_button )
self._show_files_button_ev.EVT_RIGHT_DOWN( self.EventDismiss )
self._show_files_button.hide()
2017-07-27 00:47:13 +00:00
2021-06-09 20:28:09 +00:00
self._user_callable_button = ClientGUICommon.BetterButton( self, 'run command', self.CallUserCallable )
self._user_callable_button_ev = QP.WidgetEventFilter( self._user_callable_button )
self._user_callable_button_ev.EVT_RIGHT_DOWN( self.EventDismiss )
self._user_callable_button.hide()
2017-07-27 00:47:13 +00:00
self._show_tb_button = ClientGUICommon.BetterButton( self, 'show traceback', self.ShowTB )
2019-11-14 03:56:30 +00:00
self._show_tb_button_ev = QP.WidgetEventFilter( self._show_tb_button )
self._show_tb_button_ev.EVT_RIGHT_DOWN( self.EventDismiss )
self._show_tb_button.hide()
2017-07-27 00:47:13 +00:00
2018-06-06 21:27:02 +00:00
self._tb_text = ClientGUICommon.BetterStaticText( self )
2022-10-05 21:00:47 +00:00
self._tb_text.setWordWrap( True )
self._tb_text.setMaximumWidth( popup_char_width_sub_widget )
2019-11-14 03:56:30 +00:00
self._tb_text_ev = QP.WidgetEventFilter( self._tb_text )
self._tb_text_ev.EVT_RIGHT_DOWN( self.EventDismiss )
self._tb_text.hide()
2017-07-27 00:47:13 +00:00
self._copy_tb_button = ClientGUICommon.BetterButton( self, 'copy traceback information', self.CopyTB )
2019-11-14 03:56:30 +00:00
self._copy_tb_button_ev = QP.WidgetEventFilter( self._copy_tb_button )
self._copy_tb_button_ev.EVT_RIGHT_DOWN( self.EventDismiss )
self._copy_tb_button.hide()
2020-03-11 21:52:11 +00:00
self._pause_button = ClientGUICommon.BetterBitmapButton( self, CC.global_pixmaps().pause, self.PausePlay )
2019-11-14 03:56:30 +00:00
self._pause_button_ev = QP.WidgetEventFilter( self._pause_button )
self._pause_button_ev.EVT_RIGHT_DOWN( self.EventDismiss )
self._pause_button.hide()
2020-03-11 21:52:11 +00:00
self._cancel_button = ClientGUICommon.BetterBitmapButton( self, CC.global_pixmaps().stop, self.Cancel )
2019-11-14 03:56:30 +00:00
self._cancel_button_ev = QP.WidgetEventFilter( self._cancel_button )
self._cancel_button_ev.EVT_RIGHT_DOWN( self.EventDismiss )
self._cancel_button.hide()
hbox = QP.HBoxLayout()
2020-07-29 20:52:44 +00:00
QP.AddToLayout( hbox, self._pause_button, CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( hbox, self._cancel_button, CC.FLAGS_CENTER_PERPENDICULAR )
2019-11-14 03:56:30 +00:00
yes_no_hbox = QP.HBoxLayout()
2020-07-29 20:52:44 +00:00
QP.AddToLayout( yes_no_hbox, self._yes, CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( yes_no_hbox, self._no, CC.FLAGS_CENTER_PERPENDICULAR )
2019-11-14 03:56:30 +00:00
2019-11-28 01:11:46 +00:00
QP.AddToLayout( vbox, self._title, CC.FLAGS_EXPAND_PERPENDICULAR )
QP.AddToLayout( vbox, self._text_1, CC.FLAGS_EXPAND_PERPENDICULAR )
QP.AddToLayout( vbox, self._gauge_1, CC.FLAGS_EXPAND_PERPENDICULAR )
QP.AddToLayout( vbox, self._text_2, CC.FLAGS_EXPAND_PERPENDICULAR )
QP.AddToLayout( vbox, self._gauge_2, CC.FLAGS_EXPAND_PERPENDICULAR )
QP.AddToLayout( vbox, self._text_yes_no, CC.FLAGS_EXPAND_PERPENDICULAR )
2022-10-05 21:00:47 +00:00
QP.AddToLayout( vbox, yes_no_hbox, CC.FLAGS_EXPAND_PERPENDICULAR )
QP.AddToLayout( vbox, self._network_job_ctrl, CC.FLAGS_EXPAND_PERPENDICULAR )
QP.AddToLayout( vbox, self._copy_to_clipboard_button, CC.FLAGS_EXPAND_PERPENDICULAR )
QP.AddToLayout( vbox, self._show_files_button, CC.FLAGS_EXPAND_PERPENDICULAR )
QP.AddToLayout( vbox, self._user_callable_button, CC.FLAGS_EXPAND_PERPENDICULAR )
QP.AddToLayout( vbox, self._show_tb_button, CC.FLAGS_EXPAND_PERPENDICULAR )
QP.AddToLayout( vbox, self._tb_text, CC.FLAGS_EXPAND_PERPENDICULAR )
QP.AddToLayout( vbox, self._copy_tb_button, CC.FLAGS_EXPAND_PERPENDICULAR )
2020-07-29 20:52:44 +00:00
QP.AddToLayout( vbox, hbox, CC.FLAGS_ON_RIGHT )
2019-11-14 03:56:30 +00:00
self.setLayout( vbox )
2017-07-27 00:47:13 +00:00
2017-10-04 17:51:58 +00:00
def _NoButton( self ):
self._job_key.SetVariable( 'popup_yes_no_answer', False )
2017-10-11 17:38:14 +00:00
self._job_key.Delete()
2019-11-14 03:56:30 +00:00
self._yes.hide()
self._no.hide()
2017-10-11 17:38:14 +00:00
2017-10-04 17:51:58 +00:00
2017-07-27 00:47:13 +00:00
def _ProcessText( self, text ):
2019-01-09 22:59:03 +00:00
text = str( text )
2017-07-27 00:47:13 +00:00
if len( text ) > self.TEXT_CUTOFF:
new_text = 'The text is too long to display here. Here is the start of it (the rest is printed to the log):'
new_text += os.linesep * 2
2020-03-04 22:12:53 +00:00
new_text += text[ : self.TEXT_CUTOFF ]
2017-07-27 00:47:13 +00:00
text = new_text
return text
2017-10-04 17:51:58 +00:00
def _YesButton( self ):
self._job_key.SetVariable( 'popup_yes_no_answer', True )
2017-10-11 17:38:14 +00:00
self._job_key.Delete()
2019-11-14 03:56:30 +00:00
self._yes.hide()
self._no.hide()
2017-10-11 17:38:14 +00:00
2017-10-04 17:51:58 +00:00
2021-06-09 20:28:09 +00:00
def CallUserCallable( self ):
user_callable = self._job_key.GetUserCallable()
if user_callable is not None:
user_callable()
2017-07-27 00:47:13 +00:00
def Cancel( self ):
self._job_key.Cancel()
2019-11-14 03:56:30 +00:00
self._pause_button.setEnabled( False )
self._cancel_button.setEnabled( False )
2017-07-27 00:47:13 +00:00
def CopyTB( self ):
2021-12-15 22:16:22 +00:00
info = 'v{}, {}, {}'.format( HC.SOFTWARE_VERSION, sys.platform.lower(), 'frozen' if HC.RUNNING_FROM_FROZEN_BUILD else 'source' )
trace = self._job_key.ToString()
full_text = info + os.linesep + trace
HG.client_controller.pub( 'clipboard', 'text', full_text )
2017-07-27 00:47:13 +00:00
def CopyToClipboard( self ):
result = self._job_key.GetIfHasVariable( 'popup_clipboard' )
if result is not None:
( title, text ) = result
HG.client_controller.pub( 'clipboard', 'text', text )
def PausePlay( self ):
self._job_key.PausePlay()
if self._job_key.IsPaused():
2020-03-11 21:52:11 +00:00
ClientGUIFunctions.SetBitmapButtonBitmap( self._pause_button, CC.global_pixmaps().play )
2017-07-27 00:47:13 +00:00
else:
2020-03-11 21:52:11 +00:00
ClientGUIFunctions.SetBitmapButtonBitmap( self._pause_button, CC.global_pixmaps().pause )
2017-07-27 00:47:13 +00:00
def ShowFiles( self ):
2023-02-15 21:26:44 +00:00
result = self._job_key.GetFiles()
2017-07-27 00:47:13 +00:00
if result is not None:
2023-02-15 21:26:44 +00:00
( hashes, attached_files_label ) = result
2017-07-27 00:47:13 +00:00
2022-05-25 21:30:53 +00:00
location_context = ClientLocation.LocationContext.STATICCreateSimple( CC.COMBINED_LOCAL_MEDIA_SERVICE_KEY )
2022-01-19 21:28:59 +00:00
2023-02-15 21:26:44 +00:00
HG.client_controller.pub( 'new_page_query', location_context, initial_hashes = hashes, page_name = attached_files_label )
2017-07-27 00:47:13 +00:00
def ShowTB( self ):
2019-11-14 03:56:30 +00:00
if self._tb_text.isVisible():
2017-07-27 00:47:13 +00:00
2019-11-14 03:56:30 +00:00
self._show_tb_button.setText( 'show traceback' )
2017-07-27 00:47:13 +00:00
2019-11-14 03:56:30 +00:00
self._tb_text.hide()
2017-07-27 00:47:13 +00:00
else:
2019-11-14 03:56:30 +00:00
self._show_tb_button.setText( 'hide traceback' )
2017-07-27 00:47:13 +00:00
2019-11-14 03:56:30 +00:00
self._tb_text.show()
2017-07-27 00:47:13 +00:00
2022-10-05 21:00:47 +00:00
self.updateGeometry()
self.iJustChangedSize.emit()
2017-07-27 00:47:13 +00:00
def GetJobKey( self ):
return self._job_key
def IsDeleted( self ):
return self._job_key.IsDeleted()
def TryToDismiss( self ):
if self._job_key.IsPausable() or self._job_key.IsCancellable():
return
else:
PopupWindow.TryToDismiss( self )
2018-08-15 20:40:30 +00:00
def UpdateMessage( self ):
2017-07-27 00:47:13 +00:00
2021-06-09 20:28:09 +00:00
title = self._job_key.GetStatusTitle()
2017-07-27 00:47:13 +00:00
if title is not None:
2019-11-14 03:56:30 +00:00
self._title.show()
2017-07-27 00:47:13 +00:00
2019-11-14 03:56:30 +00:00
self._title.setText( title )
2018-07-04 20:48:28 +00:00
2017-07-27 00:47:13 +00:00
else:
2019-11-14 03:56:30 +00:00
self._title.hide()
2017-07-27 00:47:13 +00:00
2021-06-09 20:28:09 +00:00
#
paused = self._job_key.IsPaused()
2023-02-15 21:26:44 +00:00
popup_text_1 = self._job_key.GetStatusText()
2017-07-27 00:47:13 +00:00
if popup_text_1 is not None or paused:
if paused:
text = 'paused'
else:
text = popup_text_1
2019-11-14 03:56:30 +00:00
self._text_1.show()
2017-07-27 00:47:13 +00:00
2019-11-14 03:56:30 +00:00
self._text_1.setText( text )
2018-07-04 20:48:28 +00:00
2017-07-27 00:47:13 +00:00
else:
2019-11-14 03:56:30 +00:00
self._text_1.hide()
2017-07-27 00:47:13 +00:00
2021-06-09 20:28:09 +00:00
#
2017-07-27 00:47:13 +00:00
popup_gauge_1 = self._job_key.GetIfHasVariable( 'popup_gauge_1' )
if popup_gauge_1 is not None and not paused:
( gauge_value, gauge_range ) = popup_gauge_1
self._gauge_1.SetRange( gauge_range )
self._gauge_1.SetValue( gauge_value )
2019-11-14 03:56:30 +00:00
self._gauge_1.show()
2017-07-27 00:47:13 +00:00
else:
2019-11-14 03:56:30 +00:00
self._gauge_1.hide()
2017-07-27 00:47:13 +00:00
2021-06-09 20:28:09 +00:00
#
2023-02-15 21:26:44 +00:00
popup_text_2 = self._job_key.GetStatusText( 2 )
2017-07-27 00:47:13 +00:00
if popup_text_2 is not None and not paused:
text = popup_text_2
2019-11-14 03:56:30 +00:00
self._text_2.setText( self._ProcessText( text ) )
2017-07-27 00:47:13 +00:00
2019-11-14 03:56:30 +00:00
self._text_2.show()
2017-07-27 00:47:13 +00:00
else:
2019-11-14 03:56:30 +00:00
self._text_2.hide()
2017-07-27 00:47:13 +00:00
2021-06-09 20:28:09 +00:00
#
2017-07-27 00:47:13 +00:00
popup_gauge_2 = self._job_key.GetIfHasVariable( 'popup_gauge_2' )
if popup_gauge_2 is not None and not paused:
( gauge_value, gauge_range ) = popup_gauge_2
self._gauge_2.SetRange( gauge_range )
self._gauge_2.SetValue( gauge_value )
2019-11-14 03:56:30 +00:00
self._gauge_2.show()
2017-07-27 00:47:13 +00:00
else:
2019-11-14 03:56:30 +00:00
self._gauge_2.hide()
2017-07-27 00:47:13 +00:00
2021-06-09 20:28:09 +00:00
#
2017-10-04 17:51:58 +00:00
popup_yes_no_question = self._job_key.GetIfHasVariable( 'popup_yes_no_question' )
if popup_yes_no_question is not None and not paused:
text = popup_yes_no_question
2021-06-09 20:28:09 +00:00
self._text_yes_no.setText( self._ProcessText( text ) )
2017-10-04 17:51:58 +00:00
2019-11-14 03:56:30 +00:00
self._text_yes_no.show()
2018-07-04 20:48:28 +00:00
2019-11-14 03:56:30 +00:00
self._yes.show()
self._no.show()
2017-10-04 17:51:58 +00:00
else:
2019-11-14 03:56:30 +00:00
self._text_yes_no.hide()
self._yes.hide()
self._no.hide()
2017-10-04 17:51:58 +00:00
2021-06-09 20:28:09 +00:00
#
network_job = self._job_key.GetNetworkJob()
if network_job is None:
2017-07-27 00:47:13 +00:00
2022-04-20 20:18:56 +00:00
if self._network_job_ctrl.HasNetworkJob():
self._network_job_ctrl.ClearNetworkJob()
2023-04-19 20:38:13 +00:00
self._time_network_job_disappeared = HydrusTime.GetNow()
2022-04-20 20:18:56 +00:00
2017-07-27 00:47:13 +00:00
2023-04-19 20:38:13 +00:00
if self._network_job_ctrl.isVisible() and HydrusTime.TimeHasPassed( self._time_network_job_disappeared + 10 ):
2022-04-20 20:18:56 +00:00
self._network_job_ctrl.hide()
2017-07-27 00:47:13 +00:00
else:
2021-06-09 20:28:09 +00:00
self._network_job_ctrl.SetNetworkJob( network_job )
2017-08-02 21:32:54 +00:00
2021-06-09 20:28:09 +00:00
self._network_job_ctrl.show()
2017-07-27 00:47:13 +00:00
2021-06-09 20:28:09 +00:00
#
2017-07-27 00:47:13 +00:00
popup_clipboard = self._job_key.GetIfHasVariable( 'popup_clipboard' )
if popup_clipboard is not None:
( title, text ) = popup_clipboard
2019-11-14 03:56:30 +00:00
if self._copy_to_clipboard_button.text() != title:
2017-07-27 00:47:13 +00:00
2019-11-14 03:56:30 +00:00
self._copy_to_clipboard_button.setText( title )
2017-07-27 00:47:13 +00:00
2019-11-14 03:56:30 +00:00
self._copy_to_clipboard_button.show()
2017-07-27 00:47:13 +00:00
else:
2019-11-14 03:56:30 +00:00
self._copy_to_clipboard_button.hide()
2017-07-27 00:47:13 +00:00
2021-06-09 20:28:09 +00:00
#
2023-02-15 21:26:44 +00:00
result = self._job_key.GetFiles()
2017-07-27 00:47:13 +00:00
2017-08-02 21:32:54 +00:00
if result is not None:
2023-02-15 21:26:44 +00:00
( hashes, attached_files_label ) = result
2017-07-27 00:47:13 +00:00
2023-02-15 21:26:44 +00:00
text = '{} - show {} files'.format( attached_files_label, HydrusData.ToHumanInt( len( hashes ) ) )
2017-07-27 00:47:13 +00:00
2019-11-14 03:56:30 +00:00
if self._show_files_button.text() != text:
2017-07-27 00:47:13 +00:00
2019-11-14 03:56:30 +00:00
self._show_files_button.setText( text )
2017-07-27 00:47:13 +00:00
2019-11-14 03:56:30 +00:00
self._show_files_button.show()
2017-07-27 00:47:13 +00:00
else:
2019-11-14 03:56:30 +00:00
self._show_files_button.hide()
2017-07-27 00:47:13 +00:00
2021-06-09 20:28:09 +00:00
#
2017-07-27 00:47:13 +00:00
2021-06-09 20:28:09 +00:00
user_callable = self._job_key.GetUserCallable()
if user_callable is None:
2017-07-27 00:47:13 +00:00
2021-06-09 20:28:09 +00:00
self._user_callable_button.hide()
2017-07-27 00:47:13 +00:00
else:
2021-06-09 20:28:09 +00:00
self._user_callable_button.setText( user_callable.GetLabel() )
self._user_callable_button.show()
2017-07-27 00:47:13 +00:00
2021-06-09 20:28:09 +00:00
#
popup_traceback = self._job_key.GetTraceback()
2017-07-27 00:47:13 +00:00
if popup_traceback is not None:
2021-06-09 20:28:09 +00:00
self._copy_tb_button.show()
self._show_tb_button.show()
2017-07-27 00:47:13 +00:00
text = popup_traceback
2020-03-04 22:12:53 +00:00
self._tb_text.setText( self._ProcessText( text ) )
2017-07-27 00:47:13 +00:00
2021-06-09 20:28:09 +00:00
# do not show automatically--that is up to the show button
2017-07-27 00:47:13 +00:00
else:
2021-06-09 20:28:09 +00:00
self._copy_tb_button.hide()
2019-11-14 03:56:30 +00:00
self._show_tb_button.hide()
self._tb_text.hide()
2017-07-27 00:47:13 +00:00
2021-06-09 20:28:09 +00:00
#
2017-07-27 00:47:13 +00:00
if self._job_key.IsPausable():
2019-11-14 03:56:30 +00:00
self._pause_button.show()
2017-07-27 00:47:13 +00:00
else:
2019-11-14 03:56:30 +00:00
self._pause_button.hide()
2017-07-27 00:47:13 +00:00
if self._job_key.IsCancellable():
2019-11-14 03:56:30 +00:00
self._cancel_button.show()
2017-07-27 00:47:13 +00:00
else:
2019-11-14 03:56:30 +00:00
self._cancel_button.hide()
2017-07-27 00:47:13 +00:00
2022-10-05 21:00:47 +00:00
class PopupMessageManager( QW.QFrame ):
2017-07-27 00:47:13 +00:00
def __init__( self, parent ):
2022-10-05 21:00:47 +00:00
QW.QFrame.__init__( self, parent )
2019-12-05 05:29:32 +00:00
2022-10-05 21:00:47 +00:00
self.setFrameStyle( QW.QFrame.Panel | QW.QFrame.Raised )
self.setLineWidth( 1 )
2017-07-27 00:47:13 +00:00
2022-10-05 21:00:47 +00:00
# We need this, or else if the QSS does not define a Widget background color (the default), these 'raised' windows are transparent lmao
self.setAutoFillBackground( True )
2019-12-05 05:29:32 +00:00
2018-08-08 20:29:54 +00:00
self._last_best_size_i_fit_on = ( 0, 0 )
2017-07-27 00:47:13 +00:00
self._max_messages_to_display = 10
2022-10-05 21:00:47 +00:00
self._current_num_messages = 0
2017-07-27 00:47:13 +00:00
2019-11-14 03:56:30 +00:00
vbox = QP.VBoxLayout()
2017-07-27 00:47:13 +00:00
2019-11-14 03:56:30 +00:00
self._message_panel = QW.QWidget( self )
2019-06-26 21:27:18 +00:00
2019-11-14 03:56:30 +00:00
self._message_vbox = QP.VBoxLayout( margin = 0 )
2019-11-28 01:11:46 +00:00
2022-10-05 21:00:47 +00:00
#vbox.setSizeConstraint( QW.QLayout.SetFixedSize )
2017-07-27 00:47:13 +00:00
2019-11-14 03:56:30 +00:00
self._message_panel.setLayout( self._message_vbox )
2019-06-26 21:27:18 +00:00
2022-10-05 21:00:47 +00:00
self._summary_bar = PopupMessageSummaryBar( self )
2017-07-27 00:47:13 +00:00
2022-10-05 21:00:47 +00:00
QP.AddToLayout( vbox, self._message_panel, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
QP.AddToLayout( vbox, self._summary_bar, CC.FLAGS_EXPAND_PERPENDICULAR )
2017-07-27 00:47:13 +00:00
2019-11-14 03:56:30 +00:00
self.setLayout( vbox )
2017-07-27 00:47:13 +00:00
self._pending_job_keys = []
parent.installEventFilter( self )
2017-07-27 00:47:13 +00:00
HG.client_controller.sub( self, 'AddMessage', 'message' )
self._old_excepthook = sys.excepthook
self._old_show_exception = HydrusData.ShowException
2021-04-07 21:26:45 +00:00
self._old_show_exception_tuple = HydrusData.ShowExceptionTuple
self._old_show_text = HydrusData.ShowText
2017-07-27 00:47:13 +00:00
sys.excepthook = ClientData.CatchExceptionClient
HydrusData.ShowException = ClientData.ShowExceptionClient
2021-04-07 21:26:45 +00:00
HydrusData.ShowExceptionTuple = ClientData.ShowExceptionTupleClient
2017-07-27 00:47:13 +00:00
HydrusData.ShowText = ClientData.ShowTextClient
job_key = ClientThreading.JobKey()
2023-02-15 21:26:44 +00:00
job_key.SetStatusText( 'initialising popup message manager\u2026' )
2017-07-27 00:47:13 +00:00
2022-10-05 21:00:47 +00:00
self._update_job = HG.client_controller.CallRepeatingQtSafe( self, 0.25, 0.25, 'repeating popup message update', self.REPEATINGUpdate )
2017-07-27 00:47:13 +00:00
2022-10-05 21:00:47 +00:00
self._summary_bar.dismissAll.connect( self.DismissAll )
2020-09-23 21:02:02 +00:00
self._summary_bar.expandCollapse.connect( self.ExpandCollapse )
2021-06-23 21:11:38 +00:00
HG.client_controller.CallLaterQtSafe( self, 0.5, 'initialise message', self.AddMessage, job_key )
2017-07-27 00:47:13 +00:00
2021-06-23 21:11:38 +00:00
HG.client_controller.CallLaterQtSafe( self, 1.0, 'delete initial message', job_key.Delete )
2017-07-27 00:47:13 +00:00
def _CheckPending( self ):
self._pending_job_keys = [ job_key for job_key in self._pending_job_keys if not job_key.IsDeleted() ]
2022-10-05 21:00:47 +00:00
we_added_some = False
2019-11-14 03:56:30 +00:00
while len( self._pending_job_keys ) > 0 and self._message_vbox.count() < self._max_messages_to_display:
2017-07-27 00:47:13 +00:00
2022-10-05 21:00:47 +00:00
we_added_some = True
2017-07-27 00:47:13 +00:00
job_key = self._pending_job_keys.pop( 0 )
2022-10-05 21:00:47 +00:00
window = PopupMessage( self._message_panel, job_key )
window.dismiss.connect( self.Dismiss )
window.iJustChangedSize.connect( self.MakeSureEverythingFits )
2017-07-27 00:47:13 +00:00
2018-08-15 20:40:30 +00:00
window.UpdateMessage()
2017-07-27 00:47:13 +00:00
2022-10-05 21:00:47 +00:00
QP.AddToLayout( self._message_vbox, window, CC.FLAGS_EXPAND_PERPENDICULAR )
2017-07-27 00:47:13 +00:00
2019-11-14 03:56:30 +00:00
total_messages = len( self._pending_job_keys ) + self._message_vbox.count()
2017-07-27 00:47:13 +00:00
2022-10-05 21:00:47 +00:00
if total_messages != self._current_num_messages:
self._current_num_messages = total_messages
self._summary_bar.SetNumMessages( self._current_num_messages )
2018-05-09 20:23:00 +00:00
2022-10-05 21:00:47 +00:00
if we_added_some:
2017-07-27 00:47:13 +00:00
2022-10-05 21:00:47 +00:00
# for whatever reason, self._message_vbox.activate does not cause the vbox.sizeHint to be recalculated at this point. it just sits at the last value unless original was (0,0)?!?
# so we'll do it callafter. it works
QP.CallAfter( self.MakeSureEverythingFits )
2017-07-27 00:47:13 +00:00
def _DisplayingError( self ):
2022-10-05 21:00:47 +00:00
# this was used when we didn't update if the mouse wasn't on the same screen
# we wouldn't be annoying unless there was a good reason such as this
# let's hang on to this for a while, just in case
2019-11-14 03:56:30 +00:00
for i in range( self._message_vbox.count() ):
2017-07-27 00:47:13 +00:00
2019-11-14 03:56:30 +00:00
sizer_item = self._message_vbox.itemAt( i )
message_window = sizer_item.widget()
2021-06-09 20:28:09 +00:00
if not message_window:
continue
2017-07-27 00:47:13 +00:00
job_key = message_window.GetJobKey()
2021-06-09 20:28:09 +00:00
if job_key.HadError():
2017-07-27 00:47:13 +00:00
return True
return False
def _SizeAndPositionAndShow( self ):
try:
2022-10-05 21:00:47 +00:00
gui_frame = self.parentWidget()
2022-09-28 17:15:23 +00:00
2020-04-01 21:51:42 +00:00
gui_is_hidden = not gui_frame.isVisible()
2021-10-13 20:16:57 +00:00
going_to_bug_out_at_hide_or_show = gui_is_hidden
2017-07-27 00:47:13 +00:00
2019-11-14 03:56:30 +00:00
num_messages_displayed = self._message_vbox.count()
2017-07-27 00:47:13 +00:00
there_is_stuff_to_display = num_messages_displayed > 0
if there_is_stuff_to_display:
2022-10-05 21:00:47 +00:00
if not self.isVisible() and not going_to_bug_out_at_hide_or_show:
self.show()
2022-10-05 21:00:47 +00:00
self.raise_()
#
2022-10-05 21:00:47 +00:00
my_ideal_size = self.sizeHint()
if my_ideal_size != self.size():
self.resize( my_ideal_size )
2020-02-26 22:28:52 +00:00
parent_size = gui_frame.size()
2018-08-15 20:40:30 +00:00
2022-10-05 21:00:47 +00:00
my_x = ( parent_size.width() - my_ideal_size.width() ) - 20
my_y = ( parent_size.height() - my_ideal_size.height() ) - 25
2018-08-15 20:40:30 +00:00
2022-10-05 21:00:47 +00:00
my_ideal_position = QC.QPoint( my_x, my_y )
2017-07-27 00:47:13 +00:00
2022-10-05 21:00:47 +00:00
if my_ideal_position != self.pos():
2017-07-27 00:47:13 +00:00
2022-10-05 21:00:47 +00:00
self.move( my_ideal_position )
2017-07-27 00:47:13 +00:00
2022-10-05 21:00:47 +00:00
self.layout()
2017-07-27 00:47:13 +00:00
else:
2022-10-05 21:00:47 +00:00
if self.isVisible() and not going_to_bug_out_at_hide_or_show:
2017-07-27 00:47:13 +00:00
2019-11-14 03:56:30 +00:00
self.hide()
2017-07-27 00:47:13 +00:00
except:
text = 'The popup message manager experienced a fatal error and will now stop working! Please restart the client as soon as possible! If this keeps happening, please email the details and your client.log to the hydrus developer.'
HydrusData.Print( text )
HydrusData.Print( traceback.format_exc() )
2019-12-05 05:29:32 +00:00
QW.QMessageBox.critical( gui_frame, 'Error', text )
2017-07-27 00:47:13 +00:00
2018-02-14 21:47:18 +00:00
self._update_job.Cancel()
2017-07-27 00:47:13 +00:00
self.CleanBeforeDestroy()
2018-02-14 21:47:18 +00:00
def _GetAllMessageJobKeys( self ):
job_keys = []
2022-10-05 21:00:47 +00:00
2019-11-14 03:56:30 +00:00
for i in range( self._message_vbox.count() ):
2018-02-14 21:47:18 +00:00
2019-11-14 03:56:30 +00:00
sizer_item = self._message_vbox.itemAt( i )
message_window = sizer_item.widget()
if not message_window: continue
2018-02-14 21:47:18 +00:00
job_key = message_window.GetJobKey()
job_keys.append( job_key )
job_keys.extend( self._pending_job_keys )
return job_keys
2018-05-09 20:23:00 +00:00
def _OKToAlterUI( self ):
2019-11-14 03:56:30 +00:00
2022-10-05 21:00:47 +00:00
if not QP.isValid( self ):
return False
2018-05-09 20:23:00 +00:00
2019-11-14 03:56:30 +00:00
main_gui = self.parentWidget()
2018-05-09 20:23:00 +00:00
2022-10-05 21:00:47 +00:00
if not main_gui.isVisible():
2021-10-13 20:16:57 +00:00
return False
if HG.client_controller.new_options.GetBoolean( 'freeze_message_manager_when_mouse_on_other_monitor' ):
2022-10-05 21:00:47 +00:00
on_my_monitor = ClientGUIFunctions.MouseIsOnMyDisplay( main_gui )
2021-10-13 20:16:57 +00:00
if not on_my_monitor:
return False
2018-05-09 20:23:00 +00:00
2021-10-13 20:16:57 +00:00
if HG.client_controller.new_options.GetBoolean( 'freeze_message_manager_when_main_gui_minimised' ):
main_gui_up = not main_gui.isMinimized()
if not main_gui_up:
return False
2018-05-09 20:23:00 +00:00
2021-10-13 20:16:57 +00:00
return True
2018-05-09 20:23:00 +00:00
2018-02-14 21:47:18 +00:00
def _TryToMergeMessage( self, job_key ):
2023-02-15 21:26:44 +00:00
if not job_key.HasVariable( 'attached_files_mergable' ):
2018-02-14 21:47:18 +00:00
return False
2023-02-15 21:26:44 +00:00
result = job_key.GetFiles()
2018-02-14 21:47:18 +00:00
if result is not None:
2023-02-15 21:26:44 +00:00
( hashes, label ) = result
2018-02-14 21:47:18 +00:00
existing_job_keys = self._GetAllMessageJobKeys()
for existing_job_key in existing_job_keys:
2023-02-15 21:26:44 +00:00
if existing_job_key.HasVariable( 'attached_files_mergable' ):
2018-02-14 21:47:18 +00:00
2023-02-15 21:26:44 +00:00
result = existing_job_key.GetFiles()
2018-02-14 21:47:18 +00:00
if result is not None:
2023-02-15 21:26:44 +00:00
( existing_hashes, existing_label ) = result
2018-02-14 21:47:18 +00:00
2023-02-15 21:26:44 +00:00
if existing_label == label:
2018-02-14 21:47:18 +00:00
if isinstance( existing_hashes, list ):
existing_hashes.extend( hashes )
elif isinstance( existing_hashes, set ):
existing_hashes.update( hashes )
return True
return False
2017-07-27 00:47:13 +00:00
def _Update( self ):
2022-01-19 21:28:59 +00:00
if HG.started_shutdown:
2017-07-27 00:47:13 +00:00
2018-02-14 21:47:18 +00:00
self._update_job.Cancel()
self.CleanBeforeDestroy()
2017-07-27 00:47:13 +00:00
2019-11-14 03:56:30 +00:00
for i in range( self._message_vbox.count() ):
2017-07-27 00:47:13 +00:00
2019-11-14 03:56:30 +00:00
sizer_item = self._message_vbox.itemAt( i )
2017-07-27 00:47:13 +00:00
2019-11-14 03:56:30 +00:00
message_window = sizer_item.widget()
if message_window:
2017-07-27 00:47:13 +00:00
2019-11-14 03:56:30 +00:00
if message_window.IsDeleted():
message_window.TryToDismiss()
break
else:
message_window.UpdateMessage()
2017-07-27 00:47:13 +00:00
def AddMessage( self, job_key ):
try:
2018-02-14 21:47:18 +00:00
was_merged = self._TryToMergeMessage( job_key )
if was_merged:
return
2017-07-27 00:47:13 +00:00
self._pending_job_keys.append( job_key )
2018-05-09 20:23:00 +00:00
if self._OKToAlterUI():
2017-09-13 20:50:41 +00:00
self._CheckPending()
2017-07-27 00:47:13 +00:00
except:
HydrusData.Print( traceback.format_exc() )
def CleanBeforeDestroy( self ):
for job_key in self._pending_job_keys:
if job_key.IsCancellable():
job_key.Cancel()
2019-11-14 03:56:30 +00:00
for i in range( self._message_vbox.count() ):
message_window = self._message_vbox.itemAt( i ).widget()
2017-07-27 00:47:13 +00:00
2022-10-05 21:00:47 +00:00
if not message_window:
continue
2017-07-27 00:47:13 +00:00
job_key = message_window.GetJobKey()
if job_key.IsCancellable():
job_key.Cancel()
sys.excepthook = self._old_excepthook
HydrusData.ShowException = self._old_show_exception
2021-04-07 21:26:45 +00:00
HydrusData.ShowExceptionTuple = self._old_show_exception_tuple
HydrusData.ShowText = self._old_show_text
2017-07-27 00:47:13 +00:00
def Dismiss( self, window ):
2019-11-14 03:56:30 +00:00
self._message_vbox.removeWidget( window )
2017-07-27 00:47:13 +00:00
2022-10-05 21:00:47 +00:00
window.hide()
# sizeHints are not immediately updated without this, lmao
# note we have to do it on the sub vbox, not the self.layout() wew, so I guess it doesn't propagate down
self._message_vbox.activate()
2019-11-14 03:56:30 +00:00
window.deleteLater()
2017-07-27 00:47:13 +00:00
2018-05-09 20:23:00 +00:00
if self._OKToAlterUI():
self._CheckPending()
2022-10-05 21:00:47 +00:00
self._SizeAndPositionAndShow()
2017-07-27 00:47:13 +00:00
def DismissAll( self ):
self._pending_job_keys = [ job_key for job_key in self._pending_job_keys if job_key.IsPausable() or job_key.IsCancellable() ]
2019-11-14 03:56:30 +00:00
items = []
for i in range( self._message_vbox.count() ):
items.append( self._message_vbox.itemAt( i ) )
2017-07-27 00:47:13 +00:00
2019-11-14 03:56:30 +00:00
for item in items:
message_window = item.widget()
2017-07-27 00:47:13 +00:00
2019-11-14 03:56:30 +00:00
if not message_window: continue
2017-07-27 00:47:13 +00:00
message_window.TryToDismiss()
self._CheckPending()
2019-06-26 21:27:18 +00:00
def ExpandCollapse( self ):
2019-11-14 03:56:30 +00:00
if self._message_panel.isVisible():
2019-06-26 21:27:18 +00:00
2019-11-14 03:56:30 +00:00
self._message_panel.setVisible( False )
2019-06-26 21:27:18 +00:00
else:
2019-11-14 03:56:30 +00:00
self._message_panel.show()
2020-09-23 21:02:02 +00:00
2019-11-14 03:56:30 +00:00
self.MakeSureEverythingFits()
def eventFilter( self, watched, event ):
2019-11-14 03:56:30 +00:00
2023-06-21 19:50:13 +00:00
try:
2019-06-26 21:27:18 +00:00
2023-06-21 19:50:13 +00:00
if watched == self.parentWidget():
2023-06-21 19:50:13 +00:00
if event.type() in ( QC.QEvent.Resize, QC.QEvent.Move, QC.QEvent.WindowStateChange ):
2023-06-21 19:50:13 +00:00
if self._OKToAlterUI():
self._SizeAndPositionAndShow()
2019-06-26 21:27:18 +00:00
2023-06-21 19:50:13 +00:00
except Exception as e:
HydrusData.ShowException( e )
return True
2019-06-26 21:27:18 +00:00
return False
2019-06-26 21:27:18 +00:00
2017-07-27 00:47:13 +00:00
def MakeSureEverythingFits( self ):
2018-05-09 20:23:00 +00:00
if self._OKToAlterUI():
self._SizeAndPositionAndShow()
2017-07-27 00:47:13 +00:00
2018-02-14 21:47:18 +00:00
def REPEATINGUpdate( self ):
2017-07-27 00:47:13 +00:00
try:
2018-05-09 20:23:00 +00:00
if self._OKToAlterUI():
2017-09-13 20:50:41 +00:00
self._Update()
self._CheckPending()
2022-10-05 21:00:47 +00:00
self._SizeAndPositionAndShow()
2017-07-27 00:47:13 +00:00
except:
2018-02-14 21:47:18 +00:00
self._update_job.Cancel()
2017-07-27 00:47:13 +00:00
raise
2021-10-06 20:59:30 +00:00
2019-11-14 03:56:30 +00:00
# This was originally a reviewpanel subclass which is a scroll area subclass, but having it in a scroll area didn't work out with dynamically updating size as the widget contents change.
class PopupMessageDialogPanel( QW.QWidget ):
2017-07-27 00:47:13 +00:00
2020-09-02 21:10:41 +00:00
def __init__( self, parent, job_key, hide_main_gui = False ):
2017-07-27 00:47:13 +00:00
2019-11-14 03:56:30 +00:00
QW.QWidget.__init__( self, parent )
2017-07-27 00:47:13 +00:00
2019-09-25 21:34:18 +00:00
self._yesno_open = False
2020-09-02 21:10:41 +00:00
self._hide_main_gui = hide_main_gui
2017-07-27 00:47:13 +00:00
self._job_key = job_key
2022-10-05 21:00:47 +00:00
self._message_window = PopupMessage( self, self._job_key )
self._message_window.dismiss.connect( self.Dismiss )
2017-07-27 00:47:13 +00:00
2019-11-14 03:56:30 +00:00
vbox = QP.VBoxLayout()
2017-07-27 00:47:13 +00:00
2019-11-14 03:56:30 +00:00
QP.AddToLayout( vbox, self._message_window )
2017-07-27 00:47:13 +00:00
2019-11-14 03:56:30 +00:00
self.setLayout( vbox )
2017-07-27 00:47:13 +00:00
2018-03-22 00:03:33 +00:00
self._windows_hidden = []
2018-01-17 22:52:10 +00:00
2018-03-22 00:03:33 +00:00
self._HideOtherWindows()
2018-01-17 22:52:10 +00:00
2017-07-27 00:47:13 +00:00
self._message_pubbed = False
2021-06-23 21:11:38 +00:00
self._update_job = HG.client_controller.CallRepeatingQtSafe( self, 0.25, 0.5, 'repeating popup dialog update', self.REPEATINGUpdate )
2019-11-28 01:11:46 +00:00
2020-04-29 21:44:12 +00:00
2019-11-14 03:56:30 +00:00
def CleanBeforeDestroy( self ):
pass
2018-03-22 00:03:33 +00:00
def _HideOtherWindows( self ):
2018-01-17 22:52:10 +00:00
2020-09-02 21:10:41 +00:00
from hydrus.client.gui import ClientGUI
2022-07-20 19:17:03 +00:00
for tlw in list( QW.QApplication.topLevelWidgets() ):
2018-01-17 22:52:10 +00:00
2020-09-02 21:10:41 +00:00
if isinstance( tlw, ClientGUI.FrameGUI ):
pass
if tlw == self.window():
2018-01-17 22:52:10 +00:00
continue
2020-09-02 21:10:41 +00:00
if not isinstance( tlw, ( ClientGUITopLevelWindows.Frame, ClientGUITopLevelWindows.MainFrame, ClientGUITopLevelWindows.NewDialog ) ):
2018-01-17 22:52:10 +00:00
continue
2019-11-14 03:56:30 +00:00
if ClientGUIFunctions.IsQtAncestor( self, tlw, through_tlws = True ):
2019-03-27 22:01:02 +00:00
continue
2020-09-02 21:10:41 +00:00
if isinstance( tlw, ClientGUI.FrameGUI ) and not self._hide_main_gui:
2018-01-17 22:52:10 +00:00
continue
2019-11-14 03:56:30 +00:00
if not tlw.isVisible() or tlw.isMinimized():
2018-01-17 22:52:10 +00:00
continue
2019-11-14 03:56:30 +00:00
tlw.hide()
2018-01-17 22:52:10 +00:00
2018-03-22 00:03:33 +00:00
self._windows_hidden.append( tlw )
2018-01-17 22:52:10 +00:00
2017-07-27 00:47:13 +00:00
def _ReleaseMessage( self ):
if not self._message_pubbed:
HG.client_controller.pub( 'message', self._job_key )
self._message_pubbed = True
2018-01-17 22:52:10 +00:00
self._RestoreOtherWindows()
def _RestoreOtherWindows( self ):
2018-03-22 00:03:33 +00:00
for tlw in self._windows_hidden:
2018-01-17 22:52:10 +00:00
2019-11-14 03:56:30 +00:00
tlw.show()
2018-01-17 22:52:10 +00:00
2018-03-22 00:03:33 +00:00
self._windows_hidden = []
2017-07-27 00:47:13 +00:00
def _Update( self ):
2018-08-15 20:40:30 +00:00
self._message_window.UpdateMessage()
2017-07-27 00:47:13 +00:00
2019-11-14 03:56:30 +00:00
# Resize the window after updates
# The problem is that when the window is created, the initial size is too small because all widgets are empty before the first update,
# but after it updates it doesn't want to resize the window, rather it just adds scrollbars.
# This is a manual fix. Need to find a better solution...
2019-12-11 23:18:37 +00:00
2019-11-14 03:56:30 +00:00
self.layout().update()
self._message_window.adjustSize()
self.adjustSize()
self.window().adjustSize()
2017-07-27 00:47:13 +00:00
def Dismiss( self, window ):
return
2020-04-29 21:44:12 +00:00
def CheckValid( self ):
return True
def UserIsOKToOK( self ):
return self.UserIsOKToCancel()
def UserIsOKToCancel( self ):
2017-07-27 00:47:13 +00:00
if self._job_key.IsDone():
self._ReleaseMessage()
2020-04-29 21:44:12 +00:00
elif self._job_key.IsCancellable():
text = 'Cancel/stop job?'
self._yesno_open = True
2017-07-27 00:47:13 +00:00
2020-04-29 21:44:12 +00:00
try:
2017-07-27 00:47:13 +00:00
2020-04-29 21:44:12 +00:00
result = ClientGUIDialogsQuick.GetYesNo( self, text )
2019-07-24 21:39:02 +00:00
2020-04-29 21:44:12 +00:00
finally:
2019-09-25 21:34:18 +00:00
2020-04-29 21:44:12 +00:00
self._yesno_open = False
2019-07-24 21:39:02 +00:00
2020-04-29 21:44:12 +00:00
if result == QW.QDialog.Accepted:
self._job_key.Cancel()
self._ReleaseMessage()
2017-07-27 00:47:13 +00:00
else:
2020-04-29 21:44:12 +00:00
return False
2017-08-02 21:32:54 +00:00
2017-07-27 00:47:13 +00:00
2020-04-29 21:44:12 +00:00
else:
QW.QMessageBox.warning( self, 'Warning', 'Unfortunately, this job cannot be cancelled. If it really is taking too long, please kill the client through task manager.' )
return False
return True
2017-07-27 00:47:13 +00:00
2018-02-14 21:47:18 +00:00
def REPEATINGUpdate( self ):
2017-07-27 00:47:13 +00:00
try:
if self._job_key.IsDone():
2019-09-25 21:34:18 +00:00
if not self._yesno_open: # don't close while a child dialog open m8
2019-11-14 03:56:30 +00:00
parent = self.parentWidget()
2017-07-27 00:47:13 +00:00
2019-11-14 03:56:30 +00:00
if parent.isModal(): # event sometimes fires after modal done
2019-09-25 21:34:18 +00:00
parent.DoOK()
2017-07-27 00:47:13 +00:00
else:
self._Update()
except:
2018-02-14 21:47:18 +00:00
self._update_job.Cancel()
2017-07-27 00:47:13 +00:00
raise
2019-06-26 21:27:18 +00:00
2022-10-05 21:00:47 +00:00
class PopupMessageSummaryBar( QW.QFrame ):
2019-06-26 21:27:18 +00:00
2022-10-05 21:00:47 +00:00
dismissAll = QC.Signal()
2020-09-23 21:02:02 +00:00
expandCollapse = QC.Signal()
2022-10-05 21:00:47 +00:00
def __init__( self, parent ):
2019-06-26 21:27:18 +00:00
2022-10-05 21:00:47 +00:00
QW.QFrame.__init__( self, parent )
self.setFrameStyle( QW.QFrame.Box | QW.QFrame.Plain )
2019-06-26 21:27:18 +00:00
2019-11-14 03:56:30 +00:00
hbox = QP.HBoxLayout()
2019-06-26 21:27:18 +00:00
self._text = ClientGUICommon.BetterStaticText( self )
self._expand_collapse = ClientGUICommon.BetterButton( self, '\u25bc', self.ExpandCollapse )
2022-10-05 21:00:47 +00:00
dismiss_all = ClientGUICommon.BetterButton( self, 'dismiss all', self.dismissAll.emit )
2019-06-26 21:27:18 +00:00
2020-07-29 20:52:44 +00:00
QP.AddToLayout( hbox, self._text, CC.FLAGS_CENTER_PERPENDICULAR )
hbox.addStretch( 1 )
QP.AddToLayout( hbox, dismiss_all, CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( hbox, self._expand_collapse, CC.FLAGS_CENTER_PERPENDICULAR )
2019-06-26 21:27:18 +00:00
2019-11-14 03:56:30 +00:00
self.setLayout( hbox )
2019-06-26 21:27:18 +00:00
def ExpandCollapse( self ):
2020-09-23 21:02:02 +00:00
self.expandCollapse.emit()
2019-06-26 21:27:18 +00:00
2019-11-14 03:56:30 +00:00
current_text = self._expand_collapse.text()
2019-06-26 21:27:18 +00:00
if current_text == '\u25bc':
new_text = '\u25b2'
else:
new_text = '\u25bc'
2019-11-14 03:56:30 +00:00
self._expand_collapse.setText( new_text )
2019-06-26 21:27:18 +00:00
2017-07-27 00:47:13 +00:00
2019-06-26 21:27:18 +00:00
def SetNumMessages( self, num_messages_pending ):
if num_messages_pending == 1:
2019-11-14 03:56:30 +00:00
self._text.setText( '1 message' )
2019-06-26 21:27:18 +00:00
else:
2019-11-14 03:56:30 +00:00
self._text.setText( HydrusData.ToHumanInt(num_messages_pending)+' messages' )
2019-06-26 21:27:18 +00:00