hydrus/include/ClientGUIDialogs.py

2050 lines
66 KiB
Python
Raw Normal View History

2019-01-09 22:59:03 +00:00
from . import HydrusConstants as HC
from . import ClientConstants as CC
from . import ClientData
from . import ClientDefaults
from . import ClientDownloading
from . import ClientDragDrop
from . import ClientExporting
from . import ClientCaches
from . import ClientFiles
from . import ClientGUIACDropdown
from . import ClientGUIFrames
from . import ClientGUICommon
from . import ClientGUIDialogsQuick
from . import ClientGUIImport
from . import ClientGUIListBoxes
from . import ClientGUIListCtrl
from . import ClientGUIPredicates
from . import ClientGUIShortcuts
from . import ClientGUITime
from . import ClientGUITopLevelWindows
from . import ClientImporting
from . import ClientThreading
2013-02-19 00:11:43 +00:00
import collections
2014-01-01 20:01:00 +00:00
import gc
2019-01-09 22:59:03 +00:00
from . import HydrusExceptions
from . import HydrusFileHandling
from . import HydrusNATPunch
from . import HydrusNetwork
from . import HydrusPaths
from . import HydrusSerialisable
from . import HydrusTagArchive
from . import HydrusTags
from . import HydrusThreading
2013-06-12 22:53:31 +00:00
import itertools
2013-02-19 00:11:43 +00:00
import os
import random
import re
2019-01-09 22:59:03 +00:00
import queue
2013-08-14 20:21:49 +00:00
import shutil
2013-11-20 21:12:21 +00:00
import stat
2013-07-17 20:56:13 +00:00
import string
2013-09-11 21:28:19 +00:00
import threading
2013-02-19 00:11:43 +00:00
import time
import traceback
import wx
2016-03-23 19:42:56 +00:00
import wx.lib.agw.customtreectrl
2013-02-19 00:11:43 +00:00
import yaml
2019-01-09 22:59:03 +00:00
from . import HydrusData
from . import ClientSearch
from . import HydrusGlobals as HG
2013-02-19 00:11:43 +00:00
# Option Enums
ID_NULL = wx.NewId()
ID_TIMER_UPDATE = wx.NewId()
2017-03-02 02:14:56 +00:00
def SelectServiceKey( service_types = HC.ALL_SERVICES, service_keys = None, unallowed = None ):
2013-02-19 00:11:43 +00:00
2014-08-27 22:15:22 +00:00
if service_keys is None:
2013-02-19 00:11:43 +00:00
2017-06-28 20:23:21 +00:00
services = HG.client_controller.services_manager.GetServices( service_types )
2013-02-19 00:11:43 +00:00
2014-09-17 21:28:26 +00:00
service_keys = [ service.GetServiceKey() for service in services ]
2013-02-19 00:11:43 +00:00
2017-03-02 02:14:56 +00:00
if unallowed is not None:
service_keys.difference_update( unallowed )
2013-02-19 00:11:43 +00:00
2017-03-02 02:14:56 +00:00
if len( service_keys ) == 0:
return None
2014-08-27 22:15:22 +00:00
elif len( service_keys ) == 1:
2013-02-19 00:11:43 +00:00
2014-08-27 22:15:22 +00:00
( service_key, ) = service_keys
2013-02-19 00:11:43 +00:00
2014-08-27 22:15:22 +00:00
return service_key
2013-02-19 00:11:43 +00:00
else:
2017-06-28 20:23:21 +00:00
services = { HG.client_controller.services_manager.GetService( service_key ) for service_key in service_keys }
2013-02-19 00:11:43 +00:00
2018-08-08 20:29:54 +00:00
choice_tuples = [ ( service.GetName(), service.GetServiceKey() ) for service in services ]
2014-08-27 22:15:22 +00:00
2018-11-14 23:10:55 +00:00
try:
2013-02-19 00:11:43 +00:00
2018-11-14 23:10:55 +00:00
service_key = ClientGUIDialogsQuick.SelectFromList( HG.client_controller.GetGUI(), 'select service', choice_tuples )
return service_key
except HydrusExceptions.CancelledException:
return None
2013-02-19 00:11:43 +00:00
class Dialog( wx.Dialog ):
def __init__( self, parent, title, style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, position = 'topleft' ):
2013-07-31 21:26:38 +00:00
if parent is not None and position == 'topleft':
2013-02-19 00:11:43 +00:00
2016-01-13 22:08:19 +00:00
if isinstance( parent, wx.TopLevelWindow ):
parent_tlp = parent
else:
parent_tlp = parent.GetTopLevelParent()
2015-02-25 19:34:30 +00:00
2018-01-03 22:37:30 +00:00
( pos_x, pos_y ) = parent_tlp.GetPosition()
2013-02-19 00:11:43 +00:00
2016-06-22 20:59:24 +00:00
pos = ( pos_x + 50, pos_y + 50 )
2013-02-19 00:11:43 +00:00
2016-01-13 22:08:19 +00:00
else:
pos = wx.DefaultPosition
2015-08-26 21:18:39 +00:00
if not HC.PLATFORM_LINUX and parent is not None:
style |= wx.FRAME_FLOAT_ON_PARENT
2013-02-19 00:11:43 +00:00
wx.Dialog.__init__( self, parent, title = title, style = style, pos = pos )
2017-12-06 22:06:56 +00:00
self._new_options = HG.client_controller.new_options
2016-06-29 19:55:46 +00:00
2016-08-10 19:04:08 +00:00
self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_FRAMEBK ) )
2013-02-19 00:11:43 +00:00
2017-11-15 22:35:49 +00:00
self.SetIcon( HG.client_controller.frame_icon )
2013-02-19 00:11:43 +00:00
2013-07-24 20:26:00 +00:00
self.Bind( wx.EVT_BUTTON, self.EventDialogButton )
2015-08-26 21:18:39 +00:00
if parent is not None and position == 'center':
wx.CallAfter( self.Center )
2014-02-05 20:54:28 +00:00
2017-05-10 21:33:58 +00:00
HG.client_controller.ResetIdleTimer()
2014-12-03 22:56:40 +00:00
2013-07-24 20:26:00 +00:00
2018-02-07 23:40:33 +00:00
def EventDialogButton( self, event ):
if self.IsModal():
self.EndModal( event.GetId() )
2013-07-24 20:26:00 +00:00
2019-01-09 22:59:03 +00:00
def SetInitialSize( self, size ):
( width, height ) = size
2015-01-07 23:09:00 +00:00
2016-12-21 22:30:54 +00:00
( display_width, display_height ) = ClientGUITopLevelWindows.GetDisplaySize( self )
2015-11-11 21:20:41 +00:00
width = min( display_width, width )
height = min( display_height, height )
2015-01-07 23:09:00 +00:00
wx.Dialog.SetInitialSize( self, ( width, height ) )
min_width = min( 240, width )
2015-11-18 22:44:07 +00:00
min_height = min( 240, height )
2015-01-07 23:09:00 +00:00
self.SetMinSize( ( min_width, min_height ) )
2013-03-15 02:38:12 +00:00
class DialogChooseNewServiceMethod( Dialog ):
def __init__( self, parent ):
2015-05-20 21:31:40 +00:00
Dialog.__init__( self, parent, 'how to set up the account?', position = 'center' )
2013-07-31 21:26:38 +00:00
2015-05-20 21:31:40 +00:00
self._hidden_cancel = wx.Button( self, id = wx.ID_CANCEL, size = ( 0, 0 ) )
2013-03-15 02:38:12 +00:00
2015-05-20 21:31:40 +00:00
register_message = 'I want to initialise a new account with the server. I have a registration key (a key starting with \'r\').'
2013-03-15 02:38:12 +00:00
2015-05-20 21:31:40 +00:00
self._register = wx.Button( self, label = register_message )
self._register.Bind( wx.EVT_BUTTON, self.EventRegister )
2013-03-15 02:38:12 +00:00
2015-05-20 21:31:40 +00:00
setup_message = 'The account is already initialised; I just want to add it to this client. I have a normal access key.'
2013-03-15 02:38:12 +00:00
2015-05-20 21:31:40 +00:00
self._setup = wx.Button( self, id = wx.ID_OK, label = setup_message )
2013-07-31 21:26:38 +00:00
2015-05-20 21:31:40 +00:00
vbox = wx.BoxSizer( wx.VERTICAL )
2018-01-03 22:37:30 +00:00
vbox.Add( self._register, CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.Add( wx.StaticText( self, label = '-or-', style = wx.ALIGN_CENTER ), CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.Add( self._setup, CC.FLAGS_EXPAND_PERPENDICULAR )
2015-05-20 21:31:40 +00:00
self.SetSizer( vbox )
( x, y ) = self.GetEffectiveMinSize()
self.SetInitialSize( ( x, y ) )
2013-03-15 02:38:12 +00:00
2013-07-24 20:26:00 +00:00
self._should_register = False
2013-03-15 02:38:12 +00:00
2013-07-31 21:26:38 +00:00
wx.CallAfter( self._register.SetFocus )
2013-03-15 02:38:12 +00:00
def EventRegister( self, event ):
2013-07-24 20:26:00 +00:00
self._should_register = True
2013-03-15 02:38:12 +00:00
self.EndModal( wx.ID_OK )
2013-07-24 20:26:00 +00:00
def GetRegister( self ): return self._should_register
2013-03-15 02:38:12 +00:00
2017-04-19 20:58:30 +00:00
class DialogCommitInterstitialFiltering( Dialog ):
def __init__( self, parent, label ):
Dialog.__init__( self, parent, 'commit and continue?', position = 'center' )
self._commit = wx.Button( self, id = wx.ID_YES, label = 'commit and continue' )
self._commit.SetForegroundColour( ( 0, 128, 0 ) )
self._back = wx.Button( self, id = wx.ID_CANCEL, label = 'go back' )
vbox = wx.BoxSizer( wx.VERTICAL )
2018-01-03 22:37:30 +00:00
vbox.Add( wx.StaticText( self, label = label, style = wx.ALIGN_CENTER ), CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.Add( self._commit, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
vbox.Add( wx.StaticText( self, label = '-or-', style = wx.ALIGN_CENTER ), CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.Add( self._back, CC.FLAGS_EXPAND_PERPENDICULAR )
2017-04-19 20:58:30 +00:00
self.SetSizer( vbox )
( x, y ) = self.GetEffectiveMinSize()
self.SetInitialSize( ( x, y ) )
wx.CallAfter( self._commit.SetFocus )
2013-02-19 00:11:43 +00:00
class DialogFinishFiltering( Dialog ):
2017-04-19 20:58:30 +00:00
def __init__( self, parent, label ):
2013-02-19 00:11:43 +00:00
2015-05-20 21:31:40 +00:00
Dialog.__init__( self, parent, 'are you sure?', position = 'center' )
2013-02-19 00:11:43 +00:00
2018-04-05 01:22:26 +00:00
self._commit = ClientGUICommon.BetterButton( self, 'commit', self.EndModal, wx.ID_YES )
2015-05-20 21:31:40 +00:00
self._commit.SetForegroundColour( ( 0, 128, 0 ) )
2013-07-31 21:26:38 +00:00
2018-04-05 01:22:26 +00:00
self._forget = ClientGUICommon.BetterButton( self, 'forget', self.EndModal, wx.ID_NO )
2015-05-20 21:31:40 +00:00
self._forget.SetForegroundColour( ( 128, 0, 0 ) )
2013-02-19 00:11:43 +00:00
2018-04-05 01:22:26 +00:00
self._back = ClientGUICommon.BetterButton( self, 'back to filtering', self.EndModal, wx.ID_CANCEL )
self._back.SetId( wx.ID_CANCEL )
2013-02-19 00:11:43 +00:00
2015-05-20 21:31:40 +00:00
hbox = wx.BoxSizer( wx.HORIZONTAL )
2013-02-19 00:11:43 +00:00
2018-01-03 22:37:30 +00:00
hbox.Add( self._commit, CC.FLAGS_EXPAND_BOTH_WAYS )
hbox.Add( self._forget, CC.FLAGS_EXPAND_BOTH_WAYS )
2013-07-31 21:26:38 +00:00
2015-05-20 21:31:40 +00:00
vbox = wx.BoxSizer( wx.VERTICAL )
2018-01-03 22:37:30 +00:00
vbox.Add( wx.StaticText( self, label = label, style = wx.ALIGN_CENTER ), CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.Add( hbox, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
vbox.Add( wx.StaticText( self, label = '-or-', style = wx.ALIGN_CENTER ), CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.Add( self._back, CC.FLAGS_EXPAND_PERPENDICULAR )
2015-05-20 21:31:40 +00:00
self.SetSizer( vbox )
( x, y ) = self.GetEffectiveMinSize()
self.SetInitialSize( ( x, y ) )
2013-07-31 21:26:38 +00:00
wx.CallAfter( self._commit.SetFocus )
2013-02-19 00:11:43 +00:00
2013-11-27 18:27:11 +00:00
class DialogGenerateNewAccounts( Dialog ):
2014-08-27 22:15:22 +00:00
def __init__( self, parent, service_key ):
2013-11-27 18:27:11 +00:00
2015-12-09 23:16:41 +00:00
Dialog.__init__( self, parent, 'configure new accounts' )
2013-11-27 18:27:11 +00:00
2015-12-09 23:16:41 +00:00
self._service_key = service_key
2013-11-27 18:27:11 +00:00
2015-12-09 23:16:41 +00:00
self._num = wx.SpinCtrl( self, min = 1, max = 10000, size = ( 80, -1 ) )
2013-11-27 18:27:11 +00:00
2017-03-02 02:14:56 +00:00
self._account_types = ClientGUICommon.BetterChoice( self )
2013-11-27 18:27:11 +00:00
2017-03-02 02:14:56 +00:00
self._lifetime = ClientGUICommon.BetterChoice( self )
2015-12-09 23:16:41 +00:00
2017-06-07 22:05:15 +00:00
self._ok = wx.Button( self, label = 'OK' )
2015-12-09 23:16:41 +00:00
self._ok.Bind( wx.EVT_BUTTON, self.EventOK )
self._ok.SetForegroundColour( ( 0, 128, 0 ) )
self._cancel = wx.Button( self, id = wx.ID_CANCEL, label = 'Cancel' )
self._cancel.SetForegroundColour( ( 128, 0, 0 ) )
#
self._num.SetValue( 1 )
2017-06-28 20:23:21 +00:00
service = HG.client_controller.services_manager.GetService( service_key )
2015-12-09 23:16:41 +00:00
response = service.Request( HC.GET, 'account_types' )
account_types = response[ 'account_types' ]
2017-03-02 02:14:56 +00:00
for account_type in account_types:
self._account_types.Append( account_type.GetTitle(), account_type )
self._account_types.Select( 0 )
2017-03-15 20:13:04 +00:00
for ( s, value ) in HC.lifetimes:
2017-03-02 02:14:56 +00:00
2017-03-15 20:13:04 +00:00
self._lifetime.Append( s, value )
2017-03-02 02:14:56 +00:00
2015-12-09 23:16:41 +00:00
self._lifetime.SetSelection( 3 ) # one year
2013-11-27 18:27:11 +00:00
2015-12-09 23:16:41 +00:00
#
ctrl_box = wx.BoxSizer( wx.HORIZONTAL )
2018-01-03 22:37:30 +00:00
ctrl_box.Add( ClientGUICommon.BetterStaticText( self, 'generate' ), CC.FLAGS_VCENTER )
ctrl_box.Add( self._num, CC.FLAGS_VCENTER )
ctrl_box.Add( self._account_types, CC.FLAGS_VCENTER )
ctrl_box.Add( ClientGUICommon.BetterStaticText( self, 'accounts, to expire in' ), CC.FLAGS_VCENTER )
ctrl_box.Add( self._lifetime, CC.FLAGS_VCENTER )
2013-11-27 18:27:11 +00:00
2015-12-09 23:16:41 +00:00
b_box = wx.BoxSizer( wx.HORIZONTAL )
2018-01-03 22:37:30 +00:00
b_box.Add( self._ok, CC.FLAGS_VCENTER )
b_box.Add( self._cancel, CC.FLAGS_VCENTER )
2013-11-27 18:27:11 +00:00
2015-12-09 23:16:41 +00:00
vbox = wx.BoxSizer( wx.VERTICAL )
2018-01-03 22:37:30 +00:00
vbox.Add( ctrl_box, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
vbox.Add( b_box, CC.FLAGS_BUTTON_SIZER )
2015-12-09 23:16:41 +00:00
self.SetSizer( vbox )
( x, y ) = self.GetEffectiveMinSize()
self.SetInitialSize( ( x, y ) )
2013-11-27 18:27:11 +00:00
wx.CallAfter( self._ok.SetFocus )
def EventOK( self, event ):
num = self._num.GetValue()
2017-03-02 02:14:56 +00:00
account_type = self._account_types.GetChoice()
account_type_key = account_type.GetAccountTypeKey()
2013-11-27 18:27:11 +00:00
2017-03-02 02:14:56 +00:00
lifetime = self._lifetime.GetChoice()
2013-11-27 18:27:11 +00:00
2017-03-02 02:14:56 +00:00
if lifetime is None:
expires = None
else:
expires = HydrusData.GetNow() + lifetime
2013-11-27 18:27:11 +00:00
2017-06-28 20:23:21 +00:00
service = HG.client_controller.services_manager.GetService( self._service_key )
2013-11-27 18:27:11 +00:00
try:
2017-03-15 20:13:04 +00:00
request_args = { 'num' : num, 'account_type_key' : account_type_key }
if expires is not None:
request_args[ 'expires' ] = expires
2013-11-27 18:27:11 +00:00
2014-01-29 21:59:42 +00:00
response = service.Request( HC.GET, 'registration_keys', request_args )
2013-11-27 18:27:11 +00:00
registration_keys = response[ 'registration_keys' ]
2016-11-02 21:09:14 +00:00
ClientGUIFrames.ShowKeys( 'registration', registration_keys )
2013-11-27 18:27:11 +00:00
2017-03-02 02:14:56 +00:00
finally:
self.EndModal( wx.ID_OK )
2013-11-27 18:27:11 +00:00
2014-07-09 22:15:14 +00:00
class DialogInputLocalBooruShare( Dialog ):
def __init__( self, parent, share_key, name, text, timeout, hashes, new_share = False ):
2015-12-09 23:16:41 +00:00
Dialog.__init__( self, parent, 'configure local booru share' )
2014-07-09 22:15:14 +00:00
2015-12-09 23:16:41 +00:00
self._name = wx.TextCtrl( self )
2014-07-09 22:15:14 +00:00
2016-11-02 21:09:14 +00:00
self._text = ClientGUICommon.SaneMultilineTextCtrl( self )
2015-12-09 23:16:41 +00:00
self._text.SetMinSize( ( -1, 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.Append( 'minutes', 60 )
self._timeout_multiplier.Append( 'hours', 60 * 60 )
self._timeout_multiplier.Append( 'days', 60 * 60 * 24 )
self._copy_internal_share_link = wx.Button( self, label = 'copy internal share link' )
self._copy_internal_share_link.Bind( wx.EVT_BUTTON, self.EventCopyInternalShareURL )
self._copy_external_share_link = wx.Button( self, label = 'copy external share link' )
self._copy_external_share_link.Bind( wx.EVT_BUTTON, self.EventCopyExternalShareURL )
self._ok = wx.Button( self, id = wx.ID_OK, label = 'ok' )
self._ok.SetForegroundColour( ( 0, 128, 0 ) )
self._cancel = wx.Button( self, id = wx.ID_CANCEL, label = 'cancel' )
self._cancel.SetForegroundColour( ( 128, 0, 0 ) )
#
self._share_key = share_key
self._name.SetValue( name )
self._text.SetValue( text )
if timeout is None:
2014-07-09 22:15:14 +00:00
2015-12-09 23:16:41 +00:00
self._timeout_number.SetValue( None )
2014-07-09 22:15:14 +00:00
2015-12-09 23:16:41 +00:00
self._timeout_multiplier.SelectClientData( 60 )
2014-07-09 22:15:14 +00:00
2015-12-09 23:16:41 +00:00
else:
2014-07-09 22:15:14 +00:00
2018-02-14 21:47:18 +00:00
time_left = HydrusData.GetTimeDeltaUntilTime( timeout )
2014-07-09 22:15:14 +00:00
2015-12-09 23:16:41 +00:00
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
2014-07-09 22:15:14 +00:00
2019-01-09 22:59:03 +00:00
self._timeout_number.SetValue( time_left // time_value )
2014-07-09 22:15:14 +00:00
2015-12-09 23:16:41 +00:00
self._timeout_multiplier.SelectClientData( time_value )
2014-07-09 22:15:14 +00:00
2015-12-09 23:16:41 +00:00
self._hashes = hashes
2017-12-06 22:06:56 +00:00
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.Disable()
self._copy_external_share_link.Disable()
2015-12-09 23:16:41 +00:00
#
2016-08-31 19:55:14 +00:00
rows = []
2015-12-09 23:16:41 +00:00
2016-08-31 19:55:14 +00:00
rows.append( ( 'share name: ', self._name ) )
rows.append( ( 'share text: ', self._text ) )
2015-12-09 23:16:41 +00:00
2016-08-31 19:55:14 +00:00
gridbox = ClientGUICommon.WrapInGrid( self, rows )
2015-12-09 23:16:41 +00:00
timeout_box = wx.BoxSizer( wx.HORIZONTAL )
2018-01-03 22:37:30 +00:00
timeout_box.Add( self._timeout_number, CC.FLAGS_EXPAND_BOTH_WAYS )
timeout_box.Add( self._timeout_multiplier, CC.FLAGS_EXPAND_BOTH_WAYS )
2015-12-09 23:16:41 +00:00
link_box = wx.BoxSizer( wx.HORIZONTAL )
2018-01-03 22:37:30 +00:00
link_box.Add( self._copy_internal_share_link, CC.FLAGS_VCENTER )
link_box.Add( self._copy_external_share_link, CC.FLAGS_VCENTER )
2015-12-09 23:16:41 +00:00
b_box = wx.BoxSizer( wx.HORIZONTAL )
2018-01-03 22:37:30 +00:00
b_box.Add( self._ok, CC.FLAGS_VCENTER )
b_box.Add( self._cancel, CC.FLAGS_VCENTER )
2015-12-09 23:16:41 +00:00
vbox = wx.BoxSizer( wx.VERTICAL )
2018-07-04 20:48:28 +00:00
intro = 'Sharing ' + HydrusData.ToHumanInt( len( self._hashes ) ) + ' files.'
2015-12-09 23:16:41 +00:00
intro += os.linesep + 'Title and text are optional.'
if new_share: intro += os.linesep + 'The link will not work until you ok this dialog.'
2018-01-03 22:37:30 +00:00
vbox.Add( ClientGUICommon.BetterStaticText( self, intro ), CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.Add( gridbox, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
vbox.Add( timeout_box, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
vbox.Add( link_box, CC.FLAGS_BUTTON_SIZER )
vbox.Add( b_box, CC.FLAGS_BUTTON_SIZER )
2015-12-09 23:16:41 +00:00
self.SetSizer( vbox )
2014-07-09 22:15:14 +00:00
2015-12-09 23:16:41 +00:00
( x, y ) = self.GetEffectiveMinSize()
2014-07-09 22:15:14 +00:00
2015-12-09 23:16:41 +00:00
x = max( x, 350 )
2014-07-09 22:15:14 +00:00
2015-12-09 23:16:41 +00:00
self.SetInitialSize( ( x, y ) )
2014-07-09 22:15:14 +00:00
wx.CallAfter( self._ok.SetFocus )
def EventCopyExternalShareURL( self, event ):
2017-06-28 20:23:21 +00:00
self._service = HG.client_controller.services_manager.GetService( CC.LOCAL_BOORU_SERVICE_KEY )
2014-07-09 22:15:14 +00:00
external_ip = HydrusNATPunch.GetExternalIP() # eventually check for optional host replacement here
2017-03-02 02:14:56 +00:00
external_port = self._service.GetUPnPPort()
2014-07-09 22:15:14 +00:00
2017-03-02 02:14:56 +00:00
if external_port is None:
external_port = self._service.GetPort()
2014-07-09 22:15:14 +00:00
2019-01-09 22:59:03 +00:00
url = 'http://' + external_ip + ':' + str( external_port ) + '/gallery?share_key=' + self._share_key.hex()
2014-07-09 22:15:14 +00:00
2017-05-10 21:33:58 +00:00
HG.client_controller.pub( 'clipboard', 'text', url )
2014-07-09 22:15:14 +00:00
def EventCopyInternalShareURL( self, event ):
2017-06-28 20:23:21 +00:00
self._service = HG.client_controller.services_manager.GetService( CC.LOCAL_BOORU_SERVICE_KEY )
2014-07-09 22:15:14 +00:00
internal_ip = '127.0.0.1'
2017-03-02 02:14:56 +00:00
internal_port = self._service.GetPort()
2014-07-09 22:15:14 +00:00
2019-01-09 22:59:03 +00:00
url = 'http://' + internal_ip + ':' + str( internal_port ) + '/gallery?share_key=' + self._share_key.hex()
2014-07-09 22:15:14 +00:00
2017-05-10 21:33:58 +00:00
HG.client_controller.pub( 'clipboard', 'text', url )
2014-07-09 22:15:14 +00:00
def GetInfo( self ):
name = self._name.GetValue()
text = self._text.GetValue()
timeout = self._timeout_number.GetValue()
2015-03-25 22:04:19 +00:00
if timeout is not None: timeout = timeout * self._timeout_multiplier.GetChoice() + HydrusData.GetNow()
2014-07-09 22:15:14 +00:00
return ( self._share_key, name, text, timeout, self._hashes )
2017-11-08 22:07:12 +00:00
class FrameInputLocalFiles( wx.Frame ):
2014-01-01 20:01:00 +00:00
2015-03-25 22:04:19 +00:00
def __init__( self, parent, paths = None ):
2018-01-03 22:37:30 +00:00
( pos_x, pos_y ) = parent.GetPosition()
2014-01-01 20:01:00 +00:00
2017-11-08 22:07:12 +00:00
pos = ( pos_x + 50, pos_y + 50 )
style = wx.DEFAULT_FRAME_STYLE | wx.FRAME_FLOAT_ON_PARENT
wx.Frame.__init__( self, parent, title = 'importing files', style = style, pos = pos )
self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_FRAMEBK ) )
2017-11-15 22:35:49 +00:00
self.SetIcon( HG.client_controller.frame_icon )
2017-11-08 22:07:12 +00:00
if paths is None:
paths = []
2014-01-01 20:01:00 +00:00
2017-11-22 21:03:07 +00:00
self.SetDropTarget( ClientDragDrop.FileDropTarget( self, filenames_callable = self._AddPathsToList ) )
2014-01-01 20:01:00 +00:00
2017-08-02 21:32:54 +00:00
listctrl_panel = ClientGUIListCtrl.SaneListCtrlPanel( self )
2017-07-27 00:47:13 +00:00
2017-08-02 21:32:54 +00:00
self._paths_list = ClientGUIListCtrl.SaneListCtrl( listctrl_panel, 120, [ ( 'path', -1 ), ( 'guessed mime', 110 ), ( 'size', 60 ) ], delete_key_callback = self.RemovePaths )
2017-07-27 00:47:13 +00:00
listctrl_panel.SetListCtrl( self._paths_list )
listctrl_panel.AddButton( 'add files', self.AddPaths )
listctrl_panel.AddButton( 'add folder', self.AddFolder )
listctrl_panel.AddButton( 'remove files', self.RemovePaths, enabled_only_on_selection = True )
2014-01-01 20:01:00 +00:00
2017-02-01 21:11:17 +00:00
self._progress = ClientGUICommon.TextAndGauge( self )
2014-01-01 20:01:00 +00:00
2017-02-01 21:11:17 +00:00
self._progress_pause = ClientGUICommon.BetterBitmapButton( self, CC.GlobalBMPs.pause, self.PauseProgress )
self._progress_pause.Disable()
2015-07-22 19:40:39 +00:00
2017-02-01 21:11:17 +00:00
self._progress_cancel = ClientGUICommon.BetterBitmapButton( self, CC.GlobalBMPs.stop, self.StopProgress )
self._progress_cancel.Disable()
2015-07-22 19:40:39 +00:00
2018-01-10 22:41:51 +00:00
file_import_options = HG.client_controller.new_options.GetDefaultFileImportOptions( 'loud' )
2018-10-03 21:00:15 +00:00
show_downloader_options = False
2017-09-13 20:50:41 +00:00
2018-10-03 21:00:15 +00:00
self._file_import_options = ClientGUIImport.FileImportOptionsButton( self, file_import_options, show_downloader_options )
2015-07-22 19:40:39 +00:00
2018-08-08 20:29:54 +00:00
menu_items = []
check_manager = ClientGUICommon.CheckboxManagerOptions( 'do_human_sort_on_hdd_file_import_paths' )
menu_items.append( ( 'check', 'sort paths as they are added', 'If checked, paths will be sorted in a numerically human-friendly (e.g. "page 9.jpg" comes before "page 10.jpg") way.', check_manager ) )
self._cog_button = ClientGUICommon.MenuBitmapButton( self, CC.GlobalBMPs.cog, menu_items )
2017-08-09 21:33:51 +00:00
self._delete_after_success_st = ClientGUICommon.BetterStaticText( self, style = wx.ALIGN_RIGHT | wx.ST_NO_AUTORESIZE )
self._delete_after_success_st.SetForegroundColour( ( 127, 0, 0 ) )
2016-06-29 19:55:46 +00:00
self._delete_after_success = wx.CheckBox( self, label = 'delete original files after successful import' )
2017-08-09 21:33:51 +00:00
self._delete_after_success.Bind( wx.EVT_CHECKBOX, self.EventDeleteAfterSuccessCheck )
2015-07-22 19:40:39 +00:00
2016-08-03 22:15:54 +00:00
self._add_button = wx.Button( self, label = 'import now' )
2015-07-22 19:40:39 +00:00
self._add_button.Bind( wx.EVT_BUTTON, self.EventOK )
self._add_button.SetForegroundColour( ( 0, 128, 0 ) )
2016-08-03 22:15:54 +00:00
self._tag_button = wx.Button( self, label = 'add tags based on filename' )
2015-07-22 19:40:39 +00:00
self._tag_button.Bind( wx.EVT_BUTTON, self.EventTags )
self._tag_button.SetForegroundColour( ( 0, 128, 0 ) )
2016-08-03 22:15:54 +00:00
self._cancel = wx.Button( self, id = wx.ID_CANCEL, label = 'cancel' )
2015-07-22 19:40:39 +00:00
self._cancel.Bind( wx.EVT_BUTTON, self.EventCancel )
self._cancel.SetForegroundColour( ( 128, 0, 0 ) )
gauge_sizer = wx.BoxSizer( wx.HORIZONTAL )
2018-01-03 22:37:30 +00:00
gauge_sizer.Add( self._progress, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
gauge_sizer.Add( self._progress_pause, CC.FLAGS_VCENTER )
gauge_sizer.Add( self._progress_cancel, CC.FLAGS_VCENTER )
2015-07-22 19:40:39 +00:00
2017-08-09 21:33:51 +00:00
delete_hbox = wx.BoxSizer( wx.HORIZONTAL )
2018-01-03 22:37:30 +00:00
delete_hbox.Add( self._delete_after_success_st, CC.FLAGS_EXPAND_BOTH_WAYS )
delete_hbox.Add( self._delete_after_success, CC.FLAGS_VCENTER )
2017-08-09 21:33:51 +00:00
2018-08-08 20:29:54 +00:00
import_options_buttons = wx.BoxSizer( wx.HORIZONTAL )
import_options_buttons.Add( self._file_import_options, CC.FLAGS_SIZER_VCENTER )
import_options_buttons.Add( self._cog_button, CC.FLAGS_SIZER_VCENTER )
2015-07-22 19:40:39 +00:00
buttons = wx.BoxSizer( wx.HORIZONTAL )
2018-01-03 22:37:30 +00:00
buttons.Add( self._add_button, CC.FLAGS_VCENTER )
buttons.Add( self._tag_button, CC.FLAGS_VCENTER )
buttons.Add( self._cancel, CC.FLAGS_VCENTER )
2015-07-22 19:40:39 +00:00
vbox = wx.BoxSizer( wx.VERTICAL )
2018-01-03 22:37:30 +00:00
vbox.Add( listctrl_panel, CC.FLAGS_EXPAND_BOTH_WAYS )
vbox.Add( gauge_sizer, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
vbox.Add( delete_hbox, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
2018-08-08 20:29:54 +00:00
vbox.Add( import_options_buttons, CC.FLAGS_LONE_BUTTON )
2018-01-03 22:37:30 +00:00
vbox.Add( buttons, CC.FLAGS_BUTTON_SIZER )
2015-07-22 19:40:39 +00:00
self.SetSizer( vbox )
( x, y ) = self.GetEffectiveMinSize()
if x < 780: x = 780
if y < 480: y = 480
self.SetInitialSize( ( x, y ) )
2014-01-01 20:01:00 +00:00
2017-02-01 21:11:17 +00:00
self._lock = threading.Lock()
2015-08-12 20:35:24 +00:00
self._current_paths = []
self._current_paths_set = set()
2014-03-12 22:08:23 +00:00
2016-02-17 22:06:47 +00:00
self._job_key = ClientThreading.JobKey()
2014-01-01 20:01:00 +00:00
2019-01-09 22:59:03 +00:00
self._unparsed_paths_queue = queue.Queue()
2018-01-24 23:09:42 +00:00
self._currently_parsing = threading.Event()
self._work_to_do = threading.Event()
2019-01-09 22:59:03 +00:00
self._parsed_path_queue = queue.Queue()
2018-01-24 23:09:42 +00:00
self._pause_event = threading.Event()
self._cancel_event = threading.Event()
2016-11-30 20:24:17 +00:00
2017-02-01 21:11:17 +00:00
self._progress_updater = ClientGUICommon.ThreadToGUIUpdater( self._progress, self._progress.SetValue )
2016-11-30 20:24:17 +00:00
2017-02-01 21:11:17 +00:00
if len( paths ) > 0:
self._AddPathsToList( paths )
2014-01-01 20:01:00 +00:00
2017-11-08 22:07:12 +00:00
self.Show()
2014-01-01 20:01:00 +00:00
2018-01-24 23:09:42 +00:00
HG.client_controller.gui.RegisterUIUpdateWindow( self )
2014-01-01 20:01:00 +00:00
2018-01-24 23:09:42 +00:00
HG.client_controller.CallToThreadLongRunning( self.THREADParseImportablePaths, self._unparsed_paths_queue, self._currently_parsing, self._work_to_do, self._parsed_path_queue, self._progress_updater, self._pause_event, self._cancel_event )
2014-01-01 20:01:00 +00:00
2018-01-24 23:09:42 +00:00
def _AddPathsToList( self, paths ):
2014-01-01 20:01:00 +00:00
2018-01-24 23:09:42 +00:00
if self._cancel_event.is_set():
2014-01-01 20:01:00 +00:00
2018-01-24 23:09:42 +00:00
message = 'Please wait for the cancel to clear.'
wx.MessageBox( message )
return
2014-01-01 20:01:00 +00:00
2018-01-24 23:09:42 +00:00
self._unparsed_paths_queue.put( paths )
2014-01-01 20:01:00 +00:00
2016-01-20 23:57:33 +00:00
def _TidyUp( self ):
2018-01-24 23:09:42 +00:00
self._pause_event.set()
2016-01-20 23:57:33 +00:00
2014-01-01 20:01:00 +00:00
2016-12-07 22:12:52 +00:00
def AddFolder( self ):
2014-01-01 20:01:00 +00:00
2016-11-30 20:24:17 +00:00
with wx.DirDialog( self, 'Select a folder to add.', style = wx.DD_DIR_MUST_EXIST ) as dlg:
2014-03-12 22:08:23 +00:00
2016-11-30 20:24:17 +00:00
if dlg.ShowModal() == wx.ID_OK:
2019-01-09 22:59:03 +00:00
path = dlg.GetPath()
2016-11-30 20:24:17 +00:00
self._AddPathsToList( ( path, ) )
2014-03-12 22:08:23 +00:00
2014-01-01 20:01:00 +00:00
2016-12-07 22:12:52 +00:00
def AddPaths( self ):
2014-01-01 20:01:00 +00:00
2014-02-19 22:37:23 +00:00
with wx.FileDialog( self, 'Select the files to add.', style = wx.FD_MULTIPLE ) as dlg:
2014-01-01 20:01:00 +00:00
if dlg.ShowModal() == wx.ID_OK:
2019-01-09 22:59:03 +00:00
paths = dlg.GetPaths()
2014-01-01 20:01:00 +00:00
self._AddPathsToList( paths )
def EventCancel( self, event ):
self._TidyUp()
2017-11-08 22:07:12 +00:00
self.Close()
2014-01-01 20:01:00 +00:00
2017-08-09 21:33:51 +00:00
def EventDeleteAfterSuccessCheck( self, event ):
if self._delete_after_success.GetValue():
self._delete_after_success_st.SetLabelText( 'YOUR ORIGINAL FILES WILL BE DELETED' )
else:
self._delete_after_success_st.SetLabelText( '' )
2014-01-01 20:01:00 +00:00
def EventOK( self, event ):
self._TidyUp()
2015-07-22 19:40:39 +00:00
if len( self._current_paths ) > 0:
2014-01-01 20:01:00 +00:00
2017-09-13 20:50:41 +00:00
file_import_options = self._file_import_options.GetValue()
2014-01-01 20:01:00 +00:00
2015-06-24 22:10:14 +00:00
paths_to_tags = {}
2014-01-01 20:01:00 +00:00
delete_after_success = self._delete_after_success.GetValue()
2017-09-13 20:50:41 +00:00
HG.client_controller.pub( 'new_hdd_import', self._current_paths, file_import_options, paths_to_tags, delete_after_success )
2014-01-01 20:01:00 +00:00
2017-11-08 22:07:12 +00:00
self.Close()
2015-07-22 19:40:39 +00:00
2014-01-01 20:01:00 +00:00
def EventTags( self, event ):
2015-07-22 19:40:39 +00:00
if len( self._current_paths ) > 0:
2014-01-01 20:01:00 +00:00
2017-09-13 20:50:41 +00:00
file_import_options = self._file_import_options.GetValue()
2014-01-01 20:01:00 +00:00
2017-11-22 21:03:07 +00:00
with ClientGUITopLevelWindows.DialogEdit( self, 'filename tagging', frame_key = 'local_import_filename_tagging' ) as dlg:
panel = ClientGUIImport.EditLocalImportFilenameTaggingPanel( dlg, self._current_paths )
dlg.SetPanel( panel )
2014-01-01 20:01:00 +00:00
2015-07-22 19:40:39 +00:00
if dlg.ShowModal() == wx.ID_OK:
2014-01-01 20:01:00 +00:00
2017-11-22 21:03:07 +00:00
paths_to_tags = panel.GetValue()
2014-01-01 20:01:00 +00:00
2015-07-22 19:40:39 +00:00
delete_after_success = self._delete_after_success.GetValue()
2014-01-01 20:01:00 +00:00
2017-09-13 20:50:41 +00:00
HG.client_controller.pub( 'new_hdd_import', self._current_paths, file_import_options, paths_to_tags, delete_after_success )
2014-01-01 20:01:00 +00:00
2017-11-08 22:07:12 +00:00
self.Close()
2014-01-01 20:01:00 +00:00
2017-02-01 21:11:17 +00:00
def PauseProgress( self ):
2018-01-24 23:09:42 +00:00
if self._pause_event.is_set():
2017-02-01 21:11:17 +00:00
2018-01-24 23:09:42 +00:00
self._pause_event.clear()
2017-02-01 21:11:17 +00:00
else:
2018-01-24 23:09:42 +00:00
self._pause_event.set()
2017-02-01 21:11:17 +00:00
2018-01-24 23:09:42 +00:00
def StopProgress( self ):
self._cancel_event.set()
2015-03-04 22:44:32 +00:00
def RemovePaths( self ):
2017-03-22 22:38:15 +00:00
with DialogYesNo( self, 'Remove all selected?' ) as dlg:
if dlg.ShowModal() == wx.ID_YES:
self._paths_list.RemoveAllSelected()
self._current_paths = [ row[0] for row in self._paths_list.GetClientData() ]
self._current_paths_set = set( self._current_paths )
2015-03-04 22:44:32 +00:00
2018-01-24 23:09:42 +00:00
def THREADParseImportablePaths( self, unparsed_paths_queue, currently_parsing, work_to_do, parsed_path_queue, progress_updater, pause_event, cancel_event ):
2014-01-01 20:01:00 +00:00
2018-06-20 20:20:22 +00:00
unparsed_paths = collections.deque()
2016-08-24 18:36:56 +00:00
2018-01-24 23:09:42 +00:00
num_files_done = 0
2014-01-01 20:01:00 +00:00
num_good_files = 0
2018-01-24 23:09:42 +00:00
2016-01-20 23:57:33 +00:00
num_empty_files = 0
2018-04-25 22:07:52 +00:00
num_unimportable_mime_files = 0
2018-01-24 23:09:42 +00:00
num_occupied_files = 0
2014-01-01 20:01:00 +00:00
2018-01-24 23:09:42 +00:00
while not HG.view_shutdown:
2014-01-01 20:01:00 +00:00
2018-01-24 23:09:42 +00:00
if not self:
2015-11-04 22:30:28 +00:00
2018-01-24 23:09:42 +00:00
return
2015-11-04 22:30:28 +00:00
2015-01-14 22:27:55 +00:00
2018-01-24 23:09:42 +00:00
if len( unparsed_paths ) > 0:
work_to_do.set()
else:
work_to_do.clear()
2014-01-01 20:01:00 +00:00
2018-01-24 23:09:42 +00:00
currently_parsing.clear()
2017-02-01 21:11:17 +00:00
2018-01-24 23:09:42 +00:00
# ready to start, let's update ui on status
2014-01-01 20:01:00 +00:00
2018-01-24 23:09:42 +00:00
total_paths = num_files_done + len( unparsed_paths )
2014-01-01 20:01:00 +00:00
2018-01-24 23:09:42 +00:00
if num_good_files == 0:
2015-07-01 22:02:07 +00:00
2018-01-24 23:09:42 +00:00
if num_files_done == 0:
message = 'waiting for paths to parse'
else:
2018-07-04 20:48:28 +00:00
message = 'none of the ' + HydrusData.ToHumanInt( total_paths ) + ' files parsed successfully'
2018-01-24 23:09:42 +00:00
else:
message = HydrusData.ConvertValueRangeToPrettyString( num_good_files, total_paths ) + ' files parsed successfully'
2015-07-01 22:02:07 +00:00
2014-01-01 20:01:00 +00:00
2018-04-25 22:07:52 +00:00
if num_empty_files > 0 or num_unimportable_mime_files > 0 or num_occupied_files > 0:
2014-01-01 20:01:00 +00:00
2018-01-24 23:09:42 +00:00
if num_good_files == 0:
message += ': '
else:
message += ', but '
2016-11-09 23:13:22 +00:00
2018-01-24 23:09:42 +00:00
bad_comments = []
2014-01-01 20:01:00 +00:00
2018-01-24 23:09:42 +00:00
if num_empty_files > 0:
2018-07-04 20:48:28 +00:00
bad_comments.append( HydrusData.ToHumanInt( num_empty_files ) + ' were empty' )
2018-01-24 23:09:42 +00:00
2018-04-25 22:07:52 +00:00
if num_unimportable_mime_files > 0:
2018-01-24 23:09:42 +00:00
2018-07-04 20:48:28 +00:00
bad_comments.append( HydrusData.ToHumanInt( num_unimportable_mime_files ) + ' had unsupported file types' )
2018-01-24 23:09:42 +00:00
if num_occupied_files > 0:
2018-09-26 19:05:12 +00:00
bad_comments.append( HydrusData.ToHumanInt( num_occupied_files ) + ' were inaccessible (maybe in use by another process)' )
2018-01-24 23:09:42 +00:00
message += ' and '.join( bad_comments )
2014-01-01 20:01:00 +00:00
2018-01-24 23:09:42 +00:00
message += '.'
2014-01-01 20:01:00 +00:00
2018-01-24 23:09:42 +00:00
progress_updater.Update( message, num_files_done, total_paths )
# status updated, lets see what work there is to do
if cancel_event.is_set():
2014-01-01 20:01:00 +00:00
2018-01-24 23:09:42 +00:00
while not unparsed_paths_queue.empty():
try:
unparsed_paths_queue.get( block = False )
2019-01-09 22:59:03 +00:00
except queue.Empty:
2018-01-24 23:09:42 +00:00
pass
2014-01-01 20:01:00 +00:00
2018-07-18 21:07:15 +00:00
unparsed_paths = collections.deque()
2017-02-01 21:11:17 +00:00
2018-01-24 23:09:42 +00:00
cancel_event.clear()
pause_event.clear()
2014-01-01 20:01:00 +00:00
2018-01-24 23:09:42 +00:00
continue
2014-01-01 20:01:00 +00:00
2018-01-24 23:09:42 +00:00
if pause_event.is_set():
2016-11-09 23:13:22 +00:00
2018-01-24 23:09:42 +00:00
time.sleep( 1 )
2014-01-01 20:01:00 +00:00
continue
2018-01-24 23:09:42 +00:00
# let's see if there is anything to parse
2014-01-01 20:01:00 +00:00
2018-01-24 23:09:42 +00:00
# first we'll flesh out unparsed_paths with anything new to look at
2014-01-01 20:01:00 +00:00
2018-08-08 20:29:54 +00:00
do_human_sort = HG.client_controller.new_options.GetBoolean( 'do_human_sort_on_hdd_file_import_paths' )
2018-01-24 23:09:42 +00:00
while not unparsed_paths_queue.empty():
try:
raw_paths = unparsed_paths_queue.get( block = False )
2018-08-08 20:29:54 +00:00
paths = ClientFiles.GetAllPaths( raw_paths, do_human_sort = do_human_sort ) # convert any dirs to subpaths
2018-01-24 23:09:42 +00:00
unparsed_paths.extend( paths )
2019-01-09 22:59:03 +00:00
except queue.Empty:
2018-01-24 23:09:42 +00:00
pass
2016-01-20 23:57:33 +00:00
2018-01-24 23:09:42 +00:00
# if unparsed_paths still has nothing, we'll nonetheless sleep on new paths
2014-01-01 20:01:00 +00:00
2018-01-24 23:09:42 +00:00
if len( unparsed_paths ) == 0:
try:
raw_paths = unparsed_paths_queue.get( timeout = 5 )
2018-08-08 20:29:54 +00:00
paths = ClientFiles.GetAllPaths( raw_paths, do_human_sort = do_human_sort ) # convert any dirs to subpaths
2018-01-24 23:09:42 +00:00
unparsed_paths.extend( paths )
2019-01-09 22:59:03 +00:00
except queue.Empty:
2018-01-24 23:09:42 +00:00
pass
continue # either we added some or didn't--in any case, restart the cycle
2014-01-01 20:01:00 +00:00
2018-06-20 20:20:22 +00:00
path = unparsed_paths.popleft()
2014-01-01 20:01:00 +00:00
2018-01-24 23:09:42 +00:00
currently_parsing.set()
2016-01-20 23:57:33 +00:00
2018-01-24 23:09:42 +00:00
# we are now dealing with a file. let's clear out quick no-gos
num_files_done += 1
if path.endswith( os.path.sep + 'Thumbs.db' ) or path.endswith( os.path.sep + 'thumbs.db' ):
2018-04-25 22:07:52 +00:00
num_unimportable_mime_files += 1
2016-01-20 23:57:33 +00:00
2018-01-24 23:09:42 +00:00
continue
2016-01-20 23:57:33 +00:00
2018-01-24 23:09:42 +00:00
if not HydrusPaths.PathIsFree( path ):
2016-01-20 23:57:33 +00:00
2018-01-24 23:09:42 +00:00
num_occupied_files += 1
continue
2016-01-20 23:57:33 +00:00
2018-01-24 23:09:42 +00:00
size = os.path.getsize( path )
2016-01-20 23:57:33 +00:00
2018-01-24 23:09:42 +00:00
if size == 0:
2016-01-20 23:57:33 +00:00
2018-01-24 23:09:42 +00:00
HydrusData.Print( 'Empty file: ' + path )
2016-01-20 23:57:33 +00:00
2018-01-24 23:09:42 +00:00
num_empty_files += 1
2016-01-20 23:57:33 +00:00
2018-01-24 23:09:42 +00:00
continue
2016-01-20 23:57:33 +00:00
2018-01-24 23:09:42 +00:00
# looks good, let's burn some CPU
mime = HydrusFileHandling.GetMime( path )
if mime in HC.ALLOWED_MIMES:
2016-08-24 18:36:56 +00:00
2018-01-24 23:09:42 +00:00
num_good_files += 1
parsed_path_queue.put( ( path, mime, size ) )
else:
2016-08-24 18:36:56 +00:00
2018-01-24 23:09:42 +00:00
HydrusData.Print( 'Unparsable file: ' + path )
2018-04-25 22:07:52 +00:00
num_unimportable_mime_files += 1
2018-01-24 23:09:42 +00:00
def TIMERUIUpdate( self ):
while not self._parsed_path_queue.empty():
2016-08-24 18:36:56 +00:00
2018-01-24 23:09:42 +00:00
( path, mime, size ) = self._parsed_path_queue.get()
pretty_mime = HC.mime_string_lookup[ mime ]
2019-01-09 22:59:03 +00:00
pretty_size = HydrusData.ToHumanBytes( size )
2018-01-24 23:09:42 +00:00
if path not in self._current_paths_set:
self._current_paths_set.add( path )
self._current_paths.append( path )
self._paths_list.Append( ( path, pretty_mime, pretty_size ), ( path, mime, size ) )
2016-01-20 23:57:33 +00:00
2018-01-24 23:09:42 +00:00
#
paused = self._pause_event.is_set()
no_work_in_queue = not self._work_to_do.is_set()
working_on_a_file_now = self._currently_parsing.is_set()
2014-01-01 20:01:00 +00:00
2018-01-24 23:09:42 +00:00
can_import = ( no_work_in_queue or paused ) and not working_on_a_file_now
2016-01-20 23:57:33 +00:00
2018-01-24 23:09:42 +00:00
if no_work_in_queue:
self._progress_pause.Disable()
self._progress_cancel.Disable()
else:
self._progress_pause.Enable()
self._progress_cancel.Enable()
if can_import:
self._add_button.Enable()
self._tag_button.Enable()
else:
self._add_button.Disable()
self._tag_button.Disable()
2017-02-01 21:11:17 +00:00
2018-01-24 23:09:42 +00:00
if paused:
ClientGUICommon.SetBitmapButtonBitmap( self._progress_pause, CC.GlobalBMPs.play )
else:
ClientGUICommon.SetBitmapButtonBitmap( self._progress_pause, CC.GlobalBMPs.pause )
2014-01-01 20:01:00 +00:00
2013-07-31 21:26:38 +00:00
class DialogInputNamespaceRegex( Dialog ):
def __init__( self, parent, namespace = '', regex = '' ):
2015-10-14 21:02:25 +00:00
Dialog.__init__( self, parent, 'configure quick namespace' )
2013-07-31 21:26:38 +00:00
2015-10-14 21:02:25 +00:00
self._namespace = wx.TextCtrl( self )
2013-07-31 21:26:38 +00:00
2015-10-14 21:02:25 +00:00
self._regex = wx.TextCtrl( self )
self._shortcuts = ClientGUICommon.RegexButton( self )
2018-08-29 20:20:41 +00:00
self._regex_intro_link = ClientGUICommon.BetterHyperLink( self, 'a good regex introduction', 'http://www.aivosto.com/vbtips/regex.html' )
self._regex_practise_link = ClientGUICommon.BetterHyperLink( self, 'regex practise', 'http://regexr.com/3cvmf' )
2015-10-14 21:02:25 +00:00
2017-06-07 22:05:15 +00:00
self._ok = wx.Button( self, id = wx.ID_OK, label = 'OK' )
2015-10-14 21:02:25 +00:00
self._ok.Bind( wx.EVT_BUTTON, self.EventOK )
self._ok.SetForegroundColour( ( 0, 128, 0 ) )
self._cancel = wx.Button( self, id = wx.ID_CANCEL, label = 'Cancel' )
self._cancel.SetForegroundColour( ( 128, 0, 0 ) )
#
self._namespace.SetValue( namespace )
self._regex.SetValue( regex )
#
control_box = wx.BoxSizer( wx.HORIZONTAL )
2018-01-03 22:37:30 +00:00
control_box.Add( self._namespace, CC.FLAGS_EXPAND_BOTH_WAYS )
control_box.Add( ClientGUICommon.BetterStaticText( self, ':' ), CC.FLAGS_VCENTER )
control_box.Add( self._regex, CC.FLAGS_EXPAND_BOTH_WAYS )
2015-10-14 21:02:25 +00:00
b_box = wx.BoxSizer( wx.HORIZONTAL )
2018-01-03 22:37:30 +00:00
b_box.Add( self._ok, CC.FLAGS_VCENTER )
b_box.Add( self._cancel, CC.FLAGS_VCENTER )
2015-10-14 21:02:25 +00:00
vbox = wx.BoxSizer( wx.VERTICAL )
2017-03-15 20:13:04 +00:00
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".'
2015-10-14 21:02:25 +00:00
2018-01-03 22:37:30 +00:00
vbox.Add( ClientGUICommon.BetterStaticText( self, intro ), CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.Add( control_box, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
vbox.Add( self._shortcuts, CC.FLAGS_LONE_BUTTON )
vbox.Add( self._regex_intro_link, CC.FLAGS_LONE_BUTTON )
vbox.Add( self._regex_practise_link, CC.FLAGS_LONE_BUTTON )
vbox.Add( b_box, CC.FLAGS_BUTTON_SIZER )
2015-10-14 21:02:25 +00:00
self.SetSizer( vbox )
( x, y ) = self.GetEffectiveMinSize()
self.SetInitialSize( ( x, y ) )
wx.CallAfter( self._ok.SetFocus )
def EventOK( self, event ):
( namespace, regex ) = self.GetInfo()
if namespace == '':
2013-07-31 21:26:38 +00:00
2015-10-14 21:02:25 +00:00
wx.MessageBox( 'Please enter something for the namespace.' )
2013-07-31 21:26:38 +00:00
2015-10-14 21:02:25 +00:00
return
2013-07-31 21:26:38 +00:00
2015-10-14 21:02:25 +00:00
try:
2013-07-31 21:26:38 +00:00
2019-01-09 22:59:03 +00:00
re.compile( regex )
2014-03-12 22:08:23 +00:00
2015-10-14 21:02:25 +00:00
except Exception as e:
2013-07-31 21:26:38 +00:00
2015-10-14 21:02:25 +00:00
text = 'That regex would not compile!'
text += os.linesep * 2
2019-01-09 22:59:03 +00:00
text += str( e )
2013-07-31 21:26:38 +00:00
2015-10-14 21:02:25 +00:00
wx.MessageBox( text )
2013-07-31 21:26:38 +00:00
2015-10-14 21:02:25 +00:00
return
2013-07-31 21:26:38 +00:00
2015-10-14 21:02:25 +00:00
self.EndModal( wx.ID_OK )
2013-07-31 21:26:38 +00:00
def GetInfo( self ):
namespace = self._namespace.GetValue()
regex = self._regex.GetValue()
return ( namespace, regex )
class DialogInputNewFormField( Dialog ):
def __init__( self, parent, form_field = None ):
Dialog.__init__( self, parent, 'configure form field' )
2013-07-24 20:26:00 +00:00
2014-09-10 22:37:38 +00:00
if form_field is None: ( name, field_type, default, editable ) = ( '', CC.FIELD_TEXT, '', True )
else: ( name, field_type, default, editable ) = form_field
2013-07-31 21:26:38 +00:00
2015-12-09 23:16:41 +00:00
self._name = wx.TextCtrl( self )
self._type = wx.Choice( self )
self._default = wx.TextCtrl( self )
self._editable = wx.CheckBox( self )
2013-07-31 21:26:38 +00:00
2017-06-07 22:05:15 +00:00
self._ok = wx.Button( self, id = wx.ID_OK, label = 'OK' )
2015-12-09 23:16:41 +00:00
self._ok.SetForegroundColour( ( 0, 128, 0 ) )
self._cancel = wx.Button( self, id = wx.ID_CANCEL, label = 'Cancel' )
self._cancel.SetForegroundColour( ( 128, 0, 0 ) )
#
self._name.SetValue( name )
for temp_type in CC.FIELDS: self._type.Append( CC.field_string_lookup[ temp_type ], temp_type )
self._type.Select( field_type )
self._default.SetValue( default )
self._editable.SetValue( editable )
#
2017-04-19 20:58:30 +00:00
rows = []
2016-02-24 21:42:54 +00:00
2017-04-19 20:58:30 +00:00
rows.append( ( 'name: ', self._name ) )
rows.append( ( 'type: ', self._type ) )
rows.append( ( 'default: ', self._default ) )
rows.append( ( 'editable: ', self._editable ) )
2016-02-24 21:42:54 +00:00
2017-04-19 20:58:30 +00:00
gridbox = ClientGUICommon.WrapInGrid( self, rows )
2016-02-24 21:42:54 +00:00
b_box = wx.BoxSizer( wx.HORIZONTAL )
2017-04-19 20:58:30 +00:00
2018-01-03 22:37:30 +00:00
b_box.Add( self._ok, CC.FLAGS_VCENTER )
b_box.Add( self._cancel, CC.FLAGS_VCENTER )
2016-02-24 21:42:54 +00:00
vbox = wx.BoxSizer( wx.VERTICAL )
2018-01-03 22:37:30 +00:00
vbox.Add( gridbox, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
vbox.Add( b_box, CC.FLAGS_BUTTON_SIZER )
2016-02-24 21:42:54 +00:00
self.SetSizer( vbox )
( x, y ) = self.GetEffectiveMinSize()
self.SetInitialSize( ( x, y ) )
2013-07-31 21:26:38 +00:00
wx.CallAfter( self._ok.SetFocus )
2013-07-24 20:26:00 +00:00
2017-04-19 20:58:30 +00:00
def GetFormField( self ):
2013-07-24 20:26:00 +00:00
2017-04-19 20:58:30 +00:00
name = self._name.GetValue()
2017-04-12 21:46:46 +00:00
2017-04-19 20:58:30 +00:00
field_type = self._type.GetClientData( self._type.GetSelection() )
2017-04-12 21:46:46 +00:00
2017-04-19 20:58:30 +00:00
default = self._default.GetValue()
2017-04-12 21:46:46 +00:00
2017-04-19 20:58:30 +00:00
editable = self._editable.GetValue()
2013-07-24 20:26:00 +00:00
2017-04-19 20:58:30 +00:00
return ( name, field_type, default, editable )
2013-07-24 20:26:00 +00:00
2013-02-19 00:11:43 +00:00
2015-10-21 21:53:10 +00:00
class DialogInputTags( Dialog ):
2018-04-11 22:30:40 +00:00
def __init__( self, parent, service_key, tags, message = '' ):
2015-10-21 21:53:10 +00:00
Dialog.__init__( self, parent, 'input tags' )
2016-05-25 21:54:03 +00:00
self._service_key = service_key
2017-02-01 21:11:17 +00:00
self._tags = ClientGUIListBoxes.ListBoxTagsStringsAddRemove( self, service_key = service_key )
2015-10-21 21:53:10 +00:00
2015-10-28 21:29:05 +00:00
expand_parents = True
2017-06-07 22:05:15 +00:00
self._tag_box = ClientGUIACDropdown.AutoCompleteDropdownTagsWrite( self, self.EnterTags, expand_parents, CC.LOCAL_FILE_SERVICE_KEY, service_key, null_entry_callable = self.OK )
2015-10-21 21:53:10 +00:00
2017-06-07 22:05:15 +00:00
self._ok = wx.Button( self, id= wx.ID_OK, label = 'OK' )
2015-10-21 21:53:10 +00:00
self._ok.SetForegroundColour( ( 0, 128, 0 ) )
self._cancel = wx.Button( self, id = wx.ID_CANCEL, label = 'Cancel' )
self._cancel.SetForegroundColour( ( 128, 0, 0 ) )
#
self._tags.SetTags( tags )
#
b_box = wx.BoxSizer( wx.HORIZONTAL )
2018-01-03 22:37:30 +00:00
b_box.Add( self._ok, CC.FLAGS_VCENTER )
b_box.Add( self._cancel, CC.FLAGS_VCENTER )
2015-10-21 21:53:10 +00:00
vbox = wx.BoxSizer( wx.VERTICAL )
2018-04-11 22:30:40 +00:00
if message != '':
vbox.Add( ClientGUICommon.BetterStaticText( self, message ), CC.FLAGS_EXPAND_PERPENDICULAR )
2018-01-03 22:37:30 +00:00
vbox.Add( self._tags, CC.FLAGS_EXPAND_BOTH_WAYS )
vbox.Add( self._tag_box, CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.Add( b_box, CC.FLAGS_BUTTON_SIZER )
2015-10-21 21:53:10 +00:00
self.SetSizer( vbox )
( x, y ) = self.GetEffectiveMinSize()
x = max( x, 300 )
self.SetInitialSize( ( x, y ) )
wx.CallAfter( self._tag_box.SetFocus )
2016-05-25 21:54:03 +00:00
def EnterTags( self, tags ):
2017-05-10 21:33:58 +00:00
tag_parents_manager = HG.client_controller.GetManager( 'tag_parents' )
2016-05-25 21:54:03 +00:00
parents = set()
2015-10-21 21:53:10 +00:00
2016-05-25 21:54:03 +00:00
for tag in tags:
2015-10-21 21:53:10 +00:00
2016-05-25 21:54:03 +00:00
some_parents = tag_parents_manager.GetParents( self._service_key, tag )
parents.update( some_parents )
2015-10-21 21:53:10 +00:00
2015-10-28 21:29:05 +00:00
if len( tags ) > 0:
2015-10-21 21:53:10 +00:00
2015-10-28 21:29:05 +00:00
self._tags.EnterTags( tags )
self._tags.AddTags( parents )
2015-10-21 21:53:10 +00:00
def GetTags( self ):
return self._tags.GetTags()
2017-06-07 22:05:15 +00:00
def OK( self ):
2015-10-28 21:29:05 +00:00
self.EndModal( wx.ID_OK )
2013-09-25 20:20:10 +00:00
class DialogInputUPnPMapping( Dialog ):
2014-04-23 20:56:12 +00:00
def __init__( self, parent, external_port, protocol_type, internal_port, description, duration ):
2013-09-25 20:20:10 +00:00
2016-06-01 20:04:15 +00:00
Dialog.__init__( self, parent, 'configure upnp mapping' )
2013-09-25 20:20:10 +00:00
2016-06-01 20:04:15 +00:00
self._external_port = wx.SpinCtrl( self, min = 0, max = 65535 )
2013-09-25 20:20:10 +00:00
2016-06-01 20:04:15 +00:00
self._protocol_type = ClientGUICommon.BetterChoice( self )
self._protocol_type.Append( 'TCP', 'TCP' )
self._protocol_type.Append( 'UDP', 'UDP' )
2013-09-25 20:20:10 +00:00
2016-06-01 20:04:15 +00:00
self._internal_port = wx.SpinCtrl( self, min = 0, max = 65535 )
self._description = wx.TextCtrl( self )
self._duration = wx.SpinCtrl( self, min = 0, max = 86400 )
2013-09-25 20:20:10 +00:00
2017-06-07 22:05:15 +00:00
self._ok = wx.Button( self, id = wx.ID_OK, label = 'OK' )
2016-06-01 20:04:15 +00:00
self._ok.SetForegroundColour( ( 0, 128, 0 ) )
2013-09-25 20:20:10 +00:00
2016-06-01 20:04:15 +00:00
self._cancel = wx.Button( self, id = wx.ID_CANCEL, label = 'Cancel' )
self._cancel.SetForegroundColour( ( 128, 0, 0 ) )
#
self._external_port.SetValue( external_port )
if protocol_type == 'TCP': self._protocol_type.Select( 0 )
elif protocol_type == 'UDP': self._protocol_type.Select( 1 )
self._internal_port.SetValue( internal_port )
self._description.SetValue( description )
self._duration.SetValue( duration )
#
2016-08-31 19:55:14 +00:00
rows = []
2016-06-01 20:04:15 +00:00
2016-08-31 19:55:14 +00:00
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 ) )
2016-06-01 20:04:15 +00:00
2016-08-31 19:55:14 +00:00
gridbox = ClientGUICommon.WrapInGrid( self, rows )
2016-06-01 20:04:15 +00:00
b_box = wx.BoxSizer( wx.HORIZONTAL )
2018-01-03 22:37:30 +00:00
b_box.Add( self._ok, CC.FLAGS_VCENTER )
b_box.Add( self._cancel, CC.FLAGS_VCENTER )
2016-06-01 20:04:15 +00:00
vbox = wx.BoxSizer( wx.VERTICAL )
2018-01-03 22:37:30 +00:00
vbox.Add( gridbox, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
vbox.Add( b_box, CC.FLAGS_BUTTON_SIZER )
2016-06-01 20:04:15 +00:00
self.SetSizer( vbox )
( x, y ) = self.GetEffectiveMinSize()
self.SetInitialSize( ( x, y ) )
2013-09-25 20:20:10 +00:00
wx.CallAfter( self._ok.SetFocus )
def GetInfo( self ):
external_port = self._external_port.GetValue()
protocol_type = self._protocol_type.GetChoice()
internal_port = self._internal_port.GetValue()
description = self._description.GetValue()
2014-04-23 20:56:12 +00:00
duration = self._duration.GetValue()
2013-09-25 20:20:10 +00:00
2014-04-23 20:56:12 +00:00
return ( external_port, protocol_type, internal_port, description, duration )
2013-09-25 20:20:10 +00:00
2013-02-19 00:11:43 +00:00
class DialogModifyAccounts( Dialog ):
2014-08-27 22:15:22 +00:00
def __init__( self, parent, service_key, subject_identifiers ):
2013-02-19 00:11:43 +00:00
2016-06-01 20:04:15 +00:00
Dialog.__init__( self, parent, 'modify account' )
2013-02-19 00:11:43 +00:00
2017-06-28 20:23:21 +00:00
self._service = HG.client_controller.services_manager.GetService( service_key )
2016-06-01 20:04:15 +00:00
self._subject_identifiers = list( subject_identifiers )
#
self._account_info_panel = ClientGUICommon.StaticBox( self, 'account info' )
self._subject_text = wx.StaticText( self._account_info_panel )
#
self._account_types_panel = ClientGUICommon.StaticBox( self, 'account types' )
self._account_types = wx.Choice( self._account_types_panel )
2017-06-07 22:05:15 +00:00
self._account_types_ok = wx.Button( self._account_types_panel, label = 'OK' )
2016-06-01 20:04:15 +00:00
self._account_types_ok.Bind( wx.EVT_BUTTON, self.EventChangeAccountType )
#
self._expiration_panel = ClientGUICommon.StaticBox( self, 'change expiration' )
self._add_to_expires = wx.Choice( self._expiration_panel )
2017-06-07 22:05:15 +00:00
self._add_to_expires_ok = wx.Button( self._expiration_panel, label = 'OK' )
2016-06-01 20:04:15 +00:00
self._add_to_expires_ok.Bind( wx.EVT_BUTTON, self.EventAddToExpires )
self._set_expires = wx.Choice( self._expiration_panel )
2017-06-07 22:05:15 +00:00
self._set_expires_ok = wx.Button( self._expiration_panel, label = 'OK' )
2016-06-01 20:04:15 +00:00
self._set_expires_ok.Bind( wx.EVT_BUTTON, self.EventSetExpires )
#
self._ban_panel = ClientGUICommon.StaticBox( self, 'bans' )
self._ban = wx.Button( self._ban_panel, label = 'ban user' )
self._ban.Bind( wx.EVT_BUTTON, self.EventBan )
self._ban.SetBackgroundColour( ( 255, 0, 0 ) )
self._ban.SetForegroundColour( ( 255, 255, 0 ) )
self._superban = wx.Button( self._ban_panel, label = 'ban user and delete every contribution they have ever made' )
self._superban.Bind( wx.EVT_BUTTON, self.EventSuperban )
self._superban.SetBackgroundColour( ( 255, 0, 0 ) )
self._superban.SetForegroundColour( ( 255, 255, 0 ) )
self._exit = wx.Button( self, id = wx.ID_CANCEL, label = 'Exit' )
#
if len( self._subject_identifiers ) == 1:
2013-02-19 00:11:43 +00:00
2016-06-01 20:04:15 +00:00
( subject_identifier, ) = self._subject_identifiers
2013-02-19 00:11:43 +00:00
2016-06-01 20:04:15 +00:00
response = self._service.Request( HC.GET, 'account_info', { 'subject_identifier' : subject_identifier } )
2013-02-19 00:11:43 +00:00
2019-01-09 22:59:03 +00:00
subject_string = str( response[ 'account_info' ] )
else:
subject_string = 'modifying ' + HydrusData.ToHumanInt( len( self._subject_identifiers ) ) + ' accounts'
2013-02-19 00:11:43 +00:00
2016-06-01 20:04:15 +00:00
self._subject_text.SetLabelText( subject_string )
#
response = self._service.Request( HC.GET, 'account_types' )
account_types = response[ 'account_types' ]
for account_type in account_types: self._account_types.Append( account_type.ConvertToString(), account_type )
self._account_types.SetSelection( 0 )
#
for ( string, value ) in HC.lifetimes:
2013-02-19 00:11:43 +00:00
2017-03-02 02:14:56 +00:00
if value is not None:
self._add_to_expires.Append( string, value ) # don't want 'add no limit'
2013-02-19 00:11:43 +00:00
2016-06-01 20:04:15 +00:00
self._add_to_expires.SetSelection( 1 ) # three months
for ( string, value ) in HC.lifetimes: self._set_expires.Append( string, value )
self._set_expires.SetSelection( 1 ) # three months
#
2013-02-19 00:11:43 +00:00
2018-01-03 22:37:30 +00:00
self._account_info_panel.Add( self._subject_text, CC.FLAGS_EXPAND_PERPENDICULAR )
2013-02-19 00:11:43 +00:00
2016-06-01 20:04:15 +00:00
account_types_hbox = wx.BoxSizer( wx.HORIZONTAL )
2013-02-19 00:11:43 +00:00
2018-01-03 22:37:30 +00:00
account_types_hbox.Add( self._account_types, CC.FLAGS_VCENTER )
account_types_hbox.Add( self._account_types_ok, CC.FLAGS_VCENTER )
2013-07-31 21:26:38 +00:00
2018-01-03 22:37:30 +00:00
self._account_types_panel.Add( account_types_hbox, CC.FLAGS_EXPAND_PERPENDICULAR )
2016-06-01 20:04:15 +00:00
add_to_expires_box = wx.BoxSizer( wx.HORIZONTAL )
2018-01-03 22:37:30 +00:00
add_to_expires_box.Add( wx.StaticText( self._expiration_panel, label = 'add to expires: ' ), CC.FLAGS_VCENTER )
add_to_expires_box.Add( self._add_to_expires, CC.FLAGS_EXPAND_BOTH_WAYS )
add_to_expires_box.Add( self._add_to_expires_ok, CC.FLAGS_VCENTER )
2016-06-01 20:04:15 +00:00
set_expires_box = wx.BoxSizer( wx.HORIZONTAL )
2018-01-03 22:37:30 +00:00
set_expires_box.Add( wx.StaticText( self._expiration_panel, label = 'set expires to: ' ), CC.FLAGS_VCENTER )
set_expires_box.Add( self._set_expires, CC.FLAGS_EXPAND_BOTH_WAYS )
set_expires_box.Add( self._set_expires_ok, CC.FLAGS_VCENTER )
2016-06-01 20:04:15 +00:00
2018-01-03 22:37:30 +00:00
self._expiration_panel.Add( add_to_expires_box, CC.FLAGS_EXPAND_PERPENDICULAR )
self._expiration_panel.Add( set_expires_box, CC.FLAGS_EXPAND_PERPENDICULAR )
2016-06-01 20:04:15 +00:00
2018-01-03 22:37:30 +00:00
self._ban_panel.Add( self._ban, CC.FLAGS_EXPAND_PERPENDICULAR )
self._ban_panel.Add( self._superban, CC.FLAGS_EXPAND_PERPENDICULAR )
2016-06-01 20:04:15 +00:00
vbox = wx.BoxSizer( wx.VERTICAL )
2018-01-03 22:37:30 +00:00
vbox.Add( self._account_info_panel, CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.Add( self._account_types_panel, CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.Add( self._expiration_panel, CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.Add( self._ban_panel, CC.FLAGS_EXPAND_PERPENDICULAR )
vbox.Add( self._exit, CC.FLAGS_BUTTON_SIZER )
2016-06-01 20:04:15 +00:00
self.SetSizer( vbox )
( x, y ) = self.GetEffectiveMinSize()
self.SetInitialSize( ( x, y ) )
2013-07-31 21:26:38 +00:00
wx.CallAfter( self._exit.SetFocus )
2013-02-19 00:11:43 +00:00
2017-03-02 02:14:56 +00:00
def _DoModification( self ):
2015-10-14 21:02:25 +00:00
2017-03-02 02:14:56 +00:00
# change this to saveaccounts or whatever. the previous func changes the accounts, and then we push that change
2018-07-18 21:07:15 +00:00
# generate accounts, with the modification having occurred
2013-08-14 20:21:49 +00:00
2017-03-02 02:14:56 +00:00
self._service.Request( HC.POST, 'account', { 'accounts' : self._accounts } )
2013-08-14 20:21:49 +00:00
if len( self._subject_identifiers ) == 1:
2013-02-19 00:11:43 +00:00
2013-08-14 20:21:49 +00:00
( subject_identifier, ) = self._subject_identifiers
2013-02-19 00:11:43 +00:00
2014-01-29 21:59:42 +00:00
response = self._service.Request( HC.GET, 'account_info', { 'subject_identifier' : subject_identifier } )
2013-10-02 22:06:06 +00:00
account_info = response[ 'account_info' ]
2019-01-09 22:59:03 +00:00
self._subject_text.SetLabelText( str( account_info ) )
2013-02-19 00:11:43 +00:00
if len( self._subject_identifiers ) > 1: wx.MessageBox( 'Done!' )
2017-03-02 02:14:56 +00:00
def EventAddToExpires( self, event ):
2018-05-09 20:23:00 +00:00
raise NotImplementedError()
#self._DoModification( HC.ADD_TO_EXPIRES, timespan = self._add_to_expires.GetClientData( self._add_to_expires.GetSelection() ) )
2017-03-02 02:14:56 +00:00
2013-02-19 00:11:43 +00:00
def EventBan( self, event ):
2014-09-24 21:50:07 +00:00
with DialogTextEntry( self, 'Enter reason for the ban.' ) as dlg:
2013-02-19 00:11:43 +00:00
2018-05-09 20:23:00 +00:00
if dlg.ShowModal() == wx.ID_OK:
raise NotImplementedError()
#self._DoModification( HC.BAN, reason = dlg.GetValue() )
2013-02-19 00:11:43 +00:00
2017-03-02 02:14:56 +00:00
def EventChangeAccountType( self, event ):
2018-05-09 20:23:00 +00:00
raise NotImplementedError()
#self._DoModification( HC.CHANGE_ACCOUNT_TYPE, account_type_key = self._account_types.GetChoice() )
2017-03-02 02:14:56 +00:00
2013-02-19 00:11:43 +00:00
2014-10-01 22:58:32 +00:00
def EventSetExpires( self, event ):
2013-07-24 20:26:00 +00:00
2014-10-01 22:58:32 +00:00
expires = self._set_expires.GetClientData( self._set_expires.GetSelection() )
2013-07-24 20:26:00 +00:00
2018-05-09 20:23:00 +00:00
if expires is not None:
expires += HydrusData.GetNow()
2013-07-24 20:26:00 +00:00
2018-05-09 20:23:00 +00:00
raise NotImplementedError()
#self._DoModification( HC.SET_EXPIRES, expires = expires )
2013-07-24 20:26:00 +00:00
2013-02-19 00:11:43 +00:00
def EventSuperban( self, event ):
2014-09-24 21:50:07 +00:00
with DialogTextEntry( self, 'Enter reason for the superban.' ) as dlg:
2013-02-19 00:11:43 +00:00
2018-05-09 20:23:00 +00:00
if dlg.ShowModal() == wx.ID_OK:
raise NotImplementedError()
#self._DoModification( HC.SUPERBAN, reason = dlg.GetValue() )
2013-02-19 00:11:43 +00:00
2016-03-23 19:42:56 +00:00
class DialogSelectFromURLTree( Dialog ):
2013-02-19 00:11:43 +00:00
2016-03-23 19:42:56 +00:00
def __init__( self, parent, url_tree ):
2013-02-19 00:11:43 +00:00
2016-03-23 19:42:56 +00:00
Dialog.__init__( self, parent, 'select items' )
agwStyle = wx.lib.agw.customtreectrl.TR_DEFAULT_STYLE | wx.lib.agw.customtreectrl.TR_AUTO_CHECK_CHILD
self._tree = wx.lib.agw.customtreectrl.CustomTreeCtrl( self, agwStyle = agwStyle )
self._ok = wx.Button( self, id = wx.ID_OK )
self._ok.SetForegroundColour( ( 0, 128, 0 ) )
self._cancel = wx.Button( self, id = wx.ID_CANCEL )
self._cancel.SetForegroundColour( ( 128, 0, 0 ) )
#
( text_gumpf, name, size, children ) = url_tree
root_name = self._RenderItemName( name, size )
root_item = self._tree.AddRoot( root_name, ct_type = 1 )
self._AddDirectory( root_item, children )
self._tree.CheckItem( root_item )
self._tree.Expand( root_item )
#
button_hbox = wx.BoxSizer( wx.HORIZONTAL )
2018-01-03 22:37:30 +00:00
button_hbox.Add( self._ok, CC.FLAGS_VCENTER )
button_hbox.Add( self._cancel, CC.FLAGS_VCENTER )
2016-03-23 19:42:56 +00:00
vbox = wx.BoxSizer( wx.VERTICAL )
2018-01-03 22:37:30 +00:00
vbox.Add( self._tree, CC.FLAGS_EXPAND_BOTH_WAYS )
vbox.Add( button_hbox, CC.FLAGS_BUTTON_SIZER )
2016-03-23 19:42:56 +00:00
self.SetSizer( vbox )
( x, y ) = self.GetEffectiveMinSize()
2016-05-25 21:54:03 +00:00
x = max( x, 640 )
2016-03-23 19:42:56 +00:00
y = max( y, 640 )
self.SetInitialSize( ( x, y ) )
def _AddDirectory( self, root, children ):
for ( child_type, name, size, data ) in children:
2013-02-19 00:11:43 +00:00
2016-03-23 19:42:56 +00:00
item_name = self._RenderItemName( name, size )
2014-02-19 22:37:23 +00:00
2016-03-23 19:42:56 +00:00
if child_type == 'file':
self._tree.AppendItem( root, item_name, ct_type = 1, data = data )
else:
subroot = self._tree.AppendItem( root, item_name, ct_type = 1 )
self._AddDirectory( subroot, data )
2013-02-19 00:11:43 +00:00
2013-07-31 21:26:38 +00:00
2016-03-23 19:42:56 +00:00
def _GetSelectedChildrenData( self, parent_item ):
result = []
cookie = 0
( child_item, cookie ) = self._tree.GetNextChild( parent_item, cookie )
while child_item is not None:
2013-02-19 00:11:43 +00:00
2016-03-23 19:42:56 +00:00
data = self._tree.GetItemPyData( child_item )
2013-02-19 00:11:43 +00:00
2016-03-23 19:42:56 +00:00
if data is None:
2013-02-19 00:11:43 +00:00
2016-03-23 19:42:56 +00:00
result.extend( self._GetSelectedChildrenData( child_item ) )
2013-02-19 00:11:43 +00:00
2016-03-23 19:42:56 +00:00
else:
if self._tree.IsItemChecked( child_item ):
2013-02-19 00:11:43 +00:00
2016-03-23 19:42:56 +00:00
result.append( data )
2013-02-19 00:11:43 +00:00
2016-03-23 19:42:56 +00:00
( child_item, cookie ) = self._tree.GetNextChild( parent_item, cookie )
2013-02-19 00:11:43 +00:00
2016-03-23 19:42:56 +00:00
return result
def _RenderItemName( self, name, size ):
2019-01-09 22:59:03 +00:00
return name + ' - ' + HydrusData.ToHumanBytes( size )
2016-03-23 19:42:56 +00:00
def GetURLs( self ):
root_item = self._tree.GetRootItem()
urls = self._GetSelectedChildrenData( root_item )
return urls
class DialogSelectImageboard( Dialog ):
def __init__( self, parent ):
Dialog.__init__( self, parent, 'select imageboard' )
self._hidden_cancel = wx.Button( self, id = wx.ID_CANCEL, size = ( 0, 0 ) )
self._tree = wx.TreeCtrl( self )
self._tree.Bind( wx.EVT_TREE_ITEM_ACTIVATED, self.EventActivate )
#
2017-05-10 21:33:58 +00:00
all_imageboards = HG.client_controller.Read( 'imageboards' )
2016-03-23 19:42:56 +00:00
root_item = self._tree.AddRoot( 'all sites' )
2019-01-09 22:59:03 +00:00
for ( site, imageboards ) in list(all_imageboards.items()):
2013-02-19 00:11:43 +00:00
2016-03-23 19:42:56 +00:00
site_item = self._tree.AppendItem( root_item, site )
2013-02-19 00:11:43 +00:00
2016-03-23 19:42:56 +00:00
for imageboard in imageboards:
name = imageboard.GetName()
self._tree.AppendItem( site_item, name, data = wx.TreeItemData( imageboard ) )
2013-02-19 00:11:43 +00:00
2016-03-23 19:42:56 +00:00
self._tree.Expand( root_item )
2013-02-19 00:11:43 +00:00
2016-03-23 19:42:56 +00:00
#
2013-02-19 00:11:43 +00:00
2016-03-23 19:42:56 +00:00
vbox = wx.BoxSizer( wx.VERTICAL )
2013-07-31 21:26:38 +00:00
2018-01-03 22:37:30 +00:00
vbox.Add( self._tree, CC.FLAGS_EXPAND_BOTH_WAYS )
2016-03-23 19:42:56 +00:00
self.SetSizer( vbox )
( x, y ) = self.GetEffectiveMinSize()
if x < 320: x = 320
if y < 640: y = 640
self.SetInitialSize( ( x, y ) )
2013-02-19 00:11:43 +00:00
2014-02-19 22:37:23 +00:00
def EventActivate( self, event ):
2013-02-19 00:11:43 +00:00
item = self._tree.GetSelection()
2013-03-15 02:38:12 +00:00
data_object = self._tree.GetItemData( item )
if data_object is None: self._tree.Toggle( item )
2013-02-19 00:11:43 +00:00
else: self.EndModal( wx.ID_OK )
def GetImageboard( self ): return self._tree.GetItemData( self._tree.GetSelection() ).GetData()
2014-08-06 20:29:17 +00:00
class DialogTextEntry( Dialog ):
2017-08-02 21:32:54 +00:00
def __init__( self, parent, message, default = '', allow_blank = False, suggestions = None, max_chars = None ):
2016-12-07 22:12:52 +00:00
if suggestions is None:
suggestions = []
2014-08-06 20:29:17 +00:00
Dialog.__init__( self, parent, 'enter text', position = 'center' )
2016-12-07 22:12:52 +00:00
self._chosen_suggestion = None
2014-08-06 20:29:17 +00:00
self._allow_blank = allow_blank
2017-08-02 21:32:54 +00:00
self._max_chars = max_chars
2014-08-06 20:29:17 +00:00
2016-12-07 22:12:52 +00:00
button_choices = []
for text in suggestions:
button_choices.append( ClientGUICommon.BetterButton( self, text, self.ButtonChoice, text ) )
2016-03-30 22:56:50 +00:00
self._text = wx.TextCtrl( self, style = wx.TE_PROCESS_ENTER )
self._text.Bind( wx.EVT_TEXT, self.EventText )
self._text.Bind( wx.EVT_TEXT_ENTER, self.EventEnter )
2014-08-06 20:29:17 +00:00
2017-08-02 21:32:54 +00:00
if self._max_chars is not None:
self._text.SetMaxLength( self._max_chars )
2016-03-30 22:56:50 +00:00
self._ok = wx.Button( self, id = wx.ID_OK, label = 'ok' )
self._ok.SetForegroundColour( ( 0, 128, 0 ) )
2014-08-06 20:29:17 +00:00
2016-03-30 22:56:50 +00:00
self._cancel = wx.Button( self, id = wx.ID_CANCEL, label = 'cancel' )
self._cancel.SetForegroundColour( ( 128, 0, 0 ) )
#
self._text.SetValue( default )
self._CheckText()
#
hbox = wx.BoxSizer( wx.HORIZONTAL )
2018-01-03 22:37:30 +00:00
hbox.Add( self._ok, CC.FLAGS_SMALL_INDENT )
hbox.Add( self._cancel, CC.FLAGS_SMALL_INDENT )
2016-03-30 22:56:50 +00:00
2017-04-19 20:58:30 +00:00
st_message = ClientGUICommon.BetterStaticText( self, message )
2018-07-04 20:48:28 +00:00
st_message.SetWrapWidth( 480 )
2016-03-30 22:56:50 +00:00
vbox = wx.BoxSizer( wx.VERTICAL )
2018-01-03 22:37:30 +00:00
vbox.Add( st_message, CC.FLAGS_BIG_INDENT )
2016-12-07 22:12:52 +00:00
for button in button_choices:
2018-01-03 22:37:30 +00:00
vbox.Add( button, CC.FLAGS_EXPAND_PERPENDICULAR )
2016-12-07 22:12:52 +00:00
2018-01-03 22:37:30 +00:00
vbox.Add( self._text, CC.FLAGS_EXPAND_BOTH_WAYS )
vbox.Add( hbox, CC.FLAGS_BUTTON_SIZER )
2016-03-30 22:56:50 +00:00
self.SetSizer( vbox )
( x, y ) = self.GetEffectiveMinSize()
x = max( x, 250 )
self.SetInitialSize( ( x, y ) )
2014-08-06 20:29:17 +00:00
def _CheckText( self ):
if not self._allow_blank:
2017-08-02 21:32:54 +00:00
if self._text.GetValue() == '':
self._ok.Disable()
else:
self._ok.Enable()
2014-08-06 20:29:17 +00:00
2016-12-07 22:12:52 +00:00
def ButtonChoice( self, text ):
self._chosen_suggestion = text
self.EndModal( wx.ID_OK )
2015-07-29 19:11:35 +00:00
def EventText( self, event ):
2014-08-06 20:29:17 +00:00
wx.CallAfter( self._CheckText )
event.Skip()
def EventEnter( self, event ):
2016-12-07 22:12:52 +00:00
if self._text.GetValue() != '':
self.EndModal( wx.ID_OK )
2014-08-06 20:29:17 +00:00
2016-12-07 22:12:52 +00:00
def GetValue( self ):
if self._chosen_suggestion is None:
return self._text.GetValue()
else:
return self._chosen_suggestion
2014-08-06 20:29:17 +00:00
2013-02-19 00:11:43 +00:00
class DialogYesNo( Dialog ):
2014-11-20 01:48:04 +00:00
def __init__( self, parent, message, title = 'Are you sure?', yes_label = 'yes', no_label = 'no' ):
2013-02-19 00:11:43 +00:00
2016-03-30 22:56:50 +00:00
Dialog.__init__( self, parent, title, position = 'center' )
2013-02-19 00:11:43 +00:00
2017-04-19 20:58:30 +00:00
self._yes = wx.Button( self, id = wx.ID_YES )
2016-03-30 22:56:50 +00:00
self._yes.SetForegroundColour( ( 0, 128, 0 ) )
2017-04-19 20:58:30 +00:00
self._yes.SetLabelText( yes_label )
2013-02-19 00:11:43 +00:00
2017-04-19 20:58:30 +00:00
self._no = wx.Button( self, id = wx.ID_NO )
2016-03-30 22:56:50 +00:00
self._no.SetForegroundColour( ( 128, 0, 0 ) )
2017-04-19 20:58:30 +00:00
self._no.SetLabelText( no_label )
2013-02-19 00:11:43 +00:00
2016-03-30 22:56:50 +00:00
self._hidden_cancel = wx.Button( self, id = wx.ID_CANCEL, size = ( 0, 0 ) )
2013-02-19 00:11:43 +00:00
2016-03-30 22:56:50 +00:00
#
2013-07-31 21:26:38 +00:00
2016-03-30 22:56:50 +00:00
hbox = wx.BoxSizer( wx.HORIZONTAL )
2013-02-19 00:11:43 +00:00
2018-01-03 22:37:30 +00:00
hbox.Add( self._yes, CC.FLAGS_SMALL_INDENT )
hbox.Add( self._no, CC.FLAGS_SMALL_INDENT )
2013-02-19 00:11:43 +00:00
2016-03-30 22:56:50 +00:00
vbox = wx.BoxSizer( wx.VERTICAL )
2013-07-31 21:26:38 +00:00
2017-04-19 20:58:30 +00:00
text = ClientGUICommon.BetterStaticText( self, message )
2013-02-19 00:11:43 +00:00
2018-07-04 20:48:28 +00:00
text.SetWrapWidth( 480 )
2016-03-30 22:56:50 +00:00
2018-01-03 22:37:30 +00:00
vbox.Add( text, CC.FLAGS_EXPAND_BOTH_WAYS )
vbox.Add( hbox, CC.FLAGS_BUTTON_SIZER )
2016-03-30 22:56:50 +00:00
self.SetSizer( vbox )
( x, y ) = self.GetEffectiveMinSize()
x = max( x, 250 )
self.SetInitialSize( ( x, y ) )
wx.CallAfter( self._yes.SetFocus )
2013-02-19 00:11:43 +00:00
2016-12-07 22:12:52 +00:00
2017-06-07 22:05:15 +00:00
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.SetForegroundColour( ( 0, 128, 0 ) )
yes_buttons.append( yes_button )
self._no = wx.Button( self, id = wx.ID_NO )
self._no.SetForegroundColour( ( 128, 0, 0 ) )
self._no.SetLabelText( no_label )
self._hidden_cancel = wx.Button( self, id = wx.ID_CANCEL, size = ( 0, 0 ) )
#
hbox = wx.BoxSizer( wx.HORIZONTAL )
for yes_button in yes_buttons:
2018-01-03 22:37:30 +00:00
hbox.Add( yes_button, CC.FLAGS_SMALL_INDENT )
2017-06-07 22:05:15 +00:00
2018-01-03 22:37:30 +00:00
hbox.Add( self._no, CC.FLAGS_SMALL_INDENT )
2017-06-07 22:05:15 +00:00
vbox = wx.BoxSizer( wx.VERTICAL )
text = ClientGUICommon.BetterStaticText( self, message )
2018-07-04 20:48:28 +00:00
text.SetWrapWidth( 480 )
2017-06-07 22:05:15 +00:00
2018-01-03 22:37:30 +00:00
vbox.Add( text, CC.FLAGS_BIG_INDENT )
vbox.Add( hbox, CC.FLAGS_BUTTON_SIZER )
2017-06-07 22:05:15 +00:00
self.SetSizer( vbox )
( x, y ) = self.GetEffectiveMinSize()
x = max( x, 250 )
self.SetInitialSize( ( x, y ) )
wx.CallAfter( yes_buttons[0].SetFocus )
def _DoYes( self, value ):
self._value = value
self.EndModal( wx.ID_YES )
def GetValue( self ):
return self._value