8088 lines
314 KiB
Python
Executable File
8088 lines
314 KiB
Python
Executable File
import Crypto.PublicKey.RSA
|
|
import HydrusConstants as HC
|
|
import HydrusMessageHandling
|
|
import ClientConstants as CC
|
|
import ClientConstantsMessages
|
|
import ClientGUICommon
|
|
import collections
|
|
import os
|
|
import random
|
|
import re
|
|
import time
|
|
import traceback
|
|
import wx
|
|
import yaml
|
|
|
|
# Option Enums
|
|
|
|
ID_NULL = wx.NewId()
|
|
|
|
ID_TIMER_UPDATE = wx.NewId()
|
|
|
|
# Hue is generally 200, Sat and Lum changes based on need
|
|
|
|
COLOUR_SELECTED = wx.Colour( 217, 242, 255 )
|
|
COLOUR_SELECTED_DARK = wx.Colour( 1, 17, 26 )
|
|
COLOUR_UNSELECTED = wx.Colour( 223, 227, 230 )
|
|
|
|
# Sizer Flags
|
|
|
|
FLAGS_NONE = wx.SizerFlags( 0 )
|
|
|
|
FLAGS_SMALL_INDENT = wx.SizerFlags( 0 ).Border( wx.ALL, 2 )
|
|
FLAGS_BIG_INDENT = wx.SizerFlags( 0 ).Border( wx.ALL, 8 )
|
|
|
|
FLAGS_EXPAND_PERPENDICULAR = wx.SizerFlags( 0 ).Border( wx.ALL, 2 ).Expand()
|
|
FLAGS_EXPAND_BOTH_WAYS = wx.SizerFlags( 2 ).Border( wx.ALL, 2 ).Expand()
|
|
FLAGS_EXPAND_DEPTH_ONLY = wx.SizerFlags( 2 ).Border( wx.ALL, 2 ).Align( wx.ALIGN_CENTER_VERTICAL )
|
|
|
|
FLAGS_BUTTON_SIZERS = wx.SizerFlags( 0 ).Align( wx.ALIGN_RIGHT )
|
|
FLAGS_LONE_BUTTON = wx.SizerFlags( 0 ).Border( wx.ALL, 2 ).Align( wx.ALIGN_RIGHT )
|
|
|
|
FLAGS_MIXED = wx.SizerFlags( 0 ).Border( wx.ALL, 2 ).Align( wx.ALIGN_CENTER_VERTICAL )
|
|
|
|
def SelectServiceIdentifier( permission = None, service_types = HC.ALL_SERVICES, service_identifiers = None, unallowed = None ):
|
|
|
|
if service_identifiers is None:
|
|
|
|
services = wx.GetApp().Read( 'services', service_types )
|
|
|
|
if permission is not None: services = [ service for service in services if service.GetAccount().HasPermission( permission ) ]
|
|
|
|
service_identifiers = [ service.GetServiceIdentifier() for service in services ]
|
|
|
|
|
|
if unallowed is not None: service_identifiers.difference_update( unallowed )
|
|
|
|
if len( service_identifiers ) == 0: return None
|
|
elif len( service_identifiers ) == 1:
|
|
|
|
( service_identifier, ) = service_identifiers
|
|
|
|
return service_identifier
|
|
|
|
else:
|
|
|
|
names_to_service_identifiers = { service_identifier.GetName() : service_identifier for service_identifier in service_identifiers }
|
|
|
|
with DialogSelectFromListOfStrings( wx.GetApp().GetGUI(), 'select service', [ service_identifier.GetName() for service_identifier in service_identifiers ] ) as dlg:
|
|
|
|
if dlg.ShowModal() == wx.ID_OK: return names_to_service_identifiers[ dlg.GetString() ]
|
|
else: return None
|
|
|
|
|
|
|
|
def ShowMessage( parent, message ):
|
|
|
|
with DialogMessage( parent, message ) as dlg: dlg.ShowModal()
|
|
|
|
class Dialog( wx.Dialog ):
|
|
|
|
def __init__( self, parent, title, style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, position = 'topleft' ):
|
|
|
|
self._options = wx.GetApp().Read( 'options' )
|
|
|
|
if position == 'topleft':
|
|
|
|
( pos_x, pos_y ) = wx.GetApp().GetGUI().GetPositionTuple()
|
|
|
|
pos = ( pos_x + 50, pos_y + 100 )
|
|
|
|
else: pos = ( -1, -1 )
|
|
|
|
wx.Dialog.__init__( self, parent, title = title, style = style, pos = pos )
|
|
|
|
self.SetDoubleBuffered( True )
|
|
|
|
self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) )
|
|
|
|
self.SetIcon( wx.Icon( HC.STATIC_DIR + os.path.sep + 'hydrus.ico', wx.BITMAP_TYPE_ICO ) )
|
|
|
|
if position == 'center': wx.CallAfter( self.Center )
|
|
|
|
|
|
class DialogFinishFiltering( Dialog ):
|
|
|
|
def __init__( self, parent, num_kept, num_deleted ):
|
|
|
|
def InitialiseControls():
|
|
|
|
self._commit = wx.Button( self, label = 'commit' )
|
|
self._commit.Bind( wx.EVT_BUTTON, self.EventCommit )
|
|
self._commit.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
self._forget = wx.Button( self, label = 'forget' )
|
|
self._forget.Bind( wx.EVT_BUTTON, self.EventForget )
|
|
self._forget.SetForegroundColour( ( 128, 0, 0 ) )
|
|
|
|
self._back = wx.Button( self, id = wx.ID_CANCEL, label = 'back to filtering' )
|
|
self._back.Bind( wx.EVT_BUTTON, self.EventBack )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
hbox.AddF( self._commit, FLAGS_EXPAND_BOTH_WAYS )
|
|
hbox.AddF( self._forget, FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
label = 'Keep ' + HC.ConvertIntToPrettyString( num_kept ) + ' and delete ' + HC.ConvertIntToPrettyString( num_deleted ) + ' files?'
|
|
|
|
vbox.AddF( wx.StaticText( self, label = label, style = wx.ALIGN_CENTER ), FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox.AddF( hbox, FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox.AddF( wx.StaticText( self, label = '-or-', style = wx.ALIGN_CENTER ), FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox.AddF( self._back, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
self.SetSizer( vbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
self.SetInitialSize( ( x, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'are you sure?', position = 'center' )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def EventBack( self, event ): self.EndModal( wx.ID_CANCEL )
|
|
|
|
def EventCommit( self, event ): self.EndModal( wx.ID_YES )
|
|
|
|
def EventForget( self, event ): self.EndModal( wx.ID_NO )
|
|
|
|
class DialogFinishRatingFiltering( Dialog ):
|
|
|
|
def __init__( self, parent, num_certain_ratings, num_uncertain_ratings ):
|
|
|
|
def InitialiseControls():
|
|
|
|
self._commit = wx.Button( self, label = 'commit' )
|
|
self._commit.Bind( wx.EVT_BUTTON, self.EventCommit )
|
|
self._commit.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
self._forget = wx.Button( self, label = 'forget' )
|
|
self._forget.Bind( wx.EVT_BUTTON, self.EventForget )
|
|
self._forget.SetForegroundColour( ( 128, 0, 0 ) )
|
|
|
|
self._back = wx.Button( self, id = wx.ID_CANCEL, label = 'back to filtering' )
|
|
self._back.Bind( wx.EVT_BUTTON, self.EventBack )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
hbox.AddF( self._commit, FLAGS_EXPAND_BOTH_WAYS )
|
|
hbox.AddF( self._forget, FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
info_strings = []
|
|
|
|
if num_certain_ratings > 0: info_strings.append( HC.ConvertIntToPrettyString( num_certain_ratings ) + ' ratings' )
|
|
if num_uncertain_ratings > 0: info_strings.append( HC.ConvertIntToPrettyString( num_uncertain_ratings ) + ' uncertain changes' )
|
|
|
|
label = 'Apply ' + ' and '.join( info_strings ) + '?'
|
|
|
|
vbox.AddF( wx.StaticText( self, label = label, style = wx.ALIGN_CENTER ), FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox.AddF( hbox, FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox.AddF( wx.StaticText( self, label = '-or-', style = wx.ALIGN_CENTER ), FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox.AddF( self._back, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
self.SetSizer( vbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
self.SetInitialSize( ( x, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'are you sure?', position = 'center' )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def EventBack( self, event ): self.EndModal( wx.ID_CANCEL )
|
|
|
|
def EventCommit( self, event ): self.EndModal( wx.ID_YES )
|
|
|
|
def EventForget( self, event ): self.EndModal( wx.ID_NO )
|
|
|
|
class DialogInputCustomFilterAction( Dialog ):
|
|
|
|
def __init__( self, parent, modifier = wx.ACCEL_NORMAL, key = wx.WXK_F7, service_identifier = None, action = 'archive' ):
|
|
|
|
self._service_identifier = service_identifier
|
|
self._action = action
|
|
|
|
self._current_ratings_like_service = None
|
|
self._current_ratings_numerical_service = None
|
|
|
|
def InitialiseControls():
|
|
|
|
service_identifiers = wx.GetApp().Read( 'service_identifiers', ( HC.LOCAL_TAG, HC.TAG_REPOSITORY, HC.LOCAL_RATING_LIKE, HC.LOCAL_RATING_NUMERICAL ) )
|
|
|
|
self._shortcut = ClientGUICommon.Shortcut( self, modifier, key )
|
|
|
|
self._none_actions = wx.Choice( self, choices = [ 'manage_tags', 'manage_ratings', 'archive', 'delete', 'frame_back', 'frame_next', 'previous', 'next', 'first', 'last' ] )
|
|
|
|
self._ok_none = wx.Button( self, label = 'ok' )
|
|
self._ok_none.Bind( wx.EVT_BUTTON, self.EventOKNone )
|
|
self._ok_none.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
self._tag_service_identifiers = wx.Choice( self )
|
|
self._tag_value = wx.TextCtrl( self, style = wx.TE_READONLY )
|
|
self._tag_input = ClientGUICommon.AutoCompleteDropdownTagsWrite( self, self.SetTag, CC.LOCAL_FILE_SERVICE_IDENTIFIER, CC.NULL_SERVICE_IDENTIFIER )
|
|
|
|
self._ok_tag = wx.Button( self, label = 'ok' )
|
|
self._ok_tag.Bind( wx.EVT_BUTTON, self.EventOKTag )
|
|
self._ok_tag.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
self._ratings_like_service_identifiers = wx.Choice( self )
|
|
self._ratings_like_service_identifiers.Bind( wx.EVT_CHOICE, self.EventRecalcActions )
|
|
self._ratings_like_like = wx.RadioButton( self, style = wx.RB_GROUP, label = 'like' )
|
|
self._ratings_like_dislike = wx.RadioButton( self, label = 'dislike' )
|
|
self._ratings_like_remove = wx.RadioButton( self, label = 'remove rating' )
|
|
|
|
self._ok_ratings_like = wx.Button( self, label = 'ok' )
|
|
self._ok_ratings_like.Bind( wx.EVT_BUTTON, self.EventOKRatingsLike )
|
|
self._ok_ratings_like.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
self._ratings_numerical_service_identifiers = wx.Choice( self )
|
|
self._ratings_numerical_service_identifiers.Bind( wx.EVT_CHOICE, self.EventRecalcActions )
|
|
self._ratings_numerical_slider = wx.Slider( self, style = wx.SL_AUTOTICKS | wx.SL_LABELS )
|
|
self._ratings_numerical_remove = wx.CheckBox( self, label = 'remove rating' )
|
|
|
|
self._ok_ratings_numerical = wx.Button( self, label = 'ok' )
|
|
self._ok_ratings_numerical.Bind( wx.EVT_BUTTON, self.EventOKRatingsNumerical )
|
|
self._ok_ratings_numerical.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
for service_identifier in service_identifiers:
|
|
|
|
service_type = service_identifier.GetType()
|
|
|
|
if service_type in ( HC.LOCAL_TAG, HC.TAG_REPOSITORY ): choice = self._tag_service_identifiers
|
|
elif service_type == HC.LOCAL_RATING_LIKE: choice = self._ratings_like_service_identifiers
|
|
elif service_type == HC.LOCAL_RATING_NUMERICAL: choice = self._ratings_numerical_service_identifiers
|
|
|
|
choice.Append( service_identifier.GetName(), service_identifier )
|
|
|
|
|
|
self._SetActions()
|
|
|
|
if self._service_identifier is None:
|
|
|
|
self._none_actions.SetStringSelection( self._action )
|
|
|
|
else:
|
|
|
|
service_name = self._service_identifier.GetName()
|
|
service_type = self._service_identifier.GetType()
|
|
|
|
if service_type in ( HC.LOCAL_TAG, HC.TAG_REPOSITORY ):
|
|
|
|
self._tag_service_identifiers.SetStringSelection( service_name )
|
|
|
|
self._tag_value.SetValue( self._action )
|
|
|
|
elif service_type == HC.LOCAL_RATING_LIKE:
|
|
|
|
self._ratings_like_service_identifiers.SetStringSelection( service_name )
|
|
|
|
self._SetActions()
|
|
|
|
if self._action is None: self._ratings_like_remove.SetValue( True )
|
|
elif self._action == True: self._ratings_like_like.SetValue( True )
|
|
elif self._action == False: self._ratings_like_dislike.SetValue( True )
|
|
|
|
elif service_type == HC.LOCAL_RATING_NUMERICAL:
|
|
|
|
self._ratings_numerical_service_identifiers.SetStringSelection( service_name )
|
|
|
|
self._SetActions()
|
|
|
|
if self._action is None: self._ratings_numerical_remove.SetValue( True )
|
|
else:
|
|
|
|
( lower, upper ) = self._current_ratings_numerical_service.GetExtraInfo()
|
|
|
|
slider_value = int( self._action * ( upper - lower ) ) + lower
|
|
|
|
self._ratings_numerical_slider.SetValue( slider_value )
|
|
|
|
|
|
|
|
|
|
self._cancel = wx.Button( self, id = wx.ID_CANCEL, label='cancel' )
|
|
self._cancel.Bind( wx.EVT_BUTTON, self.EventCancel )
|
|
self._cancel.SetSize( ( 0, 0 ) )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
shortcut_vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
shortcut_vbox.AddF( wx.StaticText( self, label = '- shortcut -' ), FLAGS_EXPAND_PERPENDICULAR )
|
|
shortcut_vbox.AddF( self._shortcut, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
none_hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
none_hbox.AddF( self._none_actions, FLAGS_EXPAND_DEPTH_ONLY )
|
|
none_hbox.AddF( self._ok_none, FLAGS_MIXED )
|
|
|
|
none_vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
none_vbox.AddF( wx.StaticText( self, label = '- non-service actions -' ), FLAGS_EXPAND_PERPENDICULAR )
|
|
none_vbox.AddF( none_hbox, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
tag_sub_vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
tag_sub_vbox.AddF( self._tag_value, FLAGS_EXPAND_BOTH_WAYS )
|
|
tag_sub_vbox.AddF( self._tag_input, FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
tag_hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
tag_hbox.AddF( self._tag_service_identifiers, FLAGS_EXPAND_DEPTH_ONLY )
|
|
tag_hbox.AddF( tag_sub_vbox, FLAGS_EXPAND_BOTH_WAYS )
|
|
tag_hbox.AddF( self._ok_tag, FLAGS_MIXED )
|
|
|
|
tag_vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
tag_vbox.AddF( wx.StaticText( self, label = '- tag service actions -' ), FLAGS_EXPAND_PERPENDICULAR )
|
|
tag_vbox.AddF( tag_hbox, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
ratings_like_hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
ratings_like_hbox.AddF( self._ratings_like_service_identifiers, FLAGS_EXPAND_DEPTH_ONLY )
|
|
ratings_like_hbox.AddF( self._ratings_like_like, FLAGS_MIXED )
|
|
ratings_like_hbox.AddF( self._ratings_like_dislike, FLAGS_MIXED )
|
|
ratings_like_hbox.AddF( self._ratings_like_remove, FLAGS_MIXED )
|
|
ratings_like_hbox.AddF( self._ok_ratings_like, FLAGS_MIXED )
|
|
|
|
ratings_like_vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
ratings_like_vbox.AddF( wx.StaticText( self, label = '- ratings like service actions -' ), FLAGS_EXPAND_PERPENDICULAR )
|
|
ratings_like_vbox.AddF( ratings_like_hbox, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
ratings_numerical_hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
ratings_numerical_hbox.AddF( self._ratings_numerical_service_identifiers, FLAGS_EXPAND_DEPTH_ONLY )
|
|
ratings_numerical_hbox.AddF( self._ratings_numerical_slider, FLAGS_MIXED )
|
|
ratings_numerical_hbox.AddF( self._ratings_numerical_remove, FLAGS_MIXED )
|
|
ratings_numerical_hbox.AddF( self._ok_ratings_numerical, FLAGS_MIXED )
|
|
|
|
ratings_numerical_vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
ratings_numerical_vbox.AddF( wx.StaticText( self, label = '- ratings numerical service actions -' ), FLAGS_EXPAND_PERPENDICULAR )
|
|
ratings_numerical_vbox.AddF( ratings_numerical_hbox, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
vbox.AddF( none_vbox, FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox.AddF( tag_vbox, FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox.AddF( ratings_like_vbox, FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox.AddF( ratings_numerical_vbox, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
hbox.AddF( shortcut_vbox, FLAGS_MIXED )
|
|
hbox.AddF( vbox, FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
self.SetSizer( hbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
self.SetInitialSize( ( 680, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'input custom filter action' )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def _SetActions( self ):
|
|
|
|
if self._ratings_like_service_identifiers.GetCount() > 0:
|
|
|
|
selection = self._ratings_like_service_identifiers.GetSelection()
|
|
|
|
if selection != wx.NOT_FOUND:
|
|
|
|
service_identifier = self._ratings_like_service_identifiers.GetClientData( selection )
|
|
|
|
service = wx.GetApp().Read( 'service', service_identifier )
|
|
|
|
self._current_ratings_like_service = service
|
|
|
|
( like, dislike ) = service.GetExtraInfo()
|
|
|
|
self._ratings_like_like.SetLabel( like )
|
|
self._ratings_like_dislike.SetLabel( dislike )
|
|
|
|
else:
|
|
|
|
self._ratings_like_like.SetLabel( 'like' )
|
|
self._ratings_like_dislike.SetLabel( 'dislike' )
|
|
|
|
|
|
|
|
if self._ratings_numerical_service_identifiers.GetCount() > 0:
|
|
|
|
selection = self._ratings_numerical_service_identifiers.GetSelection()
|
|
|
|
if selection != wx.NOT_FOUND:
|
|
|
|
service_identifier = self._ratings_numerical_service_identifiers.GetClientData( selection )
|
|
|
|
service = wx.GetApp().Read( 'service', service_identifier )
|
|
|
|
self._current_ratings_numerical_service = service
|
|
|
|
( lower, upper ) = service.GetExtraInfo()
|
|
|
|
self._ratings_numerical_slider.SetRange( lower, upper )
|
|
|
|
else: self._ratings_numerical_slider.SetRange( 0, 5 )
|
|
|
|
|
|
|
|
def EventCancel( self, event ): self.EndModal( wx.ID_CANCEL )
|
|
|
|
def EventOKNone( self, event ):
|
|
|
|
self._service_identifier = None
|
|
self._action = self._none_actions.GetStringSelection()
|
|
self._pretty_action = self._action
|
|
|
|
self.EndModal( wx.ID_OK )
|
|
|
|
|
|
def EventOKRatingsLike( self, event ):
|
|
|
|
selection = self._ratings_like_service_identifiers.GetSelection()
|
|
|
|
if selection != wx.NOT_FOUND:
|
|
|
|
self._service_identifier = self._ratings_like_service_identifiers.GetClientData( selection )
|
|
|
|
( like, dislike ) = self._current_ratings_like_service.GetExtraInfo()
|
|
|
|
if self._ratings_like_like.GetValue():
|
|
|
|
self._action = 1.0
|
|
self._pretty_action = like
|
|
|
|
elif self._ratings_like_dislike.GetValue():
|
|
|
|
self._action = 0.0
|
|
self._pretty_action = dislike
|
|
|
|
else:
|
|
|
|
self._action = None
|
|
self._pretty_action = 'remove'
|
|
|
|
|
|
self.EndModal( wx.ID_OK )
|
|
|
|
else: self.EndModal( wx.ID_CANCEL )
|
|
|
|
|
|
def EventOKRatingsNumerical( self, event ):
|
|
|
|
selection = self._ratings_numerical_service_identifiers.GetSelection()
|
|
|
|
if selection != wx.NOT_FOUND:
|
|
|
|
self._service_identifier = self._ratings_numerical_service_identifiers.GetClientData( selection )
|
|
|
|
if self._ratings_numerical_remove.GetValue():
|
|
|
|
self._action = None
|
|
self._pretty_action = 'remove'
|
|
|
|
else:
|
|
|
|
self._pretty_action = str( self._ratings_numerical_slider.GetValue() )
|
|
|
|
( lower, upper ) = self._current_ratings_numerical_service.GetExtraInfo()
|
|
|
|
self._action = ( float( self._pretty_action ) - float( lower ) ) / ( upper - lower )
|
|
|
|
|
|
self.EndModal( wx.ID_OK )
|
|
|
|
else: self.EndModal( wx.ID_CANCEL )
|
|
|
|
|
|
def EventOKTag( self, event ):
|
|
|
|
selection = self._tag_service_identifiers.GetSelection()
|
|
|
|
if selection != wx.NOT_FOUND:
|
|
|
|
self._service_identifier = self._tag_service_identifiers.GetClientData( selection )
|
|
|
|
self._action = self._tag_value.GetValue()
|
|
self._pretty_action = self._action
|
|
|
|
self.EndModal( wx.ID_OK )
|
|
|
|
else: self.EndModal( wx.ID_CANCEL )
|
|
|
|
|
|
def EventRecalcActions( self, event ):
|
|
|
|
self._SetActions()
|
|
|
|
event.Skip()
|
|
|
|
|
|
def GetInfo( self ):
|
|
|
|
( modifier, key ) = self._shortcut.GetValue()
|
|
|
|
if self._service_identifier is None: pretty_service_identifier = ''
|
|
else: pretty_service_identifier = self._service_identifier.GetName()
|
|
|
|
# ignore this pretty_action
|
|
( pretty_modifier, pretty_key, pretty_action ) = HC.ConvertShortcutToPrettyShortcut( modifier, key, self._action )
|
|
|
|
return ( ( pretty_modifier, pretty_key, pretty_service_identifier, self._pretty_action ), ( modifier, key, self._service_identifier, self._action ) )
|
|
|
|
|
|
def SetTag( self, tag ): self._tag_value.SetValue( tag )
|
|
|
|
class DialogInputNewAccounts( Dialog ):
|
|
|
|
def __init__( self, parent, service_identifier ):
|
|
|
|
def InitialiseControls():
|
|
|
|
self._num = wx.SpinCtrl( self, min=1, max=10000, initial=1 )
|
|
|
|
service = wx.GetApp().Read( 'service', service_identifier )
|
|
|
|
connection = service.GetConnection()
|
|
|
|
account_types = connection.Get( 'accounttypes' )
|
|
|
|
self._account_types = wx.Choice( self, size = ( 400, -1 ) )
|
|
|
|
for account_type in account_types: self._account_types.Append( account_type.ConvertToString(), account_type )
|
|
|
|
self._account_types.SetSelection( 0 ) # admin
|
|
|
|
self._expiration = wx.Choice( self )
|
|
for ( str, value ) in HC.expirations: self._expiration.Append( str, value )
|
|
self._expiration.SetSelection( 3 ) # one year
|
|
|
|
self._ok = wx.Button( self, label='Ok' )
|
|
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.Bind( wx.EVT_BUTTON, self.EventCancel )
|
|
self._cancel.SetForegroundColour( ( 128, 0, 0 ) )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
ctrl_box = wx.BoxSizer( wx.HORIZONTAL )
|
|
ctrl_box.AddF( self._num, FLAGS_SMALL_INDENT )
|
|
ctrl_box.AddF( self._account_types, FLAGS_SMALL_INDENT )
|
|
ctrl_box.AddF( self._expiration, FLAGS_SMALL_INDENT )
|
|
|
|
b_box = wx.BoxSizer( wx.HORIZONTAL )
|
|
b_box.AddF( self._ok, FLAGS_MIXED )
|
|
b_box.AddF( self._cancel, FLAGS_MIXED )
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
vbox.AddF( ctrl_box, FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox.AddF( b_box, FLAGS_BUTTON_SIZERS )
|
|
|
|
self.SetSizer( vbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
self.SetInitialSize( ( x, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'configure new accounts' )
|
|
|
|
self._service_identifier = service_identifier
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def EventCancel( self, event ): self.EndModal( wx.ID_CANCEL )
|
|
|
|
def EventOk( self, event ):
|
|
|
|
num = self._num.GetValue()
|
|
|
|
account_type = self._account_types.GetClientData( self._account_types.GetSelection() )
|
|
|
|
title = account_type.GetTitle()
|
|
|
|
expiration = self._expiration.GetClientData( self._expiration.GetSelection() )
|
|
|
|
service = wx.GetApp().Read( 'service', self._service_identifier )
|
|
|
|
try:
|
|
|
|
connection = service.GetConnection()
|
|
|
|
if expiration is None: access_keys = connection.Get( 'accesskeys', num = num, title = title )
|
|
else: access_keys = connection.Get( 'accesskeys', num = num, title = title, expiration = expiration )
|
|
|
|
except Exception as e: wx.MessageBox( unicode( e ) )
|
|
|
|
self.EndModal( wx.ID_OK )
|
|
|
|
|
|
class DialogInputNewAccountType( Dialog ):
|
|
|
|
def __init__( self, parent, account_type = None ):
|
|
|
|
def InitialiseControls():
|
|
|
|
self._title = wx.TextCtrl( self, value = title )
|
|
|
|
self._permissions = wx.ListBox( self )
|
|
|
|
for permission in permissions: self._permissions.Append( HC.permissions_string_lookup[ permission ], permission )
|
|
|
|
self._permission_choice = wx.Choice( self )
|
|
|
|
for permission in HC.CREATABLE_PERMISSIONS: self._permission_choice.Append( HC.permissions_string_lookup[ permission ], permission )
|
|
|
|
self._permission_choice.SetSelection( 0 )
|
|
|
|
self._add_permission = wx.Button( self, label = 'add' )
|
|
self._add_permission.Bind( wx.EVT_BUTTON, self.EventAddPermission )
|
|
|
|
self._remove_permission = wx.Button( self, label = 'remove' )
|
|
self._remove_permission.Bind( wx.EVT_BUTTON, self.EventRemovePermission )
|
|
|
|
self._max_num_mb = ClientGUICommon.NoneableSpinCtrl( self, 'max monthly data (MB)', max_num_bytes, multiplier = 1048576 )
|
|
self._max_num_requests = ClientGUICommon.NoneableSpinCtrl( self, 'max monthly requests', max_num_requests )
|
|
|
|
self._apply = wx.Button( self, label='apply' )
|
|
self._apply.Bind( wx.EVT_BUTTON, self.EventOk )
|
|
self._apply.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
self._cancel = wx.Button( self, id = wx.ID_CANCEL, label='cancel' )
|
|
self._cancel.Bind( wx.EVT_BUTTON, self.EventCancel )
|
|
self._cancel.SetForegroundColour( ( 128, 0, 0 ) )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
t_box = wx.BoxSizer( wx.HORIZONTAL )
|
|
t_box.AddF( wx.StaticText( self, label='title: ' ), FLAGS_SMALL_INDENT )
|
|
t_box.AddF( self._title, FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
perm_buttons_box = wx.BoxSizer( wx.HORIZONTAL )
|
|
perm_buttons_box.AddF( self._permission_choice, FLAGS_MIXED )
|
|
perm_buttons_box.AddF( self._add_permission, FLAGS_MIXED )
|
|
perm_buttons_box.AddF( self._remove_permission, FLAGS_MIXED )
|
|
|
|
p_box = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
p_box.AddF( wx.StaticText( self, label = '- permissions -' ), FLAGS_SMALL_INDENT )
|
|
p_box.AddF( self._permissions, FLAGS_EXPAND_BOTH_WAYS )
|
|
p_box.AddF( perm_buttons_box, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
b_box = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
b_box.AddF( self._apply, FLAGS_MIXED )
|
|
b_box.AddF( self._cancel, FLAGS_MIXED )
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
vbox.AddF( t_box, FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox.AddF( p_box, FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox.AddF( self._max_num_mb, FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox.AddF( self._max_num_requests, FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox.AddF( b_box, FLAGS_BUTTON_SIZERS )
|
|
|
|
self.SetSizer( vbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
self.SetInitialSize( ( 800, y ) )
|
|
|
|
|
|
if account_type is None:
|
|
|
|
title = ''
|
|
permissions = [ HC.GET_DATA ]
|
|
max_num_bytes = 104857600
|
|
max_num_requests = 1000
|
|
|
|
else:
|
|
|
|
title = account_type.GetTitle()
|
|
permissions = account_type.GetPermissions()
|
|
( max_num_bytes, max_num_requests ) = account_type.GetMaxMonthlyData()
|
|
|
|
|
|
Dialog.__init__( self, parent, 'edit account type' )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def EventAddPermission( self, event ):
|
|
|
|
selection = self._permission_choice.GetSelection()
|
|
|
|
if selection != wx.NOT_FOUND:
|
|
|
|
permission = self._permission_choice.GetClientData( selection )
|
|
|
|
existing_permissions = [ self._permissions.GetClientData( i ) for i in range( self._permissions.GetCount() ) ]
|
|
|
|
if permission not in existing_permissions: self._permissions.Append( HC.permissions_string_lookup[ permission ], permission )
|
|
|
|
|
|
|
|
def EventCancel( self, event ): self.EndModal( wx.ID_CANCEL )
|
|
|
|
def EventCheckBox( self, event ):
|
|
|
|
if self._max_num_requests_checkbox.GetValue(): self._max_num_requests.Disable()
|
|
else: self._max_num_requests.Enable()
|
|
|
|
|
|
def EventOk( self, event ): self.EndModal( wx.ID_OK )
|
|
|
|
def EventRemovePermission( self, event ):
|
|
|
|
selection = self._permissions.GetSelection()
|
|
|
|
if selection != wx.NOT_FOUND: self._permissions.Delete( selection )
|
|
|
|
|
|
def GetAccountType( self ):
|
|
|
|
title = self._title.GetValue()
|
|
|
|
permissions = [ self._permissions.GetClientData( i ) for i in range( self._permissions.GetCount() ) ]
|
|
|
|
max_num_bytes = self._max_num_mb.GetValue()
|
|
|
|
max_num_requests = self._max_num_requests.GetValue()
|
|
|
|
return HC.AccountType( title, permissions, ( max_num_bytes, max_num_requests ) )
|
|
|
|
|
|
class DialogInputNewFormField( Dialog ):
|
|
|
|
def __init__( self, parent, form_field = None ):
|
|
|
|
if form_field is None: ( name, type, default, editable ) = ( '', CC.FIELD_TEXT, '', True )
|
|
else: ( name, type, default, editable ) = form_field
|
|
|
|
def InitialiseControls():
|
|
|
|
self._name = wx.TextCtrl( self, value = name )
|
|
|
|
self._type = wx.Choice( self )
|
|
|
|
for temp_type in CC.FIELDS: self._type.Append( CC.field_string_lookup[ temp_type ], temp_type )
|
|
|
|
self._type.Select( type )
|
|
|
|
self._default = wx.TextCtrl( self, value = default )
|
|
|
|
self._editable = wx.CheckBox( self )
|
|
|
|
self._editable.SetValue( editable )
|
|
|
|
self._ok = wx.Button( self, label='Ok' )
|
|
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.Bind( wx.EVT_BUTTON, self.EventCancel )
|
|
self._cancel.SetForegroundColour( ( 128, 0, 0 ) )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
gridbox = wx.FlexGridSizer( 0, 2 )
|
|
|
|
gridbox.AddGrowableCol( 1, 1 )
|
|
|
|
gridbox.AddF( wx.StaticText( self, label='name' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._name, FLAGS_EXPAND_BOTH_WAYS )
|
|
gridbox.AddF( wx.StaticText( self, label='type' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._type, FLAGS_EXPAND_BOTH_WAYS )
|
|
gridbox.AddF( wx.StaticText( self, label='default' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._default, FLAGS_EXPAND_BOTH_WAYS )
|
|
gridbox.AddF( wx.StaticText( self, label='editable' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._editable, FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
b_box = wx.BoxSizer( wx.HORIZONTAL )
|
|
b_box.AddF( self._ok, FLAGS_MIXED )
|
|
b_box.AddF( self._cancel, FLAGS_MIXED )
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
vbox.AddF( gridbox, FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox.AddF( b_box, FLAGS_BUTTON_SIZERS )
|
|
|
|
self.SetSizer( vbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
self.SetInitialSize( ( x, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'configure form field' )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def EventCancel( self, event ): self.EndModal( wx.ID_CANCEL )
|
|
|
|
def EventOk( self, event ): self.EndModal( wx.ID_OK )
|
|
|
|
def GetFormField( self ):
|
|
|
|
name = self._name.GetValue()
|
|
|
|
type = self._type.GetClientData( self._type.GetSelection() )
|
|
|
|
default = self._default.GetValue()
|
|
|
|
editable = self._editable.GetValue()
|
|
|
|
return ( name, type, default, editable )
|
|
|
|
|
|
class DialogInputFileSystemPredicate( Dialog ):
|
|
|
|
def __init__( self, parent, type ):
|
|
|
|
def Age():
|
|
|
|
def InitialiseControls():
|
|
|
|
( sign, years, months, days ) = system_predicates[ 'age' ]
|
|
|
|
self._sign = wx.Choice( self, choices=[ '<', u'\u2248', '>' ] )
|
|
self._sign.SetSelection( sign )
|
|
|
|
self._years = wx.SpinCtrl( self, initial = years, max = 30 )
|
|
self._months = wx.SpinCtrl( self, initial = months, max = 60 )
|
|
self._days = wx.SpinCtrl( self, initial = days, max = 90 )
|
|
|
|
self._ok = wx.Button( self, label='Ok' )
|
|
self._ok.Bind( wx.EVT_BUTTON, self.EventOk )
|
|
self._ok.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
hbox.AddF( wx.StaticText( self, label='system:age' ), FLAGS_MIXED )
|
|
hbox.AddF( self._sign, FLAGS_MIXED )
|
|
hbox.AddF( self._years, FLAGS_MIXED )
|
|
hbox.AddF( wx.StaticText( self, label='years' ), FLAGS_MIXED )
|
|
hbox.AddF( self._months, FLAGS_MIXED )
|
|
hbox.AddF( wx.StaticText( self, label='months' ), FLAGS_MIXED )
|
|
hbox.AddF( self._days, FLAGS_MIXED )
|
|
hbox.AddF( wx.StaticText( self, label='days' ), FLAGS_MIXED )
|
|
hbox.AddF( self._ok, FLAGS_MIXED )
|
|
|
|
self.SetSizer( hbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
self.SetInitialSize( ( x, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'enter age predicate' )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def Duration():
|
|
|
|
def InitialiseControls():
|
|
|
|
( sign, s, ms ) = system_predicates[ 'duration' ]
|
|
|
|
self._sign = wx.Choice( self, choices=[ '<', u'\u2248', '=', '>' ] )
|
|
self._sign.SetSelection( sign )
|
|
|
|
self._duration_s = wx.SpinCtrl( self, initial = s, max = 3599 )
|
|
self._duration_ms = wx.SpinCtrl( self, initial = ms, max = 999 )
|
|
|
|
self._ok = wx.Button( self, label='Ok' )
|
|
self._ok.Bind( wx.EVT_BUTTON, self.EventOk )
|
|
self._ok.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
hbox.AddF( wx.StaticText( self, label='system:duration' ), FLAGS_MIXED )
|
|
hbox.AddF( self._sign, FLAGS_MIXED )
|
|
hbox.AddF( self._duration_s, FLAGS_MIXED )
|
|
hbox.AddF( wx.StaticText( self, label='s' ), FLAGS_MIXED )
|
|
hbox.AddF( self._duration_ms, FLAGS_MIXED )
|
|
hbox.AddF( wx.StaticText( self, label='ms' ), FLAGS_MIXED )
|
|
hbox.AddF( self._ok, FLAGS_MIXED )
|
|
|
|
self.SetSizer( hbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
self.SetInitialSize( ( x, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'enter duration predicate' )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def Hash():
|
|
|
|
def InitialiseControls():
|
|
|
|
self._hash = wx.TextCtrl( self )
|
|
|
|
self._ok = wx.Button( self, label='Ok' )
|
|
self._ok.Bind( wx.EVT_BUTTON, self.EventOk )
|
|
self._ok.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
hbox.AddF( wx.StaticText( self, label='system:hash=' ), FLAGS_MIXED )
|
|
hbox.AddF( self._hash, FLAGS_MIXED )
|
|
hbox.AddF( self._ok, FLAGS_MIXED )
|
|
|
|
self.SetSizer( hbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
self.SetInitialSize( ( x, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'enter hash predicate' )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def Height():
|
|
|
|
def InitialiseControls():
|
|
|
|
( sign, height ) = system_predicates[ 'height' ]
|
|
|
|
self._sign = wx.Choice( self, choices=[ '<', u'\u2248', '=', '>' ] )
|
|
self._sign.SetSelection( sign )
|
|
|
|
self._height = wx.SpinCtrl( self, initial = height, max = 200000 )
|
|
|
|
self._ok = wx.Button( self, label='Ok' )
|
|
self._ok.Bind( wx.EVT_BUTTON, self.EventOk )
|
|
self._ok.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
hbox.AddF( wx.StaticText( self, label='system:height' ), FLAGS_MIXED )
|
|
hbox.AddF( self._sign, FLAGS_MIXED )
|
|
hbox.AddF( self._height, FLAGS_MIXED )
|
|
hbox.AddF( self._ok, FLAGS_MIXED )
|
|
|
|
self.SetSizer( hbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
self.SetInitialSize( ( x, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'enter height predicate' )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def Limit():
|
|
|
|
def InitialiseControls():
|
|
|
|
limit = system_predicates[ 'limit' ]
|
|
|
|
self._limit = wx.SpinCtrl( self, initial = limit, max = 1000000 )
|
|
|
|
self._ok = wx.Button( self, label='Ok' )
|
|
self._ok.Bind( wx.EVT_BUTTON, self.EventOk )
|
|
self._ok.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
hbox.AddF( wx.StaticText( self, label='system:limit=' ), FLAGS_MIXED )
|
|
hbox.AddF( self._limit, FLAGS_MIXED )
|
|
hbox.AddF( self._ok, FLAGS_MIXED )
|
|
|
|
self.SetSizer( hbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
self.SetInitialSize( ( x, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'enter limit predicate' )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def Mime():
|
|
|
|
def InitialiseControls():
|
|
|
|
( media, type ) = system_predicates[ 'mime' ]
|
|
|
|
self._mime_media = wx.Choice( self, choices=[ 'image', 'application', 'video' ] )
|
|
self._mime_media.SetSelection( media )
|
|
self._mime_media.Bind( wx.EVT_CHOICE, self.EventMime )
|
|
|
|
self._mime_type = wx.Choice( self, choices=[], size = ( 120, -1 ) )
|
|
|
|
self.EventMime( None )
|
|
|
|
self._mime_type.SetSelection( type )
|
|
|
|
self._ok = wx.Button( self, label='Ok' )
|
|
self._ok.Bind( wx.EVT_BUTTON, self.EventOk )
|
|
self._ok.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
hbox.AddF( wx.StaticText( self, label='system:mime' ), FLAGS_MIXED )
|
|
hbox.AddF( self._mime_media, FLAGS_MIXED )
|
|
hbox.AddF( wx.StaticText( self, label='/' ), FLAGS_MIXED )
|
|
hbox.AddF( self._mime_type, FLAGS_MIXED )
|
|
hbox.AddF( self._ok, FLAGS_MIXED )
|
|
|
|
self.SetSizer( hbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
self.SetInitialSize( ( x, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'enter mime predicate' )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def NumTags():
|
|
|
|
def InitialiseControls():
|
|
|
|
( sign, num_tags ) = system_predicates[ 'num_tags' ]
|
|
|
|
self._sign = wx.Choice( self, choices=[ '<', '=', '>' ] )
|
|
self._sign.SetSelection( sign )
|
|
|
|
self._num_tags = wx.SpinCtrl( self, initial = num_tags, max = 2000 )
|
|
|
|
self._ok = wx.Button( self, label='Ok' )
|
|
self._ok.Bind( wx.EVT_BUTTON, self.EventOk )
|
|
self._ok.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
hbox.AddF( wx.StaticText( self, label='system:numtags' ), FLAGS_MIXED )
|
|
hbox.AddF( self._sign, FLAGS_MIXED )
|
|
hbox.AddF( self._num_tags, FLAGS_MIXED )
|
|
hbox.AddF( self._ok, FLAGS_MIXED )
|
|
|
|
self.SetSizer( hbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
self.SetInitialSize( ( x, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'enter number of tags predicate' )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def Rating():
|
|
|
|
def InitialiseControls():
|
|
|
|
self._service_numerical = wx.Choice( self )
|
|
for service in self._local_numericals: self._service_numerical.Append( service.GetServiceIdentifier().GetName(), service )
|
|
self._service_numerical.Bind( wx.EVT_CHOICE, self.EventRatingsService )
|
|
|
|
( sign, value ) = system_predicates[ 'local_rating_numerical' ]
|
|
|
|
self._sign_numerical = wx.Choice( self, choices=[ '>', '<', '=', u'\u2248', '=rated', '=not rated', '=uncertain' ] )
|
|
self._sign_numerical.SetSelection( sign )
|
|
|
|
self._value_numerical = wx.SpinCtrl( self, initial = value, min = 0, max = 50000 ) # set bounds based on current service
|
|
|
|
self._first_ok = wx.Button( self, label='Ok', id = HC.LOCAL_RATING_NUMERICAL )
|
|
self._first_ok.Bind( wx.EVT_BUTTON, self.EventOk )
|
|
self._first_ok.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
self._service_like = wx.Choice( self )
|
|
for service in self._local_likes: self._service_like.Append( service.GetServiceIdentifier().GetName(), service )
|
|
self._service_like.Bind( wx.EVT_CHOICE, self.EventRatingsService )
|
|
|
|
value = system_predicates[ 'local_rating_like' ]
|
|
|
|
self._value_like = wx.Choice( self, choices=[ 'like', 'dislike', 'rated', 'not rated' ] ) # set words based on current service
|
|
self._value_like.SetSelection( value )
|
|
|
|
self._second_ok = wx.Button( self, label='Ok', id = HC.LOCAL_RATING_LIKE )
|
|
self._second_ok.Bind( wx.EVT_BUTTON, self.EventOk )
|
|
self._second_ok.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
if len( self._local_numericals ) > 0: self._service_numerical.SetSelection( 0 )
|
|
if len( self._local_likes ) > 0: self._service_like.SetSelection( 0 )
|
|
|
|
self.EventRatingsService( None )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
hbox.AddF( wx.StaticText( self, label='system:rating:' ), FLAGS_MIXED )
|
|
hbox.AddF( self._service_numerical, FLAGS_MIXED )
|
|
hbox.AddF( self._sign_numerical, FLAGS_MIXED )
|
|
hbox.AddF( self._value_numerical, FLAGS_MIXED )
|
|
hbox.AddF( self._first_ok, FLAGS_MIXED )
|
|
|
|
vbox.AddF( hbox, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
hbox.AddF( wx.StaticText( self, label='system:rating:' ), FLAGS_MIXED )
|
|
hbox.AddF( self._service_like, FLAGS_MIXED )
|
|
hbox.AddF( wx.StaticText( self, label='=' ), FLAGS_MIXED )
|
|
hbox.AddF( self._value_like, FLAGS_MIXED )
|
|
hbox.AddF( self._second_ok, FLAGS_MIXED )
|
|
|
|
vbox.AddF( hbox, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
self.SetSizer( vbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
self.SetInitialSize( ( x, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'enter rating predicate' )
|
|
|
|
self._local_numericals = wx.GetApp().Read( 'services', ( HC.LOCAL_RATING_NUMERICAL, ) )
|
|
self._local_likes = wx.GetApp().Read( 'services', ( HC.LOCAL_RATING_LIKE, ) )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def Ratio():
|
|
|
|
def InitialiseControls():
|
|
|
|
( sign, width, height ) = system_predicates[ 'ratio' ]
|
|
|
|
self._sign = wx.Choice( self, choices=[ '=', u'\u2248' ] )
|
|
self._sign.SetSelection( sign )
|
|
|
|
self._width = wx.SpinCtrl( self, initial = width, max = 50000 )
|
|
|
|
self._height = wx.SpinCtrl( self, initial = height, max = 50000 )
|
|
|
|
self._ok = wx.Button( self, label='Ok' )
|
|
self._ok.Bind( wx.EVT_BUTTON, self.EventOk )
|
|
self._ok.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
hbox.AddF( wx.StaticText( self, label='system:ratio' ), FLAGS_MIXED )
|
|
hbox.AddF( self._sign, FLAGS_MIXED )
|
|
hbox.AddF( self._width, FLAGS_MIXED )
|
|
hbox.AddF( wx.StaticText( self, label=':' ), FLAGS_MIXED )
|
|
hbox.AddF( self._height, FLAGS_MIXED )
|
|
hbox.AddF( self._ok, FLAGS_MIXED )
|
|
|
|
self.SetSizer( hbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
self.SetInitialSize( ( x, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'enter ratio predicate' )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def Size():
|
|
|
|
def InitialiseControls():
|
|
|
|
( sign, size, unit ) = system_predicates[ 'size' ]
|
|
|
|
self._sign = wx.Choice( self, choices=[ '<', u'\u2248', '=', '>' ] )
|
|
self._sign.SetSelection( sign )
|
|
|
|
self._size = wx.SpinCtrl( self, initial = size, max = 1048576 )
|
|
|
|
self._unit = wx.Choice( self, choices=[ 'b', 'B', 'Kb', 'KB', 'Mb', 'MB', 'Gb', 'GB' ] )
|
|
self._unit.SetSelection( unit )
|
|
|
|
self._ok = wx.Button( self, label='Ok' )
|
|
self._ok.Bind( wx.EVT_BUTTON, self.EventOk )
|
|
self._ok.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
hbox.AddF( wx.StaticText( self, label='system:size' ), FLAGS_MIXED )
|
|
hbox.AddF( self._sign, FLAGS_MIXED )
|
|
hbox.AddF( self._size, FLAGS_MIXED )
|
|
hbox.AddF( self._unit, FLAGS_MIXED )
|
|
hbox.AddF( self._ok, FLAGS_MIXED )
|
|
|
|
self.SetSizer( hbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
self.SetInitialSize( ( x, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'enter size predicate' )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def Width():
|
|
|
|
def InitialiseControls():
|
|
|
|
( sign, width ) = system_predicates[ 'width' ]
|
|
|
|
self._sign = wx.Choice( self, choices=[ '<', u'\u2248', '=', '>' ] )
|
|
self._sign.SetSelection( sign )
|
|
|
|
self._width = wx.SpinCtrl( self, initial = width, max = 200000 )
|
|
|
|
self._ok = wx.Button( self, label='Ok' )
|
|
self._ok.Bind( wx.EVT_BUTTON, self.EventOk )
|
|
self._ok.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
hbox.AddF( wx.StaticText( self, label='system:width' ), FLAGS_MIXED )
|
|
hbox.AddF( self._sign, FLAGS_MIXED )
|
|
hbox.AddF( self._width, FLAGS_MIXED )
|
|
hbox.AddF( self._ok, FLAGS_MIXED )
|
|
|
|
self.SetSizer( hbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
self.SetInitialSize( ( x, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'enter width predicate' )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def SimilarTo():
|
|
|
|
def InitialiseControls():
|
|
|
|
self._hash = wx.TextCtrl( self )
|
|
self._hash.SetValue( 'enter hash' )
|
|
|
|
self._max_hamming = wx.SpinCtrl( self, initial = 5, max = 256 )
|
|
|
|
self._ok = wx.Button( self, label='Ok' )
|
|
self._ok.Bind( wx.EVT_BUTTON, self.EventOk )
|
|
self._ok.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
hbox.AddF( wx.StaticText( self, label='system:similar_to' ), FLAGS_MIXED )
|
|
hbox.AddF( self._hash, FLAGS_MIXED )
|
|
hbox.AddF( wx.StaticText( self, label=u'\u2248' ), FLAGS_MIXED )
|
|
hbox.AddF( self._max_hamming, FLAGS_MIXED )
|
|
hbox.AddF( self._ok, FLAGS_MIXED )
|
|
|
|
self.SetSizer( hbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
self.SetInitialSize( ( x, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'enter duration predicate' )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
options = wx.GetApp().Read( 'options' )
|
|
|
|
system_predicates = options[ 'file_system_predicates' ]
|
|
|
|
self._type = type
|
|
|
|
if self._type == 'system:age': Age()
|
|
elif self._type == 'system:duration': Duration()
|
|
elif self._type == 'system:hash': Hash()
|
|
elif self._type == 'system:height': Height()
|
|
elif self._type == 'system:limit': Limit()
|
|
elif self._type == 'system:mime': Mime()
|
|
elif self._type == 'system:numtags': NumTags()
|
|
elif self._type == 'system:rating': Rating()
|
|
elif self._type == 'system:ratio': Ratio()
|
|
elif self._type == 'system:size': Size()
|
|
elif self._type == 'system:width': Width()
|
|
elif self._type == 'system:similar_to': SimilarTo()
|
|
|
|
self._hidden_cancel_button = wx.Button( self, id = wx.ID_CANCEL, label = 'cancel', size = ( 0, 0 ) )
|
|
self._hidden_cancel_button.Bind( wx.EVT_BUTTON, self.EventCancel )
|
|
# hide doesn't keep the escape hotkey, so say size = ( 0, 0 )
|
|
# self._hidden_cancel_button.Hide()
|
|
|
|
|
|
def EventCancel( self, event ): self.EndModal( wx.ID_CANCEL )
|
|
|
|
def EventMime( self, event ):
|
|
|
|
media = self._mime_media.GetStringSelection()
|
|
|
|
self._mime_type.Clear()
|
|
|
|
if media == 'image':
|
|
|
|
self._mime_type.Append( 'any', HC.IMAGES )
|
|
self._mime_type.Append( 'jpeg', HC.IMAGE_JPEG )
|
|
self._mime_type.Append( 'png', HC.IMAGE_PNG )
|
|
self._mime_type.Append( 'gif', HC.IMAGE_GIF )
|
|
|
|
elif media == 'application':
|
|
|
|
self._mime_type.Append( 'x-shockwave-flash', HC.APPLICATION_FLASH )
|
|
|
|
elif media == 'video':
|
|
|
|
self._mime_type.Append( 'x-flv', HC.VIDEO_FLV )
|
|
|
|
|
|
self._mime_type.SetSelection( 0 )
|
|
|
|
|
|
def EventOk( self, event ):
|
|
|
|
if self._type == 'system:rating':
|
|
|
|
id = event.GetId()
|
|
|
|
if id == HC.LOCAL_RATING_LIKE: self._type = 'system:rating_like'
|
|
elif id == HC.LOCAL_RATING_NUMERICAL: self._type = 'system:rating_numerical'
|
|
|
|
|
|
self.EndModal( wx.ID_OK )
|
|
|
|
|
|
def EventRatingsService( self, event ):
|
|
|
|
try:
|
|
|
|
service = self._service_numerical.GetClientData( self._service_numerical.GetSelection() )
|
|
|
|
( min, max ) = service.GetExtraInfo()
|
|
|
|
self._value_numerical.SetRange( min, max )
|
|
|
|
service = self._service_like.GetClientData( self._service_like.GetSelection() )
|
|
|
|
except: pass
|
|
|
|
try:
|
|
|
|
( like, dislike ) = service.GetExtraInfo()
|
|
|
|
selection = self._value_like.GetSelection()
|
|
|
|
self._value_like.SetString( 0, like )
|
|
self._value_like.SetString( 1, dislike )
|
|
|
|
self._value_like.SetSelection( selection )
|
|
|
|
except: pass
|
|
|
|
|
|
def GetString( self ):
|
|
|
|
if self._type == 'system:age': return 'system:age' + self._sign.GetStringSelection() + str( self._years.GetValue() ) + 'y' + str( self._months.GetValue() ) + 'm' + str( self._days.GetValue() ) + 'd'
|
|
elif self._type == 'system:duration': return 'system:duration' + self._sign.GetStringSelection() + str( self._duration_s.GetValue() * 1000 + self._duration_ms.GetValue() )
|
|
elif self._type == 'system:hash':
|
|
|
|
hex_filter = lambda c: c in '0123456789abcdef'
|
|
|
|
hash = filter( hex_filter, self._hash.GetValue() )
|
|
|
|
if len( hash ) == 0: hash == '00'
|
|
elif len( hash ) % 2 == 1: hash += '0' # since we are later decoding to byte
|
|
|
|
return 'system:hash=' + hash
|
|
|
|
elif self._type == 'system:height': return 'system:height' + self._sign.GetStringSelection() + str( self._height.GetValue() )
|
|
elif self._type == 'system:limit': return 'system:limit=' + str( self._limit.GetValue() )
|
|
elif self._type == 'system:mime': return 'system:mime=' + HC.mime_string_lookup[ self._mime_type.GetClientData( self._mime_type.GetSelection() ) ]
|
|
elif self._type == 'system:numtags': return 'system:numtags' + self._sign.GetStringSelection() + str( self._num_tags.GetValue() )
|
|
elif self._type == 'system:rating_like':
|
|
|
|
s = 'system:rating:' + self._service_like.GetClientData( self._service_like.GetSelection() ).GetServiceIdentifier().GetName() + '='
|
|
|
|
selection = self._value_like.GetSelection()
|
|
|
|
if selection == 0: s += '1'
|
|
elif selection == 1: s += '0'
|
|
elif selection == 2: s += 'rated'
|
|
elif selection == 3: s += 'not rated'
|
|
|
|
return s
|
|
|
|
elif self._type == 'system:rating_numerical':
|
|
|
|
service = self._service_numerical.GetClientData( self._service_numerical.GetSelection() )
|
|
|
|
s = 'system:rating:' + service.GetServiceIdentifier().GetName() + self._sign_numerical.GetStringSelection()
|
|
|
|
if self._sign_numerical.GetStringSelection() not in ( '=rated', '=not rated', '=uncertain' ):
|
|
|
|
( lower, upper ) = service.GetExtraInfo()
|
|
|
|
value = self._value_numerical.GetValue()
|
|
|
|
value_normalised = float( value - lower ) / float( upper - lower )
|
|
|
|
s += str( value_normalised )
|
|
|
|
|
|
return s
|
|
|
|
elif self._type == 'system:ratio': return 'system:ratio' + self._sign.GetStringSelection() + str( self._width.GetValue() ) + ':' + str( self._height.GetValue() )
|
|
elif self._type == 'system:size': return 'system:size' + self._sign.GetStringSelection() + str( self._size.GetValue() ) + self._unit.GetStringSelection()
|
|
elif self._type == 'system:width': return 'system:width' + self._sign.GetStringSelection() + str( self._width.GetValue() )
|
|
elif self._type == 'system:similar_to': return 'system:similar_to=' + self._hash.GetValue() + u'\u2248' + str( self._max_hamming.GetValue() )
|
|
|
|
|
|
class DialogInputMessageSystemPredicate( Dialog ):
|
|
|
|
def __init__( self, parent, type ):
|
|
|
|
def Age():
|
|
|
|
def InitialiseControls():
|
|
|
|
self._sign = wx.Choice( self, choices=[ '<', u'\u2248', '>' ] )
|
|
self._sign.SetSelection( 0 )
|
|
|
|
self._years = wx.SpinCtrl( self, initial = 0, max = 30 )
|
|
self._months = wx.SpinCtrl( self, initial = 0, max = 60 )
|
|
self._days = wx.SpinCtrl( self, initial = 7, max = 90 )
|
|
|
|
self._ok = wx.Button( self, label='Ok' )
|
|
self._ok.Bind( wx.EVT_BUTTON, self.EventOk )
|
|
self._ok.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
hbox.AddF( wx.StaticText( self, label='system:age' ), FLAGS_MIXED )
|
|
hbox.AddF( self._sign, FLAGS_MIXED )
|
|
hbox.AddF( self._years, FLAGS_MIXED )
|
|
hbox.AddF( wx.StaticText( self, label='years' ), FLAGS_MIXED )
|
|
hbox.AddF( self._months, FLAGS_MIXED )
|
|
hbox.AddF( wx.StaticText( self, label='months' ), FLAGS_MIXED )
|
|
hbox.AddF( self._days, FLAGS_MIXED )
|
|
hbox.AddF( wx.StaticText( self, label='days' ), FLAGS_MIXED )
|
|
hbox.AddF( self._ok, FLAGS_MIXED )
|
|
|
|
self.SetSizer( hbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
self.SetInitialSize( ( x, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'enter age predicate' )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def From():
|
|
|
|
def InitialiseControls():
|
|
|
|
contact_names = wx.GetApp().Read( 'contact_names' )
|
|
|
|
self._contact = wx.Choice( self, choices=contact_names )
|
|
self._contact.SetSelection( 0 )
|
|
|
|
self._ok = wx.Button( self, label='Ok' )
|
|
self._ok.Bind( wx.EVT_BUTTON, self.EventOk )
|
|
self._ok.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
hbox.AddF( wx.StaticText( self, label='system:from' ), FLAGS_MIXED )
|
|
hbox.AddF( self._contact, FLAGS_MIXED )
|
|
hbox.AddF( self._ok, FLAGS_MIXED )
|
|
|
|
self.SetSizer( hbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
self.SetInitialSize( ( x, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'enter from predicate' )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def StartedBy():
|
|
|
|
def InitialiseControls():
|
|
|
|
contact_names = wx.GetApp().Read( 'contact_names' )
|
|
|
|
self._contact = wx.Choice( self, choices=contact_names )
|
|
self._contact.SetSelection( 0 )
|
|
|
|
self._ok = wx.Button( self, label='Ok' )
|
|
self._ok.Bind( wx.EVT_BUTTON, self.EventOk )
|
|
self._ok.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
hbox.AddF( wx.StaticText( self, label='system:started_by' ), FLAGS_MIXED )
|
|
hbox.AddF( self._contact, FLAGS_MIXED )
|
|
hbox.AddF( self._ok, FLAGS_MIXED )
|
|
|
|
self.SetSizer( hbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
self.SetInitialSize( ( x, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'enter started by predicate' )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def To():
|
|
|
|
def InitialiseControls():
|
|
|
|
contact_names = [ name for name in wx.GetApp().Read( 'contact_names' ) if name != 'Anonymous' ]
|
|
|
|
self._contact = wx.Choice( self, choices=contact_names )
|
|
self._contact.SetSelection( 0 )
|
|
|
|
self._ok = wx.Button( self, label='Ok' )
|
|
self._ok.Bind( wx.EVT_BUTTON, self.EventOk )
|
|
self._ok.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
hbox.AddF( wx.StaticText( self, label='system:to' ), FLAGS_MIXED )
|
|
hbox.AddF( self._contact, FLAGS_MIXED )
|
|
hbox.AddF( self._ok, FLAGS_MIXED )
|
|
|
|
self.SetSizer( hbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
self.SetInitialSize( ( x, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'enter to predicate' )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def NumAttachments():
|
|
|
|
def InitialiseControls():
|
|
|
|
self._sign = wx.Choice( self, choices=[ '<', '=', '>' ] )
|
|
self._sign.SetSelection( 0 )
|
|
|
|
self._num_attachments = wx.SpinCtrl( self, initial = 4, max = 2000 )
|
|
|
|
self._ok = wx.Button( self, label='Ok' )
|
|
self._ok.Bind( wx.EVT_BUTTON, self.EventOk )
|
|
self._ok.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
hbox.AddF( wx.StaticText( self, label='system:numattachments' ), FLAGS_MIXED )
|
|
hbox.AddF( self._sign, FLAGS_MIXED )
|
|
hbox.AddF( self._num_attachments, FLAGS_MIXED )
|
|
hbox.AddF( self._ok, FLAGS_MIXED )
|
|
|
|
self.SetSizer( hbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
self.SetInitialSize( ( x, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'enter number of attachments predicate' )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
self._type = type
|
|
|
|
if self._type == 'system:age': Age()
|
|
elif self._type == 'system:started_by': StartedBy()
|
|
elif self._type == 'system:from': From()
|
|
elif self._type == 'system:to': To()
|
|
elif self._type == 'system:numattachments': NumAttachments()
|
|
|
|
self._hidden_cancel_button = wx.Button( self, id = wx.ID_CANCEL, label = 'cancel', size = ( 0, 0 ) )
|
|
self._hidden_cancel_button.Bind( wx.EVT_BUTTON, self.EventCancel )
|
|
# hide doesn't keep the escape hotkey, so say size = ( 0, 0 )
|
|
# self._hidden_cancel_button.Hide()
|
|
|
|
|
|
def EventCancel( self, event ): self.EndModal( wx.ID_CANCEL )
|
|
|
|
def EventOk( self, event ): self.EndModal( wx.ID_OK )
|
|
|
|
def GetString( self ):
|
|
|
|
if self._type == 'system:age': return 'system:age' + self._sign.GetStringSelection() + str( self._years.GetValue() ) + 'y' + str( self._months.GetValue() ) + 'm' + str( self._days.GetValue() ) + 'd'
|
|
elif self._type == 'system:started_by': return 'system:started_by=' + self._contact.GetStringSelection()
|
|
elif self._type == 'system:from': return 'system:from=' + self._contact.GetStringSelection()
|
|
elif self._type == 'system:to': return 'system:to=' + self._contact.GetStringSelection()
|
|
elif self._type == 'system:numattachments': return 'system:numattachments' + self._sign.GetStringSelection() + str( self._num_attachments.GetValue() )
|
|
|
|
|
|
class DialogInputShortcut( Dialog ):
|
|
|
|
def __init__( self, parent, modifier = wx.ACCEL_NORMAL, key = wx.WXK_F7, action = 'new_page' ):
|
|
|
|
self._action = action
|
|
|
|
def InitialiseControls():
|
|
|
|
self._shortcut = ClientGUICommon.Shortcut( self, modifier, key )
|
|
|
|
self._actions = wx.Choice( self, choices = [ 'archive', 'close_page', 'filter', 'ratings_filter', 'frame_back', 'frame_next', 'manage_ratings', 'manage_tags', 'new_page', 'refresh', 'set_search_focus', 'show_hide_splitters', 'synchronised_wait_switch', 'previous', 'next', 'first', 'last' ] )
|
|
self._actions.SetSelection( self._actions.FindString( action ) )
|
|
|
|
self._ok = wx.Button( self, label='Ok' )
|
|
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.Bind( wx.EVT_BUTTON, self.EventCancel )
|
|
self._cancel.SetForegroundColour( ( 128, 0, 0 ) )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
hbox.AddF( self._shortcut, FLAGS_MIXED )
|
|
hbox.AddF( self._actions, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
b_box = wx.BoxSizer( wx.HORIZONTAL )
|
|
b_box.AddF( self._ok, FLAGS_MIXED )
|
|
b_box.AddF( self._cancel, FLAGS_MIXED )
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
vbox.AddF( hbox, FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox.AddF( b_box, FLAGS_BUTTON_SIZERS )
|
|
|
|
self.SetSizer( vbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
self.SetInitialSize( ( x, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'configure shortcut' )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def EventCancel( self, event ): self.EndModal( wx.ID_CANCEL )
|
|
|
|
def EventOk( self, event ): self.EndModal( wx.ID_OK )
|
|
|
|
def GetInfo( self ):
|
|
|
|
( modifier, key ) = self._shortcut.GetValue()
|
|
|
|
return ( modifier, key, self._actions.GetStringSelection() )
|
|
|
|
|
|
class DialogManageAccountTypes( Dialog ):
|
|
|
|
def __init__( self, parent, service_identifier ):
|
|
|
|
def InitialiseControls():
|
|
|
|
service = wx.GetApp().Read( 'service', service_identifier )
|
|
|
|
connection = service.GetConnection()
|
|
|
|
account_types = connection.Get( 'accounttypes' )
|
|
|
|
self._titles_to_account_types = {}
|
|
|
|
self._ctrl_account_types = ClientGUICommon.SaneListCtrl( self, 350, [ ( 'title', 120 ), ( 'permissions', -1 ), ( 'max monthly bytes', 120 ), ( 'max monthly requests', 120 ) ] )
|
|
|
|
for account_type in account_types:
|
|
|
|
title = account_type.GetTitle()
|
|
|
|
self._titles_to_account_types[ title ] = account_type
|
|
|
|
permissions = account_type.GetPermissions()
|
|
|
|
permissions_string = ', '.join( [ HC.permissions_string_lookup[ permission ] for permission in permissions ] )
|
|
|
|
( max_num_bytes, max_num_requests ) = account_type.GetMaxMonthlyData()
|
|
|
|
( max_num_bytes_string, max_num_requests_string ) = account_type.GetMaxMonthlyDataString()
|
|
|
|
self._ctrl_account_types.Append( ( title, permissions_string, max_num_bytes_string, max_num_requests_string ), ( title, len( permissions ), max_num_bytes, max_num_requests ) )
|
|
|
|
|
|
self._add = wx.Button( self, label='add' )
|
|
self._add.Bind( wx.EVT_BUTTON, self.EventAdd )
|
|
|
|
self._edit = wx.Button( self, label='edit' )
|
|
self._edit.Bind( wx.EVT_BUTTON, self.EventEdit )
|
|
|
|
self._delete = wx.Button( self, label='delete' )
|
|
self._delete.Bind( wx.EVT_BUTTON, self.EventDelete )
|
|
|
|
self._apply = wx.Button( self, label='apply' )
|
|
self._apply.Bind( wx.EVT_BUTTON, self.EventOk )
|
|
self._apply.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
self._cancel = wx.Button( self, id = wx.ID_CANCEL, label='cancel' )
|
|
self._cancel.Bind( wx.EVT_BUTTON, self.EventCancel )
|
|
self._cancel.SetForegroundColour( ( 128, 0, 0 ) )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
h_b_box = wx.BoxSizer( wx.HORIZONTAL )
|
|
h_b_box.AddF( self._add, FLAGS_MIXED )
|
|
h_b_box.AddF( self._edit, FLAGS_MIXED )
|
|
h_b_box.AddF( self._delete, FLAGS_MIXED )
|
|
|
|
a_t_vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
a_t_vbox.AddF( wx.StaticText( self, label = '- account types -' ), FLAGS_SMALL_INDENT )
|
|
a_t_vbox.AddF( self._ctrl_account_types, FLAGS_EXPAND_BOTH_WAYS )
|
|
a_t_vbox.AddF( h_b_box, FLAGS_BUTTON_SIZERS )
|
|
|
|
b_box = wx.BoxSizer( wx.HORIZONTAL )
|
|
b_box.AddF( self._apply, FLAGS_MIXED )
|
|
b_box.AddF( self._cancel, FLAGS_MIXED )
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
vbox.AddF( a_t_vbox, FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox.AddF( b_box, FLAGS_BUTTON_SIZERS )
|
|
|
|
self.SetSizer( vbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
self.SetInitialSize( ( 980, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'manage account types' )
|
|
|
|
self._service_identifier = service_identifier
|
|
|
|
self._edit_log = []
|
|
|
|
try:
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
except: raise
|
|
|
|
|
|
def EventAdd( self, event ):
|
|
|
|
try:
|
|
|
|
with DialogInputNewAccountType( self ) as dlg:
|
|
|
|
if dlg.ShowModal() == wx.ID_OK:
|
|
|
|
account_type = dlg.GetAccountType()
|
|
|
|
title = account_type.GetTitle()
|
|
|
|
permissions = account_type.GetPermissions()
|
|
|
|
permissions_string = ', '.join( [ HC.permissions_string_lookup[ permission ] for permission in permissions ] )
|
|
|
|
( max_num_bytes, max_num_requests ) = account_type.GetMaxMonthlyData()
|
|
|
|
( max_num_bytes_string, max_num_requests_string ) = account_type.GetMaxMonthlyDataString()
|
|
|
|
if title in self._titles_to_account_types: raise Exception( 'You already have an account type called ' + title + '; delete or edit that one first' )
|
|
|
|
self._titles_to_account_types[ title ] = account_type
|
|
|
|
self._edit_log.append( ( 'add', account_type ) )
|
|
|
|
self._ctrl_account_types.Append( ( title, permissions_string, max_num_bytes_string, max_num_requests_string ), ( title, len( permissions ), max_num_bytes, max_num_requests ) )
|
|
|
|
|
|
|
|
except Exception as e: wx.MessageBox( unicode( e ) )
|
|
|
|
|
|
def EventCancel( self, event ): self.EndModal( wx.ID_CANCEL )
|
|
|
|
def EventDelete( self, event ):
|
|
|
|
indices = self._ctrl_account_types.GetAllSelected()
|
|
|
|
titles_about_to_delete = { self._ctrl_account_types.GetClientData( index )[0] for index in indices }
|
|
|
|
all_titles = set( self._titles_to_account_types.keys() )
|
|
|
|
titles_can_move_to = list( all_titles - titles_about_to_delete )
|
|
|
|
if len( titles_can_move_to ) == 0:
|
|
|
|
wx.MessageBox( 'You cannot delete every account type!' )
|
|
|
|
return
|
|
|
|
|
|
for title in titles_about_to_delete:
|
|
|
|
with DialogSelectFromListOfStrings( self, 'what should deleted ' + title + ' accounts become?', titles_can_move_to ) as dlg:
|
|
|
|
if dlg.ShowModal() == wx.ID_OK: title_to_move_to = dlg.GetString()
|
|
else: return
|
|
|
|
|
|
self._edit_log.append( ( 'delete', ( title, title_to_move_to ) ) )
|
|
|
|
|
|
self._ctrl_account_types.RemoveAllSelected()
|
|
|
|
|
|
def EventEdit( self, event ):
|
|
|
|
indices = self._ctrl_account_types.GetAllSelected()
|
|
|
|
for index in indices:
|
|
|
|
title = self._ctrl_account_types.GetClientData( index )[0]
|
|
|
|
account_type = self._titles_to_account_types[ title ]
|
|
|
|
try:
|
|
|
|
with DialogInputNewAccountType( self, account_type ) as dlg:
|
|
|
|
if dlg.ShowModal() == wx.ID_OK:
|
|
|
|
old_title = title
|
|
|
|
account_type = dlg.GetAccountType()
|
|
|
|
title = account_type.GetTitle()
|
|
|
|
permissions = account_type.GetPermissions()
|
|
|
|
permissions_string = ', '.join( [ HC.permissions_string_lookup[ permission ] for permission in permissions ] )
|
|
|
|
( max_num_bytes, max_num_requests ) = account_type.GetMaxMonthlyData()
|
|
|
|
( max_num_bytes_string, max_num_requests_string ) = account_type.GetMaxMonthlyDataString()
|
|
|
|
if old_title != title:
|
|
|
|
if title in self._titles_to_account_types: raise Exception( 'You already have an account type called ' + title + '; delete or edit that one first' )
|
|
|
|
del self._titles_to_account_types[ old_title ]
|
|
|
|
|
|
self._titles_to_account_types[ title ] = account_type
|
|
|
|
self._edit_log.append( ( 'edit', ( old_title, account_type ) ) )
|
|
|
|
self._ctrl_account_types.UpdateRow( index, ( title, permissions_string, max_num_bytes_string, max_num_requests_string ), ( title, len( permissions ), max_num_bytes, max_num_requests ) )
|
|
|
|
|
|
|
|
except Exception as e: wx.MessageBox( unicode( e ) )
|
|
|
|
|
|
|
|
def EventOk( self, event ):
|
|
|
|
try:
|
|
|
|
service = wx.GetApp().Read( 'service', self._service_identifier )
|
|
|
|
connection = service.GetConnection()
|
|
|
|
connection.Post( 'accounttypesmodification', edit_log = self._edit_log )
|
|
|
|
except Exception as e: wx.MessageBox( unicode( e ) )
|
|
|
|
self.EndModal( wx.ID_OK )
|
|
|
|
|
|
class DialogManageBoorus( Dialog ):
|
|
|
|
def __init__( self, parent ):
|
|
|
|
def InitialiseControls():
|
|
|
|
self._edit_log = []
|
|
|
|
self._boorus = ClientGUICommon.ListBook( self )
|
|
|
|
boorus = wx.GetApp().Read( 'boorus' )
|
|
|
|
for booru in boorus:
|
|
|
|
name = booru.GetName()
|
|
|
|
page_info = ( DialogManageBoorusBooruPanel, ( self._boorus, booru ), {} )
|
|
|
|
self._boorus.AddPage( page_info, name )
|
|
|
|
|
|
self._add = wx.Button( self, label='add' )
|
|
self._add.Bind( wx.EVT_BUTTON, self.EventAdd )
|
|
self._add.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
self._remove = wx.Button( self, label='remove' )
|
|
self._remove.Bind( wx.EVT_BUTTON, self.EventRemove )
|
|
self._remove.SetForegroundColour( ( 128, 0, 0 ) )
|
|
|
|
self._export = wx.Button( self, label='export' )
|
|
self._export.Bind( wx.EVT_BUTTON, self.EventExport )
|
|
|
|
self._ok = wx.Button( self, label='ok' )
|
|
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.Bind( wx.EVT_BUTTON, self.EventCancel )
|
|
self._cancel.SetForegroundColour( ( 128, 0, 0 ) )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
add_remove_hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
add_remove_hbox.AddF( self._add, FLAGS_MIXED )
|
|
add_remove_hbox.AddF( self._remove, FLAGS_MIXED )
|
|
add_remove_hbox.AddF( self._export, FLAGS_MIXED )
|
|
|
|
ok_hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
ok_hbox.AddF( self._ok, FLAGS_MIXED )
|
|
ok_hbox.AddF( self._cancel, FLAGS_MIXED )
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
vbox.AddF( self._boorus, FLAGS_EXPAND_BOTH_WAYS )
|
|
vbox.AddF( add_remove_hbox, FLAGS_SMALL_INDENT )
|
|
vbox.AddF( ok_hbox, FLAGS_BUTTON_SIZERS )
|
|
|
|
self.SetSizer( vbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
self.SetInitialSize( ( 980, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'manage boorus' )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
self.SetDropTarget( ClientGUICommon.FileDropTarget( self.Import ) )
|
|
|
|
|
|
def EventAdd( self, event ):
|
|
|
|
with wx.TextEntryDialog( self, 'Enter new booru\'s name' ) as dlg:
|
|
|
|
if dlg.ShowModal() == wx.ID_OK:
|
|
|
|
try:
|
|
|
|
name = dlg.GetValue()
|
|
|
|
if self._boorus.NameExists( name ): raise Exception( 'That name is already in use!' )
|
|
|
|
if name == '': raise Exception( 'Please enter a nickname for the service.' )
|
|
|
|
booru = CC.Booru( name, 'search_url', '+', 1, 'thumbnail', '', 'original image', {} )
|
|
|
|
self._edit_log.append( ( 'add', name ) )
|
|
|
|
page = DialogManageBoorusBooruPanel( self._boorus, booru )
|
|
|
|
self._boorus.AddPage( page, name, select = True )
|
|
|
|
except Exception as e:
|
|
|
|
wx.MessageBox( unicode( e ) )
|
|
|
|
self.EventAdd( event )
|
|
|
|
|
|
|
|
|
|
|
|
def EventCancel( self, event ): self.EndModal( wx.ID_CANCEL )
|
|
|
|
def EventExport( self, event ):
|
|
|
|
booru_panel = self._boorus.GetCurrentPage()
|
|
|
|
if booru_panel is not None:
|
|
|
|
name = self._boorus.GetCurrentName()
|
|
|
|
booru = booru_panel.GetBooru()
|
|
|
|
with wx.FileDialog( self, 'select where to export booru', defaultFile = 'booru.yaml', style = wx.FD_SAVE ) as dlg:
|
|
|
|
if dlg.ShowModal() == wx.ID_OK:
|
|
|
|
with open( dlg.GetPath(), 'wb' ) as f: f.write( yaml.safe_dump( booru ) )
|
|
|
|
|
|
|
|
|
|
|
|
def EventOk( self, event ):
|
|
|
|
for ( name, page ) in self._boorus.GetNameToPageDict().items():
|
|
|
|
if page.HasChanges(): self._edit_log.append( ( 'edit', ( name, page.GetBooru() ) ) )
|
|
|
|
|
|
try:
|
|
|
|
if len( self._edit_log ) > 0: wx.GetApp().Write( 'update_boorus', self._edit_log )
|
|
|
|
except Exception as e: wx.MessageBox( 'Saving boorus to DB raised this error: ' + unicode( e ) )
|
|
|
|
self.EndModal( wx.ID_OK )
|
|
|
|
|
|
def EventRemove( self, event ):
|
|
|
|
booru_panel = self._boorus.GetCurrentPage()
|
|
|
|
if booru_panel is not None:
|
|
|
|
name = self._boorus.GetCurrentName()
|
|
|
|
self._edit_log.append( ( 'delete', name ) )
|
|
|
|
self._boorus.DeleteCurrentPage()
|
|
|
|
|
|
|
|
def Import( self, paths ):
|
|
|
|
for path in paths:
|
|
|
|
try:
|
|
|
|
with open( path, 'rb' ) as f: file = f.read()
|
|
|
|
thing = yaml.safe_load( file )
|
|
|
|
if type( thing ) == CC.Booru:
|
|
|
|
booru = thing
|
|
|
|
name = booru.GetName()
|
|
|
|
if not self._boorus.NameExists( name ):
|
|
|
|
new_booru = CC.Booru( name, 'search_url', '+', 1, 'thumbnail', '', 'original image', {} )
|
|
|
|
self._edit_log.append( ( 'add', name ) )
|
|
|
|
page = DialogManageBoorusBooruPanel( self._boorus, new_booru )
|
|
|
|
self._boorus.AddPage( page, name, select = True )
|
|
|
|
|
|
page = self._boorus.GetNameToPageDict()[ name ]
|
|
|
|
page.Update( booru )
|
|
|
|
|
|
except:
|
|
|
|
wx.MessageBox( traceback.format_exc() )
|
|
|
|
|
|
|
|
|
|
class DialogManageBoorusBooruPanel( wx.Panel ):
|
|
|
|
def __init__( self, parent, booru ):
|
|
|
|
wx.Panel.__init__( self, parent )
|
|
|
|
self._booru = booru
|
|
|
|
( search_url, search_separator, gallery_advance_num, thumb_classname, image_id, image_data, tag_classnames_to_namespaces ) = booru.GetData()
|
|
|
|
def InitialiseControls():
|
|
|
|
self._search_url = wx.TextCtrl( self, value = search_url )
|
|
self._search_url.Bind( wx.EVT_TEXT, self.EventHTML )
|
|
|
|
self._search_separator = wx.Choice( self, choices = [ '+', '&', '%20' ] )
|
|
self._search_separator.Select( self._search_separator.FindString( search_separator ) )
|
|
self._search_separator.Bind( wx.EVT_CHOICE, self.EventHTML )
|
|
|
|
self._gallery_advance_num = wx.SpinCtrl( self, min = 1, max = 1000, initial = gallery_advance_num )
|
|
self._gallery_advance_num.Bind( wx.EVT_SPIN, self.EventHTML )
|
|
|
|
self._thumb_classname = wx.TextCtrl( self, value = thumb_classname )
|
|
self._thumb_classname.Bind( wx.EVT_TEXT, self.EventHTML )
|
|
|
|
self._example_html_search = wx.StaticText( self, style = wx.ST_NO_AUTORESIZE )
|
|
|
|
self._image_info = wx.TextCtrl( self )
|
|
self._image_info.Bind( wx.EVT_TEXT, self.EventHTML )
|
|
|
|
self._image_id = wx.RadioButton( self, style = wx.RB_GROUP )
|
|
self._image_id.Bind( wx.EVT_RADIOBUTTON, self.EventHTML )
|
|
|
|
self._image_data = wx.RadioButton( self )
|
|
self._image_data.Bind( wx.EVT_RADIOBUTTON, self.EventHTML )
|
|
|
|
if image_id is None:
|
|
|
|
self._image_info.SetValue( image_data )
|
|
self._image_data.SetValue( True )
|
|
|
|
else:
|
|
|
|
self._image_info.SetValue( image_id )
|
|
self._image_id.SetValue( True )
|
|
|
|
|
|
self._example_html_image = wx.StaticText( self, style = wx.ST_NO_AUTORESIZE )
|
|
|
|
self._tag_classnames_to_namespaces = wx.ListBox( self, style = wx.LB_SORT )
|
|
self._tag_classnames_to_namespaces.Bind( wx.EVT_LEFT_DCLICK, self.EventRemove )
|
|
|
|
for ( tag_classname, namespace ) in tag_classnames_to_namespaces.items(): self._tag_classnames_to_namespaces.Append( tag_classname + ' : ' + namespace, ( tag_classname, namespace ) )
|
|
|
|
self._tag_classname = wx.TextCtrl( self )
|
|
self._namespace = wx.TextCtrl( self )
|
|
|
|
self._add = wx.Button( self, label = 'add' )
|
|
self._add.Bind( wx.EVT_BUTTON, self.EventAdd )
|
|
|
|
self._example_html_tags = wx.StaticText( self, style = wx.ST_NO_AUTORESIZE )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) )
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
vbox1 = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
gridbox = wx.FlexGridSizer( 0, 2 )
|
|
|
|
gridbox.AddGrowableCol( 1, 1 )
|
|
|
|
gridbox.AddF( wx.StaticText( self, label='search url' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._search_url, FLAGS_EXPAND_BOTH_WAYS )
|
|
gridbox.AddF( wx.StaticText( self, label='search tag separator' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._search_separator, FLAGS_EXPAND_BOTH_WAYS )
|
|
gridbox.AddF( wx.StaticText( self, label='gallery page advance' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._gallery_advance_num, FLAGS_EXPAND_BOTH_WAYS )
|
|
gridbox.AddF( wx.StaticText( self, label='thumbnail classname' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._thumb_classname, FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
vbox1.AddF( wx.StaticText( self, label = '- search -' ), FLAGS_SMALL_INDENT )
|
|
vbox1.AddF( gridbox, FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox1.AddF( self._example_html_search, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
vbox2 = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
gridbox = wx.FlexGridSizer( 0, 2 )
|
|
|
|
gridbox.AddGrowableCol( 1, 1 )
|
|
|
|
gridbox.AddF( wx.StaticText( self, label='text' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._image_info, FLAGS_EXPAND_BOTH_WAYS )
|
|
gridbox.AddF( wx.StaticText( self, label='id of <img>' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._image_id, FLAGS_EXPAND_BOTH_WAYS )
|
|
gridbox.AddF( wx.StaticText( self, label='text of <a>' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._image_data, FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
vbox2.AddF( wx.StaticText( self, label = '- image -' ), FLAGS_SMALL_INDENT )
|
|
vbox2.AddF( gridbox, FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox2.AddF( self._example_html_image, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
vbox3 = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
hbox.AddF( self._tag_classname, FLAGS_MIXED )
|
|
hbox.AddF( self._namespace, FLAGS_MIXED )
|
|
hbox.AddF( self._add, FLAGS_MIXED )
|
|
|
|
vbox3.AddF( wx.StaticText( self, label = '- tags -' ), FLAGS_SMALL_INDENT )
|
|
vbox3.AddF( self._tag_classnames_to_namespaces, FLAGS_EXPAND_BOTH_WAYS )
|
|
vbox3.AddF( hbox, FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox3.AddF( self._example_html_tags, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
vbox.AddF( wx.StaticText( self, label = '- booru -' ), FLAGS_SMALL_INDENT )
|
|
vbox.AddF( vbox1, FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox.AddF( vbox2, FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox.AddF( vbox3, FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
self.SetSizer( vbox )
|
|
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def _GetInfo( self ):
|
|
|
|
booru_name = self._booru.GetName()
|
|
|
|
search_url = self._search_url.GetValue()
|
|
|
|
search_separator = self._search_separator.GetStringSelection()
|
|
|
|
gallery_advance_num = self._gallery_advance_num.GetValue()
|
|
|
|
thumb_classname = self._thumb_classname.GetValue()
|
|
|
|
if self._image_id.GetValue():
|
|
|
|
image_id = self._image_info.GetValue()
|
|
image_data = None
|
|
|
|
else:
|
|
|
|
image_id = None
|
|
image_data = self._image_info.GetValue()
|
|
|
|
|
|
tag_classnames_to_namespaces = { tag_classname : namespace for ( tag_classname, namespace ) in [ self._tag_classnames_to_namespaces.GetClientData( i ) for i in range( self._tag_classnames_to_namespaces.GetCount() ) ] }
|
|
|
|
return ( booru_name, search_url, search_separator, gallery_advance_num, thumb_classname, image_id, image_data, tag_classnames_to_namespaces )
|
|
|
|
|
|
def EventAdd( self, event ):
|
|
|
|
tag_classname = self._tag_classname.GetValue()
|
|
namespace = self._namespace.GetValue()
|
|
|
|
if tag_classname != '':
|
|
|
|
self._tag_classnames_to_namespaces.Append( tag_classname + ' : ' + namespace, ( tag_classname, namespace ) )
|
|
|
|
self._tag_classname.SetValue( '' )
|
|
self._namespace.SetValue( '' )
|
|
|
|
self.EventHTML( event )
|
|
|
|
|
|
|
|
def EventHTML( self, event ):
|
|
|
|
pass
|
|
|
|
|
|
def EventRemove( self, event ):
|
|
|
|
selection = self._tag_classnames_to_namespaces.GetSelection()
|
|
|
|
if selection != wx.NOT_FOUND:
|
|
|
|
self._tag_classnames_to_namespaces.Delete( selection )
|
|
|
|
self.EventHTML( event )
|
|
|
|
|
|
|
|
def GetBooru( self ):
|
|
|
|
( booru_name, search_url, search_separator, gallery_advance_num, thumb_classname, image_id, image_data, tag_classnames_to_namespaces ) = self._GetInfo()
|
|
|
|
return CC.Booru( booru_name, search_url, search_separator, gallery_advance_num, thumb_classname, image_id, image_data, tag_classnames_to_namespaces )
|
|
|
|
|
|
def HasChanges( self ):
|
|
|
|
( booru_name, my_search_url, my_search_separator, my_gallery_advance_num, my_thumb_classname, my_image_id, my_image_data, my_tag_classnames_to_namespaces ) = self._GetInfo()
|
|
|
|
( search_url, search_separator, gallery_advance_num, thumb_classname, image_id, image_data, tag_classnames_to_namespaces ) = self._booru.GetData()
|
|
|
|
if search_url != my_search_url: return True
|
|
|
|
if search_separator != my_search_separator: return True
|
|
|
|
if gallery_advance_num != my_gallery_advance_num: return True
|
|
|
|
if thumb_classname != my_thumb_classname: return True
|
|
|
|
if image_id != my_image_id: return True
|
|
|
|
if image_data != my_image_data: return True
|
|
|
|
if tag_classnames_to_namespaces != my_tag_classnames_to_namespaces: return True
|
|
|
|
return False
|
|
|
|
|
|
def Update( self, booru ):
|
|
|
|
( search_url, search_separator, gallery_advance_num, thumb_classname, image_id, image_data, tag_classnames_to_namespaces ) = booru.GetData()
|
|
|
|
self._search_url.SetValue( search_url )
|
|
|
|
self._search_separator.Select( self._search_separator.FindString( search_separator ) )
|
|
|
|
self._gallery_advance_num.SetValue( gallery_advance_num )
|
|
|
|
self._thumb_classname.SetValue( thumb_classname )
|
|
|
|
if image_id is None:
|
|
|
|
self._image_info.SetValue( image_data )
|
|
self._image_data.SetValue( True )
|
|
|
|
else:
|
|
|
|
self._image_info.SetValue( image_id )
|
|
self._image_id.SetValue( True )
|
|
|
|
|
|
self._tag_classnames_to_namespaces.Clear()
|
|
|
|
for ( tag_classname, namespace ) in tag_classnames_to_namespaces.items(): self._tag_classnames_to_namespaces.Append( tag_classname + ' : ' + namespace, ( tag_classname, namespace ) )
|
|
|
|
|
|
class DialogManageContacts( Dialog ):
|
|
|
|
def __init__( self, parent ):
|
|
|
|
def InitialiseControls():
|
|
|
|
self._edit_log = []
|
|
|
|
self._contacts = ClientGUICommon.ListBook( self )
|
|
|
|
( identities, contacts, deletable_names ) = wx.GetApp().Read( 'identities_and_contacts' )
|
|
|
|
self._deletable_names = deletable_names
|
|
|
|
for identity in identities:
|
|
|
|
name = identity.GetName()
|
|
|
|
page_info = ( DialogManageContactsContactPanel, ( self._contacts, identity ), { 'is_identity' : True } )
|
|
|
|
self._contacts.AddPage( page_info, ' identity - ' + name )
|
|
|
|
|
|
for contact in contacts:
|
|
|
|
name = contact.GetName()
|
|
|
|
page_info = ( DialogManageContactsContactPanel, ( self._contacts, contact ), { 'is_identity' : False } )
|
|
|
|
self._contacts.AddPage( page_info, name )
|
|
|
|
|
|
# bind events after population
|
|
self._contacts.Bind( wx.EVT_NOTEBOOK_PAGE_CHANGING, self.EventContactChanging )
|
|
self._contacts.Bind( wx.EVT_NOTEBOOK_PAGE_CHANGED, self.EventContactChanged )
|
|
|
|
self._add_contact_address = wx.Button( self, label='add by contact address' )
|
|
self._add_contact_address.Bind( wx.EVT_BUTTON, self.EventAddByContactAddress )
|
|
self._add_contact_address.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
self._add_manually = wx.Button( self, label='add manually' )
|
|
self._add_manually.Bind( wx.EVT_BUTTON, self.EventAddManually )
|
|
self._add_manually.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
self._remove = wx.Button( self, label='remove' )
|
|
self._remove.Bind( wx.EVT_BUTTON, self.EventRemove )
|
|
self._remove.SetForegroundColour( ( 128, 0, 0 ) )
|
|
|
|
self._export = wx.Button( self, label='export' )
|
|
self._export.Bind( wx.EVT_BUTTON, self.EventExport )
|
|
|
|
self._ok = wx.Button( self, label='ok' )
|
|
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.Bind( wx.EVT_BUTTON, self.EventCancel )
|
|
self._cancel.SetForegroundColour( ( 128, 0, 0 ) )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
add_remove_hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
add_remove_hbox.AddF( self._add_manually, FLAGS_MIXED )
|
|
add_remove_hbox.AddF( self._add_contact_address, FLAGS_MIXED )
|
|
add_remove_hbox.AddF( self._remove, FLAGS_MIXED )
|
|
add_remove_hbox.AddF( self._export, FLAGS_MIXED )
|
|
|
|
ok_hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
ok_hbox.AddF( self._ok, FLAGS_MIXED )
|
|
ok_hbox.AddF( self._cancel, FLAGS_MIXED )
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
vbox.AddF( self._contacts, FLAGS_EXPAND_BOTH_WAYS )
|
|
vbox.AddF( add_remove_hbox, FLAGS_SMALL_INDENT )
|
|
vbox.AddF( ok_hbox, FLAGS_BUTTON_SIZERS )
|
|
|
|
self.SetSizer( vbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
self.SetInitialSize( ( 980, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'manage contacts' )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
self.SetDropTarget( ClientGUICommon.FileDropTarget( self.Import ) )
|
|
|
|
self.EventContactChanged( None )
|
|
|
|
|
|
def _CheckCurrentContactIsValid( self ):
|
|
|
|
contact_panel = self._contacts.GetCurrentPage()
|
|
|
|
if contact_panel is not None:
|
|
|
|
contact = contact_panel.GetContact()
|
|
|
|
old_name = self._contacts.GetCurrentName()
|
|
name = contact.GetName()
|
|
|
|
if name != old_name and ' identity - ' + name != old_name:
|
|
|
|
if self._contacts.NameExists( name ) or self._contacts.NameExists( ' identity - ' + name ) or name == 'Anonymous': raise Exception( 'That name is already in use!' )
|
|
|
|
if old_name.startswith( ' identity - ' ): self._contacts.RenamePage( old_name, ' identity - ' + name )
|
|
else: self._contacts.RenamePage( old_name, name )
|
|
|
|
|
|
|
|
|
|
def EventAddByContactAddress( self, event ):
|
|
|
|
try: self._CheckCurrentContactIsValid()
|
|
except Exception as e:
|
|
|
|
wx.MessageBox( unicode( e ) )
|
|
|
|
return
|
|
|
|
|
|
with wx.TextEntryDialog( self, 'Enter contact\'s address in the form contact_key@hostname:port' ) as dlg:
|
|
|
|
if dlg.ShowModal() == wx.ID_OK:
|
|
|
|
try:
|
|
|
|
contact_address = dlg.GetValue()
|
|
|
|
try:
|
|
|
|
( contact_key_encoded, address ) = contact_address.split( '@' )
|
|
|
|
contact_key = contact_key_encoded.decode( 'hex' )
|
|
|
|
( host, port ) = address.split( ':' )
|
|
|
|
port = int( port )
|
|
|
|
except: raise Exception( 'Could not parse the address!' )
|
|
|
|
name = contact_key_encoded
|
|
|
|
contact = ClientConstantsMessages.Contact( None, name, host, port )
|
|
|
|
try:
|
|
|
|
connection = contact.GetConnection()
|
|
|
|
public_key = connection.Get( 'publickey', contact_key = contact_key.encode( 'hex' ) )
|
|
|
|
except: raise Exception( 'Could not fetch the contact\'s public key from the address:' + os.linesep + traceback.format_exc() )
|
|
|
|
contact = ClientConstantsMessages.Contact( public_key, name, host, port )
|
|
|
|
self._edit_log.append( ( 'add', contact ) )
|
|
|
|
page = DialogManageContactsContactPanel( self._contacts, contact, is_identity = False )
|
|
|
|
self._deletable_names.add( name )
|
|
|
|
self._contacts.AddPage( page, name, select = True )
|
|
|
|
except Exception as e:
|
|
|
|
wx.MessageBox( unicode( e ) )
|
|
|
|
self.EventAddByContactAddress( event )
|
|
|
|
|
|
|
|
|
|
|
|
def EventAddManually( self, event ):
|
|
|
|
try: self._CheckCurrentContactIsValid()
|
|
except Exception as e:
|
|
|
|
wx.MessageBox( unicode( e ) )
|
|
|
|
return
|
|
|
|
|
|
with wx.TextEntryDialog( self, 'Enter new contact\'s name' ) as dlg:
|
|
|
|
if dlg.ShowModal() == wx.ID_OK:
|
|
|
|
try:
|
|
|
|
name = dlg.GetValue()
|
|
|
|
if self._contacts.NameExists( name ) or self._contacts.NameExists( ' identity - ' + name ) or name == 'Anonymous': raise Exception( 'That name is already in use!' )
|
|
|
|
if name == '': raise Exception( 'Please enter a nickname for the service.' )
|
|
|
|
public_key = None
|
|
host = 'hostname'
|
|
port = 45871
|
|
|
|
contact = ClientConstantsMessages.Contact( public_key, name, host, port )
|
|
|
|
self._edit_log.append( ( 'add', contact ) )
|
|
|
|
page = DialogManageContactsContactPanel( self._contacts, contact, is_identity = False )
|
|
|
|
self._deletable_names.add( name )
|
|
|
|
self._contacts.AddPage( page, name, select = True )
|
|
|
|
except Exception as e:
|
|
|
|
wx.MessageBox( unicode( e ) )
|
|
|
|
self.EventAddManually( event )
|
|
|
|
|
|
|
|
|
|
|
|
def EventCancel( self, event ): self.EndModal( wx.ID_CANCEL )
|
|
|
|
def EventContactChanged( self, event ):
|
|
|
|
contact_panel = self._contacts.GetCurrentPage()
|
|
|
|
if contact_panel is not None:
|
|
|
|
old_name = contact_panel.GetOriginalName()
|
|
|
|
if old_name in self._deletable_names: self._remove.Enable()
|
|
else: self._remove.Disable()
|
|
|
|
|
|
|
|
def EventContactChanging( self, event ):
|
|
|
|
try: self._CheckCurrentContactIsValid()
|
|
except Exception as e:
|
|
|
|
wx.MessageBox( unicode( e ) )
|
|
|
|
event.Veto()
|
|
|
|
|
|
|
|
def EventExport( self, event ):
|
|
|
|
contact_panel = self._contacts.GetCurrentPage()
|
|
|
|
if contact_panel is not None:
|
|
|
|
name = self._contacts.GetCurrentName()
|
|
|
|
contact = contact_panel.GetContact()
|
|
|
|
try:
|
|
|
|
with wx.FileDialog( self, 'select where to export contact', defaultFile = name + '.yaml', style = wx.FD_SAVE ) as dlg:
|
|
|
|
if dlg.ShowModal() == wx.ID_OK:
|
|
|
|
with open( dlg.GetPath(), 'wb' ) as f: f.write( yaml.safe_dump( contact ) )
|
|
|
|
|
|
|
|
except:
|
|
|
|
with wx.FileDialog( self, 'select where to export contact', defaultFile = 'contact.yaml', style = wx.FD_SAVE ) as dlg:
|
|
|
|
if dlg.ShowModal() == wx.ID_OK:
|
|
|
|
with open( dlg.GetPath(), 'wb' ) as f: f.write( yaml.safe_dump( contact ) )
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def EventOk( self, event ):
|
|
|
|
try: self._CheckCurrentContactIsValid()
|
|
except Exception as e:
|
|
|
|
wx.MessageBox( unicode( e ) )
|
|
|
|
return
|
|
|
|
|
|
for ( name, page ) in self._contacts.GetNameToPageDict().items():
|
|
|
|
if page.HasChanges(): self._edit_log.append( ( 'edit', ( page.GetOriginalName(), page.GetContact() ) ) )
|
|
|
|
|
|
try:
|
|
|
|
if len( self._edit_log ) > 0: wx.GetApp().Write( 'update_contacts', self._edit_log )
|
|
|
|
except Exception as e: wx.MessageBox( 'Saving contacts to DB raised this error: ' + unicode( e ) )
|
|
|
|
self.EndModal( wx.ID_OK )
|
|
|
|
|
|
# this isn't used yet!
|
|
def EventRemove( self, event ):
|
|
|
|
contact_panel = self._contacts.GetCurrentPage()
|
|
|
|
if contact_panel is not None:
|
|
|
|
name = contact_panel.GetOriginalName()
|
|
|
|
self._edit_log.append( ( 'delete', name ) )
|
|
|
|
self._contacts.DeleteCurrentPage()
|
|
|
|
self._deletable_names.discard( name )
|
|
|
|
|
|
|
|
def Import( self, paths ):
|
|
|
|
try: self._CheckCurrentContactIsValid()
|
|
except Exception as e:
|
|
|
|
wx.MessageBox( unicode( e ) )
|
|
|
|
return
|
|
|
|
|
|
for path in paths:
|
|
|
|
try:
|
|
|
|
with open( path, 'rb' ) as f: file = f.read()
|
|
|
|
obj = yaml.safe_load( file )
|
|
|
|
if type( obj ) == ClientConstantsMessages.Contact:
|
|
|
|
contact = obj
|
|
|
|
name = contact.GetName()
|
|
|
|
if self._contacts.NameExists( name ) or self._contacts.NameExists( ' identities - ' + name ) or name == 'Anonymous':
|
|
|
|
message = 'There already exists a contact or identity with the name ' + name + '. Do you want to overwrite, or make a new contact?'
|
|
|
|
with DialogYesNo( self, message, yes_label = 'overwrite', no_label = 'make new' ) as dlg:
|
|
|
|
if True:
|
|
|
|
name_to_page_dict = self._contacts.GetNameToPageDict()
|
|
|
|
if name in name_to_page_dict: page = name_to_page_dict[ name ]
|
|
else: page = name_to_page_dict[ ' identities - ' + name ]
|
|
|
|
page.Update( contact )
|
|
|
|
else:
|
|
|
|
while self._contacts.NameExists( name ) or self._contacts.NameExists( ' identities - ' + name ) or name == 'Anonymous': name = name + str( random.randint( 0, 9 ) )
|
|
|
|
( public_key, old_name, host, port ) = contact.GetInfo()
|
|
|
|
new_contact = ClientConstantsMessages.Contact( public_key, name, host, port )
|
|
|
|
self._edit_log.append( ( 'add', contact ) )
|
|
|
|
self._deletable_names.add( name )
|
|
|
|
page = DialogManageContactsContactPanel( self._contacts, contact, False )
|
|
|
|
self._contacts.AddPage( page, name, select = True )
|
|
|
|
|
|
|
|
else:
|
|
|
|
( public_key, old_name, host, port ) = contact.GetInfo()
|
|
|
|
new_contact = ClientConstantsMessages.Contact( public_key, name, host, port )
|
|
|
|
self._edit_log.append( ( 'add', contact ) )
|
|
|
|
self._deletable_names.add( name )
|
|
|
|
page = DialogManageContactsContactPanel( self._contacts, contact, False )
|
|
|
|
self._contacts.AddPage( page, name, select = True )
|
|
|
|
|
|
|
|
except:
|
|
|
|
wx.MessageBox( traceback.format_exc() )
|
|
|
|
|
|
|
|
|
|
class DialogManageContactsContactPanel( wx.Panel ):
|
|
|
|
def __init__( self, parent, contact, is_identity ):
|
|
|
|
wx.Panel.__init__( self, parent )
|
|
|
|
self._contact = contact
|
|
self._is_identity = is_identity
|
|
|
|
( public_key, name, host, port ) = contact.GetInfo()
|
|
|
|
contact_key = contact.GetContactKey()
|
|
|
|
def InitialiseControls():
|
|
|
|
self._name = wx.TextCtrl( self, value = name )
|
|
|
|
contact_address = host + ':' + str( port )
|
|
|
|
if contact_key is not None: contact_address = contact_key.encode( 'hex' ) + '@' + contact_address
|
|
|
|
self._contact_address = wx.TextCtrl( self, value = contact_address )
|
|
|
|
self._public_key = wx.TextCtrl( self, style = wx.TE_MULTILINE )
|
|
|
|
if public_key is not None: self._public_key.SetValue( public_key )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) )
|
|
|
|
gridbox = wx.FlexGridSizer( 0, 2 )
|
|
|
|
gridbox.AddGrowableCol( 1, 1 )
|
|
|
|
gridbox.AddF( wx.StaticText( self, label='name' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._name, FLAGS_EXPAND_BOTH_WAYS )
|
|
gridbox.AddF( wx.StaticText( self, label='contact address' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._contact_address, FLAGS_EXPAND_BOTH_WAYS )
|
|
gridbox.AddF( wx.StaticText( self, label = 'public key' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._public_key, FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
vbox.AddF( wx.StaticText( self, label = '- contact -' ), FLAGS_SMALL_INDENT )
|
|
vbox.AddF( gridbox, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
self.SetSizer( vbox )
|
|
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def _GetInfo( self ):
|
|
|
|
public_key = self._public_key.GetValue()
|
|
|
|
if public_key == '': public_key = None
|
|
|
|
name = self._name.GetValue()
|
|
|
|
contact_address = self._contact_address.GetValue()
|
|
|
|
try:
|
|
|
|
if '@' in contact_address: ( contact_key, address ) = contact_address.split( '@' )
|
|
else: address = contact_address
|
|
|
|
( host, port ) = address.split( ':' )
|
|
|
|
try: port = int( port )
|
|
except:
|
|
|
|
port = 45871
|
|
|
|
wx.MessageBox( 'Could not parse the port!' )
|
|
|
|
|
|
except:
|
|
|
|
host = 'hostname'
|
|
port = 45871
|
|
|
|
wx.MessageBox( 'Could not parse the contact\'s address!' )
|
|
|
|
|
|
return [ public_key, name, host, port ]
|
|
|
|
|
|
def GetContact( self ):
|
|
|
|
[ public_key, name, host, port ] = self._GetInfo()
|
|
|
|
return ClientConstantsMessages.Contact( public_key, name, host, port )
|
|
|
|
|
|
def GetOriginalName( self ): return self._contact.GetName()
|
|
|
|
def HasChanges( self ):
|
|
|
|
[ my_public_key, my_name, my_host, my_port ] = self._GetInfo()
|
|
|
|
[ public_key, name, host, port ] = self._contact.GetInfo()
|
|
|
|
if my_public_key != public_key: return True
|
|
|
|
if my_name != name: return True
|
|
|
|
if my_host != host: return True
|
|
|
|
if my_port != port: return True
|
|
|
|
return False
|
|
|
|
|
|
def Update( self, contact ):
|
|
|
|
( public_key, name, host, port ) = contact.GetInfo()
|
|
|
|
contact_key = contact.GetContactKey()
|
|
|
|
self._name.SetValue( name )
|
|
|
|
contact_address = host + ':' + str( port )
|
|
|
|
if contact_key is not None: contact_address = contact_key.encode( 'hex' ) + '@' + contact_address
|
|
|
|
self._contact_address.SetValue( contact_address )
|
|
|
|
if public_key is None: public_key = ''
|
|
|
|
self._public_key.SetValue( public_key )
|
|
|
|
|
|
class DialogManage4chanPass( Dialog ):
|
|
|
|
def __init__( self, parent ):
|
|
|
|
def InitialiseControls():
|
|
|
|
self._token = wx.TextCtrl( self, value = token )
|
|
self._pin = wx.TextCtrl( self, value = pin )
|
|
|
|
self._status = wx.StaticText( self )
|
|
|
|
self._SetStatus()
|
|
|
|
self._reauthenticate = wx.Button( self, label = 'reauthenticate' )
|
|
self._reauthenticate.Bind( wx.EVT_BUTTON, self.EventReauthenticate )
|
|
|
|
self._ok = wx.Button( self, label='Ok' )
|
|
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.Bind( wx.EVT_BUTTON, self.EventCancel )
|
|
self._cancel.SetForegroundColour( ( 128, 0, 0 ) )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
gridbox = wx.FlexGridSizer( 0, 2 )
|
|
|
|
gridbox.AddGrowableCol( 1, 1 )
|
|
|
|
gridbox.AddF( wx.StaticText( self, label='token' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._token, FLAGS_EXPAND_BOTH_WAYS )
|
|
gridbox.AddF( wx.StaticText( self, label='pin' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._pin, FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
b_box = wx.BoxSizer( wx.HORIZONTAL )
|
|
b_box.AddF( self._ok, FLAGS_MIXED )
|
|
b_box.AddF( self._cancel, FLAGS_MIXED )
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
vbox.AddF( gridbox, FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox.AddF( self._status, FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox.AddF( self._reauthenticate, FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox.AddF( b_box, FLAGS_BUTTON_SIZERS )
|
|
|
|
self.SetSizer( vbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
x = max( x, 240 )
|
|
|
|
self.SetInitialSize( ( x, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'manage 4chan pass' )
|
|
|
|
( token, pin, self._timeout ) = wx.GetApp().Read( '4chan_pass' )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def _SetStatus( self ):
|
|
|
|
if self._timeout == 0: label = 'not authenticated'
|
|
elif self._timeout < int( time.time() ): label = 'timed out'
|
|
else: label = 'authenticated - ' + HC.ConvertTimestampToPrettyExpires( self._timeout )
|
|
|
|
self._status.SetLabel( label )
|
|
|
|
|
|
def EventCancel( self, event ): self.EndModal( wx.ID_CANCEL )
|
|
|
|
def EventOk( self, event ):
|
|
|
|
token = self._token.GetValue()
|
|
pin = self._pin.GetValue()
|
|
|
|
wx.GetApp().Write( '4chan_pass', token, pin, self._timeout )
|
|
|
|
self.EndModal( wx.ID_OK )
|
|
|
|
|
|
def EventReauthenticate( self, event ):
|
|
|
|
try:
|
|
|
|
token = self._token.GetValue()
|
|
pin = self._pin.GetValue()
|
|
|
|
form_fields = {}
|
|
|
|
form_fields[ 'act' ] = 'do_login'
|
|
form_fields[ 'id' ] = token
|
|
form_fields[ 'pin' ] = pin
|
|
form_fields[ 'long_login' ] = 'yes'
|
|
|
|
( ct, body ) = CC.GenerateMultipartFormDataCTAndBodyFromDict( form_fields )
|
|
|
|
headers = {}
|
|
headers[ 'Content-Type' ] = ct
|
|
|
|
connection = CC.AdvancedHTTPConnection( url = 'https://sys.4chan.org/', accept_cookies = True )
|
|
|
|
connection.request( 'POST', '/auth', headers = headers, body = body )
|
|
|
|
cookies = connection.GetCookies()
|
|
|
|
self._timeout = int( time.time() ) + 365 * 24 * 3600
|
|
|
|
wx.GetApp().Write( '4chan_pass', token, pin, self._timeout )
|
|
|
|
self._SetStatus()
|
|
|
|
except Exception as e:
|
|
wx.MessageBox( traceback.format_exc() )
|
|
wx.MessageBox( unicode( e ) )
|
|
|
|
|
|
class DialogManageImageboards( Dialog ):
|
|
|
|
def __init__( self, parent ):
|
|
|
|
def InitialiseControls():
|
|
|
|
self._edit_log = []
|
|
|
|
self._sites = ClientGUICommon.ListBook( self )
|
|
|
|
sites = wx.GetApp().Read( 'imageboards' )
|
|
|
|
for ( name, imageboards ) in sites:
|
|
|
|
page_info = ( DialogManageImageboardsSitePanel, ( self._sites, imageboards ), {} )
|
|
|
|
self._sites.AddPage( page_info, name )
|
|
|
|
|
|
self._add = wx.Button( self, label='add' )
|
|
self._add.Bind( wx.EVT_BUTTON, self.EventAdd )
|
|
self._add.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
self._remove = wx.Button( self, label='remove' )
|
|
self._remove.Bind( wx.EVT_BUTTON, self.EventRemove )
|
|
self._remove.SetForegroundColour( ( 128, 0, 0 ) )
|
|
|
|
self._export = wx.Button( self, label='export' )
|
|
self._export.Bind( wx.EVT_BUTTON, self.EventExport )
|
|
|
|
self._ok = wx.Button( self, label='ok' )
|
|
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.Bind( wx.EVT_BUTTON, self.EventCancel )
|
|
self._cancel.SetForegroundColour( ( 128, 0, 0 ) )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
add_remove_hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
add_remove_hbox.AddF( self._add, FLAGS_MIXED )
|
|
add_remove_hbox.AddF( self._remove, FLAGS_MIXED )
|
|
add_remove_hbox.AddF( self._export, FLAGS_MIXED )
|
|
|
|
ok_hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
ok_hbox.AddF( self._ok, FLAGS_MIXED )
|
|
ok_hbox.AddF( self._cancel, FLAGS_MIXED )
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
vbox.AddF( self._sites, FLAGS_EXPAND_BOTH_WAYS )
|
|
vbox.AddF( add_remove_hbox, FLAGS_SMALL_INDENT )
|
|
vbox.AddF( ok_hbox, FLAGS_BUTTON_SIZERS )
|
|
|
|
self.SetSizer( vbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
self.SetInitialSize( ( 980, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'manage imageboards' )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
self.SetDropTarget( ClientGUICommon.FileDropTarget( self.Import ) )
|
|
|
|
|
|
def EventAdd( self, event ):
|
|
|
|
with wx.TextEntryDialog( self, 'Enter new site\'s name' ) as dlg:
|
|
|
|
if dlg.ShowModal() == wx.ID_OK:
|
|
|
|
try:
|
|
|
|
name = dlg.GetValue()
|
|
|
|
if self._sites.NameExists( name ): raise Exception( 'That name is already in use!' )
|
|
|
|
if name == '': raise Exception( 'Please enter a nickname for the service.' )
|
|
|
|
self._edit_log.append( ( 'add', name ) )
|
|
|
|
page = DialogManageImageboardsSitePanel( self._sites, [] )
|
|
|
|
self._sites.AddPage( page, name, select = True )
|
|
|
|
except Exception as e:
|
|
|
|
wx.MessageBox( unicode( e ) )
|
|
|
|
self.EventAdd( event )
|
|
|
|
|
|
|
|
|
|
|
|
def EventCancel( self, event ): self.EndModal( wx.ID_CANCEL )
|
|
|
|
def EventExport( self, event ):
|
|
|
|
site_panel = self._sites.GetCurrentPage()
|
|
|
|
if site_panel is not None:
|
|
|
|
name = self._sites.GetCurrentName()
|
|
|
|
imageboards = site_panel.GetImageboards()
|
|
|
|
dict = { name : imageboards }
|
|
|
|
with wx.FileDialog( self, 'select where to export site', defaultFile = 'site.yaml', style = wx.FD_SAVE ) as dlg:
|
|
|
|
if dlg.ShowModal() == wx.ID_OK:
|
|
|
|
with open( dlg.GetPath(), 'wb' ) as f: f.write( yaml.safe_dump( dict ) )
|
|
|
|
|
|
|
|
|
|
|
|
def EventOk( self, event ):
|
|
|
|
for ( name, page ) in self._sites.GetNameToPageDict().items():
|
|
|
|
if page.HasChanges(): self._edit_log.append( ( 'edit', ( name, page.GetChanges() ) ) )
|
|
|
|
|
|
try:
|
|
|
|
if len( self._edit_log ) > 0: wx.GetApp().Write( 'update_imageboards', self._edit_log )
|
|
|
|
except Exception as e: wx.MessageBox( 'Saving imageboards to DB raised this error: ' + unicode( e ) )
|
|
|
|
self.EndModal( wx.ID_OK )
|
|
|
|
|
|
def EventRemove( self, event ):
|
|
|
|
site_panel = self._sites.GetCurrentPage()
|
|
|
|
if site_panel is not None:
|
|
|
|
name = self._sites.GetCurrentName()
|
|
|
|
self._edit_log.append( ( 'delete', name ) )
|
|
|
|
self._sites.DeleteCurrentPage()
|
|
|
|
|
|
|
|
def Import( self, paths ):
|
|
|
|
for path in paths:
|
|
|
|
try:
|
|
|
|
with open( path, 'rb' ) as f: file = f.read()
|
|
|
|
thing = yaml.safe_load( file )
|
|
|
|
if type( thing ) == dict:
|
|
|
|
( name, imageboards ) = thing.items()[0]
|
|
|
|
if not self._sites.NameExists( name ):
|
|
|
|
self._edit_log.append( ( 'add', name ) )
|
|
|
|
page = DialogManageImageboardsSitePanel( self._sites, [] )
|
|
|
|
self._sites.AddPage( page, name, select = True )
|
|
|
|
|
|
page = self._sites.GetNameToPageDict()[ name ]
|
|
|
|
for imageboard in imageboards:
|
|
|
|
if type( imageboard ) == CC.Imageboard: page.UpdateImageboard( imageboard )
|
|
|
|
|
|
elif type( thing ) == CC.Imageboard:
|
|
|
|
imageboard = thing
|
|
|
|
page = self._sites.GetCurrentPage()
|
|
|
|
page.UpdateImageboard( imageboard )
|
|
|
|
|
|
except:
|
|
|
|
wx.MessageBox( traceback.format_exc() )
|
|
|
|
|
|
|
|
|
|
class DialogManageImageboardsSitePanel( wx.Panel ):
|
|
|
|
def __init__( self, parent, imageboards ):
|
|
|
|
wx.Panel.__init__( self, parent )
|
|
|
|
def InitialiseControls():
|
|
|
|
self._edit_log = []
|
|
|
|
self._imageboards = ClientGUICommon.ListBook( self )
|
|
|
|
for imageboard in imageboards:
|
|
|
|
name = imageboard.GetName()
|
|
|
|
page_info = ( DialogManageImageboardsImageboardPanel, ( self._imageboards, imageboard ), {} )
|
|
|
|
self._imageboards.AddPage( page_info, name )
|
|
|
|
|
|
self._add = wx.Button( self, label='add' )
|
|
self._add.Bind( wx.EVT_BUTTON, self.EventAdd )
|
|
self._add.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
self._remove = wx.Button( self, label='remove' )
|
|
self._remove.Bind( wx.EVT_BUTTON, self.EventRemove )
|
|
self._remove.SetForegroundColour( ( 128, 0, 0 ) )
|
|
|
|
self._export = wx.Button( self, label='export' )
|
|
self._export.Bind( wx.EVT_BUTTON, self.EventExport )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
add_remove_hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
add_remove_hbox.AddF( self._add, FLAGS_MIXED )
|
|
add_remove_hbox.AddF( self._remove, FLAGS_MIXED )
|
|
add_remove_hbox.AddF( self._export, FLAGS_MIXED )
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
vbox.AddF( wx.StaticText( self, label = '- site -' ), FLAGS_SMALL_INDENT )
|
|
vbox.AddF( self._imageboards, FLAGS_EXPAND_BOTH_WAYS )
|
|
vbox.AddF( add_remove_hbox, FLAGS_SMALL_INDENT )
|
|
|
|
self.SetSizer( vbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
self.SetInitialSize( ( 980, y ) )
|
|
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def EventAdd( self, event ):
|
|
|
|
with wx.TextEntryDialog( self, 'Enter new imageboard\'s name' ) as dlg:
|
|
|
|
if dlg.ShowModal() == wx.ID_OK:
|
|
|
|
try:
|
|
|
|
name = dlg.GetValue()
|
|
|
|
if self._imageboards.NameExists( name ): raise Exception( 'That name is already in use!' )
|
|
|
|
if name == '': raise Exception( 'Please enter a nickname for the service.' )
|
|
|
|
imageboard = CC.Imageboard( name, '', 60, [], {} )
|
|
|
|
self._edit_log.append( ( 'add', name ) )
|
|
|
|
page = DialogManageImageboardsImageboardPanel( self._imageboards, imageboard )
|
|
|
|
self._imageboards.AddPage( page, name, select = True )
|
|
|
|
except Exception as e:
|
|
|
|
wx.MessageBox( unicode( e ) )
|
|
|
|
self.EventAdd( event )
|
|
|
|
|
|
|
|
|
|
|
|
def EventExport( self, event ):
|
|
|
|
imageboard_panel = self._imageboards.GetCurrentPage()
|
|
|
|
if imageboard_panel is not None:
|
|
|
|
imageboard = imageboard_panel.GetImageboard()
|
|
|
|
with wx.FileDialog( self, 'select where to export imageboard', defaultFile = 'imageboard.yaml', style = wx.FD_SAVE ) as dlg:
|
|
|
|
if dlg.ShowModal() == wx.ID_OK:
|
|
|
|
with open( dlg.GetPath(), 'wb' ) as f: f.write( yaml.safe_dump( imageboard ) )
|
|
|
|
|
|
|
|
|
|
|
|
def EventRemove( self, event ):
|
|
|
|
imageboard_panel = self._imageboards.GetCurrentPage()
|
|
|
|
if imageboard_panel is not None:
|
|
|
|
name = self._imageboards.GetCurrentName()
|
|
|
|
self._edit_log.append( ( 'delete', name ) )
|
|
|
|
self._imageboards.DeleteCurrentPage()
|
|
|
|
|
|
|
|
def GetChanges( self ):
|
|
|
|
for page in self._imageboards.GetNameToPageDict().values():
|
|
|
|
if page.HasChanges(): self._edit_log.append( ( 'edit', page.GetImageboard() ) )
|
|
|
|
|
|
return self._edit_log
|
|
|
|
|
|
def GetImageboards( self ): return [ page.GetImageboard() for page in self._imageboards.GetNameToPageDict().values() ]
|
|
|
|
def HasChanges( self ): return len( self._edit_log ) > 0 or True in ( page.HasChanges() for page in self._imageboards.GetNameToPageDict().values() )
|
|
|
|
def UpdateImageboard( self, imageboard ):
|
|
|
|
name = imageboard.GetName()
|
|
|
|
if not self._imageboards.NameExists( name ):
|
|
|
|
new_imageboard = CC.Imageboard( name, '', 60, [], {} )
|
|
|
|
self._edit_log.append( ( 'add', name ) )
|
|
|
|
page = DialogManageImageboardsImageboardPanel( self._imageboards, new_imageboard )
|
|
|
|
self._imageboards.AddPage( page, name, select = True )
|
|
|
|
|
|
page = self._imageboards.GetNameToPageDict()[ name ]
|
|
|
|
page.Update( imageboard )
|
|
|
|
|
|
class DialogManageImageboardsImageboardPanel( wx.Panel ):
|
|
|
|
def __init__( self, parent, imageboard ):
|
|
|
|
wx.Panel.__init__( self, parent )
|
|
|
|
self._imageboard = imageboard
|
|
|
|
( post_url, flood_time, form_fields, restrictions ) = self._imageboard.GetBoardInfo()
|
|
|
|
def InitialiseControls():
|
|
|
|
self._post_url = wx.TextCtrl( self, value = post_url )
|
|
|
|
self._flood_time = wx.SpinCtrl( self, min = 5, max = 1200, initial = flood_time )
|
|
|
|
self._form_fields = ClientGUICommon.SaneListCtrl( self, 350, [ ( 'name', 120 ), ( 'type', 120 ), ( 'default', -1 ), ( 'editable', 120 ) ] )
|
|
|
|
for ( name, type, default, editable ) in form_fields:
|
|
|
|
self._form_fields.Append( ( name, CC.field_string_lookup[ type ], str( default ), str( editable ) ), ( name, type, default, editable ) )
|
|
|
|
|
|
self._add = wx.Button( self, label='add' )
|
|
self._add.Bind( wx.EVT_BUTTON, self.EventAdd )
|
|
|
|
self._edit = wx.Button( self, label='edit' )
|
|
self._edit.Bind( wx.EVT_BUTTON, self.EventEdit )
|
|
|
|
self._delete = wx.Button( self, label='delete' )
|
|
self._delete.Bind( wx.EVT_BUTTON, self.EventDelete )
|
|
|
|
if CC.RESTRICTION_MIN_RESOLUTION in restrictions: value = restrictions[ CC.RESTRICTION_MIN_RESOLUTION ]
|
|
else: value = None
|
|
|
|
self._min_resolution = ClientGUICommon.NoneableSpinCtrl( self, 'min resolution', value, num_dimensions = 2 )
|
|
|
|
if CC.RESTRICTION_MAX_RESOLUTION in restrictions: value = restrictions[ CC.RESTRICTION_MAX_RESOLUTION ]
|
|
else: value = None
|
|
|
|
self._max_resolution = ClientGUICommon.NoneableSpinCtrl( self, 'max resolution', value, num_dimensions = 2 )
|
|
|
|
if CC.RESTRICTION_MAX_FILE_SIZE in restrictions: value = restrictions[ CC.RESTRICTION_MAX_FILE_SIZE ]
|
|
else: value = None
|
|
|
|
self._max_file_size = ClientGUICommon.NoneableSpinCtrl( self, 'max file size (KB)', value, multiplier = 1024 )
|
|
|
|
self._mimes = wx.ListBox( self )
|
|
|
|
if CC.RESTRICTION_ALLOWED_MIMES in restrictions: mimes = restrictions[ CC.RESTRICTION_ALLOWED_MIMES ]
|
|
else: mimes = []
|
|
|
|
for mime in mimes: self._mimes.Append( HC.mime_string_lookup[ mime ], mime )
|
|
|
|
self._mime_choice = wx.Choice( self )
|
|
|
|
for mime in HC.ALLOWED_MIMES: self._mime_choice.Append( HC.mime_string_lookup[ mime ], mime )
|
|
|
|
self._mime_choice.SetSelection( 0 )
|
|
|
|
self._add_mime = wx.Button( self, label = 'add' )
|
|
self._add_mime.Bind( wx.EVT_BUTTON, self.EventAddMime )
|
|
|
|
self._remove_mime = wx.Button( self, label = 'remove' )
|
|
self._remove_mime.Bind( wx.EVT_BUTTON, self.EventRemoveMime )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) )
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
gridbox = wx.FlexGridSizer( 0, 2 )
|
|
|
|
gridbox.AddGrowableCol( 1, 1 )
|
|
|
|
gridbox.AddF( wx.StaticText( self, label='POST URL' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._post_url, FLAGS_EXPAND_BOTH_WAYS )
|
|
gridbox.AddF( wx.StaticText( self, label='flood time' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._flood_time, FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
field_box = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
field_box.AddF( wx.StaticText( self, label = '- form fields -' ), FLAGS_SMALL_INDENT )
|
|
field_box.AddF( self._form_fields, FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
h_b_box = wx.BoxSizer( wx.HORIZONTAL )
|
|
h_b_box.AddF( self._add, FLAGS_MIXED )
|
|
h_b_box.AddF( self._edit, FLAGS_MIXED )
|
|
h_b_box.AddF( self._delete, FLAGS_MIXED )
|
|
|
|
mime_buttons_box = wx.BoxSizer( wx.HORIZONTAL )
|
|
mime_buttons_box.AddF( self._mime_choice, FLAGS_MIXED )
|
|
mime_buttons_box.AddF( self._add_mime, FLAGS_MIXED )
|
|
mime_buttons_box.AddF( self._remove_mime, FLAGS_MIXED )
|
|
|
|
m_box = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
m_box.AddF( wx.StaticText( self, label = '- allowed mimes -' ), FLAGS_SMALL_INDENT )
|
|
m_box.AddF( self._mimes, FLAGS_EXPAND_BOTH_WAYS )
|
|
m_box.AddF( mime_buttons_box, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
restrictions_box = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
restrictions_box.AddF( wx.StaticText( self, label = '- restrictions -' ), FLAGS_SMALL_INDENT )
|
|
restrictions_box.AddF( self._min_resolution, FLAGS_EXPAND_PERPENDICULAR )
|
|
restrictions_box.AddF( self._max_resolution, FLAGS_EXPAND_PERPENDICULAR )
|
|
restrictions_box.AddF( self._max_file_size, FLAGS_EXPAND_PERPENDICULAR )
|
|
restrictions_box.AddF( m_box, FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
vbox.AddF( wx.StaticText( self, label = '- imageboard -' ), FLAGS_SMALL_INDENT )
|
|
vbox.AddF( gridbox, FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox.AddF( field_box, FLAGS_EXPAND_BOTH_WAYS )
|
|
vbox.AddF( h_b_box, FLAGS_BUTTON_SIZERS )
|
|
vbox.AddF( restrictions_box, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
self.SetSizer( vbox )
|
|
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def _GetInfo( self ):
|
|
|
|
imageboard_name = self._imageboard.GetName()
|
|
|
|
post_url = self._post_url.GetValue()
|
|
|
|
flood_time = self._flood_time.GetValue()
|
|
|
|
# list instead of tumple cause of yaml comparisons
|
|
form_fields = self._form_fields.GetClientData()
|
|
|
|
restrictions = {}
|
|
|
|
# yaml list again
|
|
value = self._min_resolution.GetValue()
|
|
if value is not None: restrictions[ CC.RESTRICTION_MIN_RESOLUTION ] = list( value )
|
|
|
|
# yaml list again
|
|
value = self._max_resolution.GetValue()
|
|
if value is not None: restrictions[ CC.RESTRICTION_MAX_RESOLUTION ] = list( value )
|
|
|
|
value = self._max_file_size.GetValue()
|
|
if value is not None: restrictions[ CC.RESTRICTION_MAX_FILE_SIZE ] = value
|
|
|
|
mimes = [ self._mimes.GetClientData( i ) for i in range( self._mimes.GetCount() ) ]
|
|
|
|
if len( mimes ) > 0: restrictions[ CC.RESTRICTION_ALLOWED_MIMES ] = mimes
|
|
|
|
return ( imageboard_name, post_url, flood_time, form_fields, restrictions )
|
|
|
|
|
|
def EventAdd( self, event ):
|
|
|
|
try:
|
|
|
|
with DialogInputNewFormField( self ) as dlg:
|
|
|
|
if dlg.ShowModal() == wx.ID_OK:
|
|
|
|
( name, type, default, editable ) = dlg.GetFormField()
|
|
|
|
if name in [ form_field[0] for form_field in self._form_fields.GetClientData() ]:
|
|
|
|
wx.MessageBox( 'There is already a field named ' + name )
|
|
|
|
self.EventAdd( event )
|
|
|
|
return
|
|
|
|
|
|
self._form_fields.Append( ( name, CC.field_string_lookup[ type ], str( default ), str( editable ) ), ( name, type, default, editable ) )
|
|
|
|
|
|
|
|
except Exception as e: wx.MessageBox( unicode( e ) )
|
|
|
|
|
|
def EventAddMime( self, event ):
|
|
|
|
selection = self._mime_choice.GetSelection()
|
|
|
|
if selection != wx.NOT_FOUND:
|
|
|
|
mime = self._mime_choice.GetClientData( selection )
|
|
|
|
existing_mimes = [ self._mimes.GetClientData( i ) for i in range( self._mimes.GetCount() ) ]
|
|
|
|
if mime not in existing_mimes: self._mimes.Append( HC.mime_string_lookup[ mime ], mime )
|
|
|
|
|
|
|
|
def EventDelete( self, event ): self._form_fields.RemoveAllSelected()
|
|
|
|
def EventRemoveMime( self, event ):
|
|
|
|
selection = self._mimes.GetSelection()
|
|
|
|
if selection != wx.NOT_FOUND: self._mimes.Delete( selection )
|
|
|
|
|
|
def EventEdit( self, event ):
|
|
|
|
indices = self._form_fields.GetAllSelected()
|
|
|
|
for index in indices:
|
|
|
|
( name, type, default, editable ) = self._form_fields.GetClientData( index )
|
|
|
|
form_field = ( name, type, default, editable )
|
|
|
|
try:
|
|
|
|
with DialogInputNewFormField( self, form_field ) as dlg:
|
|
|
|
if dlg.ShowModal() == wx.ID_OK:
|
|
|
|
old_name = name
|
|
|
|
( name, type, default, editable ) = dlg.GetFormField()
|
|
|
|
if old_name != name:
|
|
|
|
if name in [ form_field[0] for form_field in self._form_fields.GetClientData() ]: raise Exception( 'You already have a form field called ' + name + '; delete or edit that one first' )
|
|
|
|
|
|
self._form_fields.UpdateRow( index, ( name, CC.field_string_lookup[ type ], str( default ), str( editable ) ), ( name, type, default, editable ) )
|
|
|
|
|
|
|
|
except Exception as e: wx.MessageBox( unicode( e ) )
|
|
|
|
|
|
|
|
def GetImageboard( self ):
|
|
|
|
( name, post_url, flood_time, form_fields, restrictions ) = self._GetInfo()
|
|
|
|
return CC.Imageboard( name, post_url, flood_time, form_fields, restrictions )
|
|
|
|
|
|
def HasChanges( self ):
|
|
|
|
( my_name, my_post_url, my_flood_time, my_form_fields, my_restrictions ) = self._GetInfo()
|
|
|
|
( post_url, flood_time, form_fields, restrictions ) = self._imageboard.GetBoardInfo()
|
|
|
|
if post_url != my_post_url: return True
|
|
|
|
if flood_time != my_flood_time: return True
|
|
|
|
if set( [ tuple( item ) for item in form_fields ] ) != set( [ tuple( item ) for item in my_form_fields ] ): return True
|
|
|
|
if restrictions != my_restrictions: return True
|
|
|
|
return False
|
|
|
|
|
|
def Update( self, imageboard ):
|
|
|
|
( post_url, flood_time, form_fields, restrictions ) = imageboard.GetBoardInfo()
|
|
|
|
self._post_url.SetValue( post_url )
|
|
self._flood_time.SetValue( flood_time )
|
|
|
|
self._form_fields.ClearAll()
|
|
|
|
self._form_fields.InsertColumn( 0, 'name', width = 120 )
|
|
self._form_fields.InsertColumn( 1, 'type', width = 120 )
|
|
self._form_fields.InsertColumn( 2, 'default' )
|
|
self._form_fields.InsertColumn( 3, 'editable', width = 120 )
|
|
|
|
self._form_fields.setResizeColumn( 3 ) # default
|
|
|
|
for ( name, type, default, editable ) in form_fields:
|
|
|
|
self._form_fields.Append( ( name, CC.field_string_lookup[ type ], str( default ), str( editable ) ), ( name, type, default, editable ) )
|
|
|
|
|
|
if CC.RESTRICTION_MIN_RESOLUTION in restrictions: value = restrictions[ CC.RESTRICTION_MIN_RESOLUTION ]
|
|
else: value = None
|
|
|
|
self._min_resolution.SetValue( value )
|
|
|
|
if CC.RESTRICTION_MAX_RESOLUTION in restrictions: value = restrictions[ CC.RESTRICTION_MAX_RESOLUTION ]
|
|
else: value = None
|
|
|
|
self._max_resolution.SetValue( value )
|
|
|
|
if CC.RESTRICTION_MAX_FILE_SIZE in restrictions: value = restrictions[ CC.RESTRICTION_MAX_FILE_SIZE ]
|
|
else: value = None
|
|
|
|
self._max_file_size.SetValue( value )
|
|
|
|
self._mimes.Clear()
|
|
|
|
if CC.RESTRICTION_ALLOWED_MIMES in restrictions: mimes = restrictions[ CC.RESTRICTION_ALLOWED_MIMES ]
|
|
else: mimes = []
|
|
|
|
for mime in mimes: self._mimes.Append( HC.mime_string_lookup[ mime ], mime )
|
|
|
|
|
|
class DialogManageOptionsFileRepository( Dialog ):
|
|
|
|
def __init__( self, parent, service_identifier ):
|
|
|
|
def InitialiseControls():
|
|
|
|
self._max_monthly_data = ClientGUICommon.NoneableSpinCtrl( self, 'max monthly data (MB)', options[ 'max_monthly_data' ], multiplier = 1048576 )
|
|
self._max_storage = ClientGUICommon.NoneableSpinCtrl( self, 'max storage (MB)', options[ 'max_monthly_data' ], multiplier = 1048576 )
|
|
|
|
self._log_uploader_ips = wx.CheckBox( self, label='' )
|
|
self._log_uploader_ips.SetValue( options[ 'log_uploader_ips' ] )
|
|
|
|
self._message = wx.TextCtrl( self, value = options[ 'message' ] )
|
|
|
|
self._save_button = wx.Button( self, label='Save' )
|
|
self._save_button.Bind( wx.EVT_BUTTON, self.EventOK )
|
|
self._save_button.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
self._close_button = wx.Button( self, id = wx.ID_CANCEL, label='Cancel' )
|
|
self._close_button.Bind( wx.EVT_BUTTON, self.EventCancel )
|
|
self._close_button.SetForegroundColour( ( 128, 0, 0 ) )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
gridbox = wx.FlexGridSizer( 0, 2 )
|
|
|
|
gridbox.AddGrowableCol( 1, 1 )
|
|
|
|
gridbox.AddF( wx.StaticText( self, label='Log uploader ips?' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._log_uploader_ips, FLAGS_MIXED )
|
|
gridbox.AddF( wx.StaticText( self, label='Message' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._message, FLAGS_MIXED )
|
|
|
|
file_vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
file_vbox.AddF( wx.StaticText( self, label = '- file repository -' ), FLAGS_SMALL_INDENT )
|
|
file_vbox.AddF( self._max_monthly_data, FLAGS_EXPAND_PERPENDICULAR )
|
|
file_vbox.AddF( self._max_storage, FLAGS_EXPAND_PERPENDICULAR )
|
|
file_vbox.AddF( gridbox, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
buttons = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
buttons.AddF( self._save_button, FLAGS_SMALL_INDENT )
|
|
buttons.AddF( self._close_button, FLAGS_SMALL_INDENT )
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
vbox.AddF( file_vbox, FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox.AddF( buttons, FLAGS_BUTTON_SIZERS )
|
|
|
|
self.SetSizer( vbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
self.SetInitialSize( ( x + 80, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, service_identifier.GetName() + ' options' )
|
|
|
|
self._service_identifier = service_identifier
|
|
|
|
self._service = wx.GetApp().Read( 'service', service_identifier )
|
|
|
|
connection = self._service.GetConnection()
|
|
|
|
options = connection.Get( 'options' )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def EventCancel( self, event ): self.EndModal( wx.ID_CANCEL )
|
|
|
|
def EventOK( self, event ):
|
|
|
|
options = {}
|
|
|
|
options[ 'max_monthly_data' ] = self._max_monthly_data.GetValue()
|
|
|
|
options[ 'max_storage' ] = self._max_storage.GetValue()
|
|
|
|
options[ 'log_uploader_ips' ] = self._log_uploader_ips.GetValue()
|
|
|
|
options[ 'message' ] = self._message.GetValue()
|
|
|
|
try:
|
|
|
|
connection = self._service.GetConnection()
|
|
|
|
connection.Post( 'options', options = options )
|
|
|
|
except Exception as e: wx.MessageBox( 'Something went wrong when trying to send the options to the file repository: ' + unicode( e ) )
|
|
|
|
self.EndModal( wx.ID_OK )
|
|
|
|
|
|
class DialogManageOptionsLocal( Dialog ):
|
|
|
|
def __init__( self, parent ):
|
|
|
|
def InitialiseControls():
|
|
|
|
self._listbook = ClientGUICommon.ListBook( self )
|
|
|
|
# files and memory
|
|
|
|
self._file_page = wx.Panel( self._listbook )
|
|
self._file_page.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) )
|
|
|
|
self._export_location = wx.DirPickerCtrl( self._file_page, style = wx.DIRP_USE_TEXTCTRL )
|
|
|
|
if self._options[ 'export_path' ] is not None: self._export_location.SetPath( HC.ConvertPortablePathToAbsPath( self._options[ 'export_path' ] ) )
|
|
|
|
self._exclude_deleted_files = wx.CheckBox( self._file_page, label='' )
|
|
self._exclude_deleted_files.SetValue( self._options[ 'exclude_deleted_files' ] )
|
|
|
|
self._thumbnail_cache_size = wx.SpinCtrl( self._file_page, initial = int( self._options[ 'thumbnail_cache_size' ] / 1048576 ), min = 10, max = 3000 )
|
|
self._thumbnail_cache_size.Bind( wx.EVT_SPINCTRL, self.EventThumbnailsUpdate )
|
|
|
|
self._estimated_number_thumbnails = wx.StaticText( self._file_page, label = '', style = wx.ST_NO_AUTORESIZE )
|
|
|
|
self._preview_cache_size = wx.SpinCtrl( self._file_page, initial = int( self._options[ 'preview_cache_size' ] / 1048576 ), min = 20, max = 3000 )
|
|
self._preview_cache_size.Bind( wx.EVT_SPINCTRL, self.EventPreviewsUpdate )
|
|
|
|
self._estimated_number_previews = wx.StaticText( self._file_page, label = '', style = wx.ST_NO_AUTORESIZE )
|
|
|
|
self._fullscreen_cache_size = wx.SpinCtrl( self._file_page, initial = int( self._options[ 'fullscreen_cache_size' ] / 1048576 ), min = 100, max = 3000 )
|
|
self._fullscreen_cache_size.Bind( wx.EVT_SPINCTRL, self.EventFullscreensUpdate )
|
|
|
|
self._estimated_number_fullscreens = wx.StaticText( self._file_page, label = '', style = wx.ST_NO_AUTORESIZE )
|
|
|
|
( thumbnail_width, thumbnail_height ) = self._options[ 'thumbnail_dimensions' ]
|
|
|
|
self._thumbnail_width = wx.SpinCtrl( self._file_page, initial = thumbnail_width, min=20, max=200 )
|
|
self._thumbnail_width.Bind( wx.EVT_SPINCTRL, self.EventThumbnailsUpdate )
|
|
|
|
self._thumbnail_height = wx.SpinCtrl( self._file_page, initial = thumbnail_height, min=20, max=200 )
|
|
self._thumbnail_height.Bind( wx.EVT_SPINCTRL, self.EventThumbnailsUpdate )
|
|
|
|
self._num_autocomplete_chars = wx.SpinCtrl( self._file_page, initial = self._options[ 'num_autocomplete_chars' ], min = 1, max = 100 )
|
|
self._num_autocomplete_chars.SetToolTipString( 'how many characters you enter before the gui fetches autocomplete results from the db' + os.linesep + 'increase this if you find autocomplete results are slow' )
|
|
|
|
self._listbook.AddPage( self._file_page, 'files and memory' )
|
|
|
|
# gui
|
|
|
|
self._gui_page = wx.Panel( self._listbook )
|
|
self._gui_page.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) )
|
|
|
|
self._gui_capitalisation = wx.CheckBox( self._gui_page )
|
|
self._gui_capitalisation.SetValue( self._options[ 'gui_capitalisation' ] )
|
|
|
|
self._gui_show_all_tags_in_autocomplete = wx.CheckBox( self._gui_page )
|
|
self._gui_show_all_tags_in_autocomplete.SetValue( self._options[ 'show_all_tags_in_autocomplete' ] )
|
|
|
|
self._default_tag_sort = wx.Choice( self._gui_page )
|
|
|
|
self._default_tag_sort.Append( 'lexicographic (a-z)', CC.SORT_BY_LEXICOGRAPHIC_ASC )
|
|
self._default_tag_sort.Append( 'lexicographic (z-a)', CC.SORT_BY_LEXICOGRAPHIC_DESC )
|
|
self._default_tag_sort.Append( 'incidence (desc)', CC.SORT_BY_INCIDENCE_DESC )
|
|
self._default_tag_sort.Append( 'incidence (asc)', CC.SORT_BY_INCIDENCE_ASC )
|
|
|
|
if self._options[ 'default_tag_sort' ] == CC.SORT_BY_LEXICOGRAPHIC_ASC: self._default_tag_sort.Select( 0 )
|
|
elif self._options[ 'default_tag_sort' ] == CC.SORT_BY_LEXICOGRAPHIC_DESC: self._default_tag_sort.Select( 1 )
|
|
elif self._options[ 'default_tag_sort' ] == CC.SORT_BY_INCIDENCE_DESC: self._default_tag_sort.Select( 2 )
|
|
elif self._options[ 'default_tag_sort' ] == CC.SORT_BY_INCIDENCE_ASC: self._default_tag_sort.Select( 3 )
|
|
|
|
service_identifiers = wx.GetApp().Read( 'service_identifiers', ( HC.LOCAL_TAG, HC.TAG_REPOSITORY ) )
|
|
|
|
self._default_tag_repository = wx.Choice( self._gui_page )
|
|
for service_identifier in service_identifiers: self._default_tag_repository.Append( service_identifier.GetName(), service_identifier )
|
|
|
|
self._default_tag_repository.SetStringSelection( self._options[ 'default_tag_repository' ].GetName() )
|
|
|
|
self._listbook.AddPage( self._gui_page, 'gui' )
|
|
|
|
# default file system predicates
|
|
|
|
system_predicates = self._options[ 'file_system_predicates' ]
|
|
|
|
self._file_system_predicates_page = wx.Panel( self._listbook )
|
|
self._file_system_predicates_page.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) )
|
|
|
|
( sign, years, months, days ) = system_predicates[ 'age' ]
|
|
|
|
self._file_system_predicate_age_sign = wx.Choice( self._file_system_predicates_page, choices=[ '<', u'\u2248', '>' ] )
|
|
self._file_system_predicate_age_sign.SetSelection( sign )
|
|
|
|
self._file_system_predicate_age_years = wx.SpinCtrl( self._file_system_predicates_page, initial = years, max = 30 )
|
|
self._file_system_predicate_age_months = wx.SpinCtrl( self._file_system_predicates_page, initial = months, max = 60 )
|
|
self._file_system_predicate_age_days = wx.SpinCtrl( self._file_system_predicates_page, initial = days, max = 90 )
|
|
|
|
( sign, s, ms ) = system_predicates[ 'duration' ]
|
|
|
|
self._file_system_predicate_duration_sign = wx.Choice( self._file_system_predicates_page, choices=[ '<', u'\u2248', '=', '>' ] )
|
|
self._file_system_predicate_duration_sign.SetSelection( sign )
|
|
|
|
self._file_system_predicate_duration_s = wx.SpinCtrl( self._file_system_predicates_page, initial = s, max = 3599 )
|
|
self._file_system_predicate_duration_ms = wx.SpinCtrl( self._file_system_predicates_page, initial = ms, max = 999 )
|
|
|
|
( sign, height ) = system_predicates[ 'height' ]
|
|
|
|
self._file_system_predicate_height_sign = wx.Choice( self._file_system_predicates_page, choices=[ '<', u'\u2248', '=', '>' ] )
|
|
self._file_system_predicate_height_sign.SetSelection( sign )
|
|
|
|
self._file_system_predicate_height = wx.SpinCtrl( self._file_system_predicates_page, initial = height, max = 200000 )
|
|
|
|
limit = system_predicates[ 'limit' ]
|
|
|
|
self._file_system_predicate_limit = wx.SpinCtrl( self._file_system_predicates_page, initial = limit, max = 1000000 )
|
|
|
|
( media, type ) = system_predicates[ 'mime' ]
|
|
|
|
self._file_system_predicate_mime_media = wx.Choice( self._file_system_predicates_page, choices=[ 'image', 'application' ] )
|
|
self._file_system_predicate_mime_media.SetSelection( media )
|
|
self._file_system_predicate_mime_media.Bind( wx.EVT_CHOICE, self.EventFileSystemPredicateMime )
|
|
|
|
self._file_system_predicate_mime_type = wx.Choice( self._file_system_predicates_page, choices=[], size = ( 120, -1 ) )
|
|
|
|
self.EventFileSystemPredicateMime( None )
|
|
|
|
self._file_system_predicate_mime_type.SetSelection( type )
|
|
|
|
( sign, num_tags ) = system_predicates[ 'num_tags' ]
|
|
|
|
self._file_system_predicate_num_tags_sign = wx.Choice( self._file_system_predicates_page, choices=[ '<', '=', '>' ] )
|
|
self._file_system_predicate_num_tags_sign.SetSelection( sign )
|
|
|
|
self._file_system_predicate_num_tags = wx.SpinCtrl( self._file_system_predicates_page, initial = num_tags, max = 2000 )
|
|
|
|
( sign, value ) = system_predicates[ 'local_rating_numerical' ]
|
|
|
|
self._file_system_predicate_local_rating_numerical_sign = wx.Choice( self._file_system_predicates_page, choices=[ '>', '<', '=', u'\u2248', '=rated', '=not rated', '=uncertain' ] )
|
|
self._file_system_predicate_local_rating_numerical_sign.SetSelection( sign )
|
|
|
|
self._file_system_predicate_local_rating_numerical_value = wx.SpinCtrl( self._file_system_predicates_page, initial = value, min = 0, max = 50000 )
|
|
|
|
value = system_predicates[ 'local_rating_like' ]
|
|
|
|
self._file_system_predicate_local_rating_like_value = wx.Choice( self._file_system_predicates_page, choices=[ 'like', 'dislike', 'rated', 'not rated' ] )
|
|
self._file_system_predicate_local_rating_like_value.SetSelection( value )
|
|
|
|
( sign, width, height ) = system_predicates[ 'ratio' ]
|
|
|
|
self._file_system_predicate_ratio_sign = wx.Choice( self._file_system_predicates_page, choices=[ '=', u'\u2248' ] )
|
|
self._file_system_predicate_ratio_sign.SetSelection( sign )
|
|
|
|
self._file_system_predicate_ratio_width = wx.SpinCtrl( self._file_system_predicates_page, initial = width, max = 50000 )
|
|
|
|
self._file_system_predicate_ratio_height = wx.SpinCtrl( self._file_system_predicates_page, initial = height, max = 50000 )
|
|
|
|
( sign, size, unit ) = system_predicates[ 'size' ]
|
|
|
|
self._file_system_predicate_size_sign = wx.Choice( self._file_system_predicates_page, choices=[ '<', u'\u2248', '=', '>' ] )
|
|
self._file_system_predicate_size_sign.SetSelection( sign )
|
|
|
|
self._file_system_predicate_size = wx.SpinCtrl( self._file_system_predicates_page, initial = size, max = 1048576 )
|
|
|
|
self._file_system_predicate_size_unit = wx.Choice( self._file_system_predicates_page, choices=[ 'b', 'B', 'Kb', 'KB', 'Mb', 'MB', 'Gb', 'GB' ] )
|
|
self._file_system_predicate_size_unit.SetSelection( unit )
|
|
|
|
( sign, width ) = system_predicates[ 'width' ]
|
|
|
|
self._file_system_predicate_width_sign = wx.Choice( self._file_system_predicates_page, choices=[ '<', u'\u2248', '=', '>' ] )
|
|
self._file_system_predicate_width_sign.SetSelection( sign )
|
|
|
|
self._file_system_predicate_width = wx.SpinCtrl( self._file_system_predicates_page, initial = width, max = 200000 )
|
|
|
|
self._listbook.AddPage( self._file_system_predicates_page, 'default file system predicates' )
|
|
|
|
# colours
|
|
|
|
self._colour_page = wx.Panel( self._listbook )
|
|
self._colour_page.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) )
|
|
|
|
self._namespace_colours = ClientGUICommon.TagsBoxOptions( self._colour_page, self._options[ 'namespace_colours' ] )
|
|
|
|
self._edit_namespace_colour = wx.Button( self._colour_page, label = 'edit selected' )
|
|
self._edit_namespace_colour.Bind( wx.EVT_BUTTON, self.EventEditNamespaceColour )
|
|
|
|
self._new_namespace_colour = wx.TextCtrl( self._colour_page, style = wx.TE_PROCESS_ENTER )
|
|
self._new_namespace_colour.Bind( wx.EVT_KEY_DOWN, self.EventKeyDownNamespace )
|
|
|
|
self._listbook.AddPage( self._colour_page, 'colours' )
|
|
|
|
# sort/collect
|
|
|
|
self._sort_by_page = wx.Panel( self._listbook )
|
|
self._sort_by_page.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) )
|
|
|
|
self._default_sort = ClientGUICommon.ChoiceSort( self._sort_by_page, sort_by = self._options[ 'sort_by' ] )
|
|
|
|
self._default_collect = ClientGUICommon.ChoiceCollect( self._sort_by_page, sort_by = self._options[ 'sort_by' ] )
|
|
|
|
self._sort_by = wx.ListBox( self._sort_by_page )
|
|
self._sort_by.Bind( wx.EVT_LEFT_DCLICK, self.EventRemoveSortBy )
|
|
for ( sort_by_type, sort_by ) in self._options[ 'sort_by' ]: self._sort_by.Append( '-'.join( sort_by ), sort_by )
|
|
|
|
self._new_sort_by = wx.TextCtrl( self._sort_by_page, style = wx.TE_PROCESS_ENTER )
|
|
self._new_sort_by.Bind( wx.EVT_KEY_DOWN, self.EventKeyDownSortBy )
|
|
|
|
self._listbook.AddPage( self._sort_by_page, 'sort/collect' )
|
|
|
|
# shortcuts
|
|
|
|
self._shortcuts_page = wx.Panel( self._listbook )
|
|
self._shortcuts_page.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) )
|
|
|
|
self._shortcuts = ClientGUICommon.SaneListCtrl( self._shortcuts_page, 480, [ ( 'modifier', 120 ), ( 'key', 120 ), ( 'action', -1 ) ] )
|
|
|
|
for ( modifier, key_dict ) in self._options[ 'shortcuts' ].items():
|
|
|
|
for ( key, action ) in key_dict.items():
|
|
|
|
( pretty_modifier, pretty_key, pretty_action ) = HC.ConvertShortcutToPrettyShortcut( modifier, key, action )
|
|
|
|
self._shortcuts.Append( ( pretty_modifier, pretty_key, pretty_action ), ( modifier, key, action ) )
|
|
|
|
|
|
|
|
self._SortListCtrl()
|
|
|
|
self._shortcuts_add = wx.Button( self._shortcuts_page, label = 'add' )
|
|
self._shortcuts_add.Bind( wx.EVT_BUTTON, self.EventShortcutsAdd )
|
|
|
|
self._shortcuts_edit = wx.Button( self._shortcuts_page, label = 'edit' )
|
|
self._shortcuts_edit.Bind( wx.EVT_BUTTON, self.EventShortcutsEdit )
|
|
|
|
self._shortcuts_delete = wx.Button( self._shortcuts_page, label = 'delete' )
|
|
self._shortcuts_delete.Bind( wx.EVT_BUTTON, self.EventShortcutsDelete )
|
|
|
|
self._listbook.AddPage( self._shortcuts_page, 'shortcuts' )
|
|
|
|
#
|
|
|
|
self._save_button = wx.Button( self, label='Save' )
|
|
self._save_button.Bind( wx.EVT_BUTTON, self.EventOK )
|
|
self._save_button.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
self._close_button = wx.Button( self, id = wx.ID_CANCEL, label='Cancel' )
|
|
self._close_button.Bind( wx.EVT_BUTTON, self.EventCancel )
|
|
self._close_button.SetForegroundColour( ( 128, 0, 0 ) )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
thumbnails_sizer = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
thumbnails_sizer.AddF( self._thumbnail_cache_size, FLAGS_MIXED )
|
|
thumbnails_sizer.AddF( self._estimated_number_thumbnails, FLAGS_MIXED )
|
|
|
|
previews_sizer = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
previews_sizer.AddF( self._preview_cache_size, FLAGS_MIXED )
|
|
previews_sizer.AddF( self._estimated_number_previews, FLAGS_MIXED )
|
|
|
|
fullscreens_sizer = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
fullscreens_sizer.AddF( self._fullscreen_cache_size, FLAGS_MIXED )
|
|
fullscreens_sizer.AddF( self._estimated_number_fullscreens, FLAGS_MIXED )
|
|
|
|
gridbox = wx.FlexGridSizer( 0, 2 )
|
|
|
|
gridbox.AddGrowableCol( 1, 1 )
|
|
|
|
gridbox.AddF( wx.StaticText( self._file_page, label='Default export directory: ' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._export_location, FLAGS_EXPAND_BOTH_WAYS )
|
|
gridbox.AddF( wx.StaticText( self._file_page, label='Exclude deleted files from new imports and remote searches: ' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._exclude_deleted_files, FLAGS_MIXED )
|
|
gridbox.AddF( wx.StaticText( self._file_page, label='MB memory reserved for thumbnail cache: ' ), FLAGS_MIXED )
|
|
gridbox.AddF( thumbnails_sizer, FLAGS_NONE )
|
|
gridbox.AddF( wx.StaticText( self._file_page, label='MB memory reserved for preview cache: ' ), FLAGS_MIXED )
|
|
gridbox.AddF( previews_sizer, FLAGS_NONE )
|
|
gridbox.AddF( wx.StaticText( self._file_page, label='MB memory reserved for fullscreen cache: ' ), FLAGS_MIXED )
|
|
gridbox.AddF( fullscreens_sizer, FLAGS_NONE )
|
|
gridbox.AddF( wx.StaticText( self._file_page, label='Thumbnail width: ' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._thumbnail_width, FLAGS_MIXED )
|
|
gridbox.AddF( wx.StaticText( self._file_page, label='Thumbnail height: ' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._thumbnail_height, FLAGS_MIXED )
|
|
gridbox.AddF( wx.StaticText( self._file_page, label='Autocomplete character threshold: ' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._num_autocomplete_chars, FLAGS_MIXED )
|
|
|
|
self._file_page.SetSizer( gridbox )
|
|
|
|
#
|
|
|
|
gridbox = wx.FlexGridSizer( 0, 2 )
|
|
|
|
gridbox.AddGrowableCol( 1, 1 )
|
|
|
|
gridbox.AddF( wx.StaticText( self._gui_page, label = 'Default tag service in manage tag dialogs:' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._default_tag_repository, FLAGS_MIXED )
|
|
|
|
gridbox.AddF( wx.StaticText( self._gui_page, label = 'Default tag sort on management panel:' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._default_tag_sort, FLAGS_MIXED )
|
|
|
|
gridbox.AddF( wx.StaticText( self._gui_page, label='Capitalise gui: ' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._gui_capitalisation, FLAGS_MIXED )
|
|
|
|
gridbox.AddF( wx.StaticText( self._gui_page, label='By default, search non-local tags in write-autocomplete: ' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._gui_show_all_tags_in_autocomplete, FLAGS_MIXED )
|
|
|
|
self._gui_page.SetSizer( gridbox )
|
|
|
|
#
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
hbox.AddF( wx.StaticText( self._file_system_predicates_page, label='system:age' ), FLAGS_MIXED )
|
|
hbox.AddF( self._file_system_predicate_age_sign, FLAGS_MIXED )
|
|
hbox.AddF( self._file_system_predicate_age_years, FLAGS_MIXED )
|
|
hbox.AddF( wx.StaticText( self._file_system_predicates_page, label='years' ), FLAGS_MIXED )
|
|
hbox.AddF( self._file_system_predicate_age_months, FLAGS_MIXED )
|
|
hbox.AddF( wx.StaticText( self._file_system_predicates_page, label='months' ), FLAGS_MIXED )
|
|
hbox.AddF( self._file_system_predicate_age_days, FLAGS_MIXED )
|
|
hbox.AddF( wx.StaticText( self._file_system_predicates_page, label='days' ), FLAGS_MIXED )
|
|
|
|
vbox.AddF( hbox, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
hbox.AddF( wx.StaticText( self._file_system_predicates_page, label='system:duration' ), FLAGS_MIXED )
|
|
hbox.AddF( self._file_system_predicate_duration_sign, FLAGS_MIXED )
|
|
hbox.AddF( self._file_system_predicate_duration_s, FLAGS_MIXED )
|
|
hbox.AddF( wx.StaticText( self._file_system_predicates_page, label='s' ), FLAGS_MIXED )
|
|
hbox.AddF( self._file_system_predicate_duration_ms, FLAGS_MIXED )
|
|
hbox.AddF( wx.StaticText( self._file_system_predicates_page, label='ms' ), FLAGS_MIXED )
|
|
|
|
vbox.AddF( hbox, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
hbox.AddF( wx.StaticText( self._file_system_predicates_page, label='system:height' ), FLAGS_MIXED )
|
|
hbox.AddF( self._file_system_predicate_height_sign, FLAGS_MIXED )
|
|
hbox.AddF( self._file_system_predicate_height, FLAGS_MIXED )
|
|
|
|
vbox.AddF( hbox, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
hbox.AddF( wx.StaticText( self._file_system_predicates_page, label='system:limit=' ), FLAGS_MIXED )
|
|
hbox.AddF( self._file_system_predicate_limit, FLAGS_MIXED )
|
|
|
|
vbox.AddF( hbox, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
hbox.AddF( wx.StaticText( self._file_system_predicates_page, label='system:mime' ), FLAGS_MIXED )
|
|
hbox.AddF( self._file_system_predicate_mime_media, FLAGS_MIXED )
|
|
hbox.AddF( wx.StaticText( self._file_system_predicates_page, label='/' ), FLAGS_MIXED )
|
|
hbox.AddF( self._file_system_predicate_mime_type, FLAGS_MIXED )
|
|
|
|
vbox.AddF( hbox, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
hbox.AddF( wx.StaticText( self._file_system_predicates_page, label='system:numtags' ), FLAGS_MIXED )
|
|
hbox.AddF( self._file_system_predicate_num_tags_sign, FLAGS_MIXED )
|
|
hbox.AddF( self._file_system_predicate_num_tags, FLAGS_MIXED )
|
|
|
|
vbox.AddF( hbox, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
hbox.AddF( wx.StaticText( self._file_system_predicates_page, label='system:local_rating_like' ), FLAGS_MIXED )
|
|
hbox.AddF( self._file_system_predicate_local_rating_like_value, FLAGS_MIXED )
|
|
|
|
vbox.AddF( hbox, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
hbox.AddF( wx.StaticText( self._file_system_predicates_page, label='system:local_rating_numerical' ), FLAGS_MIXED )
|
|
hbox.AddF( self._file_system_predicate_local_rating_numerical_sign, FLAGS_MIXED )
|
|
hbox.AddF( self._file_system_predicate_local_rating_numerical_value, FLAGS_MIXED )
|
|
|
|
vbox.AddF( hbox, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
hbox.AddF( wx.StaticText( self._file_system_predicates_page, label='system:ratio' ), FLAGS_MIXED )
|
|
hbox.AddF( self._file_system_predicate_ratio_sign, FLAGS_MIXED )
|
|
hbox.AddF( self._file_system_predicate_ratio_width, FLAGS_MIXED )
|
|
hbox.AddF( wx.StaticText( self._file_system_predicates_page, label=':' ), FLAGS_MIXED )
|
|
hbox.AddF( self._file_system_predicate_ratio_height, FLAGS_MIXED )
|
|
|
|
vbox.AddF( hbox, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
hbox.AddF( wx.StaticText( self._file_system_predicates_page, label='system:size' ), FLAGS_MIXED )
|
|
hbox.AddF( self._file_system_predicate_size_sign, FLAGS_MIXED )
|
|
hbox.AddF( self._file_system_predicate_size, FLAGS_MIXED )
|
|
hbox.AddF( self._file_system_predicate_size_unit, FLAGS_MIXED )
|
|
|
|
vbox.AddF( hbox, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
hbox.AddF( wx.StaticText( self._file_system_predicates_page, label='system:width' ), FLAGS_MIXED )
|
|
hbox.AddF( self._file_system_predicate_width_sign, FLAGS_MIXED )
|
|
hbox.AddF( self._file_system_predicate_width, FLAGS_MIXED )
|
|
|
|
vbox.AddF( hbox, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
self._file_system_predicates_page.SetSizer( vbox )
|
|
|
|
#
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
vbox.AddF( self._namespace_colours, FLAGS_EXPAND_BOTH_WAYS )
|
|
vbox.AddF( self._new_namespace_colour, FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox.AddF( self._edit_namespace_colour, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
self._colour_page.SetSizer( vbox )
|
|
|
|
#
|
|
|
|
gridbox = wx.FlexGridSizer( 0, 2 )
|
|
|
|
gridbox.AddGrowableCol( 1, 1 )
|
|
|
|
gridbox.AddF( wx.StaticText( self._sort_by_page, label='Default sort: ' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._default_sort, FLAGS_EXPAND_BOTH_WAYS )
|
|
gridbox.AddF( wx.StaticText( self._sort_by_page, label='Default collect: ' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._default_collect, FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
vbox.AddF( gridbox, FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox.AddF( self._sort_by, FLAGS_EXPAND_BOTH_WAYS )
|
|
vbox.AddF( self._new_sort_by, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
self._sort_by_page.SetSizer( vbox )
|
|
|
|
#
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
vbox.AddF( wx.StaticText( self._shortcuts_page, label = 'These shortcuts are global to the main gui! You probably want to stick to function keys or ctrl + something!' ), FLAGS_MIXED )
|
|
vbox.AddF( self._shortcuts, FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
hbox.AddF( self._shortcuts_add, FLAGS_BUTTON_SIZERS )
|
|
hbox.AddF( self._shortcuts_edit, FLAGS_BUTTON_SIZERS )
|
|
hbox.AddF( self._shortcuts_delete, FLAGS_BUTTON_SIZERS )
|
|
|
|
vbox.AddF( hbox, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
self._shortcuts_page.SetSizer( vbox )
|
|
|
|
#
|
|
|
|
buttons = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
buttons.AddF( self._save_button, FLAGS_SMALL_INDENT )
|
|
buttons.AddF( self._close_button, FLAGS_SMALL_INDENT )
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
vbox.AddF( self._listbook, FLAGS_EXPAND_BOTH_WAYS )
|
|
vbox.AddF( buttons, FLAGS_BUTTON_SIZERS )
|
|
|
|
self.SetSizer( vbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
if x < 800: x = 800
|
|
if y < 600: y = 600
|
|
|
|
self.SetInitialSize( ( x, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'hydrus client options' )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
self.EventFullscreensUpdate( None )
|
|
self.EventPreviewsUpdate( None )
|
|
self.EventThumbnailsUpdate( None )
|
|
|
|
wx.CallAfter( self._file_page.Layout ) # draws the static texts correctly
|
|
|
|
|
|
def _SortListCtrl( self ): self._shortcuts.SortListItems( 2 )
|
|
|
|
def EventCancel( self, event ): self.EndModal( wx.ID_CANCEL )
|
|
|
|
def EventEditNamespaceColour( self, event ):
|
|
|
|
result = self._namespace_colours.GetSelectedNamespaceColour()
|
|
|
|
if result is not None:
|
|
|
|
( namespace, colour ) = result
|
|
|
|
colour_data = wx.ColourData()
|
|
|
|
colour_data.SetColour( colour )
|
|
colour_data.SetChooseFull( True )
|
|
|
|
with wx.ColourDialog( self, data = colour_data ) as dlg:
|
|
|
|
if dlg.ShowModal() == wx.ID_OK:
|
|
|
|
colour_data = dlg.GetColourData()
|
|
|
|
colour = colour_data.GetColour()
|
|
|
|
self._namespace_colours.SetNamespaceColour( namespace, colour )
|
|
|
|
|
|
|
|
|
|
|
|
def EventFileSystemPredicateMime( self, event ):
|
|
|
|
media = self._file_system_predicate_mime_media.GetStringSelection()
|
|
|
|
self._file_system_predicate_mime_type.Clear()
|
|
|
|
if media == 'image':
|
|
|
|
self._file_system_predicate_mime_type.Append( 'any', HC.IMAGES )
|
|
self._file_system_predicate_mime_type.Append( 'jpeg', HC.IMAGE_JPEG )
|
|
self._file_system_predicate_mime_type.Append( 'png', HC.IMAGE_PNG )
|
|
self._file_system_predicate_mime_type.Append( 'gif', HC.IMAGE_GIF )
|
|
|
|
elif media == 'application':
|
|
|
|
self._file_system_predicate_mime_type.Append( 'x-shockwave-flash', HC.APPLICATION_FLASH )
|
|
|
|
elif media == 'video':
|
|
|
|
self._file_system_predicate_mime_type.Append( 'x-flv', HC.VIDEO_FLV )
|
|
|
|
|
|
self._file_system_predicate_mime_type.SetSelection( 0 )
|
|
|
|
|
|
def EventFullscreensUpdate( self, event ):
|
|
|
|
( width, height ) = wx.GetDisplaySize()
|
|
|
|
estimated_bytes_per_fullscreen = 3 * width * height
|
|
|
|
self._estimated_number_fullscreens.SetLabel( '(about ' + HC.ConvertIntToPrettyString( ( self._fullscreen_cache_size.GetValue() * 1048576 ) / estimated_bytes_per_fullscreen ) + '-' + HC.ConvertIntToPrettyString( ( self._fullscreen_cache_size.GetValue() * 1048576 ) / ( estimated_bytes_per_fullscreen / 4 ) ) + ' images)' )
|
|
|
|
|
|
def EventKeyDownNamespace( self, event ):
|
|
|
|
if event.KeyCode in ( wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER ):
|
|
|
|
namespace = self._new_namespace_colour.GetValue()
|
|
|
|
if namespace != '':
|
|
|
|
self._namespace_colours.SetNamespaceColour( namespace, wx.Colour( random.randint( 0, 255 ), random.randint( 0, 255 ), random.randint( 0, 255 ) ) )
|
|
|
|
self._new_namespace_colour.SetValue( '' )
|
|
|
|
|
|
else: event.Skip()
|
|
|
|
|
|
def EventKeyDownSortBy( self, event ):
|
|
|
|
if event.KeyCode in ( wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER ):
|
|
|
|
sort_by_string = self._new_sort_by.GetValue()
|
|
|
|
if sort_by_string != '':
|
|
|
|
try: sort_by = sort_by_string.split( '-' )
|
|
except:
|
|
|
|
wx.MessageBox( 'Could not parse that sort by string!' )
|
|
|
|
return
|
|
|
|
|
|
self._sort_by.Append( sort_by_string, sort_by )
|
|
|
|
self._new_sort_by.SetValue( '' )
|
|
|
|
|
|
else: event.Skip()
|
|
|
|
|
|
def EventOK( self, event ):
|
|
|
|
self._options[ 'gui_capitalisation' ] = self._gui_capitalisation.GetValue()
|
|
self._options[ 'show_all_tags_in_autocomplete' ] = self._gui_show_all_tags_in_autocomplete.GetValue()
|
|
|
|
self._options[ 'export_path' ] = HC.ConvertAbsPathToPortablePath( self._export_location.GetPath() )
|
|
self._options[ 'default_sort' ] = self._default_sort.GetSelection()
|
|
self._options[ 'default_collect' ] = self._default_collect.GetSelection()
|
|
|
|
self._options[ 'exclude_deleted_files' ] = self._exclude_deleted_files.GetValue()
|
|
|
|
self._options[ 'thumbnail_cache_size' ] = self._thumbnail_cache_size.GetValue() * 1048576
|
|
self._options[ 'preview_cache_size' ] = self._preview_cache_size.GetValue() * 1048576
|
|
self._options[ 'fullscreen_cache_size' ] = self._fullscreen_cache_size.GetValue() * 1048576
|
|
|
|
self._options[ 'thumbnail_dimensions' ] = [ self._thumbnail_width.GetValue(), self._thumbnail_height.GetValue() ]
|
|
|
|
self._options[ 'num_autocomplete_chars' ] = self._num_autocomplete_chars.GetValue()
|
|
|
|
self._options[ 'namespace_colours' ] = self._namespace_colours.GetNamespaceColours()
|
|
|
|
sort_by_choices = []
|
|
|
|
for sort_by in [ self._sort_by.GetClientData( i ) for i in range( self._sort_by.GetCount() ) ]: sort_by_choices.append( ( 'namespaces', sort_by ) )
|
|
|
|
self._options[ 'sort_by' ] = sort_by_choices
|
|
|
|
system_predicates = {}
|
|
|
|
system_predicates[ 'age' ] = ( self._file_system_predicate_age_sign.GetSelection(), self._file_system_predicate_age_years.GetValue(), self._file_system_predicate_age_months.GetValue(), self._file_system_predicate_age_days.GetValue() )
|
|
system_predicates[ 'duration' ] = ( self._file_system_predicate_duration_sign.GetSelection(), self._file_system_predicate_duration_s.GetValue(), self._file_system_predicate_duration_ms.GetValue() )
|
|
system_predicates[ 'height' ] = ( self._file_system_predicate_height_sign.GetSelection(), self._file_system_predicate_height.GetValue() )
|
|
system_predicates[ 'limit' ] = self._file_system_predicate_limit.GetValue()
|
|
system_predicates[ 'mime' ] = ( self._file_system_predicate_mime_media.GetSelection(), self._file_system_predicate_mime_type.GetSelection() )
|
|
system_predicates[ 'num_tags' ] = ( self._file_system_predicate_num_tags_sign.GetSelection(), self._file_system_predicate_num_tags.GetValue() )
|
|
system_predicates[ 'local_rating_like' ] = self._file_system_predicate_local_rating_like_value.GetSelection()
|
|
system_predicates[ 'local_rating_numerical' ] = ( self._file_system_predicate_local_rating_numerical_sign.GetSelection(), self._file_system_predicate_local_rating_numerical_value.GetValue() )
|
|
system_predicates[ 'ratio' ] = ( self._file_system_predicate_ratio_sign.GetSelection(), self._file_system_predicate_ratio_width.GetValue(), self._file_system_predicate_ratio_height.GetValue() )
|
|
system_predicates[ 'size' ] = ( self._file_system_predicate_size_sign.GetSelection(), self._file_system_predicate_size.GetValue(), self._file_system_predicate_size_unit.GetSelection() )
|
|
system_predicates[ 'width' ] = ( self._file_system_predicate_width_sign.GetSelection(), self._file_system_predicate_width.GetValue() )
|
|
|
|
self._options[ 'file_system_predicates' ] = system_predicates
|
|
|
|
shortcuts = {}
|
|
|
|
shortcuts[ wx.ACCEL_NORMAL ] = {}
|
|
shortcuts[ wx.ACCEL_CTRL ] = {}
|
|
shortcuts[ wx.ACCEL_ALT ] = {}
|
|
shortcuts[ wx.ACCEL_SHIFT ] = {}
|
|
|
|
for ( modifier, key, action ) in self._shortcuts.GetClientData(): shortcuts[ modifier ][ key ] = action
|
|
|
|
self._options[ 'shortcuts' ] = shortcuts
|
|
|
|
self._options[ 'default_tag_repository' ] = self._default_tag_repository.GetClientData( self._default_tag_repository.GetSelection() )
|
|
self._options[ 'default_tag_sort' ] = self._default_tag_sort.GetClientData( self._default_tag_sort.GetSelection() )
|
|
|
|
try: wx.GetApp().Write( 'save_options' )
|
|
except: wx.MessageBox( traceback.format_exc() )
|
|
|
|
self.EndModal( wx.ID_OK )
|
|
|
|
|
|
def EventRemoveSortBy( self, event ):
|
|
|
|
selection = self._sort_by.GetSelection()
|
|
|
|
if selection != wx.NOT_FOUND: self._sort_by.Delete( selection )
|
|
|
|
|
|
def EventPreviewsUpdate( self, event ):
|
|
|
|
estimated_bytes_per_preview = 3 * 400 * 400
|
|
|
|
self._estimated_number_previews.SetLabel( '(about ' + HC.ConvertIntToPrettyString( ( self._preview_cache_size.GetValue() * 1048576 ) / estimated_bytes_per_preview ) + ' previews)' )
|
|
|
|
|
|
def EventShortcutsAdd( self, event ):
|
|
|
|
with DialogInputShortcut( self ) as dlg:
|
|
|
|
if dlg.ShowModal() == wx.ID_OK:
|
|
|
|
( modifier, key, action ) = dlg.GetInfo()
|
|
|
|
( pretty_modifier, pretty_key, pretty_action ) = HC.ConvertShortcutToPrettyShortcut( modifier, key, action )
|
|
|
|
self._shortcuts.Append( ( pretty_modifier, pretty_key, pretty_action ), ( modifier, key, action ) )
|
|
|
|
self._SortListCtrl()
|
|
|
|
|
|
|
|
|
|
def EventShortcutsDelete( self, event ): self._shortcuts.RemoveAllSelected()
|
|
|
|
def EventShortcutsEdit( self, event ):
|
|
|
|
indices = self._shortcuts.GetAllSelected()
|
|
|
|
for index in indices:
|
|
|
|
( modifier, key, action ) = self._shortcuts.GetClientData( index )
|
|
|
|
try:
|
|
|
|
with DialogInputShortcut( self, modifier, key, action ) as dlg:
|
|
|
|
if dlg.ShowModal() == wx.ID_OK:
|
|
|
|
( modifier, key, action ) = dlg.GetInfo()
|
|
|
|
( pretty_modifier, pretty_key, pretty_action ) = HC.ConvertShortcutToPrettyShortcut( modifier, key, action )
|
|
|
|
self._shortcuts.UpdateRow( index, ( pretty_modifier, pretty_key, pretty_action ), ( modifier, key, action ) )
|
|
|
|
self._SortListCtrl()
|
|
|
|
|
|
|
|
except Exception as e: wx.MessageBox( unicode( e ) )
|
|
|
|
|
|
|
|
def EventThumbnailsUpdate( self, event ):
|
|
|
|
estimated_bytes_per_thumb = 3 * self._thumbnail_height.GetValue() * self._thumbnail_width.GetValue()
|
|
|
|
self._estimated_number_thumbnails.SetLabel( '(about ' + HC.ConvertIntToPrettyString( ( self._thumbnail_cache_size.GetValue() * 1048576 ) / estimated_bytes_per_thumb ) + ' thumbnails)' )
|
|
|
|
|
|
class DialogManageOptionsServerAdmin( Dialog ):
|
|
|
|
def __init__( self, parent, service_identifier ):
|
|
|
|
def InitialiseControls():
|
|
|
|
self._max_monthly_data = ClientGUICommon.NoneableSpinCtrl( self, 'max monthly data (MB)', options[ 'max_monthly_data' ], multiplier = 1048576 )
|
|
self._max_storage = ClientGUICommon.NoneableSpinCtrl( self, 'max storage (MB)', options[ 'max_monthly_data' ], multiplier = 1048576 )
|
|
|
|
self._message = wx.TextCtrl( self, value = options[ 'message' ] )
|
|
|
|
self._save_button = wx.Button( self, label='Save' )
|
|
self._save_button.Bind( wx.EVT_BUTTON, self.EventOK )
|
|
self._save_button.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
self._close_button = wx.Button( self, id = wx.ID_CANCEL, label='Cancel' )
|
|
self._close_button.Bind( wx.EVT_BUTTON, self.EventCancel )
|
|
self._close_button.SetForegroundColour( ( 128, 0, 0 ) )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
gridbox = wx.FlexGridSizer( 0, 2 )
|
|
|
|
gridbox.AddGrowableCol( 1, 1 )
|
|
|
|
gridbox.AddF( wx.StaticText( self, label='Message' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._message, FLAGS_MIXED )
|
|
|
|
file_vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
file_vbox.AddF( wx.StaticText( self, label = '- server -' ), FLAGS_SMALL_INDENT )
|
|
file_vbox.AddF( self._max_monthly_data, FLAGS_EXPAND_PERPENDICULAR )
|
|
file_vbox.AddF( self._max_storage, FLAGS_EXPAND_PERPENDICULAR )
|
|
file_vbox.AddF( gridbox, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
buttons = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
buttons.AddF( self._save_button, FLAGS_SMALL_INDENT )
|
|
buttons.AddF( self._close_button, FLAGS_SMALL_INDENT )
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
vbox.AddF( file_vbox, FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox.AddF( buttons, FLAGS_BUTTON_SIZERS )
|
|
|
|
self.SetSizer( vbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
self.SetInitialSize( ( x + 80, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, service_identifier.GetName() + ' options' )
|
|
|
|
self._service_identifier = service_identifier
|
|
|
|
self._service = wx.GetApp().Read( 'service', service_identifier )
|
|
|
|
connection = self._service.GetConnection()
|
|
|
|
options = connection.Get( 'options' )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def EventCancel( self, event ): self.EndModal( wx.ID_CANCEL )
|
|
|
|
def EventOK( self, event ):
|
|
|
|
options = {}
|
|
|
|
options[ 'max_monthly_data' ] = self._max_monthly_data.GetValue()
|
|
|
|
options[ 'max_storage' ] = self._max_storage.GetValue()
|
|
|
|
options[ 'message' ] = self._message.GetValue()
|
|
|
|
try:
|
|
|
|
connection = self._service.GetConnection()
|
|
|
|
connection.Post( 'options', options = options )
|
|
|
|
except Exception as e: wx.MessageBox( 'Something went wrong when trying to send the options to the server admin: ' + unicode( e ) )
|
|
|
|
self.EndModal( wx.ID_OK )
|
|
|
|
|
|
class DialogManageOptionsTagRepository( Dialog ):
|
|
|
|
def __init__( self, parent, service_identifier ):
|
|
|
|
def InitialiseControls():
|
|
|
|
self._max_monthly_data = ClientGUICommon.NoneableSpinCtrl( self, 'max monthly data (MB)', options[ 'max_monthly_data' ], multiplier = 1048576 )
|
|
|
|
self._message = wx.TextCtrl( self, value = options[ 'message' ] )
|
|
|
|
self._save_button = wx.Button( self, label='Save' )
|
|
self._save_button.Bind( wx.EVT_BUTTON, self.EventOK )
|
|
self._save_button.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
self._close_button = wx.Button( self, id = wx.ID_CANCEL, label='Cancel' )
|
|
self._close_button.Bind( wx.EVT_BUTTON, self.EventCancel )
|
|
self._close_button.SetForegroundColour( ( 128, 0, 0 ) )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
gridbox = wx.FlexGridSizer( 0, 2 )
|
|
|
|
gridbox.AddGrowableCol( 1, 1 )
|
|
|
|
gridbox.AddF( wx.StaticText( self, label='Message' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._message, FLAGS_MIXED )
|
|
|
|
tag_vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
tag_vbox.AddF( wx.StaticText( self, label = '- tag repository -' ), FLAGS_SMALL_INDENT )
|
|
tag_vbox.AddF( self._max_monthly_data, FLAGS_EXPAND_PERPENDICULAR )
|
|
tag_vbox.AddF( gridbox, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
buttons = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
buttons.AddF( self._save_button, FLAGS_SMALL_INDENT )
|
|
buttons.AddF( self._close_button, FLAGS_SMALL_INDENT )
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
vbox.AddF( tag_vbox, FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox.AddF( buttons, FLAGS_BUTTON_SIZERS )
|
|
|
|
self.SetSizer( vbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
self.SetInitialSize( ( x + 80, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, service_identifier.GetName() + ' options' )
|
|
|
|
self._service_identifier = service_identifier
|
|
|
|
self._service = wx.GetApp().Read( 'service', service_identifier )
|
|
|
|
connection = self._service.GetConnection()
|
|
|
|
options = connection.Get( 'options' )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def EventCancel( self, event ): self.EndModal( wx.ID_CANCEL )
|
|
|
|
def EventOK( self, event ):
|
|
|
|
options = {}
|
|
|
|
options[ 'max_monthly_data' ] = self._max_monthly_data.GetValue()
|
|
|
|
options[ 'message' ] = self._message.GetValue()
|
|
|
|
try:
|
|
|
|
connection = self._service.GetConnection()
|
|
|
|
connection.Post( 'options', options = options )
|
|
|
|
except Exception as e: wx.MessageBox( 'Something went wrong when trying to send the options to the tag repository: ' + unicode( e ) )
|
|
|
|
self.EndModal( wx.ID_OK )
|
|
|
|
|
|
class DialogManageRatings( Dialog ):
|
|
|
|
def __init__( self, parent, media ):
|
|
|
|
def InitialiseControls():
|
|
|
|
service_identifiers = wx.GetApp().Read( 'service_identifiers', HC.RATINGS_SERVICES )
|
|
|
|
# sort according to local/remote, I guess
|
|
# and maybe sub-sort according to name?
|
|
# maybe just do two get s_i queries
|
|
|
|
self._panels = []
|
|
|
|
for service_identifier in service_identifiers: self._panels.append( DialogManageRatingsPanel( self, service_identifier, media ) )
|
|
|
|
self._apply = wx.Button( self, label='Apply' )
|
|
self._apply.Bind( wx.EVT_BUTTON, self.EventOk )
|
|
self._apply.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
self._cancel = wx.Button( self, id = wx.ID_CANCEL, label='Cancel' )
|
|
self._cancel.Bind( wx.EVT_BUTTON, self.EventCancel )
|
|
self._cancel.SetForegroundColour( ( 128, 0, 0 ) )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
buttonbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
buttonbox.AddF( self._apply, FLAGS_MIXED )
|
|
buttonbox.AddF( self._cancel, FLAGS_MIXED )
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
for panel in self._panels: vbox.AddF( panel, FLAGS_EXPAND_BOTH_WAYS )
|
|
vbox.AddF( buttonbox, FLAGS_BUTTON_SIZERS )
|
|
|
|
self.SetSizer( vbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
self.SetInitialSize( ( x + 200, y ) )
|
|
|
|
|
|
self._hashes = HC.IntelligentMassUnion( ( m.GetHashes() for m in media ) )
|
|
|
|
Dialog.__init__( self, parent, 'manage ratings for ' + HC.ConvertIntToPrettyString( len( self._hashes ) ) + ' files' )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
self.Bind( wx.EVT_MENU, self.EventMenu )
|
|
|
|
self.RefreshAcceleratorTable()
|
|
|
|
|
|
def EventCancel( self, event ): self.EndModal( wx.ID_CANCEL )
|
|
|
|
def EventMenu( self, event ):
|
|
|
|
action = CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetAction( event.GetId() )
|
|
|
|
if action is not None:
|
|
|
|
( command, data ) = action
|
|
|
|
if command == 'manage_ratings': self.EventCancel( event )
|
|
elif command == 'ok': self.EventOk( event )
|
|
else: event.Skip()
|
|
|
|
|
|
|
|
def EventOk( self, event ):
|
|
|
|
try:
|
|
|
|
content_updates = []
|
|
|
|
for panel in self._panels:
|
|
|
|
if panel.HasChanges():
|
|
|
|
service_identifier = panel.GetServiceIdentifier()
|
|
|
|
rating = panel.GetRating()
|
|
|
|
content_updates.append( CC.ContentUpdate( CC.CONTENT_UPDATE_RATING, service_identifier, self._hashes, info = rating ) )
|
|
|
|
|
|
|
|
if len( content_updates ) > 0: wx.GetApp().Write( 'content_updates', content_updates )
|
|
|
|
except Exception as e: wx.MessageBox( 'Saving pending mapping changes to DB raised this error: ' + unicode( e ) )
|
|
|
|
self.EndModal( wx.ID_OK )
|
|
|
|
|
|
def RefreshAcceleratorTable( self ):
|
|
|
|
interested_actions = [ 'archive', 'close_page', 'filter', 'ratings_filter', 'manage_ratings', 'manage_tags', 'new_page', 'refresh', 'set_search_focus', 'show_hide_splitters', 'synchronised_wait_switch' ]
|
|
|
|
entries = []
|
|
|
|
for ( modifier, key_dict ) in self._options[ 'shortcuts' ].items(): entries.extend( [ ( modifier, key, CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( action ) ) for ( key, action ) in key_dict.items() if action in interested_actions ] )
|
|
|
|
self.SetAcceleratorTable( wx.AcceleratorTable( entries ) )
|
|
|
|
|
|
class DialogManageRatingsPanel( wx.Panel ):
|
|
|
|
def __init__( self, parent, service_identifier, media ):
|
|
|
|
wx.Panel.__init__( self, parent )
|
|
|
|
self._service_identifier = service_identifier
|
|
self._service = wx.GetApp().Read( 'service', service_identifier )
|
|
|
|
extra_info = self._service.GetExtraInfo()
|
|
|
|
self._media = media
|
|
|
|
service_type = service_identifier.GetType()
|
|
|
|
def InitialiseControls():
|
|
|
|
self._current_score = wx.StaticText( self, style = wx.ALIGN_CENTER )
|
|
|
|
score_font = self._GetScoreFont()
|
|
|
|
self._current_score.SetFont( score_font )
|
|
|
|
if service_type in ( HC.LOCAL_RATING_LIKE, HC.LOCAL_RATING_NUMERICAL ): all_rating_services = [ local_ratings for ( local_ratings, remote_ratings ) in [ media.GetRatings() for media in self._media ] ]
|
|
elif service_type in ( HC.RATING_LIKE_REPOSITORY, HC.RATING_NUMERICAL_REPOSITORY ): all_rating_services = [ remote_ratings for ( local_ratings, remote_ratings ) in [ media.GetRatings() for media in self._media ] ]
|
|
|
|
if service_type in ( HC.LOCAL_RATING_LIKE, HC.RATING_LIKE_REPOSITORY ):
|
|
|
|
( like, dislike ) = extra_info
|
|
|
|
if service_type == HC.LOCAL_RATING_LIKE:
|
|
|
|
ratings = [ rating_services.GetRating( self._service_identifier ) for rating_services in all_rating_services ]
|
|
|
|
if all( ( i is None for i in ratings ) ):
|
|
|
|
choices = [ like, dislike, 'make no changes' ]
|
|
|
|
if len( self._media ) > 1: self._current_score.SetLabel( 'none rated' )
|
|
else: self._current_score.SetLabel( 'not rated' )
|
|
|
|
elif None in ratings:
|
|
|
|
choices = [ like, dislike, 'remove rating', 'make no changes' ]
|
|
|
|
self._current_score.SetLabel( 'not all rated' )
|
|
|
|
else:
|
|
|
|
if all( ( i == 1 for i in ratings ) ):
|
|
|
|
choices = [ dislike, 'remove rating', 'make no changes' ]
|
|
|
|
if len( self._media ) > 1: self._current_score.SetLabel( 'all ' + like )
|
|
else: self._current_score.SetLabel( like )
|
|
|
|
elif all( ( i == 0 for i in ratings ) ):
|
|
|
|
choices = [ like, 'remove rating', 'make no changes' ]
|
|
|
|
if len( self._media ) > 1: self._current_score.SetLabel( 'all ' + dislike )
|
|
else: self._current_score.SetLabel( dislike )
|
|
|
|
else:
|
|
|
|
choices = [ like, dislike, 'remove rating', 'make no changes' ]
|
|
|
|
|
|
overall_rating = float( sum( ratings ) ) / float( len( ratings ) )
|
|
|
|
self._current_score.SetLabel( str( '%.2f' % overall_rating ) )
|
|
|
|
|
|
if len( self._media ) > 1:
|
|
|
|
ratings_counter = collections.Counter( ratings )
|
|
|
|
likes = ratings_counter[ 1 ]
|
|
dislikes = ratings_counter[ 0 ]
|
|
nones = ratings_counter[ None ]
|
|
|
|
scores = []
|
|
|
|
if likes > 0: scores.append( str( likes ) + ' likes' )
|
|
if dislikes > 0: scores.append( str( dislikes ) + ' dislikes' )
|
|
if nones > 0: scores.append( str( nones ) + ' not rated' )
|
|
|
|
self._current_score.SetLabel( ', '.join( scores ) )
|
|
|
|
else:
|
|
|
|
( rating, ) = ratings
|
|
|
|
if rating is None: self._current_score.SetLabel( 'not rated' )
|
|
elif rating == 1: self._current_score.SetLabel( like )
|
|
elif rating == 0: self._current_score.SetLabel( dislike )
|
|
|
|
|
|
else:
|
|
|
|
self._current_score.SetLabel( '23 ' + like + 's, 44 ' + dislike + 's' )
|
|
|
|
|
|
elif service_type in ( HC.LOCAL_RATING_NUMERICAL, HC.RATING_NUMERICAL_REPOSITORY ):
|
|
|
|
if service_type == HC.LOCAL_RATING_NUMERICAL:
|
|
|
|
( min, max ) = extra_info
|
|
|
|
self._slider = wx.Slider( self, minValue = min, maxValue = max, style = wx.SL_AUTOTICKS | wx.SL_LABELS )
|
|
self._slider.Bind( wx.EVT_SLIDER, self.EventSlider )
|
|
|
|
ratings = [ rating_services.GetRating( self._service_identifier ) for rating_services in all_rating_services ]
|
|
|
|
if all( ( i is None for i in ratings ) ):
|
|
|
|
choices = [ 'set rating', 'make no changes' ]
|
|
|
|
if len( self._media ) > 1: self._current_score.SetLabel( 'none rated' )
|
|
else: self._current_score.SetLabel( 'not rated' )
|
|
|
|
elif None in ratings:
|
|
|
|
choices = [ 'set rating', 'remove rating', 'make no changes' ]
|
|
|
|
if len( self._media ) > 1: self._current_score.SetLabel( 'not all rated' )
|
|
else: self._current_score.SetLabel( 'not rated' )
|
|
|
|
else:
|
|
|
|
# you know what? this should really be a bargraph or something!
|
|
# *
|
|
# *
|
|
# *
|
|
# * *
|
|
# * * * *
|
|
# None 0 1 2 3 4 5
|
|
# but we can't rely on integers, so just think about it
|
|
# some kind of sense of distribution would be helpful though
|
|
|
|
choices = [ 'set rating', 'remove rating', 'make no changes' ]
|
|
|
|
overall_rating = float( sum( ratings ) ) / float( len( ratings ) )
|
|
|
|
overall_rating_converted = ( overall_rating * ( max - min ) ) + min
|
|
|
|
self._slider.SetValue( int( overall_rating_converted + 0.5 ) )
|
|
|
|
str_overall_rating = str( '%.2f' % overall_rating_converted )
|
|
|
|
if min in ( 0, 1 ): str_overall_rating += '/' + str( '%.2f' % max )
|
|
|
|
self._current_score.SetLabel( str_overall_rating )
|
|
|
|
|
|
else:
|
|
|
|
self._current_score.SetLabel( '3.82/5' )
|
|
|
|
|
|
|
|
if service_type in ( HC.LOCAL_RATING_LIKE, HC.LOCAL_RATING_NUMERICAL ):
|
|
|
|
self._choices = wx.Choice( self, choices = choices )
|
|
|
|
self._choices.SetSelection( self._choices.FindString( 'make no changes' ) )
|
|
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) )
|
|
|
|
if service_type in ( HC.LOCAL_RATING_LIKE, HC.LOCAL_RATING_NUMERICAL ): label = 'local rating'
|
|
elif service_type in ( HC.RATING_LIKE_REPOSITORY, HC.RATING_NUMERICAL_REPOSITORY ): label = 'remote rating'
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
vbox.AddF( wx.StaticText( self, label = '- ' + self._service_identifier.GetName() + ' -' ), FLAGS_SMALL_INDENT )
|
|
vbox.AddF( self._current_score, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
if service_type in ( HC.LOCAL_RATING_LIKE, HC.LOCAL_RATING_NUMERICAL ):
|
|
|
|
if service_type == HC.LOCAL_RATING_LIKE:
|
|
|
|
vbox.AddF( self._choices, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
elif service_type == HC.LOCAL_RATING_NUMERICAL:
|
|
|
|
vbox.AddF( self._slider, FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox.AddF( self._choices, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
|
|
|
|
self.SetSizer( vbox )
|
|
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def _GetScoreFont( self ):
|
|
|
|
normal_font = wx.SystemSettings.GetFont( wx.SYS_DEFAULT_GUI_FONT )
|
|
|
|
normal_font_size = normal_font.GetPointSize()
|
|
normal_font_family = normal_font.GetFamily()
|
|
|
|
return wx.Font( normal_font_size * 2, normal_font_family, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD )
|
|
|
|
|
|
def EventSlider( self, event ):
|
|
|
|
rating = self._slider.GetValue()
|
|
|
|
self._choices.SetSelection( 0 )
|
|
|
|
self._choices.SetString( 0, 'set rating to ' + str( rating ) )
|
|
|
|
event.Skip()
|
|
|
|
|
|
def GetRating( self ):
|
|
|
|
service_type = self._service_identifier.GetType()
|
|
|
|
selection = self._choices.GetSelection()
|
|
|
|
s = self._choices.GetString( selection )
|
|
|
|
if s == 'remove rating': return None
|
|
else:
|
|
|
|
if service_type == HC.LOCAL_RATING_LIKE:
|
|
|
|
( like, dislike ) = self._service.GetExtraInfo()
|
|
|
|
if s == like: rating = 1
|
|
elif s == dislike: rating = 0
|
|
|
|
elif service_type == HC.LOCAL_RATING_NUMERICAL: rating = float( self._slider.GetValue() - self._slider.GetMin() ) / float( self._slider.GetMax() - self._slider.GetMin() )
|
|
|
|
|
|
return rating
|
|
|
|
|
|
def HasChanges( self ):
|
|
|
|
selection = self._choices.GetSelection()
|
|
|
|
s = self._choices.GetString( selection )
|
|
|
|
if s == 'make no changes': return False
|
|
else: return True
|
|
|
|
|
|
def GetServiceIdentifier( self ): return self._service_identifier
|
|
|
|
class DialogManageServer( Dialog ):
|
|
|
|
def __init__( self, parent, service_identifier ):
|
|
|
|
def InitialiseControls():
|
|
|
|
self._edit_log = []
|
|
|
|
self._services_listbook = ClientGUICommon.ListBook( self )
|
|
self._services_listbook.Bind( wx.EVT_NOTEBOOK_PAGE_CHANGED, self.EventServiceChanged )
|
|
self._services_listbook.Bind( wx.EVT_NOTEBOOK_PAGE_CHANGING, self.EventServiceChanging )
|
|
|
|
self._service_types = wx.Choice( self )
|
|
|
|
for service_type in [ HC.TAG_REPOSITORY, HC.FILE_REPOSITORY, HC.MESSAGE_DEPOT ]: self._service_types.Append( HC.service_string_lookup[ service_type ], service_type )
|
|
|
|
self._service_types.SetSelection( 0 )
|
|
|
|
self._add = wx.Button( self, label='add' )
|
|
self._add.Bind( wx.EVT_BUTTON, self.EventAdd )
|
|
self._add.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
self._remove = wx.Button( self, label='remove' )
|
|
self._remove.Bind( wx.EVT_BUTTON, self.EventRemove )
|
|
self._remove.SetForegroundColour( ( 128, 0, 0 ) )
|
|
|
|
self._ok = wx.Button( self, label='ok' )
|
|
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.Bind( wx.EVT_BUTTON, self.EventCancel )
|
|
self._cancel.SetForegroundColour( ( 128, 0, 0 ) )
|
|
|
|
# goes after self._remove, because of events
|
|
|
|
for service_identifier in self._service_identifiers:
|
|
|
|
page = DialogManageServerServicePanel( self._services_listbook, service_identifier )
|
|
|
|
name = HC.service_string_lookup[ service_identifier.GetType() ]
|
|
|
|
self._services_listbook.AddPage( page, name )
|
|
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
add_remove_hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
add_remove_hbox.AddF( self._service_types, FLAGS_MIXED )
|
|
add_remove_hbox.AddF( self._add, FLAGS_MIXED )
|
|
add_remove_hbox.AddF( self._remove, FLAGS_MIXED )
|
|
|
|
ok_hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
ok_hbox.AddF( self._ok, FLAGS_MIXED )
|
|
ok_hbox.AddF( self._cancel, FLAGS_MIXED )
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
vbox.AddF( self._services_listbook, FLAGS_EXPAND_BOTH_WAYS )
|
|
vbox.AddF( add_remove_hbox, FLAGS_SMALL_INDENT )
|
|
vbox.AddF( ok_hbox, FLAGS_BUTTON_SIZERS )
|
|
|
|
self.SetSizer( vbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
if y < 400: y = 400 # listbook's setsize ( -1, 400 ) is buggy
|
|
|
|
self.SetInitialSize( ( 680, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'manage ' + service_identifier.GetName() + ' services' )
|
|
|
|
self._service = wx.GetApp().Read( 'service', service_identifier )
|
|
|
|
connection = self._service.GetConnection()
|
|
|
|
self._service_identifiers = connection.Get( 'services' )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
current_page = self._services_listbook.GetCurrentPage()
|
|
|
|
if current_page.GetOriginalServiceIdentifier().GetType() == HC.SERVER_ADMIN: self._remove.Disable()
|
|
else: self._remove.Enable()
|
|
|
|
|
|
def _CheckCurrentServiceIsValid( self ):
|
|
|
|
service_panel = self._services_listbook.GetCurrentPage()
|
|
|
|
if service_panel is not None:
|
|
|
|
port = service_panel.GetInfo()
|
|
|
|
for existing_port in [ page.GetInfo() for page in self._services_listbook.GetNameToPageDict().values() if page != service_panel ]:
|
|
|
|
if port == existing_port: raise Exception( 'That port is already in use!' )
|
|
|
|
|
|
|
|
|
|
def EventAdd( self, event ):
|
|
|
|
try:
|
|
|
|
self._CheckCurrentServiceIsValid()
|
|
|
|
service_type = self._service_types.GetClientData( self._service_types.GetSelection() )
|
|
|
|
existing_ports = [ page.GetInfo() for page in self._services_listbook.GetNameToPageDict().values() ]
|
|
|
|
port = HC.DEFAULT_SERVICE_PORT
|
|
|
|
while port in existing_ports: port += 1
|
|
|
|
service_identifier = HC.ServerServiceIdentifier( service_type, port )
|
|
|
|
self._edit_log.append( ( HC.ADD, service_identifier ) )
|
|
|
|
page = DialogManageServerServicePanel( self._services_listbook, service_identifier )
|
|
|
|
name = HC.service_string_lookup[ service_type ]
|
|
|
|
self._services_listbook.AddPage( page, name, select = True )
|
|
|
|
except Exception as e: wx.MessageBox( unicode( e ) )
|
|
|
|
|
|
def EventCancel( self, event ): self.EndModal( wx.ID_CANCEL )
|
|
|
|
def EventOk( self, event ):
|
|
|
|
try: self._CheckCurrentServiceIsValid()
|
|
except Exception as e:
|
|
|
|
wx.MessageBox( unicode( e ) )
|
|
|
|
return
|
|
|
|
|
|
for page in self._services_listbook.GetNameToPageDict().values():
|
|
|
|
if page.HasChanges(): self._edit_log.append( ( HC.EDIT, ( page.GetOriginalServiceIdentifier(), page.GetInfo() ) ) )
|
|
|
|
|
|
try:
|
|
|
|
if len( self._edit_log ) > 0:
|
|
|
|
connection = self._service.GetConnection()
|
|
|
|
connection.Post( 'servicesmodification', edit_log = self._edit_log )
|
|
|
|
wx.GetApp().Write( 'update_server_services', self._service.GetServiceIdentifier(), self._edit_log )
|
|
|
|
|
|
except Exception as e: wx.MessageBox( 'Saving services to server raised this error: ' + unicode( e ) )
|
|
|
|
self.EndModal( wx.ID_OK )
|
|
|
|
|
|
def EventRemove( self, event ):
|
|
|
|
service_panel = self._services_listbook.GetCurrentPage()
|
|
|
|
if service_panel is not None:
|
|
|
|
service_identifier = service_panel.GetOriginalServiceIdentifier()
|
|
|
|
self._edit_log.append( ( HC.DELETE, service_identifier ) )
|
|
|
|
self._services_listbook.DeleteCurrentPage()
|
|
|
|
|
|
|
|
def EventServiceChanged( self, event ):
|
|
|
|
page = self._services_listbook.GetCurrentPage()
|
|
|
|
if page.GetOriginalServiceIdentifier().GetType() == HC.SERVER_ADMIN: self._remove.Disable()
|
|
else: self._remove.Enable()
|
|
|
|
|
|
def EventServiceChanging( self, event ):
|
|
|
|
try: self._CheckCurrentServiceIsValid()
|
|
except Exception as e:
|
|
|
|
wx.MessageBox( unicode( e ) )
|
|
|
|
event.Veto()
|
|
|
|
|
|
|
|
class DialogManageServerServicePanel( wx.Panel ):
|
|
|
|
def __init__( self, parent, service_identifier ):
|
|
|
|
wx.Panel.__init__( self, parent )
|
|
|
|
self._service_identifier = service_identifier
|
|
|
|
service_type = service_identifier.GetType()
|
|
|
|
def InitialiseControls():
|
|
|
|
self._service_port = wx.SpinCtrl( self, min = 1, max = 65535 )
|
|
self._service_port.SetValue( service_identifier.GetPort() )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) )
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
gridbox = wx.FlexGridSizer( 0, 2 )
|
|
|
|
gridbox.AddGrowableCol( 1, 1 )
|
|
|
|
gridbox.AddF( wx.StaticText( self, label='port' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._service_port, FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
vbox.AddF( wx.StaticText( self, label = '- service -' ), FLAGS_SMALL_INDENT )
|
|
vbox.AddF( gridbox, FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
self.SetSizer( vbox )
|
|
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def GetInfo( self ):
|
|
|
|
port = self._service_port.GetValue()
|
|
|
|
return port
|
|
|
|
|
|
def HasChanges( self ):
|
|
|
|
port = self.GetInfo()
|
|
|
|
if port != self._service_identifier.GetPort(): return True
|
|
|
|
return False
|
|
|
|
|
|
def GetOriginalServiceIdentifier( self ): return self._service_identifier
|
|
|
|
class DialogManageServices( Dialog ):
|
|
|
|
def __init__( self, parent ):
|
|
|
|
def InitialiseControls():
|
|
|
|
self._edit_log = []
|
|
|
|
self._listbook = ClientGUICommon.ListBook( self )
|
|
self._listbook.Bind( wx.EVT_NOTEBOOK_PAGE_CHANGING, self.EventServiceChanging )
|
|
|
|
self._local_ratings_like = ClientGUICommon.ListBook( self._listbook )
|
|
self._local_ratings_like.Bind( wx.EVT_NOTEBOOK_PAGE_CHANGING, self.EventServiceChanging )
|
|
|
|
self._local_ratings_numerical = ClientGUICommon.ListBook( self._listbook )
|
|
self._local_ratings_numerical.Bind( wx.EVT_NOTEBOOK_PAGE_CHANGING, self.EventServiceChanging )
|
|
|
|
self._tag_repositories = ClientGUICommon.ListBook( self._listbook )
|
|
self._tag_repositories.Bind( wx.EVT_NOTEBOOK_PAGE_CHANGING, self.EventServiceChanging )
|
|
|
|
self._file_repositories = ClientGUICommon.ListBook( self._listbook )
|
|
self._file_repositories.Bind( wx.EVT_NOTEBOOK_PAGE_CHANGING, self.EventServiceChanging )
|
|
|
|
self._message_depots = ClientGUICommon.ListBook( self._listbook )
|
|
self._message_depots.Bind( wx.EVT_NOTEBOOK_PAGE_CHANGING, self.EventServiceChanging )
|
|
|
|
self._servers_admin = ClientGUICommon.ListBook( self._listbook )
|
|
self._servers_admin.Bind( wx.EVT_NOTEBOOK_PAGE_CHANGING, self.EventServiceChanging )
|
|
|
|
services = wx.GetApp().Read( 'services', HC.RESTRICTED_SERVICES + [ HC.LOCAL_RATING_LIKE, HC.LOCAL_RATING_NUMERICAL ] )
|
|
|
|
for service in services:
|
|
|
|
service_identifier = service.GetServiceIdentifier()
|
|
|
|
service_type = service_identifier.GetType()
|
|
name = service_identifier.GetName()
|
|
|
|
if service_type in HC.REMOTE_SERVICES: credentials = service.GetCredentials()
|
|
else: credentials = None
|
|
|
|
extra_info = service.GetExtraInfo()
|
|
|
|
if service_type == HC.LOCAL_RATING_LIKE: listbook = self._local_ratings_like
|
|
elif service_type == HC.LOCAL_RATING_NUMERICAL: listbook = self._local_ratings_numerical
|
|
elif service_type == HC.TAG_REPOSITORY: listbook = self._tag_repositories
|
|
elif service_type == HC.FILE_REPOSITORY: listbook = self._file_repositories
|
|
elif service_type == HC.MESSAGE_DEPOT: listbook = self._message_depots
|
|
elif service_type == HC.SERVER_ADMIN: listbook = self._servers_admin
|
|
else: continue
|
|
|
|
page_info = ( DialogManageServicesServicePanel, ( listbook, service_identifier, credentials, extra_info ), {} )
|
|
|
|
listbook.AddPage( page_info, name )
|
|
|
|
|
|
self._listbook.AddPage( self._local_ratings_like, 'local ratings like' )
|
|
self._listbook.AddPage( self._local_ratings_numerical, 'local ratings numerical' )
|
|
self._listbook.AddPage( self._tag_repositories, 'tags' )
|
|
self._listbook.AddPage( self._file_repositories, 'files' )
|
|
self._listbook.AddPage( self._message_depots, 'message depots' )
|
|
self._listbook.AddPage( self._servers_admin, 'servers admin' )
|
|
|
|
self._add = wx.Button( self, label='add' )
|
|
self._add.Bind( wx.EVT_BUTTON, self.EventAdd )
|
|
self._add.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
self._remove = wx.Button( self, label='remove' )
|
|
self._remove.Bind( wx.EVT_BUTTON, self.EventRemove )
|
|
self._remove.SetForegroundColour( ( 128, 0, 0 ) )
|
|
|
|
self._export = wx.Button( self, label='export' )
|
|
self._export.Bind( wx.EVT_BUTTON, self.EventExport )
|
|
|
|
self._ok = wx.Button( self, label='ok' )
|
|
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.Bind( wx.EVT_BUTTON, self.EventCancel )
|
|
self._cancel.SetForegroundColour( ( 128, 0, 0 ) )
|
|
|
|
# these need to be below the addpages because they'd fire the events
|
|
self._listbook.Bind( wx.EVT_NOTEBOOK_PAGE_CHANGING, self.EventPageChanging, source = self._listbook )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
add_remove_hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
add_remove_hbox.AddF( self._add, FLAGS_MIXED )
|
|
add_remove_hbox.AddF( self._remove, FLAGS_MIXED )
|
|
add_remove_hbox.AddF( self._export, FLAGS_MIXED )
|
|
|
|
ok_hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
ok_hbox.AddF( self._ok, FLAGS_MIXED )
|
|
ok_hbox.AddF( self._cancel, FLAGS_MIXED )
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
vbox.AddF( self._listbook, FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
vbox.AddF( add_remove_hbox, FLAGS_SMALL_INDENT )
|
|
vbox.AddF( ok_hbox, FLAGS_BUTTON_SIZERS )
|
|
|
|
self.SetSizer( vbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
self.SetInitialSize( ( 880, y + 220 ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'manage services' )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
self.SetDropTarget( ClientGUICommon.FileDropTarget( self.Import ) )
|
|
|
|
|
|
def _CheckCurrentServiceIsValid( self ):
|
|
|
|
services_listbook = self._listbook.GetCurrentPage()
|
|
|
|
if services_listbook is not None:
|
|
|
|
service_panel = services_listbook.GetCurrentPage()
|
|
|
|
if service_panel is not None:
|
|
|
|
( service_identifier, credentials, extra_info ) = service_panel.GetInfo()
|
|
|
|
old_name = services_listbook.GetCurrentName()
|
|
name = service_identifier.GetName()
|
|
|
|
if old_name is not None and name != old_name:
|
|
|
|
if services_listbook.NameExists( name ): raise Exception( 'That name is already in use!' )
|
|
|
|
services_listbook.RenamePage( old_name, name )
|
|
|
|
|
|
|
|
|
|
|
|
def EventAdd( self, event ):
|
|
|
|
with wx.TextEntryDialog( self, 'Enter new service\'s name' ) as dlg:
|
|
|
|
if dlg.ShowModal() == wx.ID_OK:
|
|
|
|
try:
|
|
|
|
name = dlg.GetValue()
|
|
|
|
services_listbook = self._listbook.GetCurrentPage()
|
|
|
|
if services_listbook.NameExists( name ): raise Exception( 'That name is already in use!' )
|
|
|
|
if name == '': raise Exception( 'Please enter a nickname for the service.' )
|
|
|
|
if services_listbook == self._local_ratings_like: service_type = HC.LOCAL_RATING_LIKE
|
|
elif services_listbook == self._local_ratings_numerical: service_type = HC.LOCAL_RATING_NUMERICAL
|
|
elif services_listbook == self._tag_repositories: service_type = HC.TAG_REPOSITORY
|
|
elif services_listbook == self._file_repositories: service_type = HC.FILE_REPOSITORY
|
|
elif services_listbook == self._message_depots: service_type = HC.MESSAGE_DEPOT
|
|
elif services_listbook == self._servers_admin: service_type = HC.SERVER_ADMIN
|
|
|
|
service_identifier = HC.ClientServiceIdentifier( os.urandom( 32 ), service_type, name )
|
|
|
|
if service_type in HC.REMOTE_SERVICES:
|
|
|
|
if service_type == HC.SERVER_ADMIN: credentials = CC.Credentials( 'hostname', 45870, '' )
|
|
elif service_type in HC.RESTRICTED_SERVICES: credentials = CC.Credentials( 'hostname', 45871, '' )
|
|
else: credentials = CC.Credentials( 'hostname', 45871 )
|
|
|
|
else: credentials = None
|
|
|
|
if service_type == HC.MESSAGE_DEPOT:
|
|
|
|
identity_name = 'identity@' + name
|
|
check_period = 180
|
|
private_key = HydrusMessageHandling.GenerateNewPrivateKey()
|
|
receive_anon = True
|
|
|
|
extra_info = ( identity_name, check_period, private_key, receive_anon )
|
|
|
|
elif service_type == HC.LOCAL_RATING_LIKE: extra_info = ( 'like', 'dislike' )
|
|
elif service_type == HC.LOCAL_RATING_NUMERICAL: extra_info = ( 0, 5 )
|
|
else: extra_info = None
|
|
|
|
self._edit_log.append( ( 'add', ( service_identifier, credentials, extra_info ) ) )
|
|
|
|
page = DialogManageServicesServicePanel( services_listbook, service_identifier, credentials, extra_info )
|
|
|
|
services_listbook.AddPage( page, name, select = True )
|
|
|
|
except Exception as e:
|
|
|
|
wx.MessageBox( unicode( e ) )
|
|
|
|
self.EventAdd( event )
|
|
|
|
|
|
|
|
|
|
|
|
def EventCancel( self, event ): self.EndModal( wx.ID_CANCEL )
|
|
|
|
def EventExport( self, event ):
|
|
|
|
services_listbook = self._listbook.GetCurrentPage()
|
|
|
|
if services_listbook is not None:
|
|
|
|
service_panel = services_listbook.GetCurrentPage()
|
|
|
|
if service_panel is not None:
|
|
|
|
( service_identifier, credentials, extra_info ) = service_panel.GetInfo()
|
|
|
|
old_name = services_listbook.GetCurrentName()
|
|
name = service_identifier.GetName()
|
|
|
|
if old_name is not None and name != old_name:
|
|
|
|
if services_listbook.NameExists( name ): raise Exception( 'That name is already in use!' )
|
|
|
|
services_listbook.RenamePage( old_name, name )
|
|
|
|
|
|
|
|
|
|
services_listbook = self._listbook.GetCurrentPage()
|
|
|
|
if services_listbook is not None:
|
|
|
|
service_panel = services_listbook.GetCurrentPage()
|
|
|
|
( service_identifier, credentials, extra_info ) = service_panel.GetInfo()
|
|
|
|
name = service_identifier.GetName()
|
|
|
|
try:
|
|
|
|
with wx.FileDialog( self, 'select where to export service', defaultFile = name + '.yaml', style = wx.FD_SAVE ) as dlg:
|
|
|
|
if dlg.ShowModal() == wx.ID_OK:
|
|
|
|
with open( dlg.GetPath(), 'wb' ) as f: f.write( yaml.safe_dump( ( service_identifier, credentials, extra_info ) ) )
|
|
|
|
|
|
|
|
except:
|
|
|
|
with wx.FileDialog( self, 'select where to export service', defaultFile = 'service.yaml', style = wx.FD_SAVE ) as dlg:
|
|
|
|
if dlg.ShowModal() == wx.ID_OK:
|
|
|
|
with open( dlg.GetPath(), 'wb' ) as f: f.write( yaml.safe_dump( ( service_identifier, credentials, extra_info ) ) )
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def EventOk( self, event ):
|
|
|
|
try: self._CheckCurrentServiceIsValid()
|
|
except Exception as e:
|
|
|
|
wx.MessageBox( unicode( e ) )
|
|
|
|
return
|
|
|
|
|
|
all_pages = []
|
|
|
|
all_pages.extend( self._local_ratings_like.GetNameToPageDict().values() )
|
|
all_pages.extend( self._local_ratings_numerical.GetNameToPageDict().values() )
|
|
all_pages.extend( self._tag_repositories.GetNameToPageDict().values() )
|
|
all_pages.extend( self._file_repositories.GetNameToPageDict().values() )
|
|
all_pages.extend( self._message_depots.GetNameToPageDict().values() )
|
|
all_pages.extend( self._servers_admin.GetNameToPageDict().values() )
|
|
|
|
for page in all_pages:
|
|
|
|
if page.HasChanges(): self._edit_log.append( ( 'edit', ( page.GetOriginalServiceIdentifier(), page.GetInfo() ) ) )
|
|
|
|
|
|
try:
|
|
|
|
if len( self._edit_log ) > 0: wx.GetApp().Write( 'update_services', self._edit_log )
|
|
|
|
except Exception as e: wx.MessageBox( 'Saving services to DB raised this error: ' + unicode( e ) )
|
|
|
|
self.EndModal( wx.ID_OK )
|
|
|
|
|
|
def EventPageChanging( self, event ):
|
|
|
|
try: self._CheckCurrentServiceIsValid()
|
|
except Exception as e:
|
|
|
|
wx.MessageBox( unicode( e ) )
|
|
|
|
event.Veto()
|
|
|
|
|
|
|
|
def EventRemove( self, event ):
|
|
|
|
services_listbook = self._listbook.GetCurrentPage()
|
|
|
|
service_panel = services_listbook.GetCurrentPage()
|
|
|
|
if service_panel is not None:
|
|
|
|
service_identifier = service_panel.GetOriginalServiceIdentifier()
|
|
|
|
self._edit_log.append( ( 'delete', service_identifier ) )
|
|
|
|
services_listbook.DeleteCurrentPage()
|
|
|
|
|
|
|
|
def EventServiceChanging( self, event ):
|
|
|
|
try: self._CheckCurrentServiceIsValid()
|
|
except Exception as e:
|
|
|
|
wx.MessageBox( unicode( e ) )
|
|
|
|
event.Veto()
|
|
|
|
|
|
|
|
def Import( self, paths ):
|
|
|
|
self._CheckCurrentServiceIsValid()
|
|
|
|
for path in paths:
|
|
|
|
try:
|
|
|
|
with open( path, 'rb' ) as f: file = f.read()
|
|
|
|
( service_identifier, credentials, extra_info ) = yaml.safe_load( file )
|
|
|
|
name = service_identifier.GetName()
|
|
|
|
service_type = service_identifier.GetType()
|
|
|
|
if service_type == HC.TAG_REPOSITORY: services_listbook = self._tag_repositories
|
|
elif service_type == HC.FILE_REPOSITORY: services_listbook = self._file_repositories
|
|
elif service_type == HC.MESSAGE_DEPOT: services_listbook = self._message_depots
|
|
elif service_type == HC.SERVER_ADMIN: services_listbook = self._servers_admin
|
|
|
|
self._listbook.SelectPage( services_listbook )
|
|
|
|
if services_listbook.NameExists( name ):
|
|
|
|
message = 'A service already exists with that name. Overwrite it?'
|
|
|
|
with DialogYesNo( self, message ) as dlg:
|
|
|
|
if dlg.ShowModal() == wx.ID_YES:
|
|
|
|
page = services_listbook.GetNameToPageDict()[ name ]
|
|
|
|
page.Update( service_identifier, credentials, extra_info )
|
|
|
|
|
|
|
|
else:
|
|
|
|
self._edit_log.append( ( 'add', ( service_identifier, credentials, extra_info ) ) )
|
|
|
|
page = DialogManageServicesServicePanel( services_listbook, service_identifier, credentials, extra_info )
|
|
|
|
services_listbook.AddPage( page, name, select = True )
|
|
|
|
|
|
except:
|
|
|
|
wx.MessageBox( traceback.format_exc() )
|
|
|
|
|
|
|
|
|
|
class DialogManageServicesServicePanel( wx.Panel ):
|
|
|
|
def __init__( self, parent, service_identifier, credentials, extra_info ):
|
|
|
|
wx.Panel.__init__( self, parent )
|
|
|
|
self._service_identifier = service_identifier
|
|
self._credentials = credentials
|
|
self._extra_info = extra_info
|
|
|
|
service_type = service_identifier.GetType()
|
|
|
|
def InitialiseControls():
|
|
|
|
self._service_name = wx.TextCtrl( self, value = self._service_identifier.GetName() )
|
|
|
|
if service_type in HC.REMOTE_SERVICES: self._service_credentials = wx.TextCtrl( self, value = self._credentials.GetConnectionString() )
|
|
|
|
if service_type == HC.MESSAGE_DEPOT:
|
|
|
|
( identity_name, check_period, private_key, receive_anon ) = self._extra_info
|
|
|
|
self._identity_name = wx.TextCtrl( self, value = identity_name )
|
|
|
|
self._check_period = wx.SpinCtrl( self, min = 60, max = 86400 * 7, initial = check_period )
|
|
|
|
self._private_key = wx.TextCtrl( self, value = private_key, style = wx.TE_MULTILINE )
|
|
|
|
self._receive_anon = wx.CheckBox( self )
|
|
self._receive_anon.SetValue( receive_anon )
|
|
|
|
elif service_identifier.GetType() == HC.LOCAL_RATING_LIKE:
|
|
|
|
( like, dislike ) = self._extra_info
|
|
|
|
self._like = wx.TextCtrl( self, value = like )
|
|
self._dislike = wx.TextCtrl( self, value = dislike )
|
|
|
|
elif service_identifier.GetType() == HC.LOCAL_RATING_NUMERICAL:
|
|
|
|
( lower, upper ) = self._extra_info
|
|
|
|
self._lower = wx.SpinCtrl( self, min = -2000, max = 2000, initial = lower )
|
|
self._upper = wx.SpinCtrl( self, min = -2000, max = 2000, initial = upper )
|
|
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) )
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
gridbox = wx.FlexGridSizer( 0, 2 )
|
|
|
|
gridbox.AddGrowableCol( 1, 1 )
|
|
|
|
gridbox.AddF( wx.StaticText( self, label='name' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._service_name, FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
if service_type in HC.REMOTE_SERVICES:
|
|
|
|
gridbox.AddF( wx.StaticText( self, label='credentials' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._service_credentials, FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
|
|
if service_type == HC.MESSAGE_DEPOT:
|
|
|
|
gridbox.AddF( wx.StaticText( self, label='identity name' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._identity_name, FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
gridbox.AddF( wx.StaticText( self, label='update period' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._check_period, FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
gridbox.AddF( wx.StaticText( self, label='private key' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._private_key, FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
gridbox.AddF( wx.StaticText( self, label='receive messages from Anonymous?' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._receive_anon, FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
elif service_identifier.GetType() == HC.LOCAL_RATING_LIKE:
|
|
|
|
gridbox.AddF( wx.StaticText( self, label='like' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._like, FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
gridbox.AddF( wx.StaticText( self, label='dislike' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._dislike, FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
elif service_identifier.GetType() == HC.LOCAL_RATING_NUMERICAL:
|
|
|
|
gridbox.AddF( wx.StaticText( self, label='lower limit' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._lower, FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
gridbox.AddF( wx.StaticText( self, label='upper limit' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._upper, FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
|
|
vbox.AddF( wx.StaticText( self, label = '- service -' ), FLAGS_SMALL_INDENT )
|
|
vbox.AddF( gridbox, FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
self.SetSizer( vbox )
|
|
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def GetInfo( self ):
|
|
|
|
service_key = self._service_identifier.GetServiceKey()
|
|
|
|
service_type = self._service_identifier.GetType()
|
|
|
|
name = self._service_name.GetValue()
|
|
|
|
if name == '': raise Exception( 'Please enter a name' )
|
|
|
|
service_identifier = HC.ClientServiceIdentifier( service_key, service_type, name )
|
|
|
|
if service_type in HC.REMOTE_SERVICES:
|
|
|
|
connection_string = self._service_credentials.GetValue()
|
|
|
|
if connection_string == '': raise Exception( 'Please enter some credentials' )
|
|
|
|
if '@' in connection_string:
|
|
|
|
try: ( access_key, address ) = connection_string.split( '@' )
|
|
except: raise Exception( 'Could not parse those credentials - no \'@\' symbol!' )
|
|
|
|
try: access_key = access_key.decode( 'hex' )
|
|
except: raise Exception( 'Could not parse those credentials - could not understand access key!' )
|
|
|
|
try: ( host, port ) = address.split( ':' )
|
|
except: raise Exception( 'Could not parse those credentials - no \':\' symbol!' )
|
|
|
|
try: port = int( port )
|
|
except: raise Exception( 'Could not parse those credentials - could not understand the port!' )
|
|
|
|
credentials = CC.Credentials( host, port, access_key )
|
|
|
|
else:
|
|
|
|
try: ( host, port ) = connection_string.split( ':' )
|
|
except: raise Exception( 'Could not parse those credentials - no \':\' symbol!' )
|
|
|
|
try: port = int( port )
|
|
except: raise Exception( 'Could not parse those credentials - could not understand the port!' )
|
|
|
|
credentials = CC.Credentials( host, port )
|
|
|
|
|
|
else: credentials = None
|
|
|
|
if service_type == HC.MESSAGE_DEPOT: extra_info = ( self._identity_name.GetValue(), self._check_period.GetValue(), self._private_key.GetValue(), self._receive_anon.GetValue() )
|
|
elif service_type == HC.LOCAL_RATING_LIKE: extra_info = ( self._like.GetValue(), self._dislike.GetValue() )
|
|
elif service_type == HC.LOCAL_RATING_NUMERICAL:
|
|
|
|
( lower, upper ) = ( self._lower.GetValue(), self._upper.GetValue() )
|
|
|
|
if upper < lower: upper = lower + 1
|
|
|
|
extra_info = ( lower, upper )
|
|
|
|
else: extra_info = None
|
|
|
|
return ( service_identifier, credentials, extra_info )
|
|
|
|
|
|
def HasChanges( self ):
|
|
|
|
( service_identifier, credentials, extra_info ) = self.GetInfo()
|
|
|
|
if service_identifier != self._service_identifier: return True
|
|
|
|
if credentials != self._credentials: return True
|
|
|
|
if extra_info != self._extra_info: return True
|
|
|
|
return False
|
|
|
|
|
|
def GetOriginalServiceIdentifier( self ): return self._service_identifier
|
|
|
|
def Update( self, service_identifier, credentials, extra_info ):
|
|
|
|
service_type = service_identifier.GetType()
|
|
|
|
self._service_name.SetValue( service_identifier.GetName() )
|
|
|
|
if service_type in HC.REMOTE_SERVICES: self._service_credentials.SetValue( credentials.GetConnectionString() )
|
|
|
|
if service_type == HC.MESSAGE_DEPOT:
|
|
|
|
if len( extra_info ) == 3:
|
|
( identity_name, check_period, private_key ) = extra_info
|
|
receive_anon = True
|
|
else: ( identity_name, check_period, private_key, receive_anon ) = extra_info
|
|
|
|
self._identity_name.SetValue( identity_name )
|
|
|
|
self._check_period.SetValue( check_period )
|
|
|
|
self._private_key.SetValue( private_key )
|
|
|
|
self._receive_anon.SetValue( receive_anon )
|
|
|
|
elif service_type == HC.LOCAL_RATING_LIKE:
|
|
|
|
( like, dislike ) = extra_info
|
|
|
|
self._like.SetValue( like )
|
|
self._dislike.SetValue( dislike )
|
|
|
|
elif service_type == HC.LOCAL_RATING_NUMERICAL:
|
|
|
|
( lower, upper ) = extra_info
|
|
|
|
self._lower.SetValue( lower )
|
|
self._upper.SetValue( upper )
|
|
|
|
|
|
|
|
class DialogManageTagServicePrecedence( Dialog ):
|
|
|
|
def __init__( self, parent ):
|
|
|
|
def InitialiseControls():
|
|
|
|
message = 'When services dispute over a file\'s tags,' + os.linesep + 'higher services will overrule those below.'
|
|
|
|
self._explain = wx.StaticText( self, label = message )
|
|
|
|
self._tag_services = wx.ListBox( self )
|
|
|
|
tag_service_precedence = wx.GetApp().Read( 'tag_service_precedence' )
|
|
|
|
for service_identifier in tag_service_precedence:
|
|
|
|
name = service_identifier.GetName()
|
|
|
|
self._tag_services.Append( name, service_identifier )
|
|
|
|
|
|
self._up = wx.Button( self, label = u'\u2191' )
|
|
self._up.Bind( wx.EVT_BUTTON, self.EventUp )
|
|
|
|
self._down = wx.Button( self, label = u'\u2193' )
|
|
self._down.Bind( wx.EVT_BUTTON, self.EventDown )
|
|
|
|
self._apply = wx.Button( self, label='apply' )
|
|
self._apply.Bind( wx.EVT_BUTTON, self.EventOK )
|
|
self._apply.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
self._cancel = wx.Button( self, id = wx.ID_CANCEL, label='cancel' )
|
|
self._cancel.Bind( wx.EVT_BUTTON, self.EventCancel )
|
|
self._cancel.SetForegroundColour( ( 128, 0, 0 ) )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
updown_vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
updown_vbox.AddF( self._up, FLAGS_MIXED )
|
|
updown_vbox.AddF( self._down, FLAGS_MIXED )
|
|
|
|
main_hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
main_hbox.AddF( self._tag_services, FLAGS_EXPAND_BOTH_WAYS )
|
|
main_hbox.AddF( updown_vbox, FLAGS_MIXED )
|
|
|
|
buttons = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
buttons.AddF( self._apply, FLAGS_SMALL_INDENT )
|
|
buttons.AddF( self._cancel, FLAGS_SMALL_INDENT )
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
vbox.AddF( self._explain, FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox.AddF( main_hbox, FLAGS_EXPAND_BOTH_WAYS )
|
|
vbox.AddF( buttons, FLAGS_BUTTON_SIZERS )
|
|
|
|
self.SetSizer( vbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
if y < 400: y = 400
|
|
|
|
self.SetInitialSize( ( x, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'manage tag service precedence' )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def EventCancel( self, event ): self.EndModal( wx.ID_CANCEL )
|
|
|
|
def EventOK( self, event ):
|
|
|
|
try:
|
|
|
|
service_identifiers = [ self._tag_services.GetClientData( i ) for i in range( self._tag_services.GetCount() ) ]
|
|
|
|
wx.GetApp().Write( 'set_tag_service_precedence', service_identifiers )
|
|
|
|
except Exception as e: wx.MessageBox( 'Something went wrong when trying to save tag service precedence to the database: ' + unicode( e ) )
|
|
|
|
self.EndModal( wx.ID_OK )
|
|
|
|
|
|
def EventUp( self, event ):
|
|
|
|
selection = self._tag_services.GetSelection()
|
|
|
|
if selection != wx.NOT_FOUND:
|
|
|
|
if selection > 0:
|
|
|
|
service_identifier = self._tag_services.GetClientData( selection )
|
|
|
|
name = service_identifier.GetName()
|
|
|
|
self._tag_services.Delete( selection )
|
|
|
|
self._tag_services.Insert( name, selection - 1, service_identifier )
|
|
|
|
self._tag_services.Select( selection - 1 )
|
|
|
|
|
|
|
|
|
|
def EventDown( self, event ):
|
|
|
|
selection = self._tag_services.GetSelection()
|
|
|
|
if selection != wx.NOT_FOUND:
|
|
|
|
if selection + 1 < self._tag_services.GetCount():
|
|
|
|
service_identifier = self._tag_services.GetClientData( selection )
|
|
|
|
name = service_identifier.GetName()
|
|
|
|
self._tag_services.Delete( selection )
|
|
|
|
self._tag_services.Insert( name, selection + 1, service_identifier )
|
|
|
|
self._tag_services.Select( selection + 1 )
|
|
|
|
|
|
|
|
|
|
class DialogManageTags( Dialog ):
|
|
|
|
def __init__( self, parent, file_service_identifier, media ):
|
|
|
|
def InitialiseControls():
|
|
|
|
self._tag_repositories = ClientGUICommon.ListBook( self )
|
|
self._tag_repositories.Bind( wx.EVT_NOTEBOOK_PAGE_CHANGED, self.EventServiceChanged )
|
|
|
|
service_identifiers = wx.GetApp().Read( 'service_identifiers', ( HC.TAG_REPOSITORY, ) )
|
|
|
|
for service_identifier in list( service_identifiers ) + [ CC.LOCAL_TAG_SERVICE_IDENTIFIER ]:
|
|
|
|
service_type = service_identifier.GetType()
|
|
|
|
page_info = ( DialogManageTagsPanel, ( self._tag_repositories, self._file_service_identifier, service_identifier, media ), {} )
|
|
|
|
name = service_identifier.GetName()
|
|
|
|
self._tag_repositories.AddPage( page_info, name )
|
|
|
|
|
|
default_tag_repository = self._options[ 'default_tag_repository' ]
|
|
|
|
self._tag_repositories.Select( default_tag_repository.GetName() )
|
|
|
|
self._apply = wx.Button( self, label='Apply' )
|
|
self._apply.Bind( wx.EVT_BUTTON, self.EventOk )
|
|
self._apply.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
self._cancel = wx.Button( self, id = wx.ID_CANCEL, label='Cancel' )
|
|
self._cancel.Bind( wx.EVT_BUTTON, self.EventCancel )
|
|
self._cancel.SetForegroundColour( ( 128, 0, 0 ) )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
buttonbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
buttonbox.AddF( self._apply, FLAGS_MIXED )
|
|
buttonbox.AddF( self._cancel, FLAGS_MIXED )
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
vbox.AddF( self._tag_repositories, FLAGS_EXPAND_BOTH_WAYS )
|
|
vbox.AddF( buttonbox, FLAGS_BUTTON_SIZERS )
|
|
|
|
self.SetSizer( vbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
self.SetInitialSize( ( x + 200, 500 ) )
|
|
|
|
|
|
self._file_service_identifier = file_service_identifier
|
|
self._hashes = HC.IntelligentMassUnion( ( m.GetHashes() for m in media ) )
|
|
|
|
Dialog.__init__( self, parent, 'manage tags for ' + HC.ConvertIntToPrettyString( len( self._hashes ) ) + ' files' )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
self.Bind( wx.EVT_MENU, self.EventMenu )
|
|
|
|
self.RefreshAcceleratorTable()
|
|
|
|
|
|
def EventCancel( self, event ): self.EndModal( wx.ID_CANCEL )
|
|
|
|
def EventMenu( self, event ):
|
|
|
|
action = CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetAction( event.GetId() )
|
|
|
|
if action is not None:
|
|
|
|
( command, data ) = action
|
|
|
|
if command == 'manage_tags': self.EventCancel( event )
|
|
elif command == 'ok': self.EventOk( event )
|
|
else: event.Skip()
|
|
|
|
|
|
|
|
def EventOk( self, event ):
|
|
|
|
try:
|
|
|
|
content_updates = []
|
|
|
|
for page in self._tag_repositories.GetNameToPageDict().values():
|
|
|
|
if page.HasChanges():
|
|
|
|
service_identifier = page.GetServiceIdentifier()
|
|
|
|
edit_log = page.GetEditLog()
|
|
|
|
content_updates.append( CC.ContentUpdate( CC.CONTENT_UPDATE_EDIT_LOG, service_identifier, self._hashes, info = edit_log ) )
|
|
|
|
|
|
|
|
if len( content_updates ) > 0: wx.GetApp().Write( 'content_updates', content_updates )
|
|
|
|
except Exception as e: wx.MessageBox( 'Saving pending mapping changes to DB raised this error: ' + unicode( e ) )
|
|
|
|
self.EndModal( wx.ID_OK )
|
|
|
|
|
|
def EventServiceChanged( self, event ):
|
|
|
|
page = self._tag_repositories.GetCurrentPage()
|
|
|
|
wx.CallAfter( page.SetTagBoxFocus )
|
|
|
|
|
|
def RefreshAcceleratorTable( self ):
|
|
|
|
entries = []
|
|
|
|
for ( modifier, key_dict ) in self._options[ 'shortcuts' ].items(): entries.extend( [ ( modifier, key, CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( action ) ) for ( key, action ) in key_dict.items() ] )
|
|
|
|
self.SetAcceleratorTable( wx.AcceleratorTable( entries ) )
|
|
|
|
|
|
class DialogManageTagsPanel( wx.Panel ):
|
|
|
|
def __init__( self, parent, file_service_identifier, tag_service_identifier, media ):
|
|
|
|
def InitialiseControls():
|
|
|
|
self._tags_box = ClientGUICommon.TagsBoxManage( self, self.AddTag, self._current_tags, self._deleted_tags, self._pending_tags, self._petitioned_tags )
|
|
|
|
self._add_tag_box = ClientGUICommon.AutoCompleteDropdownTagsWrite( self, self.AddTag, self._file_service_identifier, self._tag_service_identifier )
|
|
|
|
self._show_deleted_tags = wx.CheckBox( self, label='Show deleted tags' )
|
|
self._show_deleted_tags.Bind( wx.EVT_CHECKBOX, self.EventShowDeletedTags )
|
|
|
|
self._modify_mappers = wx.Button( self, label='Modify mappers' )
|
|
self._modify_mappers.Bind( wx.EVT_BUTTON, self.EventModify )
|
|
|
|
self._copy_tags = wx.Button( self, label = 'copy tags' )
|
|
self._copy_tags.Bind( wx.EVT_BUTTON, self.EventCopyTags )
|
|
|
|
self._paste_tags = wx.Button( self, label = 'paste tags' )
|
|
self._paste_tags.Bind( wx.EVT_BUTTON, self.EventPasteTags )
|
|
|
|
if self._i_am_local_tag_service:
|
|
|
|
self._show_deleted_tags.Hide()
|
|
self._modify_mappers.Hide()
|
|
|
|
else:
|
|
|
|
if not self._account.HasPermission( HC.POST_DATA ): self._add_tag_box.Hide()
|
|
if not self._account.HasPermission( HC.MANAGE_USERS ): self._modify_mappers.Hide()
|
|
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
self.SetBackgroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_BTNFACE ) )
|
|
|
|
special_hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
special_hbox.AddF( self._show_deleted_tags, FLAGS_MIXED )
|
|
special_hbox.AddF( self._modify_mappers, FLAGS_MIXED )
|
|
|
|
copy_paste_hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
copy_paste_hbox.AddF( self._copy_tags, FLAGS_MIXED )
|
|
copy_paste_hbox.AddF( self._paste_tags, FLAGS_MIXED )
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
vbox.AddF( self._tags_box, FLAGS_EXPAND_BOTH_WAYS )
|
|
vbox.AddF( self._add_tag_box, FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox.AddF( copy_paste_hbox, FLAGS_BUTTON_SIZERS )
|
|
vbox.AddF( special_hbox, FLAGS_BUTTON_SIZERS )
|
|
|
|
self.SetSizer( vbox )
|
|
|
|
|
|
wx.Panel.__init__( self, parent )
|
|
|
|
self._file_service_identifier = file_service_identifier
|
|
self._tag_service_identifier = tag_service_identifier
|
|
|
|
self._i_am_local_tag_service = self._tag_service_identifier.GetType() == HC.LOCAL_TAG
|
|
|
|
self._edit_log = []
|
|
|
|
if not self._i_am_local_tag_service:
|
|
|
|
service = wx.GetApp().Read( 'service', tag_service_identifier )
|
|
|
|
self._account = service.GetAccount()
|
|
|
|
|
|
( self._current_tags, self._deleted_tags, self._pending_tags, self._petitioned_tags ) = CC.MediaIntersectCDPPTagServiceIdentifiers( media, tag_service_identifier )
|
|
|
|
self._current_tags.sort()
|
|
self._pending_tags.sort()
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def AddTag( self, tag ):
|
|
|
|
if tag is None: wx.PostEvent( self, wx.CommandEvent( commandType = wx.wxEVT_COMMAND_MENU_SELECTED, winid = CC.MENU_EVENT_ID_TO_ACTION_CACHE.GetId( 'ok' ) ) )
|
|
else:
|
|
|
|
if self._i_am_local_tag_service:
|
|
|
|
if tag in self._pending_tags:
|
|
|
|
self._pending_tags.remove( tag )
|
|
|
|
self._tags_box.RescindPend( tag )
|
|
|
|
elif tag in self._petitioned_tags:
|
|
|
|
self._petitioned_tags.remove( tag )
|
|
|
|
self._tags_box.RescindPetition( tag )
|
|
|
|
elif tag in self._current_tags:
|
|
|
|
self._petitioned_tags.append( tag )
|
|
|
|
self._tags_box.PetitionTag( tag )
|
|
|
|
else:
|
|
|
|
self._pending_tags.append( tag )
|
|
|
|
self._tags_box.PendTag( tag )
|
|
|
|
|
|
self._edit_log = []
|
|
|
|
self._edit_log.extend( [ ( CC.CONTENT_UPDATE_ADD, tag ) for tag in self._pending_tags ] )
|
|
self._edit_log.extend( [ ( CC.CONTENT_UPDATE_DELETE, tag ) for tag in self._petitioned_tags ] )
|
|
|
|
else:
|
|
|
|
if tag in self._pending_tags:
|
|
|
|
self._pending_tags.remove( tag )
|
|
|
|
self._tags_box.RescindPend( tag )
|
|
|
|
self._edit_log.append( ( CC.CONTENT_UPDATE_RESCIND_PENDING, tag ) )
|
|
|
|
elif tag in self._petitioned_tags:
|
|
|
|
self._petitioned_tags.remove( tag )
|
|
|
|
self._tags_box.RescindPetition( tag )
|
|
|
|
self._edit_log.append( ( CC.CONTENT_UPDATE_RESCIND_PETITION, tag ) )
|
|
|
|
elif tag in self._current_tags:
|
|
|
|
if self._account.HasPermission( HC.RESOLVE_PETITIONS ):
|
|
|
|
self._edit_log.append( ( CC.CONTENT_UPDATE_PETITION, ( tag, 'admin' ) ) )
|
|
|
|
self._petitioned_tags.append( tag )
|
|
|
|
self._tags_box.PetitionTag( tag )
|
|
|
|
elif self._account.HasPermission( HC.POST_PETITIONS ):
|
|
|
|
message = 'Enter a reason for this tag to be removed. A janitor will review your petition.'
|
|
|
|
with wx.TextEntryDialog( self, message ) as dlg:
|
|
|
|
if dlg.ShowModal() == wx.ID_OK:
|
|
|
|
self._edit_log.append( ( CC.CONTENT_UPDATE_PETITION, ( tag, dlg.GetValue() ) ) )
|
|
|
|
self._petitioned_tags.append( tag )
|
|
|
|
self._tags_box.PetitionTag( tag )
|
|
|
|
|
|
|
|
|
|
elif tag in self._deleted_tags:
|
|
|
|
if self._account.HasPermission( HC.RESOLVE_PETITIONS ):
|
|
|
|
self._edit_log.append( ( CC.CONTENT_UPDATE_PENDING, tag ) )
|
|
|
|
self._pending_tags.append( tag )
|
|
|
|
self._tags_box.PendTag( tag )
|
|
|
|
|
|
else:
|
|
|
|
self._edit_log.append( ( CC.CONTENT_UPDATE_PENDING, tag ) )
|
|
|
|
self._pending_tags.append( tag )
|
|
|
|
self._tags_box.PendTag( tag )
|
|
|
|
|
|
|
|
|
|
|
|
def EventCopyTags( self, event ):
|
|
|
|
if wx.TheClipboard.Open():
|
|
|
|
tags = self._current_tags + self._pending_tags
|
|
|
|
text = yaml.safe_dump( tags )
|
|
|
|
data = wx.TextDataObject( text )
|
|
|
|
wx.TheClipboard.SetData( data )
|
|
|
|
wx.TheClipboard.Close()
|
|
|
|
else: wx.MessageBox( 'I could not get permission to access the clipboard.' )
|
|
|
|
|
|
def EventModify( self, event ):
|
|
|
|
tag = self._tags_box.GetSelectedTag()
|
|
|
|
if tag is not None and tag in self._current_tags or tag in self._petitioned_tags:
|
|
|
|
subject_identifiers = [ HC.AccountIdentifier( hash = hash, tag = tag ) for hash in self._hashes ]
|
|
|
|
try:
|
|
|
|
with DialogModifyAccounts( self, self._tag_service_identifier, subject_identifiers ) as dlg: dlg.ShowModal()
|
|
|
|
except Exception as e: wx.MessageBox( unicode( e ) )
|
|
|
|
|
|
|
|
def EventPasteTags( self, event ):
|
|
|
|
if wx.TheClipboard.Open():
|
|
|
|
data = wx.TextDataObject()
|
|
|
|
wx.TheClipboard.GetData( data )
|
|
|
|
wx.TheClipboard.Close()
|
|
|
|
text = data.GetText()
|
|
|
|
try:
|
|
|
|
tags = yaml.safe_load( text )
|
|
|
|
tags = [ tag for tag in tags if tag not in self._current_tags and tag not in self._pending_tags ]
|
|
|
|
for tag in tags: self.AddTag( tag )
|
|
|
|
except: wx.MessageBox( 'I could not understand what was in the clipboard' )
|
|
|
|
else: wx.MessageBox( 'I could not get permission to access the clipboard.' )
|
|
|
|
|
|
def EventShowDeletedTags( self, event ): self._tags_box.SetShowDeletedTags( self._show_deleted_tags.GetValue() )
|
|
|
|
def EventTagsBoxAction( self, event ):
|
|
|
|
tag = self._tags_box.GetSelectedTag()
|
|
|
|
if tag is not None: self.AddTag( tag )
|
|
|
|
|
|
def GetEditLog( self ): return self._edit_log
|
|
|
|
def GetServiceIdentifier( self ): return self._tag_service_identifier
|
|
|
|
def HasChanges( self ): return len( self._edit_log ) > 0
|
|
|
|
def SetTagBoxFocus( self ): self._add_tag_box.SetFocus()
|
|
|
|
class DialogMessage( Dialog ):
|
|
|
|
def __init__( self, parent, message, ok_label = 'ok' ):
|
|
|
|
def InitialiseControls():
|
|
|
|
self._ok = wx.Button( self, id = wx.ID_CANCEL, label = ok_label )
|
|
self._ok.Bind( wx.EVT_BUTTON, self.EventOk )
|
|
self._ok.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
text = wx.StaticText( self, label = str( message ) )
|
|
|
|
text.Wrap( 480 )
|
|
|
|
vbox.AddF( text, FLAGS_BIG_INDENT )
|
|
vbox.AddF( self._ok, FLAGS_BUTTON_SIZERS )
|
|
|
|
self.SetSizer( vbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
self.SetInitialSize( ( x, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'message', position = 'center' )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def EventOk( self, event ): self.EndModal( wx.ID_OK )
|
|
|
|
class DialogModifyAccounts( Dialog ):
|
|
|
|
def __init__( self, parent, service_identifier, subject_identifiers ):
|
|
|
|
def InitialiseControls():
|
|
|
|
connection = self._service.GetConnection()
|
|
|
|
if len( self._subject_identifiers ) == 1:
|
|
|
|
( subject_identifier, ) = self._subject_identifiers
|
|
|
|
subject_string = connection.Get( 'accountinfo', subject_identifier = subject_identifier )
|
|
|
|
else: subject_string = 'modifying ' + HC.ConvertIntToPrettyString( len( self._subject_identifiers ) ) + ' accounts'
|
|
|
|
self._subject_text = wx.StaticText( self, label = str( subject_string ) )
|
|
|
|
account_types = connection.Get( 'accounttypes' )
|
|
|
|
self._account_types = wx.Choice( self )
|
|
|
|
for account_type in account_types: self._account_types.Append( account_type.ConvertToString(), account_type )
|
|
|
|
self._account_types.SetSelection( 0 )
|
|
|
|
self._account_types_ok = wx.Button( self, label = 'Ok' )
|
|
self._account_types_ok.Bind( wx.EVT_BUTTON, self.EventChangeAccountType )
|
|
|
|
self._add_to_expires = wx.Choice( self )
|
|
|
|
for ( string, value ) in HC.expirations:
|
|
|
|
if value is not None: self._add_to_expires.Append( string, value ) # don't want 'add no limit'
|
|
|
|
self._add_to_expires.SetSelection( 1 ) # three months
|
|
|
|
self._add_to_expires_ok = wx.Button( self, label = 'Ok' )
|
|
self._add_to_expires_ok.Bind( wx.EVT_BUTTON, self.EventAddToExpires )
|
|
|
|
self._set_expires = wx.Choice( self )
|
|
for ( string, value ) in HC.expirations: self._set_expires.Append( string, value )
|
|
self._set_expires.SetSelection( 1 ) # three months
|
|
|
|
self._set_expires_ok = wx.Button( self, label = 'Ok' )
|
|
self._set_expires_ok.Bind( wx.EVT_BUTTON, self.EventSetExpires )
|
|
|
|
self._ban = wx.Button( self, 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, 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' )
|
|
self._exit.Bind( wx.EVT_BUTTON, lambda event: self.EndModal( wx.ID_OK ) )
|
|
|
|
if not self._service.GetAccount().HasPermission( HC.GENERAL_ADMIN ):
|
|
|
|
self._account_types_ok.Disable()
|
|
self._add_to_expires_ok.Disable()
|
|
self._set_expires_ok.Disable()
|
|
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
info_box = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
info_box.AddF( wx.StaticText( self, label = '- account info -' ), FLAGS_SMALL_INDENT )
|
|
info_box.AddF( self._subject_text, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
account_types_box = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
account_types_box.AddF( wx.StaticText( self, label = '- change account type -' ), FLAGS_SMALL_INDENT )
|
|
account_types_box.AddF( self._account_types, FLAGS_EXPAND_BOTH_WAYS )
|
|
account_types_box.AddF( self._account_types_ok, FLAGS_MIXED )
|
|
|
|
add_to_expires_box = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
add_to_expires_box.AddF( wx.StaticText( self, label = 'Add to expires: ' ), FLAGS_MIXED )
|
|
add_to_expires_box.AddF( self._add_to_expires, FLAGS_EXPAND_BOTH_WAYS )
|
|
add_to_expires_box.AddF( self._add_to_expires_ok, FLAGS_MIXED )
|
|
|
|
set_expires_box = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
set_expires_box.AddF( wx.StaticText( self, label = 'Set expires to: ' ), FLAGS_MIXED )
|
|
set_expires_box.AddF( self._set_expires, FLAGS_EXPAND_BOTH_WAYS )
|
|
set_expires_box.AddF( self._set_expires_ok, FLAGS_MIXED )
|
|
|
|
expires_box = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
expires_box.AddF( wx.StaticText( self, label = '- change expiration -' ), FLAGS_SMALL_INDENT )
|
|
expires_box.AddF( add_to_expires_box, FLAGS_EXPAND_PERPENDICULAR )
|
|
expires_box.AddF( set_expires_box, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
ban_box = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
ban_box.AddF( wx.StaticText( self, label = '- bans -' ), FLAGS_SMALL_INDENT )
|
|
ban_box.AddF( self._ban, FLAGS_BUTTON_SIZERS )
|
|
ban_box.AddF( self._superban, FLAGS_BUTTON_SIZERS )
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
vbox.AddF( info_box, FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox.AddF( account_types_box, FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox.AddF( expires_box, FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox.AddF( ban_box, FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox.AddF( self._exit, FLAGS_BUTTON_SIZERS )
|
|
|
|
self.SetSizer( vbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
self.SetInitialSize( ( x, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'modify account' )
|
|
|
|
self._service = wx.GetApp().Read( 'service', service_identifier )
|
|
self._subject_identifiers = set( subject_identifiers )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def _DoModification( self, action, **kwargs ):
|
|
|
|
try:
|
|
|
|
connection = self._service.GetConnection()
|
|
|
|
kwargs[ 'subject_identifiers' ] = list( self._subject_identifiers )
|
|
kwargs[ 'action' ] = action
|
|
|
|
connection.Post( 'accountmodification', **kwargs )
|
|
|
|
if len( self._subject_identifiers ) == 1:
|
|
|
|
( subject_identifier, ) = self._subject_identifiers
|
|
|
|
self._subject_text.SetLabel( str( connection.Get( 'accountinfo', subject_identifier = subject_identifier ) ) )
|
|
|
|
|
|
except Exception as e: wx.MessageBox( unicode( e ) )
|
|
|
|
if len( self._subject_identifiers ) > 1: wx.MessageBox( 'Done!' )
|
|
|
|
|
|
def EventAddToExpires( self, event ): self._DoModification( HC.ADD_TO_EXPIRES, expiration = self._add_to_expires.GetClientData( self._add_to_expires.GetSelection() ) )
|
|
|
|
def EventBan( self, event ):
|
|
|
|
with wx.TextEntryDialog( self, 'Enter reason for the ban' ) as dlg:
|
|
|
|
if dlg.ShowModal() == wx.ID_OK: self._DoModification( HC.BAN, reason = dlg.GetValue() )
|
|
|
|
|
|
|
|
def EventChangeAccountType( self, event ): self._DoModification( HC.CHANGE_ACCOUNT_TYPE, title = self._account_types.GetClientData( self._account_types.GetSelection() ).GetTitle() )
|
|
|
|
def EventSetExpires( self, event ): self._DoModification( HC.SET_EXPIRES, expiry = int( time.time() ) + self._set_expires.GetClientData( self._set_expires.GetSelection() ) )
|
|
|
|
def EventSuperban( self, event ):
|
|
|
|
with wx.TextEntryDialog( self, 'Enter reason for the superban' ) as dlg:
|
|
|
|
if dlg.ShowModal() == wx.ID_OK: self._DoModification( HC.SUPERBAN, reason = dlg.GetValue() )
|
|
|
|
|
|
|
|
class DialogNews( Dialog ):
|
|
|
|
def __init__( self, parent, service_identifier ):
|
|
|
|
def InitialiseControls():
|
|
|
|
self._news = wx.TextCtrl( self, style=wx.TE_READONLY | wx.TE_MULTILINE )
|
|
|
|
self._previous = wx.Button( self, label='<' )
|
|
self._previous.Bind( wx.EVT_BUTTON, self.EventPrevious )
|
|
|
|
self._news_position = wx.TextCtrl( self )
|
|
|
|
self._next = wx.Button( self, label='>' )
|
|
self._next.Bind( wx.EVT_BUTTON, self.EventNext )
|
|
|
|
self._done = wx.Button( self, id = wx.ID_CANCEL, label='Done' )
|
|
self._done.Bind( wx.EVT_BUTTON, self.EventOk )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
self._newslist = wx.GetApp().Read( 'news', service_identifier )
|
|
|
|
self._current_news_position = len( self._newslist )
|
|
|
|
self._ShowNews()
|
|
|
|
buttonbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
buttonbox.AddF( self._previous, FLAGS_MIXED )
|
|
buttonbox.AddF( self._news_position, FLAGS_MIXED )
|
|
buttonbox.AddF( self._next, FLAGS_MIXED )
|
|
|
|
donebox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
donebox.AddF( self._done, FLAGS_MIXED )
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
vbox.AddF( self._news, FLAGS_EXPAND_BOTH_WAYS )
|
|
vbox.AddF( buttonbox, FLAGS_BUTTON_SIZERS )
|
|
vbox.AddF( donebox, FLAGS_BUTTON_SIZERS )
|
|
|
|
self.SetSizer( vbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
self.SetInitialSize( ( x + 200, 580 ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'news' )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def _ShowNews( self ):
|
|
|
|
if self._current_news_position == 0:
|
|
|
|
self._news.SetValue( '' )
|
|
|
|
self._news_position.SetValue( 'No News' )
|
|
|
|
else:
|
|
|
|
( news, timestamp ) = self._newslist[ self._current_news_position - 1 ]
|
|
|
|
self._news.SetValue( time.ctime( timestamp ) + ':' + os.linesep + os.linesep + news )
|
|
|
|
self._news_position.SetValue( HC.ConvertIntToPrettyString( self._current_news_position ) + ' / ' + HC.ConvertIntToPrettyString( len( self._newslist ) ) )
|
|
|
|
|
|
|
|
def EventNext( self, event ):
|
|
|
|
if self._current_news_position < len( self._newslist ): self._current_news_position += 1
|
|
|
|
self._ShowNews()
|
|
|
|
|
|
def EventOk( self, event ): self.EndModal( wx.ID_OK )
|
|
|
|
def EventPrevious( self, event ):
|
|
|
|
if self._current_news_position > 1: self._current_news_position -= 1
|
|
|
|
self._ShowNews()
|
|
|
|
|
|
class DialogPathsToTagsRegex( Dialog ):
|
|
|
|
def __init__( self, parent, paths ):
|
|
|
|
def InitialiseControls():
|
|
|
|
self._tag_repositories = ClientGUICommon.ListBook( self )
|
|
self._tag_repositories.Bind( wx.EVT_NOTEBOOK_PAGE_CHANGED, self.EventServiceChanged )
|
|
|
|
services = wx.GetApp().Read( 'services', ( HC.TAG_REPOSITORY, ) )
|
|
|
|
for service in services:
|
|
|
|
account = service.GetAccount()
|
|
|
|
if account.HasPermission( HC.POST_DATA ):
|
|
|
|
service_identifier = service.GetServiceIdentifier()
|
|
|
|
page_info = ( DialogPathsToTagsRegexPanel, ( self._tag_repositories, service_identifier, paths ), {} )
|
|
|
|
name = service_identifier.GetName()
|
|
|
|
self._tag_repositories.AddPage( page_info, name )
|
|
|
|
|
|
|
|
page = DialogPathsToTagsRegexPanel( self._tag_repositories, CC.LOCAL_TAG_SERVICE_IDENTIFIER, paths )
|
|
|
|
name = CC.LOCAL_TAG_SERVICE_IDENTIFIER.GetName()
|
|
|
|
self._tag_repositories.AddPage( page, name )
|
|
|
|
default_tag_repository = self._options[ 'default_tag_repository' ]
|
|
|
|
self._tag_repositories.Select( default_tag_repository.GetName() )
|
|
|
|
self._add_button = wx.Button( self, label='Import Files' )
|
|
self._add_button.Bind( wx.EVT_BUTTON, self.EventOK )
|
|
self._add_button.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
self._close_button = wx.Button( self, id = wx.ID_CANCEL, label='Back to File Selection' )
|
|
self._close_button.Bind( wx.EVT_BUTTON, self.EventCancel )
|
|
self._close_button.SetForegroundColour( ( 128, 0, 0 ) )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
buttons = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
buttons.AddF( self._add_button, FLAGS_SMALL_INDENT )
|
|
buttons.AddF( self._close_button, FLAGS_SMALL_INDENT )
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
vbox.AddF( self._tag_repositories, FLAGS_EXPAND_BOTH_WAYS )
|
|
vbox.AddF( buttons, FLAGS_BUTTON_SIZERS )
|
|
|
|
self.SetSizer( vbox )
|
|
|
|
self.SetInitialSize( ( 980, 680 ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'path tagging' )
|
|
|
|
self._paths = paths
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def EventCancel( self, event ): self.EndModal( wx.ID_CANCEL )
|
|
|
|
def EventOK( self, event ): self.EndModal( wx.ID_OK )
|
|
|
|
def EventServiceChanged( self, event ):
|
|
|
|
page = self._tag_repositories.GetCurrentPage()
|
|
|
|
wx.CallAfter( page.SetTagBoxFocus )
|
|
|
|
|
|
def GetInfo( self ):
|
|
|
|
paths_to_tags = {}
|
|
|
|
try:
|
|
|
|
for path in self._paths:
|
|
|
|
all_tags = {}
|
|
|
|
for page in self._tag_repositories.GetNameToPageDict().values():
|
|
|
|
tags = page.GetTags( path )
|
|
|
|
if len( tags ) > 0:
|
|
|
|
service_identifier = page.GetServiceIdentifier()
|
|
|
|
all_tags[ service_identifier ] = tags
|
|
|
|
|
|
|
|
if len( all_tags ) > 0: paths_to_tags[ path ] = all_tags
|
|
|
|
|
|
except Exception as e: wx.MessageBox( 'Saving pending mapping changes to DB raised this error: ' + unicode( e ) )
|
|
|
|
return paths_to_tags
|
|
|
|
|
|
class DialogPathsToTagsRegexPanel( wx.Panel ):
|
|
|
|
ID_REGEX_WHITESPACE = 0
|
|
ID_REGEX_NUMBER = 1
|
|
ID_REGEX_ALPHANUMERIC = 2
|
|
ID_REGEX_ANY = 3
|
|
ID_REGEX_BEGINNING = 4
|
|
ID_REGEX_END = 5
|
|
ID_REGEX_0_OR_MORE_GREEDY = 6
|
|
ID_REGEX_1_OR_MORE_GREEDY = 7
|
|
ID_REGEX_0_OR_1_GREEDY = 8
|
|
ID_REGEX_0_OR_MORE_MINIMAL = 9
|
|
ID_REGEX_1_OR_MORE_MINIMAL = 10
|
|
ID_REGEX_0_OR_1_MINIMAL = 11
|
|
ID_REGEX_EXACTLY_M = 12
|
|
ID_REGEX_M_TO_N_GREEDY = 13
|
|
ID_REGEX_M_TO_N_MINIMAL = 14
|
|
ID_REGEX_LOOKAHEAD = 15
|
|
ID_REGEX_NEGATIVE_LOOKAHEAD = 16
|
|
ID_REGEX_LOOKBEHIND = 17
|
|
ID_REGEX_NEGATIVE_LOOKBEHIND = 18
|
|
ID_REGEX_NUMBER_WITHOUT_ZEROES = 19
|
|
ID_REGEX_NUMBER_EXT = 20
|
|
ID_REGEX_AUTHOR = 21
|
|
ID_REGEX_BACKSPACE = 22
|
|
ID_REGEX_SET = 23
|
|
ID_REGEX_NOT_SET = 24
|
|
|
|
def __init__( self, parent, service_identifier, paths ):
|
|
|
|
def InitialiseControls():
|
|
|
|
self._paths_list = ClientGUICommon.SaneListCtrl( self, 300, [ ( 'path', 400 ), ( 'tags', -1 ) ] )
|
|
|
|
self._paths_list.Bind( wx.EVT_LIST_ITEM_SELECTED, self.EventItemSelected )
|
|
|
|
self._page_regex = wx.TextCtrl( self )
|
|
self._chapter_regex = wx.TextCtrl( self )
|
|
self._volume_regex = wx.TextCtrl( self )
|
|
self._title_regex = wx.TextCtrl( self )
|
|
self._series_regex = wx.TextCtrl( self )
|
|
self._creator_regex = wx.TextCtrl( self )
|
|
|
|
self._update_button = wx.Button( self, label='update' )
|
|
self._update_button.Bind( wx.EVT_BUTTON, self.EventUpdate )
|
|
|
|
self._regex_shortcuts = wx.Button( self, label = 'regex shortcuts' )
|
|
self._regex_shortcuts.Bind( wx.EVT_BUTTON, self.EventRegexShortcuts )
|
|
|
|
self._regex_link = wx.HyperlinkCtrl( self, id = -1, label = 'a good regex introduction', url = 'http://www.aivosto.com/vbtips/regex.html' )
|
|
|
|
self._regexes = wx.ListBox( self )
|
|
self._regexes.Bind( wx.EVT_LISTBOX_DCLICK, self.EventRemoveRegex )
|
|
|
|
self._regex_box = wx.TextCtrl( self, style=wx.TE_PROCESS_ENTER )
|
|
self._regex_box.Bind( wx.EVT_TEXT_ENTER, self.EventAddRegex )
|
|
|
|
self._tags = ClientGUICommon.TagsBoxFlat( self, self.TagRemoved )
|
|
|
|
self._tag_box = ClientGUICommon.AutoCompleteDropdownTagsWrite( self, self.AddTag, CC.LOCAL_FILE_SERVICE_IDENTIFIER, service_identifier )
|
|
|
|
self._paths_to_single_tags = collections.defaultdict( list )
|
|
|
|
self._single_tags = ClientGUICommon.TagsBoxFlat( self, self.SingleTagRemoved )
|
|
|
|
self._single_tag_box = ClientGUICommon.AutoCompleteDropdownTagsWrite( self, self.AddTagSingle, CC.LOCAL_FILE_SERVICE_IDENTIFIER, service_identifier )
|
|
self._single_tag_box.Disable()
|
|
|
|
for path in self._paths:
|
|
|
|
tags = self._GetTags( path )
|
|
|
|
tags_string = ', '.join( tags )
|
|
|
|
self._paths_list.Append( ( path, tags_string ), ( path, tags ) )
|
|
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
gridbox = wx.FlexGridSizer( 0, 2 )
|
|
|
|
gridbox.AddGrowableCol( 1, 1 )
|
|
|
|
gridbox.AddF( wx.StaticText( self, label='Page regex ' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._page_regex, FLAGS_EXPAND_BOTH_WAYS )
|
|
gridbox.AddF( wx.StaticText( self, label='Chapter regex ' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._chapter_regex, FLAGS_EXPAND_BOTH_WAYS )
|
|
gridbox.AddF( wx.StaticText( self, label='Volume regex ' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._volume_regex, FLAGS_EXPAND_BOTH_WAYS )
|
|
gridbox.AddF( wx.StaticText( self, label='Title regex ' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._title_regex, FLAGS_EXPAND_BOTH_WAYS )
|
|
gridbox.AddF( wx.StaticText( self, label='Series regex ' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._series_regex, FLAGS_EXPAND_BOTH_WAYS )
|
|
gridbox.AddF( wx.StaticText( self, label='Creator regex ' ), FLAGS_MIXED )
|
|
gridbox.AddF( self._creator_regex, FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
ns_vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
ns_vbox.AddF( wx.StaticText( self, label = '- quick namespaces -' ), FLAGS_SMALL_INDENT )
|
|
|
|
ns_vbox.AddF( gridbox, FLAGS_EXPAND_PERPENDICULAR )
|
|
ns_vbox.AddF( self._update_button, FLAGS_LONE_BUTTON )
|
|
ns_vbox.AddF( self._regex_shortcuts, FLAGS_LONE_BUTTON )
|
|
ns_vbox.AddF( self._regex_link, FLAGS_LONE_BUTTON )
|
|
|
|
regex_vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
regex_vbox.AddF( wx.StaticText( self, label = '- regexes -' ), FLAGS_SMALL_INDENT )
|
|
|
|
regex_vbox.AddF( self._regexes, FLAGS_EXPAND_BOTH_WAYS )
|
|
regex_vbox.AddF( self._regex_box, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
tag_vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
tag_vbox.AddF( wx.StaticText( self, label = '- tags for all -' ), FLAGS_SMALL_INDENT )
|
|
|
|
tag_vbox.AddF( self._tags, FLAGS_EXPAND_BOTH_WAYS )
|
|
tag_vbox.AddF( self._tag_box, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
tag_single_vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
tag_single_vbox.AddF( wx.StaticText( self, label = '- tags just for this file -' ), FLAGS_SMALL_INDENT )
|
|
|
|
tag_single_vbox.AddF( self._single_tags, FLAGS_EXPAND_BOTH_WAYS )
|
|
tag_single_vbox.AddF( self._single_tag_box, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
hbox.AddF( ns_vbox, FLAGS_EXPAND_BOTH_WAYS )
|
|
hbox.AddF( regex_vbox, FLAGS_EXPAND_BOTH_WAYS )
|
|
hbox.AddF( tag_vbox, FLAGS_EXPAND_BOTH_WAYS )
|
|
hbox.AddF( tag_single_vbox, FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
vbox.AddF( self._paths_list, FLAGS_EXPAND_BOTH_WAYS )
|
|
vbox.AddF( hbox, FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
self.SetSizer( vbox )
|
|
|
|
|
|
wx.Panel.__init__( self, parent )
|
|
|
|
self._service_identifier = service_identifier
|
|
self._paths = paths
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
self.Bind( wx.EVT_MENU, self.EventMenu )
|
|
|
|
|
|
|
|
def _GetTags( self, path ):
|
|
|
|
tags = []
|
|
|
|
tags.extend( self._tags.GetTags() )
|
|
|
|
for regex in self._regexes.GetStrings():
|
|
|
|
try:
|
|
|
|
m = re.search( regex, path )
|
|
|
|
if m is not None:
|
|
|
|
match = m.group()
|
|
|
|
if len( match ) > 0: tags.append( match )
|
|
|
|
|
|
except: pass
|
|
|
|
|
|
namespaced_regexes = []
|
|
|
|
namespaced_regexes.append( ( self._page_regex, 'page:' ) )
|
|
namespaced_regexes.append( ( self._chapter_regex, 'chapter:' ) )
|
|
namespaced_regexes.append( ( self._volume_regex, 'volume:' ) )
|
|
namespaced_regexes.append( ( self._title_regex, 'title:' ) )
|
|
namespaced_regexes.append( ( self._series_regex, 'series:' ) )
|
|
namespaced_regexes.append( ( self._creator_regex, 'creator:' ) )
|
|
|
|
for ( control, prefix ) in namespaced_regexes:
|
|
|
|
try:
|
|
|
|
m = re.search( control.GetValue(), path )
|
|
|
|
if m is not None:
|
|
|
|
match = m.group()
|
|
|
|
if len( match ) > 0: tags.append( prefix + match )
|
|
|
|
|
|
except: pass
|
|
|
|
|
|
if path in self._paths_to_single_tags: tags.extend( self._paths_to_single_tags[ path ] )
|
|
|
|
return tags
|
|
|
|
|
|
def _RefreshFileList( self ):
|
|
|
|
for ( index, ( path, old_tags ) ) in enumerate( self._paths_list.GetClientData() ):
|
|
|
|
# when doing regexes, make sure not to include '' results, same for system: and - started tags.
|
|
|
|
tags = self._GetTags( path )
|
|
|
|
if tags != old_tags:
|
|
|
|
tags_string = ', '.join( tags )
|
|
|
|
self._paths_list.UpdateRow( index, ( path, tags_string ), ( path, tags ) )
|
|
|
|
|
|
|
|
|
|
def AddTag( self, tag ):
|
|
|
|
if tag is not None:
|
|
|
|
self._tags.AddTag( tag )
|
|
|
|
self._tag_box.Clear()
|
|
|
|
self._RefreshFileList()
|
|
|
|
|
|
|
|
def AddTagSingle( self, tag ):
|
|
|
|
if tag is not None:
|
|
|
|
self._single_tags.AddTag( tag )
|
|
|
|
self._single_tag_box.Clear()
|
|
|
|
indices = self._paths_list.GetAllSelected()
|
|
|
|
for index in indices:
|
|
|
|
( path, old_tags ) = self._paths_list.GetClientData( index )
|
|
|
|
self._paths_to_single_tags[ path ].append( tag )
|
|
|
|
|
|
self._RefreshFileList() # make this more clever
|
|
|
|
|
|
|
|
def EventAddRegex( self, event ):
|
|
|
|
regex = self._regex_box.GetValue()
|
|
|
|
if regex != '':
|
|
|
|
self._regexes.Append( regex )
|
|
|
|
self._regex_box.Clear()
|
|
|
|
self._RefreshFileList()
|
|
|
|
|
|
|
|
def EventItemSelected( self, event ):
|
|
|
|
single_tags = []
|
|
|
|
indices = self._paths_list.GetAllSelected()
|
|
|
|
if len( indices ) > 0:
|
|
|
|
path = self._paths_list.GetClientData( indices[0] )[0]
|
|
|
|
if path in self._paths_to_single_tags: single_tags = self._paths_to_single_tags[ path ]
|
|
|
|
self._single_tag_box.Enable()
|
|
|
|
else: self._single_tag_box.Disable()
|
|
|
|
self._single_tags.SetTags( single_tags )
|
|
|
|
|
|
def EventMenu( self, event ):
|
|
|
|
id = event.GetId()
|
|
|
|
phrase = None
|
|
|
|
if id == self.ID_REGEX_WHITESPACE: phrase = r'\s'
|
|
elif id == self.ID_REGEX_NUMBER: phrase = r'\d'
|
|
elif id == self.ID_REGEX_ALPHANUMERIC: phrase = r'\w'
|
|
elif id == self.ID_REGEX_ANY: phrase = r'.'
|
|
elif id == self.ID_REGEX_BACKSPACE: phrase = r'\\'
|
|
elif id == self.ID_REGEX_BEGINNING: phrase = r'^'
|
|
elif id == self.ID_REGEX_END: phrase = r'$'
|
|
elif id == self.ID_REGEX_SET: phrase = r'[...]'
|
|
elif id == self.ID_REGEX_NOT_SET: phrase = r'[^...]'
|
|
elif id == self.ID_REGEX_0_OR_MORE_GREEDY: phrase = r'*'
|
|
elif id == self.ID_REGEX_1_OR_MORE_GREEDY: phrase = r'+'
|
|
elif id == self.ID_REGEX_0_OR_1_GREEDY: phrase = r'?'
|
|
elif id == self.ID_REGEX_0_OR_MORE_MINIMAL: phrase = r'*?'
|
|
elif id == self.ID_REGEX_1_OR_MORE_MINIMAL: phrase = r'+?'
|
|
elif id == self.ID_REGEX_0_OR_1_MINIMAL: phrase = r'*'
|
|
elif id == self.ID_REGEX_EXACTLY_M: phrase = r'{m}'
|
|
elif id == self.ID_REGEX_M_TO_N_GREEDY: phrase = r'{m,n}'
|
|
elif id == self.ID_REGEX_M_TO_N_MINIMAL: phrase = r'{m,n}?'
|
|
elif id == self.ID_REGEX_LOOKAHEAD: phrase = r'(?=...)'
|
|
elif id == self.ID_REGEX_NEGATIVE_LOOKAHEAD: phrase = r'(?!...)'
|
|
elif id == self.ID_REGEX_LOOKBEHIND: phrase = r'(?<=...)'
|
|
elif id == self.ID_REGEX_NEGATIVE_LOOKBEHIND: phrase = r'(?<!...)'
|
|
elif id == self.ID_REGEX_NUMBER_WITHOUT_ZEROES: phrase = r'[1-9]+\d*'
|
|
elif id == self.ID_REGEX_NUMBER_EXT: phrase = r'[1-9]+\d*(?=.{4}$)'
|
|
elif id == self.ID_REGEX_AUTHOR: phrase = r'[^\\][\w\s]*(?=\s-)'
|
|
else: event.Skip()
|
|
|
|
if phrase is not None:
|
|
|
|
if wx.TheClipboard.Open():
|
|
|
|
data = wx.TextDataObject( phrase )
|
|
|
|
wx.TheClipboard.SetData( data )
|
|
|
|
wx.TheClipboard.Close()
|
|
|
|
else: wx.MessageBox( 'I could not get permission to access the clipboard.' )
|
|
|
|
|
|
|
|
def EventRegexShortcuts( self, event ):
|
|
|
|
menu = wx.Menu()
|
|
|
|
menu.Append( -1, 'click on a phrase to copy to clipboard' )
|
|
|
|
menu.AppendSeparator()
|
|
|
|
menu.Append( self.ID_REGEX_WHITESPACE, r'whitespace character - \s' )
|
|
menu.Append( self.ID_REGEX_NUMBER, r'number character - \d' )
|
|
menu.Append( self.ID_REGEX_ALPHANUMERIC, r'alphanumeric or backspace character - \w' )
|
|
menu.Append( self.ID_REGEX_ANY, r'any character - .' )
|
|
menu.Append( self.ID_REGEX_BACKSPACE, r'backspace character - \\' )
|
|
menu.Append( self.ID_REGEX_BEGINNING, r'beginning of line - ^' )
|
|
menu.Append( self.ID_REGEX_END, r'end of line - $' )
|
|
menu.Append( self.ID_REGEX_SET, r'any of these - [...]' )
|
|
menu.Append( self.ID_REGEX_NOT_SET, r'anything other than these - [^...]' )
|
|
|
|
menu.AppendSeparator()
|
|
|
|
menu.Append( self.ID_REGEX_0_OR_MORE_GREEDY, r'0 or more matches, consuming as many as possible - *' )
|
|
menu.Append( self.ID_REGEX_1_OR_MORE_GREEDY, r'1 or more matches, consuming as many as possible - +' )
|
|
menu.Append( self.ID_REGEX_0_OR_1_GREEDY, r'0 or 1 matches, preferring 1 - ?' )
|
|
menu.Append( self.ID_REGEX_0_OR_MORE_MINIMAL, r'0 or more matches, consuming as few as possible - *?' )
|
|
menu.Append( self.ID_REGEX_1_OR_MORE_MINIMAL, r'1 or more matches, consuming as few as possible - +?' )
|
|
menu.Append( self.ID_REGEX_0_OR_1_MINIMAL, r'0 or 1 matches, preferring 0 - *' )
|
|
menu.Append( self.ID_REGEX_EXACTLY_M, r'exactly m matches - {m}' )
|
|
menu.Append( self.ID_REGEX_M_TO_N_GREEDY, r'm to n matches, consuming as many as possible - {m,n}' )
|
|
menu.Append( self.ID_REGEX_M_TO_N_MINIMAL, r'm to n matches, consuming as few as possible - {m,n}?' )
|
|
|
|
menu.AppendSeparator()
|
|
|
|
menu.Append( self.ID_REGEX_LOOKAHEAD, r'the next characters are: (non-consuming) - (?=...)' )
|
|
menu.Append( self.ID_REGEX_NEGATIVE_LOOKAHEAD, r'the next characters are not: (non-consuming) - (?!...)' )
|
|
menu.Append( self.ID_REGEX_LOOKBEHIND, r'the previous characters are: (non-consuming) - (?<=...)' )
|
|
menu.Append( self.ID_REGEX_NEGATIVE_LOOKBEHIND, r'the previous characters are not: (non-consuming) - (?<!...)' )
|
|
|
|
menu.AppendSeparator()
|
|
|
|
menu.Append( self.ID_REGEX_NUMBER_WITHOUT_ZEROES, r'0074 -> 74 - [1-9]+\d*' )
|
|
menu.Append( self.ID_REGEX_NUMBER_EXT, r'...0074.jpg -> 74 - [1-9]+\d*(?=.{4}$)' )
|
|
menu.Append( self.ID_REGEX_AUTHOR, r'E:\my collection\author name - v4c1p0074.jpg -> author name - [^\\][\w\s]*(?=\s-)' )
|
|
|
|
self.PopupMenu( menu )
|
|
|
|
|
|
def EventRemoveRegex( self, event ):
|
|
|
|
selection = self._regexes.GetSelection()
|
|
|
|
if selection != wx.NOT_FOUND:
|
|
|
|
if len( self._regex_box.GetValue() ) == 0: self._regex_box.SetValue( self._regexes.GetString( selection ) )
|
|
|
|
self._regexes.Delete( selection )
|
|
|
|
self._RefreshFileList()
|
|
|
|
|
|
|
|
def EventUpdate( self, event ): self._RefreshFileList()
|
|
|
|
def GetServiceIdentifier( self ): return self._service_identifier
|
|
|
|
# this prob needs to be made cleverer if I do the extra column
|
|
def GetTags( self, path ): return self._GetTags( path )
|
|
|
|
def SetTagBoxFocus( self ): self._tag_box.SetFocus()
|
|
|
|
def SingleTagRemoved( self ):
|
|
|
|
indices = self._paths_list.GetAllSelected()
|
|
|
|
if len( indices ) > 0:
|
|
|
|
path = self._paths_list.GetClientData( indices[0] )[0]
|
|
|
|
self._paths_to_single_tags[ path ] = self._single_tags.GetTags()
|
|
|
|
|
|
self._RefreshFileList()
|
|
|
|
|
|
def TagRemoved( self ): self._RefreshFileList()
|
|
|
|
class DialogProgress( Dialog ):
|
|
|
|
def __init__( self, parent, job_key, cancel_event = None ):
|
|
|
|
def InitialiseControls():
|
|
|
|
self._status = wx.StaticText( self, label = 'initialising', style = wx.ALIGN_CENTER | wx.ST_NO_AUTORESIZE )
|
|
self._gauge = ClientGUICommon.Gauge( self, range = 100 )
|
|
self._time_taken_so_far = wx.StaticText( self, label = 'initialising', style = wx.ALIGN_CENTER | wx.ST_NO_AUTORESIZE )
|
|
self._time_left = wx.StaticText( self, label = 'initialising', style = wx.ALIGN_CENTER | wx.ST_NO_AUTORESIZE )
|
|
|
|
if cancel_event is not None:
|
|
|
|
self._cancel = wx.Button( self, id = wx.ID_CANCEL, label = 'cancel' )
|
|
self._cancel.Bind( wx.EVT_BUTTON, self.EventCancel )
|
|
|
|
|
|
self._time_started = None
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
vbox.AddF( self._status, FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox.AddF( self._gauge, FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox.AddF( self._time_taken_so_far, FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox.AddF( self._time_left, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
if cancel_event is not None: vbox.AddF( self._cancel, FLAGS_LONE_BUTTON )
|
|
|
|
self.SetSizer( vbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
if x < 640: x = 640
|
|
|
|
self.SetInitialSize( ( x, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'progress', style = wx.SYSTEM_MENU | wx.CAPTION | wx.RESIZE_BORDER, position = 'center' )
|
|
|
|
self._job_key = job_key
|
|
|
|
self._cancel_event = cancel_event
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
self.Bind( wx.EVT_TIMER, self.EventTimer, id = ID_TIMER_UPDATE )
|
|
|
|
self._timer = wx.Timer( self, id = ID_TIMER_UPDATE )
|
|
|
|
self._timer.Start( 1000, wx.TIMER_CONTINUOUS )
|
|
|
|
HC.pubsub.sub( self, 'Update', 'progress_update' )
|
|
|
|
|
|
def _DisplayTimes( self ):
|
|
|
|
value = self._gauge.GetValue()
|
|
range = self._gauge.GetRange()
|
|
|
|
if self._time_started is not None:
|
|
|
|
time_taken_so_far = time.clock() - self._time_started
|
|
|
|
if value > 1: time_left = HC.ConvertTimeToPrettyTime( time_taken_so_far * ( float( range - value ) / float( value ) ) )
|
|
else: time_left = 'unknown'
|
|
|
|
self._time_taken_so_far.SetLabel( 'elapsed: ' + HC.ConvertTimeToPrettyTime( time_taken_so_far ) )
|
|
|
|
self._time_left.SetLabel( 'remaining: ' + time_left )
|
|
|
|
|
|
|
|
def EventCancel( self, event ):
|
|
|
|
self._cancel.Disable()
|
|
self._cancel_event.set()
|
|
|
|
|
|
def EventTimer( self, event ):
|
|
|
|
value = self._gauge.GetValue()
|
|
range = self._gauge.GetRange()
|
|
|
|
if value == range: self.EndModal( wx.OK )
|
|
else: self._DisplayTimes()
|
|
|
|
|
|
def Update( self, job_key, index, range, status ):
|
|
|
|
if job_key == self._job_key:
|
|
|
|
if self._time_started is None: self._time_started = time.clock()
|
|
|
|
if range != self._gauge.GetRange(): self._gauge.SetRange( range )
|
|
|
|
self._gauge.SetValue( index )
|
|
|
|
self._status.SetLabel( status )
|
|
|
|
self._DisplayTimes()
|
|
|
|
|
|
|
|
class DialogSelectBooru( Dialog ):
|
|
|
|
def __init__( self, parent ):
|
|
|
|
def InitialiseControls():
|
|
|
|
boorus = wx.GetApp().Read( 'boorus' )
|
|
|
|
self._boorus = wx.ListBox( self, style = wx.LB_SORT )
|
|
self._boorus.Bind( wx.EVT_LISTBOX_DCLICK, self.EventSelect )
|
|
self._boorus.Bind( wx.EVT_KEY_DOWN, self.EventKeyDown )
|
|
|
|
for booru in boorus: self._boorus.Append( booru.GetName(), booru )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
vbox.AddF( self._boorus, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
self.SetSizer( vbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
if x < 320: x = 320
|
|
|
|
self.SetInitialSize( ( x, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'select booru' )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def EventKeyDown( self, event ):
|
|
|
|
if event.KeyCode == wx.WXK_SPACE:
|
|
|
|
selection = self._boorus.GetSelection()
|
|
|
|
if selection != wx.NOT_FOUND: self.EndModal( wx.ID_OK )
|
|
|
|
elif event.KeyCode == wx.WXK_ESCAPE: self.EndModal( wx.ID_CANCEL )
|
|
else: event.Skip()
|
|
|
|
|
|
def EventSelect( self, event ): self.EndModal( wx.ID_OK )
|
|
|
|
def GetBooru( self ): return self._boorus.GetClientData( self._boorus.GetSelection() )
|
|
|
|
class DialogSelectImageboard( Dialog ):
|
|
|
|
def __init__( self, parent ):
|
|
|
|
def InitialiseControls():
|
|
|
|
self._tree = wx.TreeCtrl( self )
|
|
self._tree.Bind( wx.EVT_TREE_ITEM_ACTIVATED, self.EventSelect )
|
|
|
|
all_imageboards = wx.GetApp().Read( 'imageboards' )
|
|
|
|
root_item = self._tree.AddRoot( 'all sites' )
|
|
|
|
for ( site, imageboards ) in all_imageboards:
|
|
|
|
site_item = self._tree.AppendItem( root_item, site )
|
|
|
|
for imageboard in imageboards:
|
|
|
|
name = imageboard.GetName()
|
|
|
|
self._tree.AppendItem( site_item, name, data = wx.TreeItemData( imageboard ) )
|
|
|
|
|
|
|
|
self._tree.Expand( root_item )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
vbox.AddF( self._tree, FLAGS_EXPAND_BOTH_WAYS )
|
|
|
|
self.SetSizer( vbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
if x < 320: x = 320
|
|
if y < 320: y = 320
|
|
|
|
self.SetInitialSize( ( x, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'select imageboard' )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def EventSelect( self, event ):
|
|
|
|
item = self._tree.GetSelection()
|
|
|
|
if self._tree.GetItemData( item ).GetData() is None: self._tree.Toggle( item )
|
|
else: self.EndModal( wx.ID_OK )
|
|
|
|
|
|
def GetImageboard( self ): return self._tree.GetItemData( self._tree.GetSelection() ).GetData()
|
|
|
|
class DialogSelectFromListOfStrings( Dialog ):
|
|
|
|
def __init__( self, parent, title, list_of_strings ):
|
|
|
|
def InitialiseControls():
|
|
|
|
self._strings = wx.ListBox( self, choices = list_of_strings )
|
|
self._strings.Bind( wx.EVT_KEY_DOWN, self.EventKeyDown )
|
|
self._strings.Bind( wx.EVT_LISTBOX_DCLICK, self.EventSelect )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
vbox.AddF( self._strings, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
self.SetSizer( vbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
if x < 320: x = 320
|
|
|
|
self.SetInitialSize( ( x, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, title )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def EventKeyDown( self, event ):
|
|
|
|
if event.KeyCode == wx.WXK_SPACE:
|
|
|
|
selection = self._strings.GetSelection()
|
|
|
|
if selection != wx.NOT_FOUND: self.EndModal( wx.ID_OK )
|
|
|
|
elif event.KeyCode == wx.WXK_ESCAPE: self.EndModal( wx.ID_CANCEL )
|
|
else: event.Skip()
|
|
|
|
|
|
def EventSelect( self, event ): self.EndModal( wx.ID_OK )
|
|
|
|
def GetString( self ): return self._strings.GetStringSelection()
|
|
|
|
class DialogSelectLocalFiles( Dialog ):
|
|
|
|
def __init__( self, parent, paths = [] ):
|
|
|
|
def InitialiseControls():
|
|
|
|
self._paths_list = ClientGUICommon.SaneListCtrl( self, 480, [ ( 'path', -1 ), ( 'guessed mime', 110 ), ( 'size', 60 ) ] )
|
|
|
|
self._paths_list.SetMinSize( ( 780, 360 ) )
|
|
|
|
self._add_button = wx.Button( self, label='Import now' )
|
|
self._add_button.Bind( wx.EVT_BUTTON, self.EventOK )
|
|
self._add_button.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
self._tag_button = wx.Button( self, label = 'Add tags before importing' )
|
|
self._tag_button.Bind( wx.EVT_BUTTON, self.EventTags )
|
|
self._tag_button.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
self._close_button = wx.Button( self, id = wx.ID_CANCEL, label='Cancel' )
|
|
self._close_button.Bind( wx.EVT_BUTTON, self.EventCancel )
|
|
self._close_button.SetForegroundColour( ( 128, 0, 0 ) )
|
|
|
|
self._advanced_import_options = ClientGUICommon.AdvancedImportOptions( self )
|
|
|
|
self._add_files_button = wx.Button( self, label='Add Files' )
|
|
self._add_files_button.Bind( wx.EVT_BUTTON, self.EventAddPaths )
|
|
|
|
self._add_folder_button = wx.Button( self, label='Add Folder' )
|
|
self._add_folder_button.Bind( wx.EVT_BUTTON, self.EventAddFolder )
|
|
|
|
self._remove_files_button = wx.Button( self, label='Remove Files' )
|
|
self._remove_files_button.Bind( wx.EVT_BUTTON, self.EventRemovePaths )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
file_buttons = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
file_buttons.AddF( ( 20, 0 ), FLAGS_NONE )
|
|
file_buttons.AddF( self._add_files_button, FLAGS_MIXED )
|
|
file_buttons.AddF( self._add_folder_button, FLAGS_MIXED )
|
|
file_buttons.AddF( self._remove_files_button, FLAGS_MIXED )
|
|
|
|
buttons = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
buttons.AddF( self._add_button, FLAGS_MIXED )
|
|
buttons.AddF( self._tag_button, FLAGS_MIXED )
|
|
buttons.AddF( self._close_button, FLAGS_MIXED )
|
|
|
|
advanced_import_options = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
advanced_import_options.AddF( wx.StaticText( self, label = '- advanced import options -' ), FLAGS_SMALL_INDENT )
|
|
advanced_import_options.AddF( self._advanced_import_options, FLAGS_EXPAND_PERPENDICULAR )
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
vbox.AddF( self._paths_list, FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox.AddF( file_buttons, FLAGS_BUTTON_SIZERS )
|
|
vbox.AddF( advanced_import_options, FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox.AddF( ( 0, 5 ), FLAGS_NONE )
|
|
vbox.AddF( buttons, FLAGS_BUTTON_SIZERS )
|
|
|
|
self.SetSizer( vbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
self.SetInitialSize( ( x, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'importing files' )
|
|
|
|
self.SetDropTarget( ClientGUICommon.FileDropTarget( self._AddPathsToList ) )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
self._AddPathsToList( paths )
|
|
|
|
|
|
|
|
def _AddPathsToList( self, paths ):
|
|
|
|
good_paths = CC.ParseImportablePaths( paths )
|
|
|
|
odd_paths = False
|
|
|
|
for path in good_paths:
|
|
|
|
mime = HC.GetMimeFromPath( path )
|
|
|
|
if mime in HC.ALLOWED_MIMES:
|
|
|
|
info = os.lstat( path )
|
|
|
|
size = info[6]
|
|
|
|
if size > 0:
|
|
|
|
pretty_size = HC.ConvertIntToBytes( size )
|
|
|
|
self._paths_list.Append( ( path, HC.mime_string_lookup[ mime ], pretty_size ), ( path, HC.mime_string_lookup[ mime ], size ) )
|
|
|
|
|
|
else: odd_paths = True
|
|
|
|
|
|
if odd_paths: wx.MessageBox( 'At present hydrus can handle only jpegs, pngs, bmps, gifs, swfs and flvs. The other files have not been added.' )
|
|
|
|
|
|
def _GetPaths( self ): return [ row[0] for row in self._paths_list.GetClientData() ]
|
|
|
|
def EventAddPaths( self, event ):
|
|
|
|
with wx.FileDialog( self, 'Select the files to add.', style=wx.FD_MULTIPLE ) as dlg:
|
|
|
|
if dlg.ShowModal() == wx.ID_OK:
|
|
|
|
paths = dlg.GetPaths()
|
|
|
|
self._AddPathsToList( paths )
|
|
|
|
|
|
|
|
|
|
def EventAddFolder( self, event ):
|
|
|
|
with wx.DirDialog( self, 'Select a folder to add.', style=wx.DD_DIR_MUST_EXIST ) as dlg:
|
|
|
|
if dlg.ShowModal() == wx.ID_OK:
|
|
|
|
path = dlg.GetPath()
|
|
|
|
self._AddPathsToList( ( path, ) )
|
|
|
|
|
|
|
|
|
|
def EventCancel( self, event ): self.EndModal( wx.ID_CANCEL )
|
|
|
|
def EventOK( self, event ):
|
|
|
|
paths = self._GetPaths()
|
|
|
|
if len( paths ) > 0:
|
|
|
|
advanced_import_options = self._advanced_import_options.GetInfo()
|
|
|
|
HC.pubsub.pub( 'new_hdd_import', paths, advanced_import_options = advanced_import_options )
|
|
|
|
self.EndModal( wx.ID_OK )
|
|
|
|
|
|
|
|
def EventRemovePaths( self, event ): self._paths_list.RemoveAllSelected()
|
|
|
|
def EventTags( self, event ):
|
|
|
|
try:
|
|
|
|
paths = self._GetPaths()
|
|
|
|
if len( paths ) > 0:
|
|
|
|
advanced_import_options = self._advanced_import_options.GetInfo()
|
|
|
|
with DialogPathsToTagsRegex( self, paths ) as dlg:
|
|
|
|
if dlg.ShowModal() == wx.ID_OK:
|
|
|
|
paths_to_tags = dlg.GetInfo()
|
|
|
|
HC.pubsub.pub( 'new_hdd_import', paths, advanced_import_options = advanced_import_options, paths_to_tags = paths_to_tags )
|
|
|
|
self.EndModal( wx.ID_OK )
|
|
|
|
|
|
|
|
|
|
except: wx.MessageBox( traceback.format_exc() )
|
|
|
|
|
|
class DialogSetupCustomFilterActions( Dialog ):
|
|
|
|
def __init__( self, parent ):
|
|
|
|
def InitialiseControls():
|
|
|
|
self._actions = ClientGUICommon.SaneListCtrl( self, 480, [ ( 'modifier', 150 ), ( 'key', 150 ), ( 'service', -1 ), ( 'action', 250 ) ] )
|
|
|
|
self._actions.SetMinSize( ( 780, 360 ) )
|
|
|
|
for ( modifier, key_dict ) in self._options[ 'shortcuts' ].items():
|
|
|
|
for ( key, action ) in key_dict.items():
|
|
|
|
if action in ( 'manage_tags', 'manage_ratings', 'archive', 'frame_back', 'frame_next', 'previous', 'next', 'first', 'last' ):
|
|
|
|
service_identifier = None
|
|
pretty_service_identifier = ''
|
|
|
|
( pretty_modifier, pretty_key, pretty_action ) = HC.ConvertShortcutToPrettyShortcut( modifier, key, action )
|
|
|
|
self._actions.Append( ( pretty_modifier, pretty_key, pretty_service_identifier, pretty_action ), ( modifier, key, service_identifier, action ) )
|
|
|
|
|
|
|
|
|
|
( modifier, key, service_identifier, action ) = ( wx.ACCEL_NORMAL, wx.WXK_DELETE, None, 'delete' )
|
|
|
|
pretty_service_identifier = ''
|
|
|
|
( pretty_modifier, pretty_key, pretty_action ) = HC.ConvertShortcutToPrettyShortcut( modifier, key, action )
|
|
|
|
self._actions.Append( ( pretty_modifier, pretty_key, pretty_service_identifier, pretty_action ), ( modifier, key, service_identifier, action ) )
|
|
|
|
self._SortListCtrl()
|
|
|
|
self._add = wx.Button( self, label='add' )
|
|
self._add.Bind( wx.EVT_BUTTON, self.EventAdd )
|
|
self._add.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
self._edit = wx.Button( self, label='edit' )
|
|
self._edit.Bind( wx.EVT_BUTTON, self.EventEdit )
|
|
|
|
self._remove = wx.Button( self, label='remove' )
|
|
self._remove.Bind( wx.EVT_BUTTON, self.EventRemove )
|
|
self._remove.SetForegroundColour( ( 128, 0, 0 ) )
|
|
|
|
self._ok = wx.Button( self, label = 'ok' )
|
|
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.Bind( wx.EVT_BUTTON, self.EventCancel )
|
|
self._cancel.SetForegroundColour( ( 128, 0, 0 ) )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
action_buttons = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
action_buttons.AddF( self._add, FLAGS_MIXED )
|
|
action_buttons.AddF( self._edit, FLAGS_MIXED )
|
|
action_buttons.AddF( self._remove, FLAGS_MIXED )
|
|
|
|
buttons = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
buttons.AddF( self._ok, FLAGS_MIXED )
|
|
buttons.AddF( self._cancel, FLAGS_MIXED )
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
vbox.AddF( self._actions, FLAGS_EXPAND_PERPENDICULAR )
|
|
vbox.AddF( action_buttons, FLAGS_BUTTON_SIZERS )
|
|
vbox.AddF( buttons, FLAGS_BUTTON_SIZERS )
|
|
|
|
self.SetSizer( vbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
self.SetInitialSize( ( x, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'setup custom filter' )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
|
|
def _SortListCtrl( self ): self._actions.SortListItems( 3 )
|
|
|
|
def EventAdd( self, event ):
|
|
|
|
with DialogInputCustomFilterAction( self ) as dlg:
|
|
|
|
if dlg.ShowModal() == wx.ID_OK:
|
|
|
|
( pretty_tuple, data_tuple ) = dlg.GetInfo()
|
|
|
|
self._actions.Append( pretty_tuple, data_tuple )
|
|
|
|
self._SortListCtrl()
|
|
|
|
|
|
|
|
|
|
def EventCancel( self, event ): self.EndModal( wx.ID_CANCEL )
|
|
|
|
def EventEdit( self, event ):
|
|
|
|
for index in self._actions.GetAllSelected():
|
|
|
|
( modifier, key, service_identifier, action ) = self._actions.GetClientData( index )
|
|
|
|
with DialogInputCustomFilterAction( self, modifier = modifier, key = key, service_identifier = service_identifier, action = action ) as dlg:
|
|
|
|
if dlg.ShowModal() == wx.ID_OK:
|
|
|
|
( pretty_tuple, data_tuple ) = dlg.GetInfo()
|
|
|
|
self._actions.UpdateRow( index, pretty_tuple, data_tuple )
|
|
|
|
self._SortListCtrl()
|
|
|
|
|
|
|
|
|
|
|
|
def EventOK( self, event ): self.EndModal( wx.ID_OK )
|
|
|
|
def EventRemove( self, event ): self._actions.RemoveAllSelected()
|
|
|
|
def GetActions( self ):
|
|
|
|
raw_data = self._actions.GetClientData()
|
|
|
|
actions = collections.defaultdict( dict )
|
|
|
|
for ( modifier, key, service_identifier, action ) in raw_data: actions[ modifier ][ key ] = ( service_identifier, action )
|
|
|
|
return actions
|
|
|
|
|
|
class DialogYesNo( Dialog ):
|
|
|
|
def __init__( self, parent, message, yes_label = 'yes', no_label = 'no' ):
|
|
|
|
def InitialiseControls():
|
|
|
|
self._yes = wx.Button( self, label = yes_label )
|
|
self._yes.Bind( wx.EVT_BUTTON, self.EventYes )
|
|
self._yes.SetForegroundColour( ( 0, 128, 0 ) )
|
|
|
|
self._no = wx.Button( self, id = wx.ID_CANCEL, label = no_label )
|
|
self._no.Bind( wx.EVT_BUTTON, self.EventNo )
|
|
self._no.SetForegroundColour( ( 128, 0, 0 ) )
|
|
|
|
|
|
def InitialisePanel():
|
|
|
|
hbox = wx.BoxSizer( wx.HORIZONTAL )
|
|
|
|
hbox.AddF( self._yes, FLAGS_SMALL_INDENT )
|
|
hbox.AddF( self._no, FLAGS_SMALL_INDENT )
|
|
|
|
vbox = wx.BoxSizer( wx.VERTICAL )
|
|
|
|
text = wx.StaticText( self, label = message )
|
|
|
|
text.Wrap( 480 )
|
|
|
|
vbox.AddF( text, FLAGS_BIG_INDENT )
|
|
vbox.AddF( hbox, FLAGS_BUTTON_SIZERS )
|
|
|
|
self.SetSizer( vbox )
|
|
|
|
( x, y ) = self.GetEffectiveMinSize()
|
|
|
|
self.SetInitialSize( ( x, y ) )
|
|
|
|
|
|
Dialog.__init__( self, parent, 'are you sure?', position = 'center' )
|
|
|
|
InitialiseControls()
|
|
|
|
InitialisePanel()
|
|
|
|
self.Bind( wx.EVT_CHAR_HOOK, self.EventCharHook )
|
|
|
|
|
|
def EventCharHook( self, event ):
|
|
|
|
if event.KeyCode == wx.WXK_ESCAPE: self.EndModal( wx.ID_NO )
|
|
else: event.Skip()
|
|
|
|
|
|
def EventNo( self, event ): self.EndModal( wx.ID_NO )
|
|
|
|
def EventYes( self, event ): self.EndModal( wx.ID_YES )
|
|
|