hydrus/hydrus/client/gui/ClientGUIDialogs.py

1058 lines
33 KiB
Python

import os
import re
from qtpy import QtCore as QC
from qtpy import QtWidgets as QW
from qtpy import QtGui as QG
from hydrus.core import HydrusConstants as HC
from hydrus.core import HydrusData
from hydrus.core import HydrusGlobals as HG
from hydrus.client import ClientConstants as CC
from hydrus.client.gui import ClientGUIFrames
from hydrus.client.gui import ClientGUIFunctions
from hydrus.client.gui import ClientGUIShortcuts
from hydrus.client.gui import QtPorting as QP
from hydrus.client.gui.lists import ClientGUIListBoxes
from hydrus.client.gui.search import ClientGUIACDropdown
from hydrus.client.gui.widgets import ClientGUICommon
class Dialog( QP.Dialog ):
def __init__( self, parent, title, style = QC.Qt.Dialog, position = 'topleft' ):
QP.Dialog.__init__( self, parent )
self.setWindowFlags( style )
self.setWindowTitle( title )
if parent is not None and position == 'topleft':
parent_tlw = self.parentWidget().window()
pos = parent_tlw.pos() + QC.QPoint( 50, 50 )
self.move( pos )
self.setWindowFlag( QC.Qt.WindowContextHelpButtonHint, on = False )
self._new_options = HG.client_controller.new_options
self.setWindowIcon( QG.QIcon( HG.client_controller.frame_icon_pixmap ) )
self._widget_event_filter = QP.WidgetEventFilter( self )
if parent is not None and position == 'center':
QP.CallAfter( QP.CenterOnWindow, parent, self )
HG.client_controller.ResetIdleTimer()
def keyPressEvent( self, event ):
( modifier, key ) = ClientGUIShortcuts.ConvertKeyEventToSimpleTuple( event )
if key == QC.Qt.Key_Escape:
self.done( QW.QDialog.Rejected )
else:
QP.Dialog.keyPressEvent( self, event )
def SetInitialSize( self, size: QC.QSize ):
display_size = ClientGUIFunctions.GetDisplaySize( self )
width = min( display_size.width(), size.width() )
height = min( display_size.height(), size.height() )
self.resize( QC.QSize( width, height ) )
min_width = min( 240, width )
min_height = min( 240, height )
self.setMinimumSize( QC.QSize( min_width, min_height ) )
class DialogChooseNewServiceMethod( Dialog ):
def __init__( self, parent ):
Dialog.__init__( self, parent, 'how to set up the account?', position = 'center' )
register_message = 'I want to initialise a new account with the server. I have a registration token (a hexadecimal key starting with \'r\').'
self._register = QW.QPushButton( register_message, self )
self._register.clicked.connect( self.EventRegister )
setup_message = 'The account is already initialised; I just want to add it to this client. I have a normal access key.'
self._setup = QW.QPushButton( setup_message, self )
self._setup.clicked.connect( self.accept )
vbox = QP.VBoxLayout()
QP.AddToLayout( vbox, self._register, CC.FLAGS_EXPAND_PERPENDICULAR )
st = ClientGUICommon.BetterStaticText( self, '-or-' )
st.setAlignment( QC.Qt.AlignCenter )
QP.AddToLayout( vbox, st, CC.FLAGS_EXPAND_PERPENDICULAR )
QP.AddToLayout( vbox, self._setup, CC.FLAGS_EXPAND_PERPENDICULAR )
self.setLayout( vbox )
size_hint = self.sizeHint()
QP.SetInitialSize( self, size_hint )
self._should_register = False
ClientGUIFunctions.SetFocusLater( self._register )
def EventRegister( self ):
self._should_register = True
self.done( QW.QDialog.Accepted )
def GetRegister( self ):
return self._should_register
class DialogGenerateNewAccounts( Dialog ):
def __init__( self, parent, service_key ):
Dialog.__init__( self, parent, 'configure new accounts' )
self._service_key = service_key
self._num = ClientGUICommon.BetterSpinBox( self, min=1, max=10000, width = 80 )
self._account_types = ClientGUICommon.BetterChoice( self )
self._lifetime = ClientGUICommon.BetterChoice( self )
self._ok = QW.QPushButton( 'OK', self )
self._ok.clicked.connect( self.EventOK )
self._ok.setObjectName( 'HydrusAccept' )
self._cancel = QW.QPushButton( 'Cancel', self )
self._cancel.clicked.connect( self.reject )
self._cancel.setObjectName( 'HydrusCancel' )
#
self._num.setValue( 1 )
service = HG.client_controller.services_manager.GetService( service_key )
response = service.Request( HC.GET, 'account_types' )
account_types = response[ 'account_types' ]
for account_type in account_types:
self._account_types.addItem( account_type.GetTitle(), account_type )
self._account_types.setCurrentIndex( 0 )
for ( s, value ) in HC.lifetimes:
self._lifetime.addItem( s, value )
self._lifetime.setCurrentIndex( 3 ) # one year
#
ctrl_box = QP.HBoxLayout()
QP.AddToLayout( ctrl_box, ClientGUICommon.BetterStaticText(self,'generate'), CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( ctrl_box, self._num, CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( ctrl_box, self._account_types, CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( ctrl_box, ClientGUICommon.BetterStaticText(self,'accounts, to expire in'), CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( ctrl_box, self._lifetime, CC.FLAGS_CENTER_PERPENDICULAR )
b_box = QP.HBoxLayout()
QP.AddToLayout( b_box, self._ok, CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( b_box, self._cancel, CC.FLAGS_CENTER_PERPENDICULAR )
vbox = QP.VBoxLayout()
QP.AddToLayout( vbox, ctrl_box, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
QP.AddToLayout( vbox, b_box, CC.FLAGS_ON_RIGHT )
self.setLayout( vbox )
size_hint = self.sizeHint()
QP.SetInitialSize( self, size_hint )
ClientGUIFunctions.SetFocusLater( self._ok )
def EventOK( self ):
num = self._num.value()
account_type = self._account_types.GetValue()
account_type_key = account_type.GetAccountTypeKey()
lifetime = self._lifetime.GetValue()
if lifetime is None:
expires = None
else:
expires = HydrusData.GetNow() + lifetime
service = HG.client_controller.services_manager.GetService( self._service_key )
try:
request_args = { 'num' : num, 'account_type_key' : account_type_key }
if expires is not None:
request_args[ 'expires' ] = expires
response = service.Request( HC.GET, 'registration_keys', request_args )
registration_keys = response[ 'registration_keys' ]
ClientGUIFrames.ShowKeys( 'registration', registration_keys )
finally:
self.done( QW.QDialog.Accepted )
class DialogInputLocalBooruShare( Dialog ):
def __init__( self, parent, share_key, name, text, timeout, hashes, new_share = False ):
Dialog.__init__( self, parent, 'configure local booru share' )
self._name = QW.QLineEdit( self )
self._text = QW.QPlainTextEdit( self )
self._text.setMinimumHeight( 100 )
message = 'expires in'
self._timeout_number = ClientGUICommon.NoneableSpinCtrl( self, message, none_phrase = 'no expiration', max = 1000000, multiplier = 1 )
self._timeout_multiplier = ClientGUICommon.BetterChoice( self )
self._timeout_multiplier.addItem( 'minutes', 60 )
self._timeout_multiplier.addItem( 'hours', 60 * 60 )
self._timeout_multiplier.addItem( 'days', 60 * 60 * 24 )
self._copy_internal_share_link = QW.QPushButton( 'copy internal share link', self )
self._copy_internal_share_link.clicked.connect( self.EventCopyInternalShareURL )
self._copy_external_share_link = QW.QPushButton( 'copy external share link', self )
self._copy_external_share_link.clicked.connect( self.EventCopyExternalShareURL )
self._ok = QW.QPushButton( 'ok', self )
self._ok.clicked.connect( self.accept )
self._ok.setObjectName( 'HydrusAccept' )
self._cancel = QW.QPushButton( 'cancel', self )
self._cancel.clicked.connect( self.reject )
self._cancel.setObjectName( 'HydrusCancel' )
#
self._share_key = share_key
self._name.setText( name )
self._text.setPlainText( text )
if timeout is None:
self._timeout_number.SetValue( None )
self._timeout_multiplier.SetValue( 60 )
else:
time_left = HydrusData.GetTimeDeltaUntilTime( timeout )
if time_left < 60 * 60 * 12: time_value = 60
elif time_left < 60 * 60 * 24 * 7: time_value = 60 * 60
else: time_value = 60 * 60 * 24
self._timeout_number.SetValue( time_left // time_value )
self._timeout_multiplier.SetValue( time_value )
self._hashes = hashes
self._service = HG.client_controller.services_manager.GetService( CC.LOCAL_BOORU_SERVICE_KEY )
internal_port = self._service.GetPort()
if internal_port is None:
self._copy_internal_share_link.setEnabled( False )
self._copy_external_share_link.setEnabled( False )
#
rows = []
rows.append( ( 'share name: ', self._name ) )
rows.append( ( 'share text: ', self._text ) )
gridbox = ClientGUICommon.WrapInGrid( self, rows )
timeout_box = QP.HBoxLayout()
QP.AddToLayout( timeout_box, self._timeout_number, CC.FLAGS_EXPAND_BOTH_WAYS )
QP.AddToLayout( timeout_box, self._timeout_multiplier, CC.FLAGS_EXPAND_BOTH_WAYS )
link_box = QP.HBoxLayout()
QP.AddToLayout( link_box, self._copy_internal_share_link, CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( link_box, self._copy_external_share_link, CC.FLAGS_CENTER_PERPENDICULAR )
b_box = QP.HBoxLayout()
QP.AddToLayout( b_box, self._ok, CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( b_box, self._cancel, CC.FLAGS_CENTER_PERPENDICULAR )
vbox = QP.VBoxLayout()
intro = 'Sharing ' + HydrusData.ToHumanInt( len( self._hashes ) ) + ' files.'
intro += os.linesep + 'Title and text are optional.'
if new_share: intro += os.linesep + 'The link will not work until you ok this dialog.'
QP.AddToLayout( vbox, ClientGUICommon.BetterStaticText(self,intro), CC.FLAGS_EXPAND_PERPENDICULAR )
QP.AddToLayout( vbox, gridbox, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
QP.AddToLayout( vbox, timeout_box, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
QP.AddToLayout( vbox, link_box, CC.FLAGS_ON_RIGHT )
QP.AddToLayout( vbox, b_box, CC.FLAGS_ON_RIGHT )
self.setLayout( vbox )
size_hint = self.sizeHint()
size_hint.setWidth( max( size_hint.width(), 350 ) )
QP.SetInitialSize( self, size_hint )
ClientGUIFunctions.SetFocusLater( self._ok )
def EventCopyExternalShareURL( self ):
internal_port = self._service.GetPort()
if internal_port is None:
QW.QMessageBox.warning( self, 'Warning', 'The local booru is not currently running!' )
try:
url = self._service.GetExternalShareURL( self._share_key )
except Exception as e:
HydrusData.ShowException( e )
QW.QMessageBox.critical( self, 'Error', 'Unfortunately, could not generate an external URL: {}'.format(e) )
return
HG.client_controller.pub( 'clipboard', 'text', url )
def EventCopyInternalShareURL( self ):
self._service = HG.client_controller.services_manager.GetService( CC.LOCAL_BOORU_SERVICE_KEY )
url = self._service.GetInternalShareURL( self._share_key )
HG.client_controller.pub( 'clipboard', 'text', url )
def GetInfo( self ):
name = self._name.text()
text = self._text.toPlainText()
timeout = self._timeout_number.GetValue()
if timeout is not None: timeout = timeout * self._timeout_multiplier.GetValue() + HydrusData.GetNow()
return ( self._share_key, name, text, timeout, self._hashes )
class DialogInputNamespaceRegex( Dialog ):
def __init__( self, parent, namespace = '', regex = '' ):
Dialog.__init__( self, parent, 'configure quick namespace' )
self._namespace = QW.QLineEdit( self )
self._regex = QW.QLineEdit( self )
self._shortcuts = ClientGUICommon.RegexButton( self )
self._regex_intro_link = ClientGUICommon.BetterHyperLink( self, 'a good regex introduction', 'https://www.aivosto.com/vbtips/regex.html' )
self._regex_practise_link = ClientGUICommon.BetterHyperLink( self, 'regex practice', 'https://regexr.com/3cvmf' )
self._ok = QW.QPushButton( 'OK', self )
self._ok.clicked.connect( self.EventOK )
self._ok.setObjectName( 'HydrusAccept' )
self._cancel = QW.QPushButton( 'Cancel', self )
self._cancel.clicked.connect( self.reject )
self._cancel.setObjectName( 'HydrusCancel' )
#
self._namespace.setText( namespace )
self._regex.setText( regex )
#
control_box = QP.HBoxLayout()
QP.AddToLayout( control_box, self._namespace, CC.FLAGS_EXPAND_BOTH_WAYS )
QP.AddToLayout( control_box, ClientGUICommon.BetterStaticText(self,':'), CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( control_box, self._regex, CC.FLAGS_EXPAND_BOTH_WAYS )
b_box = QP.HBoxLayout()
QP.AddToLayout( b_box, self._ok, CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( b_box, self._cancel, CC.FLAGS_CENTER_PERPENDICULAR )
vbox = QP.VBoxLayout()
intro = r'Put the namespace (e.g. page) on the left.' + os.linesep + r'Put the regex (e.g. [1-9]+\d*(?=.{4}$)) on the right.' + os.linesep + r'All files will be tagged with "namespace:regex".'
QP.AddToLayout( vbox, ClientGUICommon.BetterStaticText(self,intro), CC.FLAGS_EXPAND_PERPENDICULAR )
QP.AddToLayout( vbox, control_box, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
QP.AddToLayout( vbox, self._shortcuts, CC.FLAGS_ON_RIGHT )
QP.AddToLayout( vbox, self._regex_intro_link, CC.FLAGS_ON_RIGHT )
QP.AddToLayout( vbox, self._regex_practise_link, CC.FLAGS_ON_RIGHT )
QP.AddToLayout( vbox, b_box, CC.FLAGS_ON_RIGHT )
self.setLayout( vbox )
size_hint = self.sizeHint()
QP.SetInitialSize( self, size_hint )
ClientGUIFunctions.SetFocusLater( self._ok )
def EventOK( self ):
( namespace, regex ) = self.GetInfo()
if namespace == '':
QW.QMessageBox.warning( self, 'Warning', 'Please enter something for the namespace.' )
return
try:
re.compile( regex )
except Exception as e:
text = 'That regex would not compile!'
text += os.linesep * 2
text += str( e )
QW.QMessageBox.critical( self, 'Error', text )
return
self.done( QW.QDialog.Accepted )
def GetInfo( self ):
namespace = self._namespace.text()
regex = self._regex.text()
return ( namespace, regex )
class DialogInputTags( Dialog ):
def __init__( self, parent, service_key, tag_display_type, tags, message = '' ):
Dialog.__init__( self, parent, 'input tags' )
self._service_key = service_key
self._tags = ClientGUIListBoxes.ListBoxTagsStringsAddRemove( self, service_key, tag_display_type )
default_location_context = HG.client_controller.new_options.GetDefaultLocalLocationContext()
self._tag_autocomplete = ClientGUIACDropdown.AutoCompleteDropdownTagsWrite( self, self.EnterTags, default_location_context, service_key, null_entry_callable = self.OK, show_paste_button = True )
self._ok = ClientGUICommon.BetterButton( self, 'OK', self.done, QW.QDialog.Accepted )
self._ok.setObjectName( 'HydrusAccept' )
self._cancel = QW.QPushButton( 'Cancel', self )
self._cancel.clicked.connect( self.reject )
self._cancel.setObjectName( 'HydrusCancel' )
#
self._tags.SetTags( tags )
#
b_box = QP.HBoxLayout()
QP.AddToLayout( b_box, self._ok, CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( b_box, self._cancel, CC.FLAGS_CENTER_PERPENDICULAR )
vbox = QP.VBoxLayout()
if message != '':
st = ClientGUICommon.BetterStaticText( self, message )
st.setWordWrap( True )
QP.AddToLayout( vbox, st, CC.FLAGS_EXPAND_PERPENDICULAR )
QP.AddToLayout( vbox, self._tags, CC.FLAGS_EXPAND_BOTH_WAYS )
QP.AddToLayout( vbox, self._tag_autocomplete )
QP.AddToLayout( vbox, b_box, CC.FLAGS_ON_RIGHT )
self.setLayout( vbox )
size_hint = self.sizeHint()
size_hint.setWidth( max( size_hint.width(), 300 ) )
QP.SetInitialSize( self, size_hint )
ClientGUIFunctions.SetFocusLater( self._tag_autocomplete )
def EnterTags( self, tags ):
if len( tags ) > 0:
self._tags.EnterTags( tags )
def GetTags( self ):
return self._tags.GetTags()
def OK( self ):
self.done( QW.QDialog.Accepted )
class DialogInputUPnPMapping( Dialog ):
def __init__( self, parent, external_port, protocol_type, internal_port, description, duration ):
Dialog.__init__( self, parent, 'configure upnp mapping' )
self._external_port = ClientGUICommon.BetterSpinBox( self, min=0, max=65535 )
self._protocol_type = ClientGUICommon.BetterChoice( self )
self._protocol_type.addItem( 'TCP', 'TCP' )
self._protocol_type.addItem( 'UDP', 'UDP' )
self._internal_port = ClientGUICommon.BetterSpinBox( self, min=0, max=65535 )
self._description = QW.QLineEdit( self )
self._duration = ClientGUICommon.BetterSpinBox( self, min=0, max=86400 )
self._ok = ClientGUICommon.BetterButton( self, 'OK', self.done, QW.QDialog.Accepted )
self._ok.setObjectName( 'HydrusAccept' )
self._cancel = QW.QPushButton( 'Cancel', self )
self._cancel.clicked.connect( self.reject )
self._cancel.setObjectName( 'HydrusCancel' )
#
self._external_port.setValue( external_port )
if protocol_type == 'TCP': self._protocol_type.setCurrentIndex( 0 )
elif protocol_type == 'UDP': self._protocol_type.setCurrentIndex( 1 )
self._internal_port.setValue( internal_port )
self._description.setText( description )
self._duration.setValue( duration )
#
rows = []
rows.append( ( 'external port: ', self._external_port ) )
rows.append( ( 'protocol type: ', self._protocol_type ) )
rows.append( ( 'internal port: ', self._internal_port ) )
rows.append( ( 'description: ', self._description ) )
rows.append( ( 'duration (0 = indefinite): ', self._duration ) )
gridbox = ClientGUICommon.WrapInGrid( self, rows )
b_box = QP.HBoxLayout()
QP.AddToLayout( b_box, self._ok, CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( b_box, self._cancel, CC.FLAGS_CENTER_PERPENDICULAR )
vbox = QP.VBoxLayout()
QP.AddToLayout( vbox, gridbox, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
QP.AddToLayout( vbox, b_box, CC.FLAGS_ON_RIGHT )
self.setLayout( vbox )
size_hint = self.sizeHint()
QP.SetInitialSize( self, size_hint )
ClientGUIFunctions.SetFocusLater( self._ok )
def GetInfo( self ):
external_port = self._external_port.value()
protocol_type = self._protocol_type.GetValue()
internal_port = self._internal_port.value()
description = self._description.text()
duration = self._duration.value()
return ( external_port, protocol_type, internal_port, description, duration )
class DialogSelectFromURLTree( Dialog ):
def __init__( self, parent, url_tree ):
Dialog.__init__( self, parent, 'select items' )
self._tree = QP.TreeWidgetWithInheritedCheckState( self )
self._ok = ClientGUICommon.BetterButton( self, 'OK', self.done, QW.QDialog.Accepted )
self._ok.setObjectName( 'HydrusAccept' )
self._cancel = QW.QPushButton( 'Cancel', self )
self._cancel.clicked.connect( self.reject )
self._cancel.setObjectName( 'HydrusCancel' )
#
( text_gumpf, name, size, children ) = url_tree
root_name = self._RenderItemName( name, size )
root_item = QW.QTreeWidgetItem()
root_item.setText( 0, root_name )
root_item.setCheckState( 0, QC.Qt.Checked )
self._tree.addTopLevelItem( root_item )
self._AddDirectory( root_item, children )
root_item.setExpanded( True )
#
button_hbox = QP.HBoxLayout()
QP.AddToLayout( button_hbox, self._ok, CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( button_hbox, self._cancel, CC.FLAGS_CENTER_PERPENDICULAR )
vbox = QP.VBoxLayout()
QP.AddToLayout( vbox, self._tree, CC.FLAGS_EXPAND_BOTH_WAYS )
QP.AddToLayout( vbox, button_hbox, CC.FLAGS_ON_RIGHT )
self.setLayout( vbox )
size_hint = self.sizeHint()
size_hint.setWidth( max( size_hint.width(), 640 ) )
size_hint.setHeight( max( size_hint.height(), 640 ) )
QP.SetInitialSize( self, size_hint )
def _AddDirectory( self, root, children ):
for ( child_type, name, size, data ) in children:
item_name = self._RenderItemName( name, size )
if child_type == 'file':
item = QW.QTreeWidgetItem()
item.setText( 0, item_name )
item.setCheckState( 0, root.checkState( 0 ) )
item.setData( 0, QC.Qt.UserRole, data )
root.addChild( item )
else:
subroot = QW.QTreeWidgetItem()
subroot.setText( 0, item_name )
subroot.setCheckState( 0, root.checkState( 0 ) )
root.addChild( subroot )
self._AddDirectory( subroot, data )
def _GetSelectedChildrenData( self, parent_item ):
result = []
for i in range( parent_item.childCount() ):
child_item = parent_item.child( i )
if child_item.checkState( 0 ) == QC.Qt.Checked:
data = child_item.data( 0, QC.Qt.UserRole )
if data is not None:
result.append( data )
result.extend( self._GetSelectedChildrenData( child_item ) )
return result
def _RenderItemName( self, name, size ):
return name + ' - ' + HydrusData.ToHumanBytes( size )
def GetURLs( self ):
root_item = self._tree.topLevelItem( 0 )
urls = self._GetSelectedChildrenData( root_item )
return urls
class DialogSelectImageboard( Dialog ):
def __init__( self, parent ):
Dialog.__init__( self, parent, 'select imageboard' )
self._tree = QW.QTreeWidget( self )
self._tree.itemActivated.connect( self.EventActivate )
#
all_imageboards = HG.client_controller.Read( 'imageboards' )
root_item = QW.QTreeWidgetItem()
root_item.setText( 0, 'all sites' )
self._tree.addTopLevelItem( root_item )
for ( site, imageboards ) in list(all_imageboards.items()):
site_item = QW.QTreeWidgetItem()
site_item.setText( 0, site )
root_item.addChild( site_item )
for imageboard in imageboards:
name = imageboard.GetName()
imageboard_item = QW.QTreeWidgetItem()
imageboard_item.setText( 0, name )
imageboard_item.setData( 0, QC.Qt.UserRole, imageboard )
site_item.addChild( imageboard_item )
root_item.setExpanded( True )
#
vbox = QP.VBoxLayout()
QP.AddToLayout( vbox, self._tree, CC.FLAGS_EXPAND_BOTH_WAYS )
self.setLayout( vbox )
size_hint = self.sizeHint()
size_hint.setWidth( max( size_hint.width(), 320 ) )
size_hint.setHeight( max( size_hint.height(), 640 ) )
QP.SetInitialSize( self, size_hint )
def EventActivate( self, item, column ):
data_object = item.data( 0, QC.Qt.UserRole )
if data_object is None: item.setExpanded( not item.isExpanded() )
else: self.done( QW.QDialog.Accepted )
def GetImageboard( self ):
items = self._tree.selectedItems()
if len(items):
return items[0].data( 0, QC.Qt.UserRole ).GetData()
class DialogTextEntry( Dialog ):
def __init__( self, parent, message, default = '', placeholder = None, allow_blank = False, suggestions = None, max_chars = None, password_entry = False, min_char_width = 72 ):
if suggestions is None:
suggestions = []
Dialog.__init__( self, parent, 'enter text', position = 'center' )
self._chosen_suggestion = None
self._allow_blank = allow_blank
self._max_chars = max_chars
button_choices = []
for text in suggestions:
button_choices.append( ClientGUICommon.BetterButton( self, text, self.ButtonChoice, text ) )
self._text = QW.QLineEdit( self )
self._text.textChanged.connect( self.EventText )
self._text.installEventFilter( ClientGUICommon.TextCatchEnterEventFilter( self._text, self.EnterText ) )
width = ClientGUIFunctions.ConvertTextToPixelWidth( self._text, min_char_width )
self._text.setMinimumWidth( width )
if password_entry:
self._text.setEchoMode( QW.QLineEdit.Password )
if self._max_chars is not None:
self._text.setMaxLength( self._max_chars )
self._ok = ClientGUICommon.BetterButton( self, 'ok', self.done, QW.QDialog.Accepted )
self._ok.setObjectName( 'HydrusAccept' )
self._cancel = QW.QPushButton( 'cancel', self )
self._cancel.clicked.connect( self.reject )
self._cancel.setObjectName( 'HydrusCancel' )
#
self._text.setText( default )
if placeholder is not None:
self._text.setPlaceholderText( placeholder )
if len( default ) > 0:
self._text.setSelection( 0, len( default ) )
self._CheckText()
#
hbox = QP.HBoxLayout()
QP.AddToLayout( hbox, self._ok, CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( hbox, self._cancel, CC.FLAGS_CENTER_PERPENDICULAR )
st_message = ClientGUICommon.BetterStaticText( self, message )
st_message.setWordWrap( True )
vbox = QP.VBoxLayout()
QP.AddToLayout( vbox, st_message, CC.FLAGS_EXPAND_PERPENDICULAR )
for button in button_choices:
QP.AddToLayout( vbox, button, CC.FLAGS_EXPAND_PERPENDICULAR )
QP.AddToLayout( vbox, self._text, CC.FLAGS_EXPAND_BOTH_WAYS )
QP.AddToLayout( vbox, hbox, CC.FLAGS_ON_RIGHT )
self.setLayout( vbox )
size_hint = self.sizeHint()
size_hint.setWidth( max( size_hint.width(), 250 ) )
QP.SetInitialSize( self, size_hint )
self._text.setFocus( QC.Qt.OtherFocusReason )
def _CheckText( self ):
if not self._allow_blank:
if self._text.text() == '':
self._ok.setEnabled( False )
else:
self._ok.setEnabled( True )
def ButtonChoice( self, text ):
self._chosen_suggestion = text
self.done( QW.QDialog.Accepted )
def EventText( self, text ):
QP.CallAfter( self._CheckText )
def EnterText( self ):
if self._ok.isEnabled():
self.done( QW.QDialog.Accepted )
def GetValue( self ):
if self._chosen_suggestion is None:
return self._text.text()
else:
return self._chosen_suggestion
class DialogYesYesNo( Dialog ):
def __init__( self, parent, message, title = 'Are you sure?', yes_tuples = None, no_label = 'no' ):
if yes_tuples is None:
yes_tuples = [ ( 'yes', 'yes' ) ]
Dialog.__init__( self, parent, title, position = 'center' )
self._value = None
yes_buttons = []
for ( label, data ) in yes_tuples:
yes_button = ClientGUICommon.BetterButton( self, label, self._DoYes, data )
yes_button.setObjectName( 'HydrusAccept' )
yes_buttons.append( yes_button )
self._no = ClientGUICommon.BetterButton( self, no_label, self.done, QW.QDialog.Rejected )
self._no.setObjectName( 'HydrusCancel' )
#
hbox = QP.HBoxLayout()
for yes_button in yes_buttons:
QP.AddToLayout( hbox, yes_button, CC.FLAGS_CENTER_PERPENDICULAR )
QP.AddToLayout( hbox, self._no, CC.FLAGS_CENTER_PERPENDICULAR )
vbox = QP.VBoxLayout()
text = ClientGUICommon.BetterStaticText( self, message )
text.setWordWrap( True )
QP.AddToLayout( vbox, text, CC.FLAGS_EXPAND_BOTH_WAYS )
QP.AddToLayout( vbox, hbox, CC.FLAGS_ON_RIGHT )
self.setLayout( vbox )
size_hint = self.sizeHint()
size_hint.setWidth( max( size_hint.width(), 250 ) )
QP.SetInitialSize( self, size_hint )
ClientGUIFunctions.SetFocusLater( yes_buttons[0] )
def _DoYes( self, value ):
self._value = value
self.done( QW.QDialog.Accepted )
def GetValue( self ):
return self._value