2013-02-19 00:11:43 +00:00
import collections
import HydrusConstants as HC
import ClientConstants as CC
import ClientGUIMixins
2013-05-29 20:19:54 +00:00
import itertools
2013-02-19 00:11:43 +00:00
import os
import random
2013-08-14 20:21:49 +00:00
import sys
2013-02-19 00:11:43 +00:00
import time
import traceback
import wx
2013-03-15 02:38:12 +00:00
import wx . combo
2013-02-19 00:11:43 +00:00
import wx . richtext
from wx . lib . mixins . listctrl import ListCtrlAutoWidthMixin
from wx . lib . mixins . listctrl import ColumnSorterMixin
ID_TIMER_ANIMATED = wx . NewId ( )
ID_TIMER_SLIDESHOW = wx . NewId ( )
ID_TIMER_MEDIA_INFO_DISPLAY = wx . NewId ( )
2013-03-15 02:38:12 +00:00
ID_TIMER_DROPDOWN_HIDE = wx . NewId ( )
ID_TIMER_AC_LAG = wx . NewId ( )
2013-02-19 00:11:43 +00:00
# Zooms
ZOOMINS = [ 0.01 , 0.05 , 0.1 , 0.15 , 0.2 , 0.3 , 0.5 , 0.7 , 0.8 , 0.9 , 1.0 , 1.1 , 1.2 , 1.5 , 2.0 , 3.0 , 5.0 , 10.0 , 20.0 ]
ZOOMOUTS = [ 20.0 , 10.0 , 5.0 , 3.0 , 2.0 , 1.5 , 1.2 , 1.1 , 1.0 , 0.9 , 0.8 , 0.7 , 0.5 , 0.3 , 0.2 , 0.15 , 0.1 , 0.05 , 0.01 ]
# Sizer Flags
FLAGS_NONE = wx . SizerFlags ( 0 )
FLAGS_SMALL_INDENT = wx . SizerFlags ( 0 ) . Border ( wx . ALL , 2 )
FLAGS_EXPAND_PERPENDICULAR = wx . SizerFlags ( 0 ) . Border ( wx . ALL , 2 ) . Expand ( )
FLAGS_EXPAND_BOTH_WAYS = wx . SizerFlags ( 2 ) . Border ( wx . ALL , 2 ) . Expand ( )
2013-03-15 02:38:12 +00:00
FLAGS_EXPAND_SIZER_PERPENDICULAR = wx . SizerFlags ( 0 ) . Expand ( )
FLAGS_EXPAND_SIZER_BOTH_WAYS = wx . SizerFlags ( 2 ) . Expand ( )
2013-02-19 00:11:43 +00:00
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 )
2013-03-15 02:38:12 +00:00
class AnimatedStaticTextTimestamp ( wx . StaticText ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def __init__ ( self , parent , prefix , rendering_function , timestamp , suffix ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _prefix = prefix
self . _rendering_function = rendering_function
self . _timestamp = timestamp
self . _suffix = suffix
2013-02-19 00:11:43 +00:00
2013-07-31 21:26:38 +00:00
self . _last_tick = HC . GetNow ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
wx . StaticText . __init__ ( self , parent , label = self . _prefix + self . _rendering_function ( self . _timestamp ) + self . _suffix )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
HC . pubsub . sub ( self , ' Tick ' , ' animated_tick ' )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def Tick ( self ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
update = False
2013-02-19 00:11:43 +00:00
2013-07-31 21:26:38 +00:00
now = HC . GetNow ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
difference = abs ( now - self . _timestamp )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if difference < 3600 : update = True
elif difference < 3600 * 24 and now - self . _last_tick > 60 : update = True
elif now - self . _last_tick > 3600 : update = True
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if update :
self . SetLabel ( self . _prefix + self . _rendering_function ( self . _timestamp ) + self . _suffix )
wx . PostEvent ( self . GetEventHandler ( ) , wx . SizeEvent ( ) )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
# much of this is based on the excellent TexCtrlAutoComplete class by Edward Flick, Michele Petrazzo and Will Sadkin, just with plenty of simplification and integration into hydrus
class AutoCompleteDropdown ( wx . TextCtrl ) :
def __init__ ( self , parent ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
wx . TextCtrl . __init__ ( self , parent , style = wx . TE_PROCESS_ENTER )
2013-02-19 00:11:43 +00:00
2013-03-23 17:57:29 +00:00
#self._dropdown_window = wx.PopupWindow( self, flags = wx.BORDER_RAISED )
#self._dropdown_window = wx.PopupTransientWindow( self, style = wx.BORDER_RAISED )
#self._dropdown_window = wx.Window( self, style = wx.BORDER_RAISED )
#self._dropdown_window = wx.Panel( self )
2013-04-17 21:48:18 +00:00
self . _dropdown_window = wx . Frame ( self , style = wx . FRAME_TOOL_WINDOW | wx . FRAME_NO_TASKBAR | wx . FRAME_FLOAT_ON_PARENT | wx . BORDER_RAISED )
2013-03-23 17:57:29 +00:00
2013-03-15 02:38:12 +00:00
self . _dropdown_window . SetBackgroundColour ( wx . SystemSettings . GetColour ( wx . SYS_COLOUR_BTNFACE ) )
2013-02-19 00:11:43 +00:00
2013-03-23 17:57:29 +00:00
self . _dropdown_list = self . _InitDropDownList ( )
2013-03-15 02:38:12 +00:00
self . _first_letters = ' '
self . _cached_results = self . _InitCachedResults ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . Bind ( wx . EVT_SET_FOCUS , self . EventSetFocus )
self . Bind ( wx . EVT_KILL_FOCUS , self . EventKillFocus )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . Bind ( wx . EVT_TEXT , self . EventText , self )
self . Bind ( wx . EVT_KEY_DOWN , self . EventKeyDown , self )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . Bind ( wx . EVT_MOVE , self . EventMove )
self . Bind ( wx . EVT_SIZE , self . EventMove )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . Bind ( wx . EVT_MOUSEWHEEL , self . EventMouseWheel )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . Bind ( wx . EVT_TIMER , self . EventDropdownHideTimer , id = ID_TIMER_DROPDOWN_HIDE )
self . Bind ( wx . EVT_TIMER , self . EventLagTimer , id = ID_TIMER_AC_LAG )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _move_hide_timer = wx . Timer ( self , id = ID_TIMER_DROPDOWN_HIDE )
self . _lag_timer = wx . Timer ( self , id = ID_TIMER_AC_LAG )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
tlp = self . GetTopLevelParent ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
tlp . Bind ( wx . EVT_MOVE , self . EventMove )
2013-02-19 00:11:43 +00:00
2013-09-11 21:28:19 +00:00
parent = self
while True :
try :
parent = parent . GetParent ( )
if issubclass ( type ( parent ) , wx . ScrolledWindow ) :
parent . Bind ( wx . EVT_SCROLLWIN , self . EventMove )
except : break
2013-08-28 21:31:52 +00:00
wx . CallAfter ( self . _UpdateList )
2013-03-15 02:38:12 +00:00
def _BroadcastChoice ( self , predicate ) : pass
def BroadcastChoice ( self , predicate ) :
2013-02-19 00:11:43 +00:00
2013-08-28 21:31:52 +00:00
if self . GetValue ( ) != ' ' :
self . SetValue ( ' ' )
2013-02-19 00:11:43 +00:00
2013-08-28 21:31:52 +00:00
self . _BroadcastChoice ( predicate )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def _HideDropdown ( self ) : self . _dropdown_window . Show ( False )
def _ShowDropdownIfFocussed ( self ) :
2013-02-19 00:11:43 +00:00
2013-09-11 21:28:19 +00:00
if self . GetTopLevelParent ( ) . IsActive ( ) and wx . Window . FindFocus ( ) == self :
2013-03-15 02:38:12 +00:00
( my_width , my_height ) = self . GetSize ( )
2013-09-11 21:28:19 +00:00
if not self . _dropdown_window . IsShown ( ) :
self . _dropdown_window . Fit ( )
self . _dropdown_window . SetSize ( ( my_width , - 1 ) )
self . _dropdown_window . Layout ( )
2013-03-15 02:38:12 +00:00
self . _dropdown_window . SetPosition ( self . ClientToScreenXY ( - 2 , my_height - 2 ) )
self . _dropdown_window . Show ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def _UpdateList ( self ) : pass
def EventDropdownHideTimer ( self , event ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
try : self . _ShowDropdownIfFocussed ( )
except : pass
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def EventKeyDown ( self , event ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if event . KeyCode in ( wx . WXK_RETURN , wx . WXK_NUMPAD_ENTER ) and self . GetValue ( ) == ' ' and len ( self . _dropdown_list ) == 0 : self . _BroadcastChoice ( None )
elif event . KeyCode == wx . WXK_ESCAPE : self . GetTopLevelParent ( ) . SetFocus ( )
elif event . KeyCode in ( wx . WXK_UP , wx . WXK_NUMPAD_UP , wx . WXK_DOWN , wx . WXK_NUMPAD_DOWN ) and self . GetValue ( ) == ' ' and len ( self . _dropdown_list ) == 0 :
if event . KeyCode in ( wx . WXK_UP , wx . WXK_NUMPAD_UP ) : id = CC . MENU_EVENT_ID_TO_ACTION_CACHE . GetId ( ' select_up ' )
elif event . KeyCode in ( wx . WXK_DOWN , wx . WXK_NUMPAD_DOWN ) : id = CC . MENU_EVENT_ID_TO_ACTION_CACHE . GetId ( ' select_down ' )
new_event = wx . CommandEvent ( commandType = wx . wxEVT_COMMAND_MENU_SELECTED , winid = id )
self . ProcessEvent ( new_event )
else : self . _dropdown_list . ProcessEvent ( event )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def EventKillFocus ( self , event ) :
2013-02-19 00:11:43 +00:00
2013-03-23 17:57:29 +00:00
new_window = event . GetWindow ( )
if new_window == self . _dropdown_window or new_window in self . _dropdown_window . GetChildren ( ) : pass
else : self . _HideDropdown ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
event . Skip ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def EventLagTimer ( self , event ) : self . _UpdateList ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def EventMouseWheel ( self , event ) :
if self . GetValue ( ) == ' ' and len ( self . _dropdown_list ) == 0 :
if event . GetWheelRotation ( ) > 0 : id = CC . MENU_EVENT_ID_TO_ACTION_CACHE . GetId ( ' select_up ' )
else : id = CC . MENU_EVENT_ID_TO_ACTION_CACHE . GetId ( ' select_down ' )
new_event = wx . CommandEvent ( commandType = wx . wxEVT_COMMAND_MENU_SELECTED , winid = id )
self . ProcessEvent ( new_event )
else :
if event . CmdDown ( ) :
key_event = wx . KeyEvent ( wx . EVT_KEY_DOWN . typeId )
if event . GetWheelRotation ( ) > 0 : key_event . m_keyCode = wx . WXK_UP
else : key_event . m_keyCode = wx . WXK_DOWN
self . _dropdown_list . ProcessEvent ( key_event )
else :
# for some reason, the scrolledwindow list doesn't process scroll events properly when in a popupwindow
# so let's just tell it to scroll manually
( start_x , start_y ) = self . _dropdown_list . GetViewStart ( )
if event . GetWheelRotation ( ) > 0 : self . _dropdown_list . Scroll ( - 1 , start_y - 3 )
else : self . _dropdown_list . Scroll ( - 1 , start_y + 3 )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def EventMove ( self , event ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
try :
2013-03-23 17:57:29 +00:00
try : self . _HideDropdown ( )
except : pass
2013-03-15 02:38:12 +00:00
2013-09-11 21:28:19 +00:00
lag = 250
2013-03-15 02:38:12 +00:00
self . _move_hide_timer . Start ( lag , wx . TIMER_ONE_SHOT )
except wx . PyDeadObjectError : pass
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
event . Skip ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def EventSetFocus ( self , event ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _ShowDropdownIfFocussed ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
event . Skip ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def EventText ( self , event ) :
2013-02-19 00:11:43 +00:00
2013-08-28 21:31:52 +00:00
if len ( self . GetValue ( ) ) == 0 : self . _UpdateList ( )
else : self . _lag_timer . Start ( 150 , wx . TIMER_ONE_SHOT )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
class AutoCompleteDropdownContacts ( AutoCompleteDropdown ) :
def __init__ ( self , parent , compose_key , identity ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
AutoCompleteDropdown . __init__ ( self , parent )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _compose_key = compose_key
self . _identity = identity
2013-02-19 00:11:43 +00:00
vbox = wx . BoxSizer ( wx . VERTICAL )
2013-03-15 02:38:12 +00:00
vbox . AddF ( self . _dropdown_list , FLAGS_EXPAND_BOTH_WAYS )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _dropdown_window . SetSizer ( vbox )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def _BroadcastChoice ( self , contact_name ) : HC . pubsub . pub ( ' add_contact ' , self . _compose_key , contact_name )
def _GenerateMatches ( self ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
num_first_letters = 1
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
entry = self . GetValue ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if entry == ' ' :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _first_letters = ' '
matches = [ ]
else :
if len ( entry ) > = num_first_letters :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if entry [ : num_first_letters ] != self . _first_letters :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _first_letters = entry [ : num_first_letters ]
2013-02-19 00:11:43 +00:00
2013-07-10 20:25:57 +00:00
self . _cached_results = HC . app . Read ( ' autocomplete_contacts ' , entry , name_to_exclude = self . _identity . GetName ( ) )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
matches = self . _cached_results . GetMatches ( entry )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
else : matches = [ ]
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
return matches
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def _InitCachedResults ( self ) : return CC . AutocompleteMatches ( [ ] )
def _InitDropDownList ( self ) : return ListBoxMessagesActiveOnly ( self . _dropdown_window , self . BroadcastChoice )
def _UpdateList ( self ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
matches = self . _GenerateMatches ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
# this obv needs to be SetValues or whatever
self . _dropdown_list . SetTexts ( matches )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if len ( matches ) > 0 : self . _ShowDropdownIfFocussed ( )
else : self . _HideDropdown ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
class AutoCompleteDropdownMessageTerms ( AutoCompleteDropdown ) :
def __init__ ( self , parent , page_key , identity ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
AutoCompleteDropdown . __init__ ( self , parent )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _page_key = page_key
self . _identity = identity
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
vbox = wx . BoxSizer ( wx . VERTICAL )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
vbox . AddF ( self . _dropdown_list , FLAGS_EXPAND_BOTH_WAYS )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _dropdown_window . SetSizer ( vbox )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def _BroadcastChoice ( self , predicate ) : HC . pubsub . pub ( ' add_predicate ' , self . _page_key , predicate )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def _InitCachedResults ( self ) : return CC . AutocompleteMatchesCounted ( { } )
def _InitDropDownList ( self ) : return ListBoxMessagesActiveOnly ( self . _dropdown_window , self . BroadcastChoice )
def _GenerateMatches ( self ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
entry = self . GetValue ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if entry . startswith ( ' - ' ) : search_term = entry [ 1 : ]
else : search_term = entry
2013-02-19 00:11:43 +00:00
2013-07-10 20:25:57 +00:00
if search_term == ' ' : matches = HC . app . Read ( ' message_system_predicates ' , self . _identity )
2013-03-15 02:38:12 +00:00
else : matches = [ ( entry , None ) ]
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
return matches
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def _UpdateList ( self ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
matches = self . _GenerateMatches ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _dropdown_list . SetTerms ( matches )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if len ( matches ) > 0 : self . _ShowDropdownIfFocussed ( )
else : self . _HideDropdown ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
class AutoCompleteDropdownTags ( AutoCompleteDropdown ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def __init__ ( self , parent , file_service_identifier , tag_service_identifier ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
AutoCompleteDropdown . __init__ ( self , parent )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _current_namespace = ' '
self . _current_matches = [ ]
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _file_service_identifier = file_service_identifier
self . _tag_service_identifier = tag_service_identifier
2013-02-19 00:11:43 +00:00
2013-05-29 20:19:54 +00:00
name = self . _file_service_identifier . GetName ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _file_repo_button = wx . Button ( self . _dropdown_window , label = name )
self . _file_repo_button . Bind ( wx . EVT_BUTTON , self . EventFileButton )
2013-02-19 00:11:43 +00:00
2013-05-29 20:19:54 +00:00
name = self . _tag_service_identifier . GetName ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _tag_repo_button = wx . Button ( self . _dropdown_window , label = name )
self . _tag_repo_button . Bind ( wx . EVT_BUTTON , self . EventTagButton )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . Bind ( wx . EVT_MENU , self . EventMenu )
2013-02-19 00:11:43 +00:00
2013-05-15 18:58:14 +00:00
def _InitCachedResults ( self ) : return CC . AutocompleteMatchesPredicates ( HC . LOCAL_FILE_SERVICE_IDENTIFIER , [ ] )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def _InitDropDownList ( self ) : return TagsBoxActiveOnly ( self . _dropdown_window , self . BroadcastChoice )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def _UpdateList ( self ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
matches = self . _GenerateMatches ( )
2013-03-27 20:02:51 +00:00
self . _dropdown_list . SetPredicates ( matches )
2013-03-15 02:38:12 +00:00
self . _current_matches = matches
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def EventFileButton ( self , event ) :
2013-02-19 00:11:43 +00:00
2013-05-29 20:19:54 +00:00
service_identifiers = [ ]
service_identifiers . append ( HC . COMBINED_FILE_SERVICE_IDENTIFIER )
service_identifiers . append ( HC . LOCAL_FILE_SERVICE_IDENTIFIER )
2013-07-10 20:25:57 +00:00
service_identifiers . extend ( HC . app . Read ( ' service_identifiers ' , ( HC . FILE_REPOSITORY , ) ) )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
menu = wx . Menu ( )
for service_identifier in service_identifiers : menu . Append ( CC . MENU_EVENT_ID_TO_ACTION_CACHE . GetId ( ' change_file_repository ' , service_identifier ) , service_identifier . GetName ( ) )
self . PopupMenu ( menu )
2013-02-19 00:11:43 +00:00
2013-03-23 17:57:29 +00:00
menu . Destroy ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def EventMenu ( self , event ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
action = CC . MENU_EVENT_ID_TO_ACTION_CACHE . GetAction ( event . GetId ( ) )
if action is not None :
2013-02-19 00:11:43 +00:00
2013-08-14 20:21:49 +00:00
( command , data ) = action
if command == ' change_file_repository ' :
2013-02-19 00:11:43 +00:00
2013-08-14 20:21:49 +00:00
service_identifier = data
2013-02-19 00:11:43 +00:00
2013-08-14 20:21:49 +00:00
self . _file_service_identifier = service_identifier
2013-02-19 00:11:43 +00:00
2013-08-14 20:21:49 +00:00
name = service_identifier . GetName ( )
self . _file_repo_button . SetLabel ( name )
2013-02-19 00:11:43 +00:00
2013-08-14 20:21:49 +00:00
HC . pubsub . pub ( ' change_file_repository ' , self . _page_key , service_identifier )
2013-02-19 00:11:43 +00:00
2013-08-14 20:21:49 +00:00
elif command == ' change_tag_repository ' :
2013-02-19 00:11:43 +00:00
2013-08-14 20:21:49 +00:00
service_identifier = data
self . _tag_service_identifier = service_identifier
name = service_identifier . GetName ( )
self . _tag_repo_button . SetLabel ( name )
HC . pubsub . pub ( ' change_tag_repository ' , self . _page_key , service_identifier )
else :
event . Skip ( )
return # this is about select_up and select_down
2013-02-19 00:11:43 +00:00
2013-08-14 20:21:49 +00:00
self . _first_letters = ' '
self . _current_namespace = ' '
self . _UpdateList ( )
2013-02-19 00:11:43 +00:00
def EventTagButton ( self , event ) :
2013-05-29 20:19:54 +00:00
service_identifiers = [ ]
service_identifiers . append ( HC . COMBINED_TAG_SERVICE_IDENTIFIER )
service_identifiers . append ( HC . LOCAL_TAG_SERVICE_IDENTIFIER )
2013-07-10 20:25:57 +00:00
service_identifiers . extend ( HC . app . Read ( ' service_identifiers ' , ( HC . TAG_REPOSITORY , ) ) )
2013-02-19 00:11:43 +00:00
menu = wx . Menu ( )
for service_identifier in service_identifiers : menu . Append ( CC . MENU_EVENT_ID_TO_ACTION_CACHE . GetId ( ' change_tag_repository ' , service_identifier ) , service_identifier . GetName ( ) )
self . PopupMenu ( menu )
2013-03-23 17:57:29 +00:00
menu . Destroy ( )
2013-02-19 00:11:43 +00:00
class AutoCompleteDropdownTagsRead ( AutoCompleteDropdownTags ) :
def __init__ ( self , parent , page_key , file_service_identifier , tag_service_identifier , media_callable ) :
AutoCompleteDropdownTags . __init__ ( self , parent , file_service_identifier , tag_service_identifier )
self . _media_callable = media_callable
self . _page_key = page_key
self . _include_current = True
self . _include_pending = True
self . _include_current_tags = OnOffButton ( self . _dropdown_window , self . _page_key , ' notify_include_current ' , on_label = ' include current tags ' , off_label = ' exclude current tags ' )
self . _include_current_tags . SetToolTipString ( ' select whether to include current tags in the search ' )
self . _include_pending_tags = OnOffButton ( self . _dropdown_window , self . _page_key , ' notify_include_pending ' , on_label = ' include pending tags ' , off_label = ' exclude pending tags ' )
self . _include_pending_tags . SetToolTipString ( ' select whether to include pending tags in the search ' )
self . _synchronised = OnOffButton ( self . _dropdown_window , self . _page_key , ' notify_search_immediately ' , on_label = ' searching immediately ' , off_label = ' waiting ' )
self . _synchronised . SetToolTipString ( ' select whether to renew the search as soon as a new predicate is entered ' )
button_hbox_1 = wx . BoxSizer ( wx . HORIZONTAL )
button_hbox_1 . AddF ( self . _include_current_tags , FLAGS_EXPAND_BOTH_WAYS )
button_hbox_1 . AddF ( self . _include_pending_tags , FLAGS_EXPAND_BOTH_WAYS )
button_hbox_2 = wx . BoxSizer ( wx . HORIZONTAL )
button_hbox_2 . AddF ( self . _file_repo_button , FLAGS_EXPAND_BOTH_WAYS )
button_hbox_2 . AddF ( self . _tag_repo_button , FLAGS_EXPAND_BOTH_WAYS )
vbox = wx . BoxSizer ( wx . VERTICAL )
2013-03-15 02:38:12 +00:00
vbox . AddF ( button_hbox_1 , FLAGS_EXPAND_SIZER_PERPENDICULAR )
2013-02-19 00:11:43 +00:00
vbox . AddF ( self . _synchronised , FLAGS_EXPAND_PERPENDICULAR )
2013-03-15 02:38:12 +00:00
vbox . AddF ( button_hbox_2 , FLAGS_EXPAND_SIZER_PERPENDICULAR )
2013-02-19 00:11:43 +00:00
vbox . AddF ( self . _dropdown_list , FLAGS_EXPAND_BOTH_WAYS )
self . _dropdown_window . SetSizer ( vbox )
HC . pubsub . sub ( self , ' SetSynchronisedWait ' , ' synchronised_wait_switch ' )
HC . pubsub . sub ( self , ' IncludeCurrent ' , ' notify_include_current ' )
HC . pubsub . sub ( self , ' IncludePending ' , ' notify_include_pending ' )
def _BroadcastChoice ( self , predicate ) : HC . pubsub . pub ( ' add_predicate ' , self . _page_key , predicate )
def _GenerateMatches ( self ) :
2013-08-14 20:21:49 +00:00
num_first_letters = HC . options [ ' num_autocomplete_chars ' ]
2013-02-19 00:11:43 +00:00
raw_entry = self . GetValue ( )
2013-03-27 20:02:51 +00:00
if raw_entry . startswith ( ' - ' ) :
operator = ' - '
search_text = raw_entry [ 1 : ]
else :
operator = ' + '
search_text = raw_entry
2013-02-19 00:11:43 +00:00
search_text = HC . CleanTag ( search_text )
if search_text == ' ' :
self . _first_letters = ' '
self . _current_namespace = ' '
2013-05-29 20:19:54 +00:00
if self . _file_service_identifier == HC . COMBINED_FILE_SERVICE_IDENTIFIER : s_i = self . _tag_service_identifier
2013-02-19 00:11:43 +00:00
else : s_i = self . _file_service_identifier
2013-07-10 20:25:57 +00:00
matches = HC . app . Read ( ' file_system_predicates ' , s_i )
2013-02-19 00:11:43 +00:00
else :
must_do_a_search = False
if ' : ' in search_text :
( namespace , half_complete_tag ) = search_text . split ( ' : ' )
if namespace != self . _current_namespace :
self . _current_namespace = namespace # do a new search, no matter what half_complete tag is
must_do_a_search = True
else :
self . _current_namespace = ' '
half_complete_tag = search_text
if len ( half_complete_tag ) > = num_first_letters :
2013-03-27 20:02:51 +00:00
if must_do_a_search or self . _first_letters == ' ' or not half_complete_tag . startswith ( self . _first_letters ) :
2013-02-19 00:11:43 +00:00
2013-03-27 20:02:51 +00:00
self . _first_letters = half_complete_tag
2013-02-19 00:11:43 +00:00
media = self . _media_callable ( )
2013-06-19 20:25:06 +00:00
# if synchro not on, then can't rely on current media as being accurate for current preds, so search db normally
2013-07-10 20:25:57 +00:00
if media is None or not self . _synchronised . IsOn ( ) : self . _cached_results = HC . app . Read ( ' autocomplete_tags ' , file_service_identifier = self . _file_service_identifier , tag_service_identifier = self . _tag_service_identifier , half_complete_tag = search_text , include_current = self . _include_current , include_pending = self . _include_pending )
2013-02-19 00:11:43 +00:00
else :
2013-05-29 20:19:54 +00:00
tags_managers = [ ]
2013-02-19 00:11:43 +00:00
for m in media :
2013-05-29 20:19:54 +00:00
if m . IsCollection ( ) : tags_managers . extend ( m . GetSingletonsTagsManagers ( ) )
else : tags_managers . append ( m . GetTagsManager ( ) )
2013-02-19 00:11:43 +00:00
2013-05-29 20:19:54 +00:00
lists_of_tags = [ ]
2013-02-19 00:11:43 +00:00
2013-05-29 20:19:54 +00:00
if self . _include_current : lists_of_tags + = [ list ( tags_manager . GetCurrent ( self . _tag_service_identifier ) ) for tags_manager in tags_managers ]
if self . _include_pending : lists_of_tags + = [ list ( tags_manager . GetPending ( self . _tag_service_identifier ) ) for tags_manager in tags_managers ]
2013-02-19 00:11:43 +00:00
2013-05-29 20:19:54 +00:00
all_tags_flat_iterable = itertools . chain . from_iterable ( lists_of_tags )
2013-02-19 00:11:43 +00:00
2013-05-29 20:19:54 +00:00
all_tags_flat = [ tag for tag in all_tags_flat_iterable if HC . SearchEntryMatchesTag ( half_complete_tag , tag ) ]
2013-02-19 00:11:43 +00:00
2013-05-29 20:19:54 +00:00
if self . _current_namespace != ' ' : all_tags_flat = [ tag for tag in all_tags_flat if tag . startswith ( self . _current_namespace + ' : ' ) ]
tags_to_count = collections . Counter ( all_tags_flat )
2013-02-19 00:11:43 +00:00
2013-05-15 18:58:14 +00:00
self . _cached_results = CC . AutocompleteMatchesPredicates ( self . _tag_service_identifier , [ HC . Predicate ( HC . PREDICATE_TYPE_TAG , ( operator , tag ) , count ) for ( tag , count ) in tags_to_count . items ( ) ] )
2013-02-19 00:11:43 +00:00
matches = self . _cached_results . GetMatches ( half_complete_tag )
else : matches = [ ]
2013-03-27 20:02:51 +00:00
if self . _current_namespace != ' ' : matches . insert ( 0 , HC . Predicate ( HC . PREDICATE_TYPE_NAMESPACE , ( operator , namespace ) , None ) )
2013-05-29 20:19:54 +00:00
entry_predicate = HC . Predicate ( HC . PREDICATE_TYPE_TAG , ( operator , search_text ) , None )
try :
index = matches . index ( entry_predicate )
predicate = matches [ index ]
del matches [ index ]
matches . insert ( 0 , predicate )
except : pass
2013-03-27 20:02:51 +00:00
for match in matches :
if match . GetPredicateType ( ) == HC . PREDICATE_TYPE_TAG : match . SetOperator ( operator )
2013-02-19 00:11:43 +00:00
return matches
def IncludeCurrent ( self , page_key , value ) :
if page_key == self . _page_key : self . _include_current = value
self . _first_letters = ' '
self . _current_namespace = ' '
def IncludePending ( self , page_key , value ) :
if page_key == self . _page_key : self . _include_pending = value
self . _first_letters = ' '
self . _current_namespace = ' '
def SetSynchronisedWait ( self , page_key ) :
if page_key == self . _page_key : self . _synchronised . EventButton ( None )
class AutoCompleteDropdownTagsWrite ( AutoCompleteDropdownTags ) :
def __init__ ( self , parent , chosen_tag_callable , file_service_identifier , tag_service_identifier ) :
self . _chosen_tag_callable = chosen_tag_callable
2013-03-15 02:38:12 +00:00
self . _page_key = None # this makes the parent's eventmenu pubsubs with page_key simpler!
2013-08-14 20:21:49 +00:00
if HC . options [ ' show_all_tags_in_autocomplete ' ] : file_service_identifier = HC . COMBINED_FILE_SERVICE_IDENTIFIER
2013-03-15 02:38:12 +00:00
AutoCompleteDropdownTags . __init__ ( self , parent , file_service_identifier , tag_service_identifier )
vbox = wx . BoxSizer ( wx . VERTICAL )
hbox = wx . BoxSizer ( wx . HORIZONTAL )
hbox . AddF ( self . _file_repo_button , FLAGS_EXPAND_BOTH_WAYS )
hbox . AddF ( self . _tag_repo_button , FLAGS_EXPAND_BOTH_WAYS )
vbox . AddF ( hbox , FLAGS_EXPAND_SIZER_PERPENDICULAR )
vbox . AddF ( self . _dropdown_list , FLAGS_EXPAND_BOTH_WAYS )
self . _dropdown_window . SetSizer ( vbox )
2013-03-27 20:02:51 +00:00
def _BroadcastChoice ( self , predicate ) :
2013-05-15 18:58:14 +00:00
if predicate is None : self . _chosen_tag_callable ( None )
2013-03-27 20:02:51 +00:00
else :
( operator , tag ) = predicate . GetValue ( )
2013-07-10 20:25:57 +00:00
parent_manager = HC . app . GetTagParentsManager ( )
2013-05-15 18:58:14 +00:00
parents = parent_manager . GetParents ( self . _tag_service_identifier , tag )
self . _chosen_tag_callable ( tag , parents )
2013-03-27 20:02:51 +00:00
2013-03-15 02:38:12 +00:00
def _GenerateMatches ( self ) :
2013-08-14 20:21:49 +00:00
num_first_letters = HC . options [ ' num_autocomplete_chars ' ]
2013-03-15 02:38:12 +00:00
raw_entry = self . GetValue ( )
search_text = HC . CleanTag ( raw_entry )
if search_text == ' ' :
self . _first_letters = ' '
self . _current_namespace = ' '
matches = [ ]
else :
must_do_a_search = False
if ' : ' in search_text :
( namespace , half_complete_tag ) = search_text . split ( ' : ' )
if namespace != self . _current_namespace :
self . _current_namespace = namespace # do a new search, no matter what half_complete tag is
must_do_a_search = True
else :
self . _current_namespace = ' '
half_complete_tag = search_text
if len ( half_complete_tag ) > = num_first_letters :
2013-03-27 20:02:51 +00:00
if must_do_a_search or self . _first_letters == ' ' or not half_complete_tag . startswith ( self . _first_letters ) :
2013-03-15 02:38:12 +00:00
2013-03-27 20:02:51 +00:00
self . _first_letters = half_complete_tag
2013-03-15 02:38:12 +00:00
2013-07-10 20:25:57 +00:00
self . _cached_results = HC . app . Read ( ' autocomplete_tags ' , file_service_identifier = self . _file_service_identifier , tag_service_identifier = self . _tag_service_identifier , half_complete_tag = search_text , collapse = False )
2013-03-15 02:38:12 +00:00
matches = self . _cached_results . GetMatches ( half_complete_tag )
else : matches = [ ]
2013-05-15 18:58:14 +00:00
# do the 'put whatever they typed in at the top, whether it has count or not'
2013-05-08 20:31:00 +00:00
# now with sibling support!
2013-05-15 18:58:14 +00:00
# and parent support!
# this is getting pretty ugly, and I should really move it into the matches processing, I think!
2013-03-27 20:02:51 +00:00
2013-05-08 20:31:00 +00:00
top_predicates = [ ]
top_predicates . append ( HC . Predicate ( HC . PREDICATE_TYPE_TAG , ( ' + ' , search_text ) , 0 ) )
2013-07-10 20:25:57 +00:00
siblings_manager = HC . app . GetTagSiblingsManager ( )
2013-05-08 20:31:00 +00:00
sibling = siblings_manager . GetSibling ( search_text )
if sibling is not None : top_predicates . append ( HC . Predicate ( HC . PREDICATE_TYPE_TAG , ( ' + ' , sibling ) , 0 ) )
for predicate in top_predicates :
2013-05-15 18:58:14 +00:00
parents = [ ]
2013-05-08 20:31:00 +00:00
try :
2013-05-15 18:58:14 +00:00
index = matches . index ( predicate )
predicate = matches [ index ]
2013-05-08 20:31:00 +00:00
matches . remove ( predicate )
2013-05-15 18:58:14 +00:00
while matches [ index ] . GetPredicateType ( ) == HC . PREDICATE_TYPE_PARENT :
parent = matches [ index ]
matches . remove ( parent )
parents . append ( parent )
except :
if predicate . GetPredicateType ( ) == HC . PREDICATE_TYPE_TAG :
tag = predicate . GetTag ( )
2013-07-10 20:25:57 +00:00
parents_manager = HC . app . GetTagParentsManager ( )
2013-05-15 18:58:14 +00:00
raw_parents = parents_manager . GetParents ( self . _tag_service_identifier , tag )
parents = [ HC . Predicate ( HC . PREDICATE_TYPE_PARENT , raw_parent , None ) for raw_parent in raw_parents ]
2013-03-15 02:38:12 +00:00
2013-05-15 18:58:14 +00:00
parents . reverse ( )
for parent in parents : matches . insert ( 0 , parent )
2013-03-15 02:38:12 +00:00
2013-05-08 20:31:00 +00:00
matches . insert ( 0 , predicate )
2013-03-15 02:38:12 +00:00
return matches
class BufferedWindow ( wx . Window ) :
def __init__ ( self , * args , * * kwargs ) :
wx . Window . __init__ ( self , * args , * * kwargs )
if ' size ' in kwargs :
( x , y ) = kwargs [ ' size ' ]
self . _canvas_bmp = wx . EmptyBitmap ( x , y , 24 )
else : self . _canvas_bmp = wx . EmptyBitmap ( 0 , 0 , 24 )
self . Bind ( wx . EVT_PAINT , self . EventPaint )
self . Bind ( wx . EVT_SIZE , self . EventResize )
def GetDC ( self ) : return wx . BufferedDC ( wx . ClientDC ( self ) , self . _canvas_bmp )
def EventPaint ( self , event ) : wx . BufferedPaintDC ( self , self . _canvas_bmp )
def EventResize ( self , event ) :
( my_width , my_height ) = self . GetClientSize ( )
( current_bmp_width , current_bmp_height ) = self . _canvas_bmp . GetSize ( )
if my_width != current_bmp_width or my_height != current_bmp_height : self . _canvas_bmp = wx . EmptyBitmap ( my_width , my_height , 24 )
class BetterChoice ( wx . Choice ) :
def GetChoice ( self ) :
selection = self . GetSelection ( )
if selection != wx . NOT_FOUND : return self . GetClientData ( selection )
else : raise Exception ( ' choice not chosen ' )
class CheckboxCollect ( wx . combo . ComboCtrl ) :
2013-04-03 20:56:07 +00:00
def __init__ ( self , parent , page_key = None ) :
2013-03-15 02:38:12 +00:00
wx . combo . ComboCtrl . __init__ ( self , parent , style = wx . CB_READONLY )
self . _page_key = page_key
2013-08-14 20:21:49 +00:00
sort_by = HC . options [ ' sort_by ' ]
2013-04-03 20:56:07 +00:00
collect_types = set ( )
2013-03-15 02:38:12 +00:00
2013-04-03 20:56:07 +00:00
for ( sort_by_type , namespaces ) in sort_by : collect_types . update ( namespaces )
2013-03-15 02:38:12 +00:00
2013-04-03 20:56:07 +00:00
collect_types = list ( [ ( namespace , ( ' namespace ' , namespace ) ) for namespace in collect_types ] )
collect_types . sort ( )
2013-07-10 20:25:57 +00:00
ratings_service_identifiers = HC . app . Read ( ' service_identifiers ' , ( HC . LOCAL_RATING_LIKE , HC . LOCAL_RATING_NUMERICAL ) )
2013-03-15 02:38:12 +00:00
2013-04-03 20:56:07 +00:00
for service_identifier in ratings_service_identifiers : collect_types . append ( ( service_identifier . GetName ( ) , ( ' rating ' , service_identifier ) ) )
2013-03-15 02:38:12 +00:00
2013-04-03 20:56:07 +00:00
popup = self . _Popup ( collect_types )
2013-03-15 02:38:12 +00:00
#self.UseAltPopupWindow( True )
self . SetPopupControl ( popup )
def GetChoice ( self ) : return self . _collect_by
2013-04-03 20:56:07 +00:00
def SetCollectTypes ( self , collect_types , collect_type_strings ) :
2013-03-15 02:38:12 +00:00
2013-04-03 20:56:07 +00:00
if len ( collect_type_strings ) > 0 :
2013-03-15 02:38:12 +00:00
2013-04-03 20:56:07 +00:00
self . SetValue ( ' collect by ' + ' - ' . join ( collect_type_strings ) )
2013-03-15 02:38:12 +00:00
2013-04-03 20:56:07 +00:00
self . _collect_by = collect_types
2013-03-15 02:38:12 +00:00
else :
self . SetValue ( ' no collections ' )
self . _collect_by = None
HC . pubsub . pub ( ' collect_media ' , self . _page_key , self . _collect_by )
2013-03-23 17:57:29 +00:00
class _Popup ( wx . combo . ComboPopup ) :
2013-03-15 02:38:12 +00:00
2013-04-03 20:56:07 +00:00
def __init__ ( self , collect_types ) :
2013-03-15 02:38:12 +00:00
2013-03-23 17:57:29 +00:00
wx . combo . ComboPopup . __init__ ( self )
2013-03-15 02:38:12 +00:00
2013-04-03 20:56:07 +00:00
self . _collect_types = collect_types
2013-03-15 02:38:12 +00:00
2013-03-23 17:57:29 +00:00
def Create ( self , parent ) :
2013-04-03 20:56:07 +00:00
self . _control = self . _Control ( parent , self . GetCombo ( ) , self . _collect_types )
2013-03-23 17:57:29 +00:00
return True
2013-03-15 02:38:12 +00:00
2013-03-23 17:57:29 +00:00
def GetAdjustedSize ( self , preferred_width , preferred_height , max_height ) :
return ( ( preferred_width , - 1 ) )
2013-03-15 02:38:12 +00:00
2013-03-23 17:57:29 +00:00
def GetControl ( self ) : return self . _control
2013-03-15 02:38:12 +00:00
2013-03-23 17:57:29 +00:00
class _Control ( wx . CheckListBox ) :
2013-04-03 20:56:07 +00:00
def __init__ ( self , parent , special_parent , collect_types ) :
texts = [ text for ( text , data ) in collect_types ] # we do this so it sizes its height properly on init
wx . CheckListBox . __init__ ( self , parent , choices = texts )
2013-03-23 17:57:29 +00:00
2013-04-03 20:56:07 +00:00
self . Clear ( )
for ( text , data ) in collect_types : self . Append ( text , data )
2013-03-23 17:57:29 +00:00
self . _special_parent = special_parent
2013-08-14 20:21:49 +00:00
default = HC . options [ ' default_collect ' ]
2013-03-23 17:57:29 +00:00
2013-09-04 16:48:44 +00:00
if default is not None :
strings_we_added = { text for ( text , data ) in collect_types }
strings_to_check = [ s for ( namespace_gumpf , s ) in default if s in strings_we_added ]
self . SetCheckedStrings ( strings_to_check )
2013-03-23 17:57:29 +00:00
self . Bind ( wx . EVT_CHECKLISTBOX , self . EventChanged )
self . Bind ( wx . EVT_LEFT_DOWN , self . EventLeftDown )
self . EventChanged ( None )
# as inspired by http://trac.wxwidgets.org/attachment/ticket/14413/test_clb_workaround.py
# what a clusterfuck
def EventLeftDown ( self , event ) :
index = self . HitTest ( event . GetPosition ( ) )
if index != wx . NOT_FOUND :
self . Check ( index , not self . IsChecked ( index ) )
self . EventChanged ( event )
event . Skip ( )
def EventChanged ( self , event ) :
2013-04-03 20:56:07 +00:00
collect_types = [ ]
for i in self . GetChecked ( ) : collect_types . append ( self . GetClientData ( i ) )
collect_type_strings = self . GetCheckedStrings ( )
2013-03-23 17:57:29 +00:00
2013-04-03 20:56:07 +00:00
self . _special_parent . SetCollectTypes ( collect_types , collect_type_strings )
2013-03-23 17:57:29 +00:00
2013-03-15 02:38:12 +00:00
class ChoiceSort ( BetterChoice ) :
def __init__ ( self , parent , page_key = None , sort_by = None ) :
BetterChoice . __init__ ( self , parent )
self . _page_key = page_key
2013-08-14 20:21:49 +00:00
if sort_by is None : sort_by = HC . options [ ' sort_by ' ]
2013-03-15 02:38:12 +00:00
sort_choices = CC . SORT_CHOICES + sort_by
2013-07-10 20:25:57 +00:00
ratings_service_identifiers = HC . app . Read ( ' service_identifiers ' , ( HC . LOCAL_RATING_LIKE , HC . LOCAL_RATING_NUMERICAL ) )
2013-03-15 02:38:12 +00:00
for ratings_service_identifier in ratings_service_identifiers :
sort_choices . append ( ( ' rating_descend ' , ratings_service_identifier ) )
sort_choices . append ( ( ' rating_ascend ' , ratings_service_identifier ) )
for ( sort_by_type , sort_by_data ) in sort_choices :
if sort_by_type == ' system ' : string = CC . sort_string_lookup [ sort_by_data ]
elif sort_by_type == ' namespaces ' : string = ' - ' . join ( sort_by_data )
elif sort_by_type == ' rating_descend ' : string = sort_by_data . GetName ( ) + ' rating highest first '
elif sort_by_type == ' rating_ascend ' : string = sort_by_data . GetName ( ) + ' rating lowest first '
self . Append ( ' sort by ' + string , ( sort_by_type , sort_by_data ) )
2013-08-14 20:21:49 +00:00
try : self . SetSelection ( HC . options [ ' default_sort ' ] )
2013-03-15 02:38:12 +00:00
except : pass
self . Bind ( wx . EVT_CHOICE , self . EventChoice )
HC . pubsub . sub ( self , ' ACollectHappened ' , ' collect_media ' )
def _BroadcastSort ( self ) :
selection = self . GetSelection ( )
if selection != wx . NOT_FOUND :
sort_by = self . GetClientData ( selection )
HC . pubsub . pub ( ' sort_media ' , self . _page_key , sort_by )
def ACollectHappened ( self , page_key , collect_by ) :
if page_key == self . _page_key : self . _BroadcastSort ( )
def EventChoice ( self , event ) :
if self . _page_key is not None : self . _BroadcastSort ( )
class FileDropTarget ( wx . FileDropTarget ) :
def __init__ ( self , callable ) :
wx . FileDropTarget . __init__ ( self )
self . _callable = callable
def OnDropFiles ( self , x , y , paths ) : wx . CallAfter ( self . _callable , paths )
class Frame ( wx . Frame ) :
def __init__ ( self , * args , * * kwargs ) :
wx . Frame . __init__ ( self , * args , * * kwargs )
#self.SetDoubleBuffered( True )
self . SetBackgroundColour ( wx . SystemSettings . GetColour ( wx . SYS_COLOUR_BTNFACE ) )
2013-09-04 16:48:44 +00:00
self . SetIcon ( wx . Icon ( HC . STATIC_DIR + os . path . sep + ' hydrus.ico ' , wx . BITMAP_TYPE_ICO ) )
class FrameThatResizes ( Frame ) :
def __init__ ( self , * args , * * kwargs ) :
self . _resize_option_prefix = kwargs [ ' resize_option_prefix ' ]
del kwargs [ ' resize_option_prefix ' ]
Frame . __init__ ( self , * args , * * kwargs )
client_size = HC . options [ ' client_size ' ]
self . SetInitialSize ( client_size [ self . _resize_option_prefix + ' restored_size ' ] )
self . SetMinSize ( ( 480 , 360 ) )
self . _TryToSetPosition ( )
if client_size [ self . _resize_option_prefix + ' maximised ' ] : self . Maximize ( )
self . Bind ( wx . EVT_SIZE , self . EventSpecialResize )
self . Bind ( wx . EVT_MOVE_END , self . EventSpecialMoveEnd )
def _TryToSetPosition ( self ) :
client_size = HC . options [ ' client_size ' ]
position = client_size [ self . _resize_option_prefix + ' restored_position ' ]
display_index = wx . Display . GetFromPoint ( position )
if display_index == wx . NOT_FOUND : client_size [ self . _resize_option_prefix + ' restored_position ' ] = [ 20 , 20 ]
else :
display = wx . Display ( display_index )
geometry = display . GetGeometry ( )
( p_x , p_y ) = position
x_bad = p_x < geometry . x or p_x > geometry . x + geometry . width
y_bad = p_y < geometry . y or p_y > geometry . y + geometry . height
if x_bad or y_bad : client_size [ self . _resize_option_prefix + ' restored_position ' ] = [ 20 , 20 ]
self . SetPosition ( client_size [ self . _resize_option_prefix + ' restored_position ' ] )
def EventSpecialMoveEnd ( self , event ) :
client_size = HC . options [ ' client_size ' ]
client_size [ self . _resize_option_prefix + ' restored_position ' ] = list ( self . GetPosition ( ) )
event . Skip ( )
def EventSpecialResize ( self , event ) :
client_size = HC . options [ ' client_size ' ]
if self . IsMaximized ( ) or self . IsFullScreen ( ) :
client_size [ self . _resize_option_prefix + ' maximised ' ] = True
else :
if client_size [ self . _resize_option_prefix + ' maximised ' ] : # we have just restored, so set size
self . SetSize ( client_size [ self . _resize_option_prefix + ' restored_size ' ] )
self . _TryToSetPosition ( )
else : # we have resized manually, so set new size
client_size [ self . _resize_option_prefix + ' restored_size ' ] = list ( self . GetSize ( ) )
client_size [ self . _resize_option_prefix + ' restored_position ' ] = list ( self . GetPosition ( ) )
client_size [ self . _resize_option_prefix + ' maximised ' ] = False
event . Skip ( )
2013-03-15 02:38:12 +00:00
class Gauge ( wx . Gauge ) :
def __init__ ( self , * args , * * kwargs ) :
wx . Gauge . __init__ ( self , * args , * * kwargs )
self . _actual_max = None
def SetRange ( self , max ) :
if max > 1000 :
self . _actual_max = max
wx . Gauge . SetRange ( self , 1000 )
else :
self . _actual_max = None
wx . Gauge . SetRange ( self , max )
def SetValue ( self , value ) :
if self . _actual_max is None : wx . Gauge . SetValue ( self , value )
else : wx . Gauge . SetValue ( self , min ( int ( 1000 * ( float ( value ) / self . _actual_max ) ) , 1000 ) )
class ListBook ( wx . Panel ) :
def __init__ ( self , * args , * * kwargs ) :
wx . Panel . __init__ ( self , * args , * * kwargs )
self . SetBackgroundColour ( wx . SystemSettings . GetColour ( wx . SYS_COLOUR_BTNFACE ) )
self . _list_box = wx . ListBox ( self , style = wx . LB_SINGLE | wx . LB_SORT )
self . _empty_panel = wx . Panel ( self )
self . _empty_panel . SetBackgroundColour ( wx . SystemSettings . GetColour ( wx . SYS_COLOUR_BTNFACE ) )
self . _current_name = None
self . _current_panel = self . _empty_panel
self . _panel_sizer = wx . BoxSizer ( wx . VERTICAL )
self . _panel_sizer . AddF ( self . _empty_panel , FLAGS_EXPAND_BOTH_WAYS )
hbox = wx . BoxSizer ( wx . HORIZONTAL )
hbox . AddF ( self . _list_box , FLAGS_EXPAND_PERPENDICULAR )
hbox . AddF ( self . _panel_sizer , FLAGS_EXPAND_SIZER_BOTH_WAYS )
self . _list_box . Bind ( wx . EVT_LISTBOX , self . EventSelection )
self . SetSizer ( hbox )
self . Bind ( wx . EVT_MENU , self . EventMenu )
def _RecalcListBoxWidth ( self ) : self . Layout ( )
def _Select ( self , selection ) :
2013-03-23 17:57:29 +00:00
if selection == wx . NOT_FOUND : self . _current_name = None
else : self . _current_name = self . _list_box . GetString ( selection )
self . _current_panel . Hide ( )
self . _list_box . SetSelection ( selection )
if selection == wx . NOT_FOUND : self . _current_panel = self . _empty_panel
else :
2013-03-15 02:38:12 +00:00
2013-03-23 17:57:29 +00:00
panel_info = self . _list_box . GetClientData ( selection )
2013-03-15 02:38:12 +00:00
2013-03-23 17:57:29 +00:00
if type ( panel_info ) == tuple :
2013-03-15 02:38:12 +00:00
2013-03-23 17:57:29 +00:00
( classname , args , kwargs ) = panel_info
2013-03-15 02:38:12 +00:00
2013-03-23 17:57:29 +00:00
page = classname ( * args , * * kwargs )
page . Hide ( )
self . _panel_sizer . AddF ( page , FLAGS_EXPAND_SIZER_BOTH_WAYS )
self . _list_box . SetClientData ( selection , page )
2013-03-15 02:38:12 +00:00
2013-03-23 17:57:29 +00:00
self . _RecalcListBoxWidth ( )
2013-03-15 02:38:12 +00:00
2013-03-23 17:57:29 +00:00
self . _current_panel = self . _list_box . GetClientData ( selection )
2013-03-15 02:38:12 +00:00
self . _current_panel . Show ( )
self . Layout ( )
2013-09-11 21:28:19 +00:00
self . Refresh ( )
2013-03-15 02:38:12 +00:00
event = wx . NotifyEvent ( wx . wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED , - 1 )
self . ProcessEvent ( event )
def AddPage ( self , page , name , select = False ) :
if type ( page ) != tuple :
page . Hide ( )
self . _panel_sizer . AddF ( page , FLAGS_EXPAND_SIZER_BOTH_WAYS )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _list_box . Append ( name , page )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _RecalcListBoxWidth ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if self . _list_box . GetCount ( ) == 1 : self . _Select ( 0 )
elif select : self . _Select ( self . _list_box . FindString ( name ) )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def DeleteAllPages ( self ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _panel_sizer . Detach ( self . _empty_panel )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _panel_sizer . Clear ( deleteWindows = True )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _panel_sizer . AddF ( self . _empty_panel , FLAGS_EXPAND_SIZER_BOTH_WAYS )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _current_name = None
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _current_panel = self . _empty_panel
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _list_box . Clear ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def EventMenu ( self , event ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
action = CC . MENU_EVENT_ID_TO_ACTION_CACHE . GetAction ( event . GetId ( ) )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if action is not None :
2013-02-19 00:11:43 +00:00
2013-08-14 20:21:49 +00:00
( command , data ) = action
if command == ' select_down ' : self . SelectDown ( )
elif command == ' select_up ' : self . SelectUp ( )
else : event . Skip ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def EventSelection ( self , event ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if self . _list_box . GetSelection ( ) != self . _list_box . FindString ( self . _current_name ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
event = wx . NotifyEvent ( wx . wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING , - 1 )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . GetEventHandler ( ) . ProcessEvent ( event )
if event . IsAllowed ( ) : self . _Select ( self . _list_box . GetSelection ( ) )
else : self . _list_box . SetSelection ( self . _list_box . FindString ( self . _current_name ) )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def GetCurrentName ( self ) : return self . _current_name
def GetCurrentPage ( self ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if self . _current_panel == self . _empty_panel : return None
else : return self . _current_panel
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def GetNameToPageDict ( self ) : return { self . _list_box . GetString ( i ) : self . _list_box . GetClientData ( i ) for i in range ( self . _list_box . GetCount ( ) ) if type ( self . _list_box . GetClientData ( i ) ) != tuple }
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def NameExists ( self , name , panel = None ) : return self . _list_box . FindString ( name ) != wx . NOT_FOUND
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def DeleteCurrentPage ( self ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
selection = self . _list_box . GetSelection ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if selection != wx . NOT_FOUND :
next_selection = selection + 1
previous_selection = selection - 1
if next_selection < self . _list_box . GetCount ( ) : self . _Select ( next_selection )
elif previous_selection > = 0 : self . _Select ( previous_selection )
else : self . _Select ( wx . NOT_FOUND )
panel_info = self . _list_box . GetClientData ( selection )
if type ( panel_info ) != tuple : self . _panel_sizer . Remove ( panel_info )
self . _list_box . Delete ( selection )
self . _RecalcListBoxWidth ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def RenamePage ( self , name , new_name ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if self . _list_box . FindString ( new_name ) != wx . NOT_FOUND : raise Exception ( ' That name is already in use! ' )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if self . _current_name == name : self . _current_name = new_name
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _list_box . SetString ( self . _list_box . FindString ( name ) , new_name )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _RecalcListBoxWidth ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def Select ( self , name ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
selection = self . _list_box . FindString ( name )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if selection != wx . NOT_FOUND and selection != self . _list_box . GetSelection ( ) :
event = wx . NotifyEvent ( wx . wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING , - 1 )
self . GetEventHandler ( ) . ProcessEvent ( event )
if event . IsAllowed ( ) : self . _Select ( selection )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def SelectDown ( self ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
current_selection = self . _list_box . FindString ( self . _current_name )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if current_selection != wx . NOT_FOUND :
num_entries = self . _list_box . GetCount ( )
if current_selection == num_entries - 1 : selection = 0
else : selection = current_selection + 1
if selection != current_selection : self . _Select ( selection )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def SelectPage ( self , page ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
for i in range ( self . _list_box . GetCount ( ) ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if self . _list_box . GetClientData ( i ) == page :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _Select ( i )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
return
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def SelectUp ( self ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
current_selection = self . _list_box . FindString ( self . _current_name )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if current_selection != wx . NOT_FOUND :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
num_entries = self . _list_box . GetCount ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if current_selection == 0 : selection = num_entries - 1
else : selection = current_selection - 1
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if selection != current_selection : self . _Select ( selection )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
class ListCtrlAutoWidth ( wx . ListCtrl , ListCtrlAutoWidthMixin ) :
def __init__ ( self , parent , height ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
wx . ListCtrl . __init__ ( self , parent , size = ( - 1 , height ) , style = wx . LC_REPORT )
ListCtrlAutoWidthMixin . __init__ ( self )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def GetAllSelected ( self ) :
indices = [ ]
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
i = self . GetFirstSelected ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
while i != - 1 :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
indices . append ( i )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
i = self . GetNextSelected ( i )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
return indices
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def RemoveAllSelected ( self ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
indices = self . GetAllSelected ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
indices . reverse ( ) # so we don't screw with the indices of deletees below
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
for index in indices : self . DeleteItem ( index )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
class ListBox ( wx . ScrolledWindow ) :
def __init__ ( self , parent , min_height = 250 ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
wx . ScrolledWindow . __init__ ( self , parent , style = wx . VSCROLL | wx . BORDER_DOUBLE )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _ordered_strings = [ ]
self . _strings_to_terms = { }
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _canvas_bmp = wx . EmptyBitmap ( 0 , 0 , 24 )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _current_selected_index = None
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
dc = self . _GetScrolledDC ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
dc . SetFont ( wx . SystemSettings . GetFont ( wx . SYS_DEFAULT_GUI_FONT ) )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
( text_x , self . _text_y ) = dc . GetTextExtent ( ' abcdefghijklmnopqrstuvwxyz ' )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _num_rows_per_page = 0
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . SetScrollRate ( 0 , self . _text_y )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . SetMinSize ( ( 50 , min_height ) )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . Bind ( wx . EVT_PAINT , self . EventPaint )
self . Bind ( wx . EVT_SIZE , self . EventResize )
self . Bind ( wx . EVT_LEFT_DOWN , self . EventMouseSelect )
self . Bind ( wx . EVT_LEFT_DCLICK , self . EventDClick )
2013-03-23 17:57:29 +00:00
self . Bind ( wx . EVT_RIGHT_DOWN , self . EventMouseRightClick )
2013-03-15 02:38:12 +00:00
self . Bind ( wx . EVT_KEY_DOWN , self . EventKeyDown )
2013-03-23 17:57:29 +00:00
self . Bind ( wx . EVT_MENU , self . EventMenu )
2013-03-15 02:38:12 +00:00
def __len__ ( self ) : return len ( self . _ordered_strings )
2013-05-08 20:31:00 +00:00
def _Activate ( self , s , term ) : pass
2013-03-15 02:38:12 +00:00
def _DrawTexts ( self ) :
( my_width , my_height ) = self . GetClientSize ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
dc = self . _GetScrolledDC ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
dc . SetFont ( wx . SystemSettings . GetFont ( wx . SYS_DEFAULT_GUI_FONT ) )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
i = 0
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
dc . SetBackground ( wx . Brush ( wx . Colour ( 255 , 255 , 255 ) ) )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
dc . Clear ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
for ( i , text ) in enumerate ( self . _ordered_strings ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
( r , g , b ) = self . _GetTextColour ( text )
text_colour = wx . Colour ( r , g , b )
if self . _current_selected_index is not None and i == self . _current_selected_index :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
dc . SetBrush ( wx . Brush ( text_colour ) )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
dc . SetPen ( wx . TRANSPARENT_PEN )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
dc . DrawRectangle ( 0 , i * self . _text_y , my_width , self . _text_y )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
text_colour = wx . WHITE
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
dc . SetTextForeground ( text_colour )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
( x , y ) = ( 3 , i * self . _text_y )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
dc . DrawText ( text , x , y )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def _GetIndexUnderMouse ( self , mouse_event ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
( xUnit , yUnit ) = self . GetScrollPixelsPerUnit ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
( x_scroll , y_scroll ) = self . GetViewStart ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
y_offset = y_scroll * yUnit
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
y = mouse_event . GetY ( ) + y_offset
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
row_index = ( y / self . _text_y )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if row_index > = len ( self . _ordered_strings ) : return None
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
return row_index
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def _GetScrolledDC ( self ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
cdc = wx . ClientDC ( self )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . DoPrepareDC ( cdc ) # because this is a scrolled window
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
return wx . BufferedDC ( cdc , self . _canvas_bmp )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def _GetTextColour ( self , text ) : return ( 0 , 111 , 250 )
def _Select ( self , index ) :
if index is not None :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if index == - 1 or index > len ( self . _ordered_strings ) : index = len ( self . _ordered_strings ) - 1
elif index == len ( self . _ordered_strings ) or index < - 1 : index = 0
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _current_selected_index = index
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _DrawTexts ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if self . _current_selected_index is not None :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
# scroll to index, if needed
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
y = self . _text_y * self . _current_selected_index
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
( start_x , start_y ) = self . GetViewStart ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
( x_unit , y_unit ) = self . GetScrollPixelsPerUnit ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
( width , height ) = self . GetClientSize ( )
if y < start_y * y_unit :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
y_to_scroll_to = y / y_unit
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . Scroll ( - 1 , y_to_scroll_to )
wx . PostEvent ( self , wx . ScrollWinEvent ( wx . wxEVT_SCROLLWIN_THUMBRELEASE ) )
elif y > ( start_y * y_unit ) + height :
y_to_scroll_to = ( y - height ) / y_unit
self . Scroll ( - 1 , y_to_scroll_to + 3 )
wx . PostEvent ( self , wx . ScrollWinEvent ( wx . wxEVT_SCROLLWIN_THUMBRELEASE ) )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def _TextsHaveChanged ( self ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _current_selected_index = None
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
total_height = self . _text_y * len ( self . _ordered_strings )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
( my_x , my_y ) = self . _canvas_bmp . GetSize ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if my_y != total_height : wx . PostEvent ( self , wx . SizeEvent ( ) )
else : self . _DrawTexts ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def EventDClick ( self , event ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
index = self . _GetIndexUnderMouse ( event )
2013-02-19 00:11:43 +00:00
2013-05-08 20:31:00 +00:00
if index is not None and index == self . _current_selected_index :
s = self . _ordered_strings [ self . _current_selected_index ]
term = self . _strings_to_terms [ s ]
self . _Activate ( s , term )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def EventKeyDown ( self , event ) :
key_code = event . GetKeyCode ( )
if self . _current_selected_index is not None :
2013-02-19 00:11:43 +00:00
2013-05-08 20:31:00 +00:00
if key_code in ( wx . WXK_RETURN , wx . WXK_NUMPAD_ENTER ) :
s = self . _ordered_strings [ self . _current_selected_index ]
term = self . _strings_to_terms [ s ]
self . _Activate ( s , term )
2013-03-15 02:38:12 +00:00
elif key_code in ( wx . WXK_UP , wx . WXK_NUMPAD_UP ) : self . _Select ( self . _current_selected_index - 1 )
elif key_code in ( wx . WXK_DOWN , wx . WXK_NUMPAD_DOWN ) : self . _Select ( self . _current_selected_index + 1 )
elif key_code == wx . WXK_PAGEUP : self . _Select ( self . _current_selected_index - self . _num_rows_per_page )
elif key_code == wx . WXK_PAGEDOWN : self . _Select ( self . _current_selected_index + self . _num_rows_per_page )
else : event . Skip ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
else : event . Skip ( )
2013-02-19 00:11:43 +00:00
2013-03-23 17:57:29 +00:00
def EventMenu ( self , event ) :
action = CC . MENU_EVENT_ID_TO_ACTION_CACHE . GetAction ( event . GetId ( ) )
if action is not None :
2013-08-14 20:21:49 +00:00
( command , data ) = action
if command == ' copy ' : HC . pubsub . pub ( ' clipboard ' , ' text ' , data )
else :
2013-03-23 17:57:29 +00:00
2013-08-14 20:21:49 +00:00
event . Skip ( )
2013-03-23 17:57:29 +00:00
2013-08-14 20:21:49 +00:00
return # this is about select_up and select_down
2013-03-23 17:57:29 +00:00
def EventMouseRightClick ( self , event ) :
index = self . _GetIndexUnderMouse ( event )
self . _Select ( index )
if self . _current_selected_index is not None :
menu = wx . Menu ( )
term = self . _strings_to_terms [ self . _ordered_strings [ self . _current_selected_index ] ]
menu . Append ( CC . MENU_EVENT_ID_TO_ACTION_CACHE . GetId ( ' copy ' , term ) , ' copy ' + term )
if ' : ' in term :
sub_term = term . split ( ' : ' , 1 ) [ 1 ]
menu . Append ( CC . MENU_EVENT_ID_TO_ACTION_CACHE . GetId ( ' copy ' , sub_term ) , ' copy ' + sub_term )
self . PopupMenu ( menu )
menu . Destroy ( )
event . Skip ( )
2013-03-15 02:38:12 +00:00
def EventMouseSelect ( self , event ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
index = self . _GetIndexUnderMouse ( event )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _Select ( index )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
event . Skip ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def EventPaint ( self , event ) : wx . BufferedPaintDC ( self , self . _canvas_bmp , wx . BUFFER_VIRTUAL_AREA )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def EventResize ( self , event ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
( client_x , client_y ) = self . GetClientSize ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
( my_x , my_y ) = self . _canvas_bmp . GetSize ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _num_rows_per_page = client_y / self . _text_y
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
total_height = self . _text_y * len ( self . _ordered_strings )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if my_x != client_x or my_y != total_height :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
new_y = max ( client_y , total_height )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . SetVirtualSize ( ( client_x , new_y ) )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _canvas_bmp = wx . EmptyBitmap ( client_x , new_y , 24 )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _DrawTexts ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def SetTexts ( self , ordered_strings ) :
if ordered_strings != self . _ordered_strings :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _ordered_strings = ordered_strings
self . _strings_to_terms = { s : s for s in ordered_strings }
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _TextsHaveChanged ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if len ( ordered_strings ) > 0 : self . _Select ( 0 )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
class ListBoxMessages ( ListBox ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def _GetTextColour ( self , predicate_string ) :
if predicate_string . startswith ( ' system: ' ) : ( r , g , b ) = ( 153 , 101 , 21 )
else : ( r , g , b ) = ( 0 , 111 , 250 )
return ( r , g , b )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
class ListBoxMessagesActiveOnly ( ListBoxMessages ) :
def __init__ ( self , parent , callable ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
ListBoxMessages . __init__ ( self , parent )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _callable = callable
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _matches = { }
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
2013-05-08 20:31:00 +00:00
def _Activate ( self , s , term ) : self . _callable ( term )
2013-03-15 02:38:12 +00:00
def SetTerms ( self , matches ) :
if matches != self . _matches :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _matches = matches
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _ordered_strings = [ ]
self . _strings_to_terms = { }
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
for ( term , count ) in matches :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if count is None : term_string = term
else : term_string = term + ' ( ' + HC . ConvertIntToPrettyString ( count ) + ' ) '
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _ordered_strings . append ( term_string )
self . _strings_to_terms [ term_string ] = term
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _TextsHaveChanged ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if len ( matches ) > 0 : self . _Select ( 0 )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
class ListBoxMessagesPredicates ( ListBoxMessages ) :
def __init__ ( self , parent , page_key , initial_predicates = [ ] ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
ListBoxMessages . __init__ ( self , parent )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _page_key = page_key
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if len ( initial_predicates ) > 0 :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
for predicate in initial_predicates :
self . _ordered_strings . append ( predicate )
self . _strings_to_terms [ predicate ] = predicate
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _TextsHaveChanged ( )
2013-02-19 00:11:43 +00:00
2013-05-08 20:31:00 +00:00
def _Activate ( self , s , term ) : HC . pubsub . pub ( ' remove_predicate ' , self . _page_key , term )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def ActivatePredicate ( self , term ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if term in self . _ordered_strings :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _ordered_strings . remove ( term )
del self . _strings_to_terms [ term ]
2013-02-19 00:11:43 +00:00
else :
2013-03-15 02:38:12 +00:00
if term == ' system:inbox ' and ' system:archive ' in self . _ordered_strings : self . _ordered_strings . remove ( ' system:archive ' )
elif term == ' system:archive ' and ' system:inbox ' in self . _ordered_strings : self . _ordered_strings . remove ( ' system:inbox ' )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _ordered_strings . append ( term )
self . _strings_to_terms [ term ] = term
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _ordered_strings . sort ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _TextsHaveChanged ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def AddPredicate ( self , predicate ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _ordered_strings . append ( predicate )
self . _strings_to_terms [ predicate ] = predicate
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _ordered_strings . sort ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _TextsHaveChanged ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def GetPredicates ( self ) : return self . _ordered_strings
def HasPredicate ( self , predicate ) : return predicate in self . _ordered_strings
def RemovePredicate ( self , predicate ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _ordered_strings . remove ( predicate )
del self . _strings_to_terms [ predicate ]
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _TextsHaveChanged ( )
2013-02-19 00:11:43 +00:00
2013-03-23 17:57:29 +00:00
class NoneableSpinCtrl ( wx . Panel ) :
2013-07-31 21:26:38 +00:00
def __init__ ( self , parent , message , none_phrase = ' no limit ' , max = 1000000 , multiplier = 1 , num_dimensions = 1 ) :
2013-03-23 17:57:29 +00:00
wx . Panel . __init__ ( self , parent )
self . _num_dimensions = num_dimensions
self . _multiplier = multiplier
self . _checkbox = wx . CheckBox ( self , label = none_phrase )
self . _checkbox . Bind ( wx . EVT_CHECKBOX , self . EventCheckBox )
2013-07-31 21:26:38 +00:00
self . _one = wx . SpinCtrl ( self , max = max , size = ( 80 , - 1 ) )
if num_dimensions == 2 : self . _two = wx . SpinCtrl ( self , initial = 0 , max = max , size = ( 80 , - 1 ) )
2013-03-23 17:57:29 +00:00
hbox = wx . BoxSizer ( wx . HORIZONTAL )
2013-07-31 21:26:38 +00:00
2013-03-23 17:57:29 +00:00
hbox . AddF ( wx . StaticText ( self , label = message + ' : ' ) , FLAGS_MIXED )
hbox . AddF ( self . _one , FLAGS_MIXED )
if self . _num_dimensions == 2 :
hbox . AddF ( wx . StaticText ( self , label = ' x ' ) , FLAGS_MIXED )
hbox . AddF ( self . _two , FLAGS_MIXED )
hbox . AddF ( self . _checkbox , FLAGS_MIXED )
self . SetSizer ( hbox )
def EventCheckBox ( self , event ) :
if self . _checkbox . GetValue ( ) :
self . _one . Disable ( )
if self . _num_dimensions == 2 : self . _two . Disable ( )
else :
self . _one . Enable ( )
if self . _num_dimensions == 2 : self . _two . Enable ( )
def GetValue ( self ) :
if self . _checkbox . GetValue ( ) : return None
else :
if self . _num_dimensions == 2 : return ( self . _one . GetValue ( ) * self . _multiplier , self . _two . GetValue ( ) * self . _multiplier )
else : return self . _one . GetValue ( ) * self . _multiplier
def SetValue ( self , value ) :
if value is None :
self . _checkbox . SetValue ( True )
self . _one . Disable ( )
if self . _num_dimensions == 2 : self . _two . Disable ( )
else :
self . _checkbox . SetValue ( False )
if self . _num_dimensions == 2 :
2013-07-31 21:26:38 +00:00
self . _two . Enable ( )
2013-03-23 17:57:29 +00:00
( value , y ) = value
self . _two . SetValue ( y / self . _multiplier )
2013-07-31 21:26:38 +00:00
self . _one . Enable ( )
2013-03-23 17:57:29 +00:00
self . _one . SetValue ( value / self . _multiplier )
class OnOffButton ( wx . Button ) :
def __init__ ( self , parent , page_key , topic , on_label , off_label = None , start_on = True ) :
if start_on : label = on_label
else : label = off_label
wx . Button . __init__ ( self , parent , label = label )
self . _page_key = page_key
self . _topic = topic
self . _on_label = on_label
if off_label is None : self . _off_label = on_label
else : self . _off_label = off_label
self . _on = start_on
if self . _on : self . SetForegroundColour ( ( 0 , 128 , 0 ) )
else : self . SetForegroundColour ( ( 128 , 0 , 0 ) )
self . Bind ( wx . EVT_BUTTON , self . EventButton )
HC . pubsub . sub ( self , ' HitButton ' , ' hit_on_off_button ' )
def EventButton ( self , event ) :
if self . _on :
self . _on = False
self . SetLabel ( self . _off_label )
self . SetForegroundColour ( ( 128 , 0 , 0 ) )
HC . pubsub . pub ( self . _topic , self . _page_key , False )
else :
self . _on = True
self . SetLabel ( self . _on_label )
self . SetForegroundColour ( ( 0 , 128 , 0 ) )
HC . pubsub . pub ( self . _topic , self . _page_key , True )
def IsOn ( self ) : return self . _on
2013-07-24 20:26:00 +00:00
class PopupMessage ( wx . Window ) :
def __init__ ( self , parent ) :
wx . Window . __init__ ( self , parent , style = wx . BORDER_SIMPLE )
2013-09-04 16:48:44 +00:00
self . Bind ( wx . EVT_RIGHT_DOWN , self . EventDismiss )
2013-07-24 20:26:00 +00:00
def EventDismiss ( self , event ) :
self . GetParent ( ) . Dismiss ( self )
2013-08-14 20:21:49 +00:00
class PopupMessageDismissAll ( PopupMessage ) :
def __init__ ( self , parent ) :
PopupMessage . __init__ ( self , parent )
hbox = wx . BoxSizer ( wx . HORIZONTAL )
self . _text = wx . StaticText ( self )
self . _text . Bind ( wx . EVT_RIGHT_DOWN , self . EventDismiss )
button = wx . Button ( self , label = ' dismiss all ' )
button . Bind ( wx . EVT_BUTTON , self . EventButton )
button . Bind ( wx . EVT_RIGHT_DOWN , self . EventDismiss )
hbox . AddF ( self . _text , FLAGS_MIXED )
hbox . AddF ( button , FLAGS_MIXED )
self . SetSizer ( hbox )
def EventButton ( self , event ) : self . GetParent ( ) . DismissAll ( )
def SetNumMessages ( self , num_messages_pending ) : self . _text . SetLabel ( HC . ConvertIntToPrettyString ( num_messages_pending ) + ' more messages ' )
2013-07-24 20:26:00 +00:00
class PopupMessageError ( PopupMessage ) :
2013-08-14 20:21:49 +00:00
def __init__ ( self , parent , etype , value , trace ) :
2013-07-24 20:26:00 +00:00
PopupMessage . __init__ ( self , parent )
2013-08-14 20:21:49 +00:00
self . _copy_text = HC . u ( etype . __name__ ) + ' : ' + HC . u ( value ) + os . linesep + trace
2013-07-24 20:26:00 +00:00
vbox = wx . BoxSizer ( wx . VERTICAL )
2013-08-14 20:21:49 +00:00
error = wx . StaticText ( self , label = HC . u ( etype . __name__ ) , style = wx . ALIGN_CENTER )
2013-07-24 20:26:00 +00:00
error . Bind ( wx . EVT_RIGHT_DOWN , self . EventDismiss )
2013-08-14 20:21:49 +00:00
text = wx . StaticText ( self , label = HC . u ( value ) )
2013-07-31 21:26:38 +00:00
text . Wrap ( 380 )
2013-07-24 20:26:00 +00:00
text . Bind ( wx . EVT_RIGHT_DOWN , self . EventDismiss )
2013-08-14 20:21:49 +00:00
self . _show_tb_button = wx . Button ( self , label = ' show traceback ' )
self . _show_tb_button . Bind ( wx . EVT_BUTTON , self . EventShowButton )
self . _show_tb_button . Bind ( wx . EVT_RIGHT_DOWN , self . EventDismiss )
self . _tb_text = wx . StaticText ( self , label = trace )
self . _tb_text . Wrap ( 380 )
self . _tb_text . Bind ( wx . EVT_RIGHT_DOWN , self . EventDismiss )
self . _tb_text . Hide ( )
self . _copy_tb_button = wx . Button ( self , label = ' copy info ' )
self . _copy_tb_button . Bind ( wx . EVT_BUTTON , self . EventCopyButton )
self . _copy_tb_button . Bind ( wx . EVT_RIGHT_DOWN , self . EventDismiss )
self . _copy_tb_button . Hide ( )
2013-07-24 20:26:00 +00:00
vbox . AddF ( error , FLAGS_EXPAND_PERPENDICULAR )
vbox . AddF ( text , FLAGS_EXPAND_PERPENDICULAR )
2013-08-14 20:21:49 +00:00
vbox . AddF ( self . _show_tb_button , FLAGS_EXPAND_PERPENDICULAR )
vbox . AddF ( self . _tb_text , FLAGS_EXPAND_PERPENDICULAR )
vbox . AddF ( self . _copy_tb_button , FLAGS_EXPAND_PERPENDICULAR )
2013-07-24 20:26:00 +00:00
self . SetSizer ( vbox )
2013-08-14 20:21:49 +00:00
def EventCopyButton ( self , event ) : HC . pubsub . pub ( ' clipboard ' , ' text ' , self . _copy_text )
def EventShowButton ( self , event ) :
if self . _tb_text . IsShown ( ) :
self . _show_tb_button . SetLabel ( ' show traceback ' )
self . _tb_text . Hide ( )
self . _copy_tb_button . Hide ( )
else :
self . _show_tb_button . SetLabel ( ' hide traceback ' )
self . _tb_text . Show ( )
self . _copy_tb_button . Show ( )
2013-09-11 21:28:19 +00:00
self . GetParent ( ) . MakeSureEverythingFits ( )
2013-08-14 20:21:49 +00:00
2013-07-24 20:26:00 +00:00
class PopupMessageFiles ( PopupMessage ) :
def __init__ ( self , parent , message_string , hashes ) :
PopupMessage . __init__ ( self , parent )
self . _hashes = hashes
vbox = wx . BoxSizer ( wx . VERTICAL )
2013-08-07 22:25:18 +00:00
button = wx . Button ( self , label = message_string )
2013-07-24 20:26:00 +00:00
button . Bind ( wx . EVT_BUTTON , self . EventButton )
2013-08-07 22:25:18 +00:00
button . Bind ( wx . EVT_RIGHT_DOWN , self . EventDismiss )
2013-07-24 20:26:00 +00:00
vbox . AddF ( button , FLAGS_EXPAND_PERPENDICULAR )
self . SetSizer ( vbox )
def EventButton ( self , event ) :
2013-08-28 21:31:52 +00:00
media_results = HC . app . Read ( ' media_results ' , HC . LOCAL_FILE_SERVICE_IDENTIFIER , self . _hashes )
2013-07-24 20:26:00 +00:00
HC . pubsub . pub ( ' new_page_query ' , HC . LOCAL_FILE_SERVICE_IDENTIFIER , initial_media_results = media_results )
2013-09-11 21:28:19 +00:00
class PopupMessageGauge ( PopupMessage ) :
def __init__ ( self , parent , job_key , message_string ) :
PopupMessage . __init__ ( self , parent )
self . _message_string = message_string
self . _job_key = job_key
self . _hashes = set ( )
self . _done = False
vbox = wx . BoxSizer ( wx . VERTICAL )
self . _text = wx . StaticText ( self , label = self . _message_string , style = wx . ALIGN_CENTER )
self . _text . Wrap ( 380 )
self . _text . Bind ( wx . EVT_RIGHT_DOWN , self . EventDismiss )
hbox = wx . BoxSizer ( wx . HORIZONTAL )
self . _gauge = Gauge ( self , size = ( 380 , - 1 ) )
self . _gauge . Bind ( wx . EVT_RIGHT_DOWN , self . EventDismiss )
self . _cancel_button = wx . Button ( self , label = ' cancel ' )
self . _cancel_button . Bind ( wx . EVT_BUTTON , self . EventCancelButton )
self . _cancel_button . Bind ( wx . EVT_RIGHT_DOWN , self . EventDismiss )
hbox . AddF ( self . _gauge , FLAGS_EXPAND_BOTH_WAYS )
hbox . AddF ( self . _cancel_button , FLAGS_MIXED )
self . _show_file_button = wx . Button ( self , label = self . _message_string )
self . _show_file_button . Bind ( wx . EVT_BUTTON , self . EventShowFileButton )
self . _show_file_button . Bind ( wx . EVT_RIGHT_DOWN , self . EventDismiss )
self . _show_file_button . Hide ( )
vbox . AddF ( self . _text , FLAGS_EXPAND_PERPENDICULAR )
vbox . AddF ( hbox , FLAGS_EXPAND_PERPENDICULAR )
vbox . AddF ( self . _show_file_button , FLAGS_EXPAND_PERPENDICULAR )
self . SetSizer ( vbox )
HC . pubsub . sub ( self , ' Failed ' , ' message_gauge_failed ' )
HC . pubsub . sub ( self , ' SetInfo ' , ' message_gauge_info ' )
HC . pubsub . sub ( self , ' Importing ' , ' message_gauge_importing ' )
HC . pubsub . sub ( self , ' Done ' , ' message_gauge_done ' )
def Done ( self , job_key , hashes ) :
if job_key == self . _job_key :
self . _done = True
self . _hashes = hashes
self . _text . Hide ( )
self . _gauge . Hide ( )
self . _show_file_button . Show ( )
self . GetParent ( ) . MakeSureEverythingFits ( )
def EventCancelButton ( self , event ) :
self . _job_key . Cancel ( )
self . GetParent ( ) . Dismiss ( self )
def EventDismiss ( self , event ) :
if not self . _done :
import ClientGUIDialogs
with ClientGUIDialogs . DialogYesNo ( self , ' Do you want to continue the download in the background, or cancel it? ' , yes_label = ' continue ' , no_label = ' cancel ' ) as dlg :
if dlg . ShowModal ( ) != wx . ID_YES : self . _job_key . Cancel ( )
self . GetParent ( ) . Dismiss ( self )
def EventShowFileButton ( self , event ) :
media_results = HC . app . Read ( ' media_results ' , HC . LOCAL_FILE_SERVICE_IDENTIFIER , self . _hashes )
HC . pubsub . pub ( ' new_page_query ' , HC . LOCAL_FILE_SERVICE_IDENTIFIER , initial_media_results = media_results )
def Failed ( self , job_key ) :
if job_key == self . _job_key : self . GetParent ( ) . Dismiss ( self )
def Importing ( self , job_key ) :
if job_key == self . _job_key :
self . _text . SetLabel ( ' importing ' + self . _message_string )
self . _text . Show ( )
self . _gauge . Hide ( )
self . _cancel_button . Hide ( )
self . _show_file_button . Hide ( )
self . GetParent ( ) . MakeSureEverythingFits ( )
def SetInfo ( self , job_key , range , value ) :
if job_key == self . _job_key :
if range is None :
self . _gauge . Pulse ( )
byte_info = HC . ConvertIntToBytes ( value )
else :
self . _gauge . SetRange ( range )
self . _gauge . SetValue ( value )
byte_info = HC . ConvertIntToBytes ( value ) + ' / ' + HC . ConvertIntToBytes ( range )
self . _text . SetLabel ( self . _message_string + ' - ' + byte_info )
self . GetParent ( ) . MakeSureEverythingFits ( )
2013-07-24 20:26:00 +00:00
class PopupMessageText ( PopupMessage ) :
def __init__ ( self , parent , message_string ) :
PopupMessage . __init__ ( self , parent )
vbox = wx . BoxSizer ( wx . VERTICAL )
text = wx . StaticText ( self , label = message_string ) # make this multi-line. There's an easy way to do that, right? A func that takes a pixel width, I think
2013-07-31 21:26:38 +00:00
text . Wrap ( 380 )
2013-07-24 20:26:00 +00:00
text . Bind ( wx . EVT_RIGHT_DOWN , self . EventDismiss )
vbox . AddF ( text , FLAGS_EXPAND_PERPENDICULAR )
self . SetSizer ( vbox )
class PopupMessageManager ( wx . Frame ) :
def __init__ ( self , top_level_parent ) :
wx . Frame . __init__ ( self , top_level_parent , style = wx . FRAME_TOOL_WINDOW | wx . FRAME_NO_TASKBAR | wx . FRAME_FLOAT_ON_PARENT | wx . BORDER_NONE )
self . SetBackgroundColour ( wx . SystemSettings . GetColour ( wx . SYS_COLOUR_BTNFACE ) )
2013-07-31 21:26:38 +00:00
self . _max_messages_to_display = 10
2013-07-24 20:26:00 +00:00
vbox = wx . BoxSizer ( wx . VERTICAL )
2013-08-14 20:21:49 +00:00
self . _message_vbox = wx . BoxSizer ( wx . VERTICAL )
self . _dismiss_all = PopupMessageDismissAll ( self )
self . _dismiss_all . Hide ( )
vbox . AddF ( self . _message_vbox , FLAGS_EXPAND_SIZER_PERPENDICULAR )
vbox . AddF ( self . _dismiss_all , FLAGS_EXPAND_PERPENDICULAR )
2013-07-24 20:26:00 +00:00
self . SetSizer ( vbox )
2013-07-31 21:26:38 +00:00
self . _pending_messages = [ ]
2013-07-24 20:26:00 +00:00
top_level_parent . Bind ( wx . EVT_SIZE , self . EventMove )
top_level_parent . Bind ( wx . EVT_MOVE , self . EventMove )
self . _SizeAndPositionAndShow ( )
HC . pubsub . sub ( self , ' AddMessage ' , ' message ' )
# maybe make a ding noise when a new message arrives
2013-08-14 20:21:49 +00:00
self . _old_excepthook = sys . excepthook
self . _old_show_exception = HC . ShowException
sys . excepthook = CC . CatchExceptionClient
2013-08-28 21:31:52 +00:00
HC . ShowException = CC . ShowExceptionClient
2013-08-14 20:21:49 +00:00
2013-07-31 21:26:38 +00:00
def _CheckPending ( self ) :
2013-08-14 20:21:49 +00:00
num_messages_displayed = self . _message_vbox . GetItemCount ( )
if len ( self . _pending_messages ) > 0 and num_messages_displayed < self . _max_messages_to_display :
2013-07-31 21:26:38 +00:00
message = self . _pending_messages . pop ( 0 )
window = self . _CreateMessageWindow ( message )
2013-08-14 20:21:49 +00:00
self . _message_vbox . AddF ( window , FLAGS_EXPAND_PERPENDICULAR )
2013-07-31 21:26:38 +00:00
2013-08-14 20:21:49 +00:00
num_messages_pending = len ( self . _pending_messages )
if num_messages_pending > 0 :
2013-07-31 21:26:38 +00:00
2013-08-14 20:21:49 +00:00
self . _dismiss_all . SetNumMessages ( num_messages_pending )
2013-07-31 21:26:38 +00:00
2013-08-14 20:21:49 +00:00
self . _dismiss_all . Show ( )
2013-07-31 21:26:38 +00:00
2013-08-14 20:21:49 +00:00
else : self . _dismiss_all . Hide ( )
self . _SizeAndPositionAndShow ( )
2013-07-24 20:26:00 +00:00
def _CreateMessageWindow ( self , message ) :
message_type = message . GetType ( )
info = message . GetInfo ( )
if message_type == HC . MESSAGE_TYPE_TEXT :
message_string = info
window = PopupMessageText ( self , message_string )
elif message_type == HC . MESSAGE_TYPE_ERROR :
2013-08-14 20:21:49 +00:00
( etype , value , trace ) = info
2013-07-24 20:26:00 +00:00
2013-08-14 20:21:49 +00:00
window = PopupMessageError ( self , etype , value , trace )
2013-07-24 20:26:00 +00:00
elif message_type == HC . MESSAGE_TYPE_FILES :
( message_string , hashes ) = info
window = PopupMessageFiles ( self , message_string , hashes )
2013-09-11 21:28:19 +00:00
elif message_type == HC . MESSAGE_TYPE_FILE_DOWNLOAD_GAUGE :
( job_key , message_string ) = info
window = PopupMessageGauge ( self , job_key , message_string )
2013-07-24 20:26:00 +00:00
return window
2013-08-14 20:21:49 +00:00
def _PrintMessage ( self , message ) :
message_type = message . GetType ( )
info = message . GetInfo ( )
if message_type == HC . MESSAGE_TYPE_TEXT :
2013-09-04 16:48:44 +00:00
message_string = HC . u ( info )
2013-08-14 20:21:49 +00:00
elif message_type == HC . MESSAGE_TYPE_ERROR :
( etype , value , trace ) = info
2013-09-04 16:48:44 +00:00
message_string = HC . u ( etype . __name__ ) + ' : ' + HC . u ( value ) + os . linesep + HC . u ( trace )
2013-08-14 20:21:49 +00:00
elif message_type == HC . MESSAGE_TYPE_FILES :
( message_string , hashes ) = info
2013-09-04 16:48:44 +00:00
message_string = HC . u ( message_string )
2013-09-11 21:28:19 +00:00
elif message_type == HC . MESSAGE_TYPE_FILE_DOWNLOAD_GAUGE :
( job_key , message_string ) = info
2013-08-14 20:21:49 +00:00
2013-09-04 16:48:44 +00:00
try : print ( message_string )
except : print ( repr ( message_string ) )
2013-08-14 20:21:49 +00:00
2013-07-24 20:26:00 +00:00
def _SizeAndPositionAndShow ( self ) :
self . Fit ( )
parent = self . GetParent ( )
( parent_width , parent_height ) = parent . GetClientSize ( )
( my_width , my_height ) = self . GetClientSize ( )
my_x = ( parent_width - my_width ) - 5
my_y = ( parent_height - my_height ) - 15
self . SetPosition ( parent . ClientToScreenXY ( my_x , my_y ) )
2013-08-14 20:21:49 +00:00
num_messages_displayed = self . _message_vbox . GetItemCount ( )
if num_messages_displayed > 0 : self . Show ( )
2013-07-24 20:26:00 +00:00
else : self . Hide ( )
def AddMessage ( self , message ) :
2013-08-14 20:21:49 +00:00
self . _PrintMessage ( message )
2013-07-31 21:26:38 +00:00
self . _pending_messages . append ( message )
2013-07-24 20:26:00 +00:00
2013-07-31 21:26:38 +00:00
self . _CheckPending ( )
2013-07-24 20:26:00 +00:00
2013-08-14 20:21:49 +00:00
def CleanUp ( self ) :
2013-07-24 20:26:00 +00:00
2013-08-14 20:21:49 +00:00
sys . excepthook = self . _old_excepthook
2013-07-24 20:26:00 +00:00
2013-08-14 20:21:49 +00:00
HC . ShowException = self . _old_show_exception
2013-07-24 20:26:00 +00:00
2013-09-04 16:48:44 +00:00
self . DismissAll ( )
self . Hide ( )
2013-08-14 20:21:49 +00:00
def Dismiss ( self , window ) :
self . _message_vbox . Detach ( window )
2013-07-24 20:26:00 +00:00
window . Destroy ( )
self . _SizeAndPositionAndShow ( )
2013-07-31 21:26:38 +00:00
self . _CheckPending ( )
2013-07-24 20:26:00 +00:00
2013-08-14 20:21:49 +00:00
def DismissAll ( self ) :
self . _pending_messages = [ ]
sizer_items = self . _message_vbox . GetChildren ( )
for sizer_item in sizer_items :
message_window = sizer_item . GetWindow ( )
self . Dismiss ( message_window )
2013-07-24 20:26:00 +00:00
def EventMove ( self , event ) :
self . _SizeAndPositionAndShow ( )
event . Skip ( )
2013-09-11 21:28:19 +00:00
def MakeSureEverythingFits ( self ) : self . _SizeAndPositionAndShow ( )
2013-04-24 21:23:53 +00:00
class RegexButton ( wx . Button ) :
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 ) :
wx . Button . __init__ ( self , parent , label = ' regex shortcuts ' )
self . Bind ( wx . EVT_BUTTON , self . EventButton )
self . Bind ( wx . EVT_MENU , self . EventMenu )
def EventButton ( 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 )
menu . Destroy ( )
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. ' )
2013-03-15 02:38:12 +00:00
class SaneListCtrl ( wx . ListCtrl , ListCtrlAutoWidthMixin , ColumnSorterMixin ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def __init__ ( self , parent , height , columns ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
num_columns = len ( columns )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
wx . ListCtrl . __init__ ( self , parent , size = ( - 1 , height ) , style = wx . LC_REPORT )
ListCtrlAutoWidthMixin . __init__ ( self )
ColumnSorterMixin . __init__ ( self , num_columns )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . GetTopLevelParent ( ) . SetDoubleBuffered ( False ) # windows double buffer makes listctrls refresh and bug out
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . itemDataMap = { }
self . _next_data_index = 0
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
resize_column = 1
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
for ( i , ( name , width ) ) in enumerate ( columns ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . InsertColumn ( i , name , width = width )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if width == - 1 : resize_column = i + 1
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . setResizeColumn ( resize_column )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def Append ( self , display_tuple , data_tuple ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
index = wx . ListCtrl . Append ( self , display_tuple )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . SetItemData ( index , self . _next_data_index )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . itemDataMap [ self . _next_data_index ] = list ( data_tuple )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _next_data_index + = 1
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def GetAllSelected ( self ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
indices = [ ]
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
i = self . GetFirstSelected ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
while i != - 1 :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
indices . append ( i )
i = self . GetNextSelected ( i )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
return indices
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def GetClientData ( self , index = None ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if index is None :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
data_indicies = [ self . GetItemData ( index ) for index in range ( self . GetItemCount ( ) ) ]
2013-02-19 00:11:43 +00:00
2013-05-08 20:31:00 +00:00
datas = [ tuple ( self . itemDataMap [ data_index ] ) for data_index in data_indicies ]
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
return datas
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
else :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
data_index = self . GetItemData ( index )
2013-02-19 00:11:43 +00:00
2013-05-08 20:31:00 +00:00
return tuple ( self . itemDataMap [ data_index ] )
2013-02-19 00:11:43 +00:00
2013-06-12 22:53:31 +00:00
def GetIndexFromClientData ( self , data ) :
for index in range ( self . GetItemCount ( ) ) :
if self . GetClientData ( index ) == data : return index
raise Exception ( ' Data not found! ' )
2013-03-15 02:38:12 +00:00
def GetListCtrl ( self ) : return self
def RemoveAllSelected ( self ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
indices = self . GetAllSelected ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
indices . reverse ( ) # so we don't screw with the indices of deletees below
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
for index in indices : self . DeleteItem ( index )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def UpdateValue ( self , index , column , display_value , data_value ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . SetStringItem ( index , column , display_value )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
data_index = self . GetItemData ( index )
self . itemDataMap [ data_index ] [ column ] = data_value
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def UpdateRow ( self , index , display_tuple , data_tuple ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
column = 0
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
for value in display_tuple :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . SetStringItem ( index , column , value )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
column + = 1
data_index = self . GetItemData ( index )
self . itemDataMap [ data_index ] = data_tuple
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
class Shortcut ( wx . TextCtrl ) :
def __init__ ( self , parent , modifier = wx . ACCEL_NORMAL , key = wx . WXK_F7 ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _modifier = modifier
self . _key = key
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
wx . TextCtrl . __init__ ( self , parent , style = wx . TE_PROCESS_ENTER )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . Bind ( wx . EVT_KEY_DOWN , self . EventKeyDown )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _SetShortcutString ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def _SetShortcutString ( self ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
display_string = ' '
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if self . _modifier == wx . ACCEL_ALT : display_string + = ' alt + '
elif self . _modifier == wx . ACCEL_CTRL : display_string + = ' ctrl + '
elif self . _modifier == wx . ACCEL_SHIFT : display_string + = ' shift + '
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if self . _key in range ( 65 , 91 ) : display_string + = chr ( self . _key + 32 ) # + 32 for converting ascii A -> a
elif self . _key in range ( 97 , 123 ) : display_string + = chr ( self . _key )
else : display_string + = HC . wxk_code_string_lookup [ self . _key ]
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
wx . TextCtrl . SetValue ( self , display_string )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def EventKeyDown ( self , event ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if event . KeyCode in range ( 65 , 91 ) or event . KeyCode in HC . wxk_code_string_lookup . keys ( ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
modifier = wx . ACCEL_NORMAL
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if event . AltDown ( ) : modifier = wx . ACCEL_ALT
elif event . ControlDown ( ) : modifier = wx . ACCEL_CTRL
elif event . ShiftDown ( ) : modifier = wx . ACCEL_SHIFT
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
( self . _modifier , self . _key ) = HC . GetShortcutFromEvent ( event )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _SetShortcutString ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def GetValue ( self ) : return ( self . _modifier , self . _key )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def SetValue ( self , modifier , key ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
( self . _modifier , self . _key ) = ( modifier , key )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _SetShortcutString ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
class StaticBox ( wx . Panel ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def __init__ ( self , parent , title ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
wx . Panel . __init__ ( self , parent , style = wx . BORDER_DOUBLE )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . SetBackgroundColour ( wx . SystemSettings . GetColour ( wx . SYS_COLOUR_BTNFACE ) )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _sizer = wx . BoxSizer ( wx . VERTICAL )
normal_font = wx . SystemSettings . GetFont ( wx . SYS_DEFAULT_GUI_FONT )
normal_font_size = normal_font . GetPointSize ( )
normal_font_family = normal_font . GetFamily ( )
title_font = wx . Font ( int ( normal_font_size ) , normal_font_family , wx . FONTSTYLE_NORMAL , wx . FONTWEIGHT_BOLD )
title_text = wx . StaticText ( self , label = title , style = wx . ALIGN_CENTER )
title_text . SetFont ( title_font )
self . _sizer . AddF ( title_text , FLAGS_EXPAND_PERPENDICULAR )
self . SetSizer ( self . _sizer )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def AddF ( self , widget , flags ) : self . _sizer . AddF ( widget , flags )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
class AdvancedOptions ( StaticBox ) :
def __init__ ( self , parent , title ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
StaticBox . __init__ ( self , parent , title )
self . _collapsible_panel = wx . CollapsiblePane ( self , label = ' expand ' )
my_panel = self . _collapsible_panel . GetPane ( )
self . _InitPanel ( my_panel )
self . AddF ( self . _collapsible_panel , FLAGS_EXPAND_PERPENDICULAR )
self . Bind ( wx . EVT_COLLAPSIBLEPANE_CHANGED , self . EventChanged )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def _InitPanel ( self , panel ) : pass
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def EventChanged ( self , event ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . GetParent ( ) . Layout ( ) # make this vertical only?
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if self . _collapsible_panel . IsExpanded ( ) : label = ' collapse '
else : label = ' expand '
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _collapsible_panel . SetLabel ( label )
event . Skip ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
class AdvancedHentaiFoundryOptions ( AdvancedOptions ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def __init__ ( self , parent ) : AdvancedOptions . __init__ ( self , parent , ' advanced hentai foundry options ' )
def _InitPanel ( self , panel ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def offensive_choice ( ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
c = wx . Choice ( panel )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
c . Append ( ' none ' , 0 )
c . Append ( ' mild ' , 1 )
c . Append ( ' moderate ' , 2 )
c . Append ( ' strong ' , 3 )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
c . SetSelection ( 3 )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
return c
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _rating_nudity = offensive_choice ( )
self . _rating_violence = offensive_choice ( )
self . _rating_profanity = offensive_choice ( )
self . _rating_racism = offensive_choice ( )
self . _rating_sex = offensive_choice ( )
self . _rating_spoilers = offensive_choice ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _rating_yaoi = wx . CheckBox ( panel )
self . _rating_yuri = wx . CheckBox ( panel )
self . _rating_loli = wx . CheckBox ( panel )
self . _rating_shota = wx . CheckBox ( panel )
self . _rating_teen = wx . CheckBox ( panel )
self . _rating_guro = wx . CheckBox ( panel )
self . _rating_furry = wx . CheckBox ( panel )
self . _rating_beast = wx . CheckBox ( panel )
self . _rating_male = wx . CheckBox ( panel )
self . _rating_female = wx . CheckBox ( panel )
self . _rating_futa = wx . CheckBox ( panel )
self . _rating_other = wx . CheckBox ( panel )
self . _rating_yaoi . SetValue ( True )
self . _rating_yuri . SetValue ( True )
self . _rating_loli . SetValue ( True )
self . _rating_shota . SetValue ( True )
self . _rating_teen . SetValue ( True )
self . _rating_guro . SetValue ( True )
self . _rating_furry . SetValue ( True )
self . _rating_beast . SetValue ( True )
self . _rating_male . SetValue ( True )
self . _rating_female . SetValue ( True )
self . _rating_futa . SetValue ( True )
self . _rating_other . SetValue ( True )
self . _filter_order = wx . Choice ( panel )
self . _filter_order . Append ( ' newest first ' , ' date_new ' )
self . _filter_order . Append ( ' oldest first ' , ' date_old ' )
self . _filter_order . Append ( ' most views first ' , ' views most ' ) # no underscore
self . _filter_order . Append ( ' highest rating first ' , ' rating highest ' ) # no underscore
self . _filter_order . Append ( ' most favourites first ' , ' faves most ' ) # no underscore
self . _filter_order . Append ( ' most popular first ' , ' popularity most ' ) # no underscore
self . _filter_order . SetSelection ( 0 )
gridbox = wx . FlexGridSizer ( 0 , 2 )
gridbox . AddGrowableCol ( 1 , 1 )
gridbox . AddF ( wx . StaticText ( panel , label = ' nudity ' ) , FLAGS_MIXED )
gridbox . AddF ( self . _rating_nudity , FLAGS_EXPAND_BOTH_WAYS )
gridbox . AddF ( wx . StaticText ( panel , label = ' violence ' ) , FLAGS_MIXED )
gridbox . AddF ( self . _rating_violence , FLAGS_EXPAND_BOTH_WAYS )
gridbox . AddF ( wx . StaticText ( panel , label = ' profanity ' ) , FLAGS_MIXED )
gridbox . AddF ( self . _rating_profanity , FLAGS_EXPAND_BOTH_WAYS )
gridbox . AddF ( wx . StaticText ( panel , label = ' racism ' ) , FLAGS_MIXED )
gridbox . AddF ( self . _rating_racism , FLAGS_EXPAND_BOTH_WAYS )
gridbox . AddF ( wx . StaticText ( panel , label = ' sex ' ) , FLAGS_MIXED )
gridbox . AddF ( self . _rating_sex , FLAGS_EXPAND_BOTH_WAYS )
gridbox . AddF ( wx . StaticText ( panel , label = ' spoilers ' ) , FLAGS_MIXED )
gridbox . AddF ( self . _rating_spoilers , FLAGS_EXPAND_BOTH_WAYS )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
gridbox . AddF ( wx . StaticText ( panel , label = ' yaoi ' ) , FLAGS_MIXED )
gridbox . AddF ( self . _rating_yaoi , FLAGS_EXPAND_BOTH_WAYS )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
gridbox . AddF ( wx . StaticText ( panel , label = ' yuri ' ) , FLAGS_MIXED )
gridbox . AddF ( self . _rating_yuri , FLAGS_EXPAND_BOTH_WAYS )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
gridbox . AddF ( wx . StaticText ( panel , label = ' loli ' ) , FLAGS_MIXED )
gridbox . AddF ( self . _rating_loli , FLAGS_EXPAND_BOTH_WAYS )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
gridbox . AddF ( wx . StaticText ( panel , label = ' shota ' ) , FLAGS_MIXED )
gridbox . AddF ( self . _rating_shota , FLAGS_EXPAND_BOTH_WAYS )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
gridbox . AddF ( wx . StaticText ( panel , label = ' teen ' ) , FLAGS_MIXED )
gridbox . AddF ( self . _rating_teen , FLAGS_EXPAND_BOTH_WAYS )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
gridbox . AddF ( wx . StaticText ( panel , label = ' guro ' ) , FLAGS_MIXED )
gridbox . AddF ( self . _rating_guro , FLAGS_EXPAND_BOTH_WAYS )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
gridbox . AddF ( wx . StaticText ( panel , label = ' furry ' ) , FLAGS_MIXED )
gridbox . AddF ( self . _rating_furry , FLAGS_EXPAND_BOTH_WAYS )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
gridbox . AddF ( wx . StaticText ( panel , label = ' beast ' ) , FLAGS_MIXED )
gridbox . AddF ( self . _rating_beast , FLAGS_EXPAND_BOTH_WAYS )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
gridbox . AddF ( wx . StaticText ( panel , label = ' male ' ) , FLAGS_MIXED )
gridbox . AddF ( self . _rating_male , FLAGS_EXPAND_BOTH_WAYS )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
gridbox . AddF ( wx . StaticText ( panel , label = ' female ' ) , FLAGS_MIXED )
gridbox . AddF ( self . _rating_female , FLAGS_EXPAND_BOTH_WAYS )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
gridbox . AddF ( wx . StaticText ( panel , label = ' futa ' ) , FLAGS_MIXED )
gridbox . AddF ( self . _rating_futa , FLAGS_EXPAND_BOTH_WAYS )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
gridbox . AddF ( wx . StaticText ( panel , label = ' other ' ) , FLAGS_MIXED )
gridbox . AddF ( self . _rating_other , FLAGS_EXPAND_BOTH_WAYS )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
gridbox . AddF ( wx . StaticText ( panel , label = ' order ' ) , FLAGS_MIXED )
gridbox . AddF ( self . _filter_order , FLAGS_EXPAND_BOTH_WAYS )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
panel . SetSizer ( gridbox )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def GetInfo ( self ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
info = { }
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
info [ ' rating_nudity ' ] = self . _rating_nudity . GetClientData ( self . _rating_nudity . GetSelection ( ) )
info [ ' rating_violence ' ] = self . _rating_violence . GetClientData ( self . _rating_violence . GetSelection ( ) )
info [ ' rating_profanity ' ] = self . _rating_profanity . GetClientData ( self . _rating_profanity . GetSelection ( ) )
info [ ' rating_racism ' ] = self . _rating_racism . GetClientData ( self . _rating_racism . GetSelection ( ) )
info [ ' rating_sex ' ] = self . _rating_sex . GetClientData ( self . _rating_sex . GetSelection ( ) )
info [ ' rating_spoilers ' ] = self . _rating_spoilers . GetClientData ( self . _rating_spoilers . GetSelection ( ) )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
info [ ' rating_yaoi ' ] = int ( self . _rating_yaoi . GetValue ( ) )
info [ ' rating_yuri ' ] = int ( self . _rating_yuri . GetValue ( ) )
info [ ' rating_loli ' ] = int ( self . _rating_loli . GetValue ( ) )
info [ ' rating_shota ' ] = int ( self . _rating_shota . GetValue ( ) )
info [ ' rating_teen ' ] = int ( self . _rating_teen . GetValue ( ) )
info [ ' rating_guro ' ] = int ( self . _rating_guro . GetValue ( ) )
info [ ' rating_furry ' ] = int ( self . _rating_furry . GetValue ( ) )
info [ ' rating_beast ' ] = int ( self . _rating_beast . GetValue ( ) )
info [ ' rating_male ' ] = int ( self . _rating_male . GetValue ( ) )
info [ ' rating_female ' ] = int ( self . _rating_female . GetValue ( ) )
info [ ' rating_futa ' ] = int ( self . _rating_futa . GetValue ( ) )
info [ ' rating_other ' ] = int ( self . _rating_other . GetValue ( ) )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
info [ ' filter_media ' ] = ' A '
info [ ' filter_order ' ] = self . _filter_order . GetClientData ( self . _filter_order . GetSelection ( ) )
info [ ' filter_type ' ] = 0
return info
2013-02-19 00:11:43 +00:00
2013-04-17 21:48:18 +00:00
def SetInfo ( self , info ) :
self . _rating_nudity . SetSelection ( info [ ' rating_nudity ' ] )
self . _rating_violence . SetSelection ( info [ ' rating_violence ' ] )
self . _rating_profanity . SetSelection ( info [ ' rating_profanity ' ] )
self . _rating_racism . SetSelection ( info [ ' rating_racism ' ] )
self . _rating_sex . SetSelection ( info [ ' rating_sex ' ] )
self . _rating_spoilers . SetSelection ( info [ ' rating_spoilers ' ] )
self . _rating_yaoi . SetValue ( bool ( info [ ' rating_yaoi ' ] ) )
self . _rating_yuri . SetValue ( bool ( info [ ' rating_yuri ' ] ) )
self . _rating_loli . SetValue ( bool ( info [ ' rating_loli ' ] ) )
self . _rating_shota . SetValue ( bool ( info [ ' rating_shota ' ] ) )
self . _rating_teen . SetValue ( bool ( info [ ' rating_teen ' ] ) )
self . _rating_guro . SetValue ( bool ( info [ ' rating_guro ' ] ) )
self . _rating_furry . SetValue ( bool ( info [ ' rating_furry ' ] ) )
self . _rating_beast . SetValue ( bool ( info [ ' rating_beast ' ] ) )
self . _rating_male . SetValue ( bool ( info [ ' rating_male ' ] ) )
self . _rating_female . SetValue ( bool ( info [ ' rating_female ' ] ) )
self . _rating_futa . SetValue ( bool ( info [ ' rating_futa ' ] ) )
self . _rating_other . SetValue ( bool ( info [ ' rating_other ' ] ) )
#info[ 'filter_media' ] = 'A'
self . _filter_order . SetSelection ( info [ ' filter_order ' ] )
#info[ 'filter_type' ] = 0
2013-03-15 02:38:12 +00:00
class AdvancedImportOptions ( AdvancedOptions ) :
2013-04-10 18:10:37 +00:00
def __init__ ( self , parent , initial_settings = { } ) :
self . _initial_settings = initial_settings
AdvancedOptions . __init__ ( self , parent , ' advanced import options ' )
2013-03-15 02:38:12 +00:00
def _InitPanel ( self , panel ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _auto_archive = wx . CheckBox ( panel )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _exclude_deleted = wx . CheckBox ( panel )
2013-02-19 00:11:43 +00:00
2013-07-31 21:26:38 +00:00
self . _min_size = NoneableSpinCtrl ( panel , ' minimum size (KB): ' , multiplier = 1024 )
self . _min_size . SetValue ( 5120 )
2013-02-19 00:11:43 +00:00
2013-07-31 21:26:38 +00:00
self . _min_resolution = NoneableSpinCtrl ( panel , ' minimum resolution: ' , num_dimensions = 2 )
self . _min_resolution . SetValue ( ( 50 , 50 ) )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
hbox1 = wx . BoxSizer ( wx . HORIZONTAL )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
hbox1 . AddF ( self . _auto_archive , FLAGS_MIXED )
hbox1 . AddF ( wx . StaticText ( panel , label = ' archive all imports ' ) , FLAGS_MIXED )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
hbox2 = wx . BoxSizer ( wx . HORIZONTAL )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
hbox2 . AddF ( self . _exclude_deleted , FLAGS_MIXED )
hbox2 . AddF ( wx . StaticText ( panel , label = ' exclude already deleted files ' ) , FLAGS_MIXED )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
vbox = wx . BoxSizer ( wx . VERTICAL )
vbox . AddF ( hbox1 , FLAGS_EXPAND_SIZER_PERPENDICULAR )
vbox . AddF ( hbox2 , FLAGS_EXPAND_SIZER_PERPENDICULAR )
vbox . AddF ( self . _min_size , FLAGS_EXPAND_PERPENDICULAR )
vbox . AddF ( self . _min_resolution , FLAGS_EXPAND_PERPENDICULAR )
panel . SetSizer ( vbox )
2013-02-19 00:11:43 +00:00
2013-04-17 21:48:18 +00:00
self . _SetControls ( self . _initial_settings )
def _SetControls ( self , info ) :
if ' auto_archive ' in info : self . _auto_archive . SetValue ( info [ ' auto_archive ' ] )
else : self . _auto_archive . SetValue ( False )
if ' exclude_deleted_files ' in info : self . _exclude_deleted . SetValue ( info [ ' exclude_deleted_files ' ] )
2013-08-14 20:21:49 +00:00
else : self . _exclude_deleted . SetValue ( HC . options [ ' exclude_deleted_files ' ] )
2013-04-17 21:48:18 +00:00
if ' min_size ' in info : self . _min_size . SetValue ( info [ ' min_size ' ] )
else : self . _min_size . SetValue ( None )
if ' min_resolution ' in info : self . _min_resolution . SetValue ( info [ ' min_resolution ' ] )
else : self . _min_resolution . SetValue ( None )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def GetInfo ( self ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
info = { }
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if self . _auto_archive . GetValue ( ) : info [ ' auto_archive ' ] = True
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if self . _exclude_deleted . GetValue ( ) : info [ ' exclude_deleted_files ' ] = True
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
min_size = self . _min_size . GetValue ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if min_size is not None : info [ ' min_size ' ] = min_size
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
min_resolution = self . _min_resolution . GetValue ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if min_resolution is not None : info [ ' min_resolution ' ] = min_resolution
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
return info
2013-02-19 00:11:43 +00:00
2013-04-17 21:48:18 +00:00
def SetInfo ( self , info ) : self . _SetControls ( info )
2013-03-15 02:38:12 +00:00
class AdvancedTagOptions ( AdvancedOptions ) :
2013-02-19 00:11:43 +00:00
2013-04-10 18:10:37 +00:00
def __init__ ( self , parent , info_string , namespaces = [ ] , initial_settings = { } ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _info_string = info_string
self . _namespaces = namespaces
2013-04-10 18:10:37 +00:00
self . _initial_settings = initial_settings
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
self . _checkboxes_to_service_identifiers = { }
self . _service_identifiers_to_namespaces = { }
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
AdvancedOptions . __init__ ( self , parent , ' advanced tag options ' )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
def _InitPanel ( self , panel ) :
2013-02-19 00:11:43 +00:00
2013-07-10 20:25:57 +00:00
service_identifiers = HC . app . Read ( ' service_identifiers ' , ( HC . TAG_REPOSITORY , HC . LOCAL_TAG ) )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
vbox = wx . BoxSizer ( wx . VERTICAL )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if len ( service_identifiers ) > 0 :
for service_identifier in service_identifiers :
hbox = wx . BoxSizer ( wx . HORIZONTAL )
checkbox = wx . CheckBox ( panel )
2013-04-10 18:10:37 +00:00
if service_identifier in self . _initial_settings : checkbox . SetValue ( True )
2013-03-15 02:38:12 +00:00
checkbox . Bind ( wx . EVT_CHECKBOX , self . EventChecked )
self . _checkboxes_to_service_identifiers [ checkbox ] = service_identifier
hbox . AddF ( wx . StaticText ( panel , label = service_identifier . GetName ( ) ) , FLAGS_MIXED )
hbox . AddF ( checkbox , FLAGS_MIXED )
if len ( self . _namespaces ) > 0 :
namespace_vbox = wx . BoxSizer ( wx . VERTICAL )
self . _service_identifiers_to_namespaces [ service_identifier ] = [ ]
gridbox = wx . FlexGridSizer ( 0 , 2 )
gridbox . AddGrowableCol ( 1 , 1 )
for namespace in self . _namespaces :
if namespace == ' ' : text = wx . StaticText ( panel , label = ' no namespace ' )
else : text = wx . StaticText ( panel , label = namespace )
namespace_checkbox = wx . CheckBox ( panel )
2013-04-10 18:10:37 +00:00
if service_identifier in self . _initial_settings and namespace not in self . _initial_settings [ service_identifier ] : namespace_checkbox . SetValue ( False )
else : namespace_checkbox . SetValue ( True )
2013-03-15 02:38:12 +00:00
namespace_checkbox . Bind ( wx . EVT_CHECKBOX , self . EventChecked )
self . _service_identifiers_to_namespaces [ service_identifier ] . append ( ( namespace , namespace_checkbox ) )
gridbox . AddF ( text , FLAGS_MIXED )
gridbox . AddF ( namespace_checkbox , FLAGS_EXPAND_BOTH_WAYS )
hbox . AddF ( gridbox , FLAGS_MIXED )
vbox . AddF ( hbox , FLAGS_EXPAND_SIZER_PERPENDICULAR )
hbox = wx . BoxSizer ( wx . HORIZONTAL )
hbox . AddF ( wx . StaticText ( panel , label = self . _info_string ) , FLAGS_MIXED )
hbox . AddF ( vbox , FLAGS_EXPAND_SIZER_PERPENDICULAR )
panel . SetSizer ( hbox )
else :
vbox . AddF ( wx . StaticText ( panel , label = ' no tag repositories ' ) , FLAGS_EXPAND_BOTH_WAYS )
panel . SetSizer ( vbox )
2013-02-19 00:11:43 +00:00
2013-04-10 18:10:37 +00:00
def EventChecked ( self , event ) :
wx . PostEvent ( self , wx . CommandEvent ( commandType = wx . wxEVT_COMMAND_MENU_SELECTED , winid = CC . MENU_EVENT_ID_TO_ACTION_CACHE . GetId ( ' advanced_tag_options_changed ' ) ) )
event . Skip ( )
2013-03-15 02:38:12 +00:00
def GetInfo ( self ) :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
service_identifiers = [ self . _checkboxes_to_service_identifiers [ checkbox ] for checkbox in self . _checkboxes_to_service_identifiers . keys ( ) if checkbox . GetValue ( ) ]
2013-04-10 18:10:37 +00:00
result = { }
2013-03-15 02:38:12 +00:00
for service_identifier in service_identifiers :
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
good_namespaces = [ ]
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if service_identifier in self . _service_identifiers_to_namespaces :
namespaces = self . _service_identifiers_to_namespaces [ service_identifier ]
for ( namespace , namespace_checkbox ) in namespaces :
if namespace_checkbox . GetValue ( ) : good_namespaces . append ( namespace )
2013-02-19 00:11:43 +00:00
2013-04-10 18:10:37 +00:00
result [ service_identifier ] = good_namespaces
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
return result
2013-02-19 00:11:43 +00:00
2013-04-17 21:48:18 +00:00
def SetInfo ( self , info ) :
for ( checkbox , service_identifier ) in self . _checkboxes_to_service_identifiers . items ( ) :
if service_identifier in info :
checkbox . SetValue ( True )
for ( namespace , namespace_checkbox ) in self . _service_identifiers_to_namespaces [ service_identifier ] :
if namespace in info [ service_identifier ] : namespace_checkbox . SetValue ( True )
else : namespace_checkbox . SetValue ( False )
else :
checkbox . SetValue ( False )
for ( namespace , namespace_checkbox ) in self . _service_identifiers_to_namespaces [ service_identifier ] : namespace_checkbox . SetValue ( True )
2013-04-03 20:56:07 +00:00
class RadioBox ( StaticBox ) :
def __init__ ( self , parent , title , choice_pairs , initial_index = None ) :
StaticBox . __init__ ( self , parent , title )
self . _indices_to_radio_buttons = { }
self . _radio_buttons_to_data = { }
first_button = True
for ( index , ( text , data ) ) in enumerate ( choice_pairs ) :
if first_button :
style = wx . RB_GROUP
first_button = False
else : style = 0
radio_button = wx . RadioButton ( self , label = text , style = style )
self . AddF ( radio_button , FLAGS_EXPAND_PERPENDICULAR )
self . _indices_to_radio_buttons [ index ] = radio_button
self . _radio_buttons_to_data [ radio_button ] = data
if initial_index is not None and initial_index in self . _indices_to_radio_buttons : self . _indices_to_radio_buttons [ index ] . SetValue ( True )
def GetSelectedClientData ( self ) :
for radio_button in self . _radio_buttons_to_data . keys ( ) :
if radio_button . GetValue ( ) == True : return self . _radio_buttons_to_data [ radio_button ]
def SetSelection ( self , index ) : self . _indices_to_radio_buttons [ index ] . SetValue ( True )
def SetString ( self , index , text ) : self . _indices_to_radio_buttons [ index ] . SetLabel ( text )
2013-02-19 00:11:43 +00:00
class TagsBox ( ListBox ) :
2013-08-14 20:21:49 +00:00
def _GetNamespaceColours ( self ) : return HC . options [ ' namespace_colours ' ]
2013-02-19 00:11:43 +00:00
def _GetTextColour ( self , tag_string ) :
namespace_colours = self . _GetNamespaceColours ( )
if ' : ' in tag_string :
( namespace , sub_tag ) = tag_string . split ( ' : ' , 1 )
if namespace . startswith ( ' - ' ) : namespace = namespace [ 1 : ]
if namespace . startswith ( ' (+) ' ) : namespace = namespace [ 4 : ]
if namespace . startswith ( ' (-) ' ) : namespace = namespace [ 4 : ]
if namespace . startswith ( ' (X) ' ) : namespace = namespace [ 4 : ]
2013-05-15 18:58:14 +00:00
if namespace . startswith ( ' ' ) : namespace = namespace [ 4 : ]
2013-02-19 00:11:43 +00:00
if namespace in namespace_colours : ( r , g , b ) = namespace_colours [ namespace ]
else : ( r , g , b ) = namespace_colours [ None ]
else : ( r , g , b ) = namespace_colours [ ' ' ]
return ( r , g , b )
2013-07-24 20:26:00 +00:00
def EventMenu ( self , event ) :
action = CC . MENU_EVENT_ID_TO_ACTION_CACHE . GetAction ( event . GetId ( ) )
if action is not None :
2013-08-14 20:21:49 +00:00
( command , data ) = action
if command == ' copy ' : HC . pubsub . pub ( ' clipboard ' , ' text ' , data )
elif command in ( ' parent ' , ' sibling ' ) :
2013-07-24 20:26:00 +00:00
2013-08-14 20:21:49 +00:00
tag = data
2013-07-24 20:26:00 +00:00
2013-08-14 20:21:49 +00:00
import ClientGUIDialogsManage
if command == ' parent ' :
2013-07-24 20:26:00 +00:00
2013-08-14 20:21:49 +00:00
with ClientGUIDialogsManage . DialogManageTagParents ( self , tag ) as dlg : dlg . ShowModal ( )
2013-07-24 20:26:00 +00:00
2013-08-14 20:21:49 +00:00
elif command == ' sibling ' :
2013-07-24 20:26:00 +00:00
2013-08-14 20:21:49 +00:00
with ClientGUIDialogsManage . DialogManageTagSiblings ( self , tag ) as dlg : dlg . ShowModal ( )
2013-07-24 20:26:00 +00:00
2013-08-14 20:21:49 +00:00
else :
event . Skip ( )
2013-07-24 20:26:00 +00:00
2013-08-14 20:21:49 +00:00
return # this is about select_up and select_down
2013-07-24 20:26:00 +00:00
def EventMouseRightClick ( self , event ) :
index = self . _GetIndexUnderMouse ( event )
self . _Select ( index )
if self . _current_selected_index is not None :
menu = wx . Menu ( )
term = self . _strings_to_terms [ self . _ordered_strings [ self . _current_selected_index ] ]
menu . Append ( CC . MENU_EVENT_ID_TO_ACTION_CACHE . GetId ( ' copy ' , term ) , ' copy ' + term )
if ' : ' in term :
sub_term = term . split ( ' : ' , 1 ) [ 1 ]
menu . Append ( CC . MENU_EVENT_ID_TO_ACTION_CACHE . GetId ( ' copy ' , sub_term ) , ' copy ' + sub_term )
menu . AppendSeparator ( )
menu . Append ( CC . MENU_EVENT_ID_TO_ACTION_CACHE . GetId ( ' parent ' , term ) , ' add parent to ' + term )
menu . Append ( CC . MENU_EVENT_ID_TO_ACTION_CACHE . GetId ( ' sibling ' , term ) , ' add sibling to ' + term )
self . PopupMenu ( menu )
menu . Destroy ( )
event . Skip ( )
2013-02-19 00:11:43 +00:00
class TagsBoxActiveOnly ( TagsBox ) :
def __init__ ( self , parent , callable ) :
TagsBox . __init__ ( self , parent )
self . _callable = callable
2013-03-27 20:02:51 +00:00
self . _predicates = { }
2013-02-19 00:11:43 +00:00
2013-05-08 20:31:00 +00:00
def _Activate ( self , s , term ) : self . _callable ( term )
2013-02-19 00:11:43 +00:00
2013-05-15 18:58:14 +00:00
def _Select ( self , index ) :
if index is not None :
if self . _current_selected_index is None : direction = 1
elif index - self . _current_selected_index in ( - 1 , 1 ) : direction = index - self . _current_selected_index
else : direction = 1
if index == - 1 or index > len ( self . _ordered_strings ) : index = len ( self . _ordered_strings ) - 1
elif index == len ( self . _ordered_strings ) or index < - 1 : index = 0
s = self . _ordered_strings [ index ]
new_term = self . _strings_to_terms [ s ]
while new_term . GetPredicateType ( ) == HC . PREDICATE_TYPE_PARENT :
index + = direction
if index == - 1 or index > len ( self . _ordered_strings ) : index = len ( self . _ordered_strings ) - 1
elif index == len ( self . _ordered_strings ) or index < - 1 : index = 0
s = self . _ordered_strings [ index ]
new_term = self . _strings_to_terms [ s ]
ListBox . _Select ( self , index )
2013-03-27 20:02:51 +00:00
def SetPredicates ( self , predicates ) :
2013-02-19 00:11:43 +00:00
2013-05-08 20:31:00 +00:00
# need to do a clever compare, since normal predicate compare doesn't take count into account
they_are_the_same = True
if len ( predicates ) == len ( self . _predicates ) :
p_list_1 = list ( predicates )
p_list_2 = list ( self . _predicates )
p_list_1 . sort ( )
p_list_2 . sort ( )
for index in range ( len ( p_list_1 ) ) :
p_1 = p_list_1 [ index ]
p_2 = p_list_2 [ index ]
if p_1 != p_2 or p_1 . GetCount ( ) != p_2 . GetCount ( ) :
they_are_the_same = False
break
else : they_are_the_same = False
if not they_are_the_same :
2013-02-19 00:11:43 +00:00
2013-03-27 20:02:51 +00:00
self . _predicates = predicates
2013-02-19 00:11:43 +00:00
self . _ordered_strings = [ ]
self . _strings_to_terms = { }
2013-03-27 20:02:51 +00:00
for predicate in predicates :
2013-02-19 00:11:43 +00:00
2013-03-27 20:02:51 +00:00
tag_string = predicate . GetUnicode ( )
2013-02-19 00:11:43 +00:00
self . _ordered_strings . append ( tag_string )
2013-03-27 20:02:51 +00:00
self . _strings_to_terms [ tag_string ] = predicate
2013-02-19 00:11:43 +00:00
self . _TextsHaveChanged ( )
2013-03-27 20:02:51 +00:00
if len ( predicates ) > 0 : self . _Select ( 0 )
2013-02-19 00:11:43 +00:00
class TagsBoxCPP ( TagsBox ) :
def __init__ ( self , parent , page_key ) :
TagsBox . __init__ ( self , parent , min_height = 200 )
2013-08-14 20:21:49 +00:00
self . _sort = HC . options [ ' default_tag_sort ' ]
2013-02-19 00:11:43 +00:00
self . _page_key = page_key
2013-05-29 20:19:54 +00:00
self . _tag_service_identifier = HC . COMBINED_TAG_SERVICE_IDENTIFIER
2013-02-19 00:11:43 +00:00
self . _last_media = None
2013-08-28 21:31:52 +00:00
self . _current_tags_to_count = collections . Counter ( )
self . _pending_tags_to_count = collections . Counter ( )
self . _petitioned_tags_to_count = collections . Counter ( )
2013-02-19 00:11:43 +00:00
HC . pubsub . sub ( self , ' SetTagsByMedia ' , ' new_tags_selection ' )
HC . pubsub . sub ( self , ' ChangeTagRepository ' , ' change_tag_repository ' )
2013-05-08 20:31:00 +00:00
def _Activate ( self , s , term ) :
2013-03-27 20:02:51 +00:00
2013-05-08 20:31:00 +00:00
predicate = HC . Predicate ( HC . PREDICATE_TYPE_TAG , ( ' + ' , term ) , None )
2013-03-27 20:02:51 +00:00
HC . pubsub . pub ( ' add_predicate ' , self . _page_key , predicate )
2013-02-19 00:11:43 +00:00
2013-08-28 21:31:52 +00:00
def _RecalcStrings ( self ) :
siblings_manager = HC . app . GetTagSiblingsManager ( )
all_current = ( tag for tag in self . _current_tags_to_count if self . _current_tags_to_count [ tag ] > 0 )
all_pending = ( tag for tag in self . _pending_tags_to_count if self . _pending_tags_to_count [ tag ] > 0 )
all_petitioned = ( tag for tag in self . _petitioned_tags_to_count if self . _petitioned_tags_to_count [ tag ] > 0 )
all_tags = set ( itertools . chain ( all_current , all_pending , all_petitioned ) )
self . _ordered_strings = [ ]
self . _strings_to_terms = { }
for tag in all_tags :
tag_string = tag
if tag in self . _current_tags_to_count : tag_string + = ' ( ' + HC . ConvertIntToPrettyString ( self . _current_tags_to_count [ tag ] ) + ' ) '
if tag in self . _pending_tags_to_count : tag_string + = ' (+ ' + HC . ConvertIntToPrettyString ( self . _pending_tags_to_count [ tag ] ) + ' ) '
if tag in self . _petitioned_tags_to_count : tag_string + = ' (- ' + HC . ConvertIntToPrettyString ( self . _petitioned_tags_to_count [ tag ] ) + ' ) '
sibling = siblings_manager . GetSibling ( tag )
if sibling is not None : tag_string + = ' ( ' + sibling + ' ) '
self . _ordered_strings . append ( tag_string )
self . _strings_to_terms [ tag_string ] = tag
self . _SortTags ( )
2013-02-19 00:11:43 +00:00
def _SortTags ( self ) :
if self . _sort == CC . SORT_BY_LEXICOGRAPHIC_ASC : compare_function = lambda a , b : cmp ( a , b )
elif self . _sort == CC . SORT_BY_LEXICOGRAPHIC_DESC : compare_function = lambda a , b : cmp ( b , a )
elif self . _sort in ( CC . SORT_BY_INCIDENCE_ASC , CC . SORT_BY_INCIDENCE_DESC ) :
tags_to_count = collections . defaultdict ( lambda : 0 )
tags_to_count . update ( self . _current_tags_to_count )
2013-03-15 02:38:12 +00:00
for ( tag , count ) in self . _pending_tags_to_count . items ( ) : tags_to_count [ tag ] + = count
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
if self . _sort == CC . SORT_BY_INCIDENCE_ASC : compare_function = lambda a , b : cmp ( ( tags_to_count [ self . _strings_to_terms [ a ] ] , a ) , ( tags_to_count [ self . _strings_to_terms [ b ] ] , b ) )
elif self . _sort == CC . SORT_BY_INCIDENCE_DESC : compare_function = lambda a , b : cmp ( ( tags_to_count [ self . _strings_to_terms [ b ] ] , a ) , ( tags_to_count [ self . _strings_to_terms [ a ] ] , b ) )
2013-02-19 00:11:43 +00:00
self . _ordered_strings . sort ( compare_function )
self . _TextsHaveChanged ( )
def ChangeTagRepository ( self , page_key , service_identifier ) :
if page_key == self . _page_key :
self . _tag_service_identifier = service_identifier
if self . _last_media is not None : self . SetTagsByMedia ( self . _page_key , self . _last_media )
def SetSort ( self , sort ) :
self . _sort = sort
self . _SortTags ( )
def SetTags ( self , current_tags_to_count , pending_tags_to_count , petitioned_tags_to_count ) :
2013-07-10 20:25:57 +00:00
siblings_manager = HC . app . GetTagSiblingsManager ( )
2013-05-08 20:31:00 +00:00
current_tags_to_count = siblings_manager . CollapseTagsToCount ( current_tags_to_count )
2013-08-28 21:31:52 +00:00
self . _current_tags_to_count = current_tags_to_count
self . _pending_tags_to_count = pending_tags_to_count
self . _petitioned_tags_to_count = petitioned_tags_to_count
self . _RecalcStrings ( )
def SetTagsByMedia ( self , page_key , media , force_reload = False ) :
if page_key == self . _page_key :
2013-02-19 00:11:43 +00:00
2013-08-28 21:31:52 +00:00
media = set ( media )
2013-02-19 00:11:43 +00:00
2013-08-28 21:31:52 +00:00
if force_reload :
( current_tags_to_count , deleted_tags_to_count , pending_tags_to_count , petitioned_tags_to_count ) = CC . GetMediasTagCount ( media , self . _tag_service_identifier )
self . SetTags ( current_tags_to_count , pending_tags_to_count , petitioned_tags_to_count )
else :
2013-02-19 00:11:43 +00:00
2013-08-28 21:31:52 +00:00
if self . _last_media is None : ( removees , adds ) = ( set ( ) , media )
else :
removees = self . _last_media . difference ( media )
adds = media . difference ( self . _last_media )
2013-02-19 00:11:43 +00:00
2013-08-28 21:31:52 +00:00
siblings_manager = HC . app . GetTagSiblingsManager ( )
2013-02-19 00:11:43 +00:00
2013-08-28 21:31:52 +00:00
( current_tags_to_count , deleted_tags_to_count , pending_tags_to_count , petitioned_tags_to_count ) = CC . GetMediasTagCount ( removees , self . _tag_service_identifier )
2013-05-08 20:31:00 +00:00
2013-08-28 21:31:52 +00:00
current_tags_to_count = siblings_manager . CollapseTagsToCount ( current_tags_to_count )
2013-05-08 20:31:00 +00:00
2013-08-28 21:31:52 +00:00
self . _current_tags_to_count . subtract ( current_tags_to_count )
self . _pending_tags_to_count . subtract ( pending_tags_to_count )
self . _petitioned_tags_to_count . subtract ( petitioned_tags_to_count )
( current_tags_to_count , deleted_tags_to_count , pending_tags_to_count , petitioned_tags_to_count ) = CC . GetMediasTagCount ( adds , self . _tag_service_identifier )
current_tags_to_count = siblings_manager . CollapseTagsToCount ( current_tags_to_count )
self . _current_tags_to_count . update ( current_tags_to_count )
self . _pending_tags_to_count . update ( pending_tags_to_count )
self . _petitioned_tags_to_count . update ( petitioned_tags_to_count )
2013-02-19 00:11:43 +00:00
self . _last_media = media
2013-08-28 21:31:52 +00:00
self . _RecalcStrings ( )
2013-02-19 00:11:43 +00:00
2013-03-15 02:38:12 +00:00
class TagsBoxCPPWithSorter ( StaticBox ) :
2013-02-19 00:11:43 +00:00
def __init__ ( self , parent , page_key ) :
2013-03-15 02:38:12 +00:00
StaticBox . __init__ ( self , parent , ' selection tags ' )
2013-02-19 00:11:43 +00:00
self . _sorter = wx . Choice ( self )
self . _sorter . Append ( ' lexicographic (a-z) ' , CC . SORT_BY_LEXICOGRAPHIC_ASC )
self . _sorter . Append ( ' lexicographic (z-a) ' , CC . SORT_BY_LEXICOGRAPHIC_DESC )
self . _sorter . Append ( ' incidence (desc) ' , CC . SORT_BY_INCIDENCE_DESC )
self . _sorter . Append ( ' incidence (asc) ' , CC . SORT_BY_INCIDENCE_ASC )
2013-08-14 20:21:49 +00:00
if HC . options [ ' default_tag_sort ' ] == CC . SORT_BY_LEXICOGRAPHIC_ASC : self . _sorter . Select ( 0 )
elif HC . options [ ' default_tag_sort ' ] == CC . SORT_BY_LEXICOGRAPHIC_DESC : self . _sorter . Select ( 1 )
elif HC . options [ ' default_tag_sort ' ] == CC . SORT_BY_INCIDENCE_DESC : self . _sorter . Select ( 2 )
elif HC . options [ ' default_tag_sort ' ] == CC . SORT_BY_INCIDENCE_ASC : self . _sorter . Select ( 3 )
2013-02-19 00:11:43 +00:00
self . _sorter . Bind ( wx . EVT_CHOICE , self . EventSort )
self . _tags_box = TagsBoxCPP ( self , page_key )
2013-03-15 02:38:12 +00:00
self . AddF ( self . _sorter , FLAGS_EXPAND_PERPENDICULAR )
self . AddF ( self . _tags_box , FLAGS_EXPAND_BOTH_WAYS )
2013-02-19 00:11:43 +00:00
def EventSort ( self , event ) :
selection = self . _sorter . GetSelection ( )
if selection != wx . NOT_FOUND :
sort = self . _sorter . GetClientData ( selection )
self . _tags_box . SetSort ( sort )
class TagsBoxFlat ( TagsBox ) :
def __init__ ( self , parent , removed_callable ) :
TagsBox . __init__ ( self , parent )
self . _removed_callable = removed_callable
2013-05-29 20:19:54 +00:00
self . _tags = set ( )
2013-02-19 00:11:43 +00:00
def _RecalcTags ( self ) :
2013-05-08 20:31:00 +00:00
self . _strings_to_terms = { }
2013-07-10 20:25:57 +00:00
siblings_manager = HC . app . GetTagSiblingsManager ( )
2013-05-08 20:31:00 +00:00
for tag in self . _tags :
tag_string = tag
sibling = siblings_manager . GetSibling ( tag )
if sibling is not None : tag_string + = ' ( ' + sibling + ' ) '
self . _strings_to_terms [ tag_string ] = tag
self . _ordered_strings = self . _strings_to_terms . keys ( )
2013-02-19 00:11:43 +00:00
self . _ordered_strings . sort ( )
self . _TextsHaveChanged ( )
2013-05-29 20:19:54 +00:00
def _Activate ( self , s , tag ) :
2013-02-19 00:11:43 +00:00
2013-05-29 20:19:54 +00:00
if tag in self . _tags :
2013-05-08 20:31:00 +00:00
2013-05-29 20:19:54 +00:00
self . _tags . discard ( tag )
2013-05-08 20:31:00 +00:00
self . _RecalcTags ( )
self . _removed_callable ( tag )
2013-02-19 00:11:43 +00:00
2013-05-29 20:19:54 +00:00
def AddTag ( self , tag , parents ) :
2013-02-19 00:11:43 +00:00
2013-05-29 20:19:54 +00:00
if tag in self . _tags : self . _tags . discard ( tag )
else :
self . _tags . add ( tag )
self . _tags . update ( parents )
2013-02-19 00:11:43 +00:00
self . _RecalcTags ( )
2013-05-08 20:31:00 +00:00
def GetTags ( self ) : return self . _tags
2013-02-19 00:11:43 +00:00
def SetTags ( self , tags ) :
2013-05-08 20:31:00 +00:00
self . _tags = tags
2013-02-19 00:11:43 +00:00
self . _RecalcTags ( )
class TagsBoxManage ( TagsBox ) :
def __init__ ( self , parent , callable , current_tags , deleted_tags , pending_tags , petitioned_tags ) :
TagsBox . __init__ ( self , parent )
self . _callable = callable
self . _current_tags = set ( current_tags )
self . _deleted_tags = set ( deleted_tags )
self . _pending_tags = set ( pending_tags )
self . _petitioned_tags = set ( petitioned_tags )
self . _RebuildTagStrings ( )
2013-05-08 20:31:00 +00:00
def _Activate ( self , s , term ) : self . _callable ( term )
2013-02-19 00:11:43 +00:00
def _RebuildTagStrings ( self ) :
2013-07-10 20:25:57 +00:00
siblings_manager = HC . app . GetTagSiblingsManager ( )
2013-05-08 20:31:00 +00:00
2013-07-03 18:49:26 +00:00
all_tags = self . _current_tags | self . _deleted_tags | self . _pending_tags | self . _petitioned_tags
2013-02-19 00:11:43 +00:00
self . _ordered_strings = [ ]
self . _strings_to_terms = { }
for tag in all_tags :
2013-06-12 22:53:31 +00:00
if tag in self . _petitioned_tags : prefix = HC . ConvertStatusToPrefix ( HC . PETITIONED )
elif tag in self . _current_tags : prefix = HC . ConvertStatusToPrefix ( HC . CURRENT )
elif tag in self . _pending_tags :
if tag in self . _deleted_tags : prefix = HC . ConvertStatusToPrefix ( HC . DELETED_PENDING )
else : prefix = HC . ConvertStatusToPrefix ( HC . PENDING )
else : prefix = HC . ConvertStatusToPrefix ( HC . DELETED )
2013-06-19 20:25:06 +00:00
tag_string = prefix + tag
2013-02-19 00:11:43 +00:00
2013-05-08 20:31:00 +00:00
sibling = siblings_manager . GetSibling ( tag )
if sibling is not None : tag_string + = ' ( ' + sibling + ' ) '
2013-02-19 00:11:43 +00:00
self . _ordered_strings . append ( tag_string )
self . _strings_to_terms [ tag_string ] = tag
self . _ordered_strings . sort ( )
self . _TextsHaveChanged ( )
def PetitionTag ( self , tag ) :
self . _petitioned_tags . add ( tag )
self . _RebuildTagStrings ( )
def PendTag ( self , tag ) :
self . _pending_tags . add ( tag )
self . _RebuildTagStrings ( )
def RescindPetition ( self , tag ) :
self . _petitioned_tags . discard ( tag )
self . _RebuildTagStrings ( )
def RescindPend ( self , tag ) :
self . _pending_tags . discard ( tag )
self . _RebuildTagStrings ( )
class TagsBoxOptions ( TagsBox ) :
def __init__ ( self , parent , initial_namespace_colours ) :
TagsBox . __init__ ( self , parent )
self . _namespace_colours = dict ( initial_namespace_colours )
for namespace in self . _namespace_colours :
if namespace is None : namespace_string = ' default namespace:tag '
elif namespace == ' ' : namespace_string = ' unnamespaced tag '
else : namespace_string = namespace + ' :tag '
self . _ordered_strings . append ( namespace_string )
self . _strings_to_terms [ namespace_string ] = namespace
self . _TextsHaveChanged ( )
2013-05-08 20:31:00 +00:00
def _Activate ( self , s , term ) : self . RemoveNamespace ( term )
2013-02-19 00:11:43 +00:00
def _GetNamespaceColours ( self ) : return self . _namespace_colours
def SetNamespaceColour ( self , namespace , colour ) :
if namespace not in self . _namespace_colours :
namespace_string = namespace + ' :tag '
self . _ordered_strings . append ( namespace_string )
self . _strings_to_terms [ namespace_string ] = namespace
self . _ordered_strings . sort ( )
self . _namespace_colours [ namespace ] = colour . Get ( )
self . _TextsHaveChanged ( )
def GetNamespaceColours ( self ) : return self . _namespace_colours
def GetSelectedNamespaceColour ( self ) :
if self . _current_selected_index is not None :
namespace_string = self . _ordered_strings [ self . _current_selected_index ]
namespace = self . _strings_to_terms [ namespace_string ]
( r , g , b ) = self . _namespace_colours [ namespace ]
colour = wx . Colour ( r , g , b )
return ( namespace , colour )
return None
def RemoveNamespace ( self , namespace ) :
if namespace is not None and namespace != ' ' :
namespace_string = namespace + ' :tag '
self . _ordered_strings . remove ( namespace_string )
del self . _strings_to_terms [ namespace_string ]
del self . _namespace_colours [ namespace ]
self . _TextsHaveChanged ( )
class TagsBoxPredicates ( TagsBox ) :
def __init__ ( self , parent , page_key , initial_predicates = [ ] ) :
TagsBox . __init__ ( self , parent , min_height = 100 )
self . _page_key = page_key
if len ( initial_predicates ) > 0 :
for predicate in initial_predicates :
2013-04-10 18:10:37 +00:00
predicate_string = predicate . GetUnicode ( )
self . _ordered_strings . append ( predicate_string )
self . _strings_to_terms [ predicate_string ] = predicate
2013-02-19 00:11:43 +00:00
self . _TextsHaveChanged ( )
2013-05-08 20:31:00 +00:00
def _Activate ( self , s , term ) : HC . pubsub . pub ( ' remove_predicate ' , self . _page_key , term )
2013-02-19 00:11:43 +00:00
2013-03-27 20:02:51 +00:00
def AddPredicate ( self , predicate ) :
2013-02-19 00:11:43 +00:00
2013-03-27 20:02:51 +00:00
predicate = predicate . GetCountlessCopy ( )
2013-02-19 00:11:43 +00:00
2013-03-27 20:02:51 +00:00
predicate_string = predicate . GetUnicode ( )
2013-02-19 00:11:43 +00:00
2013-04-03 20:56:07 +00:00
inbox_predicate = HC . SYSTEM_PREDICATE_INBOX
archive_predicate = HC . SYSTEM_PREDICATE_ARCHIVE
2013-02-19 00:11:43 +00:00
2013-03-27 20:02:51 +00:00
if predicate == inbox_predicate and self . HasPredicate ( archive_predicate ) : self . RemovePredicate ( archive_predicate )
elif predicate == archive_predicate and self . HasPredicate ( inbox_predicate ) : self . RemovePredicate ( inbox_predicate )
2013-04-03 20:56:07 +00:00
local_predicate = HC . SYSTEM_PREDICATE_LOCAL
not_local_predicate = HC . SYSTEM_PREDICATE_NOT_LOCAL
2013-03-27 20:02:51 +00:00
if predicate == local_predicate and self . HasPredicate ( not_local_predicate ) : self . RemovePredicate ( not_local_predicate )
elif predicate == not_local_predicate and self . HasPredicate ( local_predicate ) : self . RemovePredicate ( local_predicate )
self . _ordered_strings . append ( predicate_string )
self . _strings_to_terms [ predicate_string ] = predicate
2013-02-19 00:11:43 +00:00
self . _ordered_strings . sort ( )
self . _TextsHaveChanged ( )
2013-03-27 20:02:51 +00:00
def GetPredicates ( self ) : return self . _strings_to_terms . values ( )
2013-02-19 00:11:43 +00:00
2013-03-27 20:02:51 +00:00
def HasPredicate ( self , predicate ) : return predicate in self . _strings_to_terms . values ( )
2013-02-19 00:11:43 +00:00
def RemovePredicate ( self , predicate ) :
2013-03-27 20:02:51 +00:00
for ( s , existing_predicate ) in self . _strings_to_terms . items ( ) :
if existing_predicate == predicate :
self . _ordered_strings . remove ( s )
del self . _strings_to_terms [ s ]
self . _TextsHaveChanged ( )
break
2013-02-19 00:11:43 +00:00