387 lines
14 KiB
Python
387 lines
14 KiB
Python
import typing
|
|
|
|
from qtpy import QtCore as QC
|
|
from qtpy import QtWidgets as QW
|
|
|
|
from hydrus.core import HydrusConstants as HC
|
|
from hydrus.core import HydrusData
|
|
from hydrus.core import HydrusExceptions
|
|
from hydrus.core import HydrusGlobals as HG
|
|
|
|
from hydrus.client import ClientConstants as CC
|
|
from hydrus.client.gui import ClientGUICore as CGC
|
|
from hydrus.client.gui import ClientGUIFunctions
|
|
from hydrus.client.gui import ClientGUIMenus
|
|
from hydrus.client.gui import ClientGUITopLevelWindowsPanels
|
|
from hydrus.client.gui import QtPorting as QP
|
|
from hydrus.client.gui.networking import ClientGUINetwork
|
|
from hydrus.client.gui.widgets import ClientGUICommon
|
|
from hydrus.client.networking import ClientNetworkingContexts
|
|
from hydrus.client.networking import ClientNetworkingJobs
|
|
|
|
class NetworkJobControl( QW.QFrame ):
|
|
|
|
def __init__( self, parent ):
|
|
|
|
QW.QFrame.__init__( self, parent )
|
|
|
|
self.setFrameStyle( QW.QFrame.Box | QW.QFrame.Raised )
|
|
|
|
self._network_job = None
|
|
|
|
self._auto_override_bandwidth_rules = False
|
|
|
|
self._left_text = ClientGUICommon.BetterStaticText( self, ellipsize_end = True )
|
|
self._right_text = ClientGUICommon.BetterStaticText( self )
|
|
self._right_text.setAlignment( QC.Qt.AlignRight | QC.Qt.AlignVCenter )
|
|
|
|
self._last_right_min_width = 0
|
|
|
|
self._gauge = ClientGUICommon.Gauge( self )
|
|
|
|
self._cog_button = ClientGUICommon.BetterBitmapButton( self, CC.global_pixmaps().cog, self._ShowCogMenu )
|
|
self._cancel_button = ClientGUICommon.BetterBitmapButton( self, CC.global_pixmaps().stop, self.Cancel )
|
|
self._error_button = ClientGUICommon.BetterBitmapButton( self, CC.global_pixmaps().dump_fail, self._ShowErrorMenu )
|
|
|
|
self._error_button.setToolTip( 'Click here to see the last job\'s error.' )
|
|
|
|
self._error_button.hide()
|
|
|
|
self._error_text = None
|
|
|
|
#
|
|
|
|
self._Update()
|
|
|
|
#
|
|
|
|
st_hbox = QP.HBoxLayout()
|
|
|
|
QP.AddToLayout( st_hbox, self._left_text, CC.FLAGS_EXPAND_BOTH_WAYS )
|
|
QP.AddToLayout( st_hbox, self._right_text, CC.FLAGS_CENTER_PERPENDICULAR )
|
|
|
|
left_vbox = QP.VBoxLayout()
|
|
|
|
QP.AddToLayout( left_vbox, st_hbox, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
|
|
QP.AddToLayout( left_vbox, self._gauge, CC.FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
hbox = QP.HBoxLayout()
|
|
|
|
QP.AddToLayout( hbox, left_vbox, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
|
|
QP.AddToLayout( hbox, self._cog_button, CC.FLAGS_CENTER_PERPENDICULAR )
|
|
QP.AddToLayout( hbox, self._cancel_button, CC.FLAGS_CENTER_PERPENDICULAR )
|
|
QP.AddToLayout( hbox, self._error_button, CC.FLAGS_CENTER_PERPENDICULAR )
|
|
|
|
self.setLayout( hbox )
|
|
|
|
|
|
def _EditBandwidthRules( self, network_context: ClientNetworkingContexts.NetworkContext ):
|
|
|
|
with ClientGUITopLevelWindowsPanels.DialogEdit( self, 'edit bandwidth rules for {}'.format( network_context.ToString() ) ) as dlg:
|
|
|
|
bandwidth_rules = HG.client_controller.network_engine.bandwidth_manager.GetRules( network_context )
|
|
|
|
summary = network_context.GetSummary()
|
|
|
|
panel = ClientGUINetwork.EditBandwidthRulesPanel( dlg, bandwidth_rules, summary )
|
|
|
|
dlg.SetPanel( panel )
|
|
|
|
if dlg.exec() == QW.QDialog.Accepted:
|
|
|
|
bandwidth_rules = panel.GetValue()
|
|
|
|
HG.client_controller.network_engine.bandwidth_manager.SetRules( network_context, bandwidth_rules )
|
|
|
|
|
|
|
|
|
|
def _ShowCogMenu( self ):
|
|
|
|
menu = QW.QMenu()
|
|
|
|
if self._network_job is not None and self._network_job.engine is not None:
|
|
|
|
network_contexts = self._network_job.GetNetworkContexts()
|
|
|
|
if len( network_contexts ) > 0:
|
|
|
|
bandwidth_manager = self._network_job.engine.bandwidth_manager
|
|
|
|
submenu = QW.QMenu( menu )
|
|
|
|
menu_network_contexts = []
|
|
|
|
network_contexts_used = set()
|
|
|
|
for network_context in network_contexts:
|
|
|
|
uses_default = False
|
|
|
|
if bandwidth_manager.UsesDefaultRules( network_context ):
|
|
|
|
uses_default = True
|
|
|
|
default_network_context = network_context.GetDefault()
|
|
|
|
if default_network_context not in network_contexts_used:
|
|
|
|
menu_network_contexts.append( ( False, default_network_context, network_context ) )
|
|
|
|
network_contexts_used.add( default_network_context )
|
|
|
|
|
|
|
|
if not network_context.IsEphemeral():
|
|
|
|
menu_network_contexts.append( ( uses_default, network_context, network_context ) )
|
|
|
|
|
|
|
|
for ( uses_default, network_context_to_edit, network_context_to_test ) in menu_network_contexts:
|
|
|
|
network_context_text = network_context_to_edit.ToString()
|
|
|
|
if uses_default:
|
|
|
|
network_context_text = 'set rules for {}'.format( network_context_text )
|
|
|
|
else:
|
|
|
|
( waiting_estimate, gumpf ) = bandwidth_manager.GetWaitingEstimateAndContext( [ network_context_to_test ] )
|
|
|
|
if waiting_estimate > 0:
|
|
|
|
network_context_text = '{} ({})'.format( network_context_text, HydrusData.TimeDeltaToPrettyTimeDelta( waiting_estimate ) )
|
|
|
|
|
|
|
|
ClientGUIMenus.AppendMenuItem( submenu, network_context_text, 'edit the bandwidth rules for this network context', self._EditBandwidthRules, network_context_to_edit )
|
|
|
|
|
|
ClientGUIMenus.AppendMenu( menu, submenu, 'edit bandwidth rules' )
|
|
|
|
ClientGUIMenus.AppendSeparator( menu )
|
|
|
|
|
|
if self._network_job.CurrentlyWaitingOnConnectionError():
|
|
|
|
ClientGUIMenus.AppendMenuItem( menu, 'reattempt connection now', 'Stop waiting on a connection error and reattempt the job now.', self._network_job.OverrideConnectionErrorWait )
|
|
|
|
|
|
if self._network_job.CurrentlyWaitingOnServersideBandwidth():
|
|
|
|
ClientGUIMenus.AppendMenuItem( menu, 'reattempt request now (server reports low bandwidth)', 'Stop waiting on a serverside bandwidth delay and reattempt the job now.', self._network_job.OverrideServersideBandwidthWait )
|
|
|
|
|
|
if self._network_job.ObeysBandwidth():
|
|
|
|
ClientGUIMenus.AppendMenuItem( menu, 'override bandwidth rules for this job', 'Tell the current job to ignore existing bandwidth rules and go ahead anyway.', self._network_job.OverrideBandwidth )
|
|
|
|
|
|
if not self._network_job.TokensOK():
|
|
|
|
ClientGUIMenus.AppendMenuItem( menu, 'override forced gallery wait times for this job', 'Force-allow this download to proceed, ignoring the normal gallery wait times.', self._network_job.OverrideToken )
|
|
|
|
|
|
ClientGUIMenus.AppendSeparator( menu )
|
|
|
|
|
|
ClientGUIMenus.AppendMenuCheckItem( menu, 'auto-override bandwidth rules for all jobs here after five seconds', 'Ignore existing bandwidth rules for all jobs under this control, instead waiting a flat five seconds.', self._auto_override_bandwidth_rules, self.FlipAutoOverrideBandwidth )
|
|
|
|
CGC.core().PopupMenu( self._cog_button, menu )
|
|
|
|
|
|
def _ShowErrorMenu( self ):
|
|
|
|
if self._error_text is None:
|
|
|
|
return
|
|
|
|
|
|
menu = QW.QMenu()
|
|
|
|
ClientGUIMenus.AppendMenuItem( menu, 'show error', 'Show the recent error in a messagebox.', self.ShowError )
|
|
ClientGUIMenus.AppendMenuItem( menu, 'copy error', 'Copy the recent error to the clipboard.', self.CopyError )
|
|
|
|
CGC.core().PopupMenu( self._cog_button, menu )
|
|
|
|
|
|
def _OverrideBandwidthIfAppropriate( self ):
|
|
|
|
if self._network_job is None or self._network_job.NoEngineYet():
|
|
|
|
return
|
|
|
|
else:
|
|
|
|
if self._auto_override_bandwidth_rules and HydrusData.TimeHasPassed( self._network_job.GetCreationTime() + 5 ):
|
|
|
|
self._network_job.OverrideBandwidth()
|
|
|
|
|
|
|
|
|
|
def _Update( self ):
|
|
|
|
if self._network_job is None or self._network_job.NoEngineYet():
|
|
|
|
can_cancel = False
|
|
|
|
self._left_text.clear()
|
|
self._right_text.clear()
|
|
self._gauge.SetRange( 1 )
|
|
self._gauge.SetValue( 0 )
|
|
|
|
else:
|
|
|
|
can_cancel = not self._network_job.IsDone()
|
|
|
|
( status_text, current_speed, bytes_read, bytes_to_read ) = self._network_job.GetStatus()
|
|
|
|
self._left_text.setText( status_text )
|
|
|
|
speed_text = ''
|
|
|
|
if bytes_read is not None and bytes_read > 0 and not self._network_job.HasError():
|
|
|
|
if bytes_to_read is not None and bytes_read != bytes_to_read:
|
|
|
|
speed_text += HydrusData.ConvertValueRangeToBytes( bytes_read, bytes_to_read )
|
|
|
|
else:
|
|
|
|
speed_text += HydrusData.ToHumanBytes( bytes_read )
|
|
|
|
|
|
if current_speed != bytes_to_read: # if it is a real quick download, just say its size
|
|
|
|
speed_text += ' ' + HydrusData.ToHumanBytes( current_speed ) + '/s'
|
|
|
|
|
|
|
|
show_right_text = speed_text != ''
|
|
|
|
if self._right_text.isVisible() != show_right_text:
|
|
|
|
self._right_text.setVisible( show_right_text )
|
|
|
|
self.updateGeometry()
|
|
|
|
|
|
if speed_text != '':
|
|
|
|
self._right_text.setText( speed_text )
|
|
|
|
right_width = ClientGUIFunctions.ConvertTextToPixelWidth( self._right_text, len( speed_text ) )
|
|
|
|
right_min_width = right_width
|
|
|
|
if right_min_width != self._last_right_min_width:
|
|
|
|
self._last_right_min_width = right_min_width
|
|
|
|
self._right_text.setMinimumWidth( right_min_width )
|
|
|
|
self.updateGeometry()
|
|
|
|
|
|
|
|
self._gauge.SetRange( bytes_to_read )
|
|
self._gauge.SetValue( bytes_read )
|
|
|
|
|
|
if self._cancel_button.isEnabled() != can_cancel:
|
|
|
|
self._cancel_button.setEnabled( can_cancel )
|
|
|
|
|
|
|
|
def Cancel( self ):
|
|
|
|
if self._network_job is not None:
|
|
|
|
self._network_job.Cancel( 'Cancelled by user.' )
|
|
|
|
|
|
|
|
def ClearError( self ):
|
|
|
|
self._error_text = None
|
|
|
|
self._error_button.hide()
|
|
|
|
|
|
def CopyError( self ):
|
|
|
|
if self._error_text is None:
|
|
|
|
return
|
|
|
|
|
|
HG.client_controller.pub( 'clipboard', 'text', self._error_text )
|
|
|
|
|
|
def ClearNetworkJob( self ):
|
|
|
|
self.SetNetworkJob( None )
|
|
|
|
|
|
def FlipAutoOverrideBandwidth( self ):
|
|
|
|
self._auto_override_bandwidth_rules = not self._auto_override_bandwidth_rules
|
|
|
|
|
|
def SetNetworkJob( self, network_job: typing.Optional[ ClientNetworkingJobs.NetworkJob ] ):
|
|
|
|
if network_job is None:
|
|
|
|
if self._network_job is not None:
|
|
|
|
self._network_job = None
|
|
|
|
self._Update()
|
|
|
|
HG.client_controller.gui.UnregisterUIUpdateWindow( self )
|
|
|
|
|
|
else:
|
|
|
|
if self._network_job != network_job:
|
|
|
|
self._network_job = network_job
|
|
|
|
self._Update()
|
|
|
|
HG.client_controller.gui.RegisterUIUpdateWindow( self )
|
|
|
|
|
|
|
|
|
|
def SetError( self, error: str ):
|
|
|
|
self._error_text = error
|
|
|
|
self._error_button.show()
|
|
|
|
|
|
def ShowError( self ):
|
|
|
|
if self._error_text is None:
|
|
|
|
return
|
|
|
|
|
|
QW.QMessageBox.critical( self, 'network error', self._error_text )
|
|
|
|
|
|
def TIMERUIUpdate( self ):
|
|
|
|
self._OverrideBandwidthIfAppropriate()
|
|
|
|
if HG.client_controller.gui.IShouldRegularlyUpdate( self ):
|
|
|
|
self._Update()
|
|
|
|
|
|
|