hydrus/include/ClientGUIListBoxes.py

2719 lines
80 KiB
Python
Raw Normal View History

2017-02-01 21:11:17 +00:00
import ClientCaches
import ClientConstants as CC
import ClientData
2017-04-05 21:16:40 +00:00
import ClientGUICommon
2017-03-15 20:13:04 +00:00
import ClientGUIMenus
2017-02-01 21:11:17 +00:00
import ClientSearch
2017-03-22 22:38:15 +00:00
import ClientTags
2017-02-01 21:11:17 +00:00
import collections
import HydrusConstants as HC
import HydrusData
2017-03-22 22:38:15 +00:00
import HydrusExceptions
2017-05-10 21:33:58 +00:00
import HydrusGlobals as HG
2017-02-01 21:11:17 +00:00
import HydrusTags
import os
import wx
2017-11-29 21:48:23 +00:00
( ListBoxEvent, EVT_LIST_BOX ) = wx.lib.newevent.NewCommandEvent()
2018-01-24 23:09:42 +00:00
class AddEditDeleteListBox( wx.Panel ):
def __init__( self, parent, height_num_chars, data_to_pretty_callable, add_callable, edit_callable ):
self._data_to_pretty_callable = data_to_pretty_callable
self._add_callable = add_callable
self._edit_callable = edit_callable
wx.Panel.__init__( self, parent )
self._listbox = wx.ListBox( self, style = wx.LB_EXTENDED )
self._add_button = ClientGUICommon.BetterButton( self, 'add', self._Add )
self._edit_button = ClientGUICommon.BetterButton( self, 'edit', self._Edit )
self._delete_button = ClientGUICommon.BetterButton( self, 'delete', self._Delete )
#
vbox = wx.BoxSizer( wx.VERTICAL )
buttons_hbox = wx.BoxSizer( wx.HORIZONTAL )
buttons_hbox.Add( self._add_button, CC.FLAGS_EXPAND_BOTH_WAYS )
buttons_hbox.Add( self._edit_button, CC.FLAGS_EXPAND_BOTH_WAYS )
buttons_hbox.Add( self._delete_button, CC.FLAGS_EXPAND_BOTH_WAYS )
vbox.Add( self._listbox, CC.FLAGS_EXPAND_BOTH_WAYS )
vbox.Add( buttons_hbox, CC.FLAGS_EXPAND_PERPENDICULAR )
self.SetSizer( vbox )
#
( width, height ) = ClientData.ConvertTextToPixels( self._listbox, ( 20, height_num_chars ) )
self._listbox.SetInitialSize( ( width, height ) )
#
self._listbox.Bind( wx.EVT_LISTBOX, self.EventSelection )
self._listbox.Bind( wx.EVT_LISTBOX_DCLICK, self.EventEdit )
def _Add( self ):
( result, data ) = self._add_callable()
if result:
self._AddData( data )
def _AddData( self, data ):
pretty_data = self._data_to_pretty_callable( data )
self._listbox.Append( pretty_data, data )
def _Delete( self ):
indices = list( self._listbox.GetSelections() )
if len( indices ) == 0:
return
indices.sort( reverse = True )
import ClientGUIDialogs
with ClientGUIDialogs.DialogYesNo( self, 'Remove all selected?' ) as dlg_yn:
if dlg_yn.ShowModal() == wx.ID_YES:
for i in indices:
self._listbox.Delete( i )
2018-02-21 21:59:37 +00:00
wx.QueueEvent( self.GetEventHandler(), ListBoxEvent( -1 ) )
2018-01-24 23:09:42 +00:00
def _Edit( self ):
for i in range( self._listbox.GetCount() ):
if not self._listbox.IsSelected( i ):
continue
data = self._listbox.GetClientData( i )
( result, new_data ) = self._edit_callable( data )
if result:
self._listbox.Delete( i )
pretty_new_data = self._data_to_pretty_callable( new_data )
self._listbox.Insert( pretty_new_data, i, new_data )
else:
break
2018-02-21 21:59:37 +00:00
wx.QueueEvent( self.GetEventHandler(), ListBoxEvent( -1 ) )
2018-01-24 23:09:42 +00:00
def AddDatas( self, datas ):
for data in datas:
self._AddData( data )
2018-02-21 21:59:37 +00:00
wx.QueueEvent( self.GetEventHandler(), ListBoxEvent( -1 ) )
2018-01-24 23:09:42 +00:00
def Bind( self, event, handler ):
self._listbox.Bind( event, handler )
def EventEdit( self, event ):
self._Edit()
def EventSelection( self, event ):
if len( self._listbox.GetSelections() ) == 0:
self._edit_button.Disable()
self._delete_button.Disable()
else:
self._edit_button.Enable()
self._delete_button.Enable()
event.Skip()
def GetCount( self ):
return self._listbox.GetCount()
def GetData( self, only_selected = False ):
datas = []
for i in range( self._listbox.GetCount() ):
data = self._listbox.GetClientData( i )
datas.append( data )
return datas
2017-09-27 21:52:54 +00:00
class QueueListBox( wx.Panel ):
2017-12-13 22:33:07 +00:00
def __init__( self, parent, data_to_pretty_callable, add_callable = None, edit_callable = None ):
2017-09-27 21:52:54 +00:00
self._data_to_pretty_callable = data_to_pretty_callable
self._add_callable = add_callable
self._edit_callable = edit_callable
wx.Panel.__init__( self, parent )
2017-11-29 21:48:23 +00:00
self._listbox = wx.ListBox( self, style = wx.LB_EXTENDED )
2017-09-27 21:52:54 +00:00
self._up_button = ClientGUICommon.BetterButton( self, u'\u2191', self._Up )
self._delete_button = ClientGUICommon.BetterButton( self, 'X', self._Delete )
self._down_button = ClientGUICommon.BetterButton( self, u'\u2193', self._Down )
self._add_button = ClientGUICommon.BetterButton( self, 'add', self._Add )
self._edit_button = ClientGUICommon.BetterButton( self, 'edit', self._Edit )
2017-12-13 22:33:07 +00:00
if self._add_callable is None:
self._add_button.Hide()
if self._edit_callable is None:
self._edit_button.Hide()
2017-09-27 21:52:54 +00:00
#
vbox = wx.BoxSizer( wx.VERTICAL )
buttons_vbox = wx.BoxSizer( wx.VERTICAL )
2018-01-03 22:37:30 +00:00
buttons_vbox.Add( self._up_button, CC.FLAGS_VCENTER )
buttons_vbox.Add( self._delete_button, CC.FLAGS_VCENTER )
buttons_vbox.Add( self._down_button, CC.FLAGS_VCENTER )
2017-09-27 21:52:54 +00:00
hbox = wx.BoxSizer( wx.HORIZONTAL )
2018-01-03 22:37:30 +00:00
hbox.Add( self._listbox, CC.FLAGS_EXPAND_BOTH_WAYS )
hbox.Add( buttons_vbox, CC.FLAGS_VCENTER )
2017-09-27 21:52:54 +00:00
buttons_hbox = wx.BoxSizer( wx.HORIZONTAL )
2018-01-03 22:37:30 +00:00
buttons_hbox.Add( self._add_button, CC.FLAGS_EXPAND_BOTH_WAYS )
buttons_hbox.Add( self._edit_button, CC.FLAGS_EXPAND_BOTH_WAYS )
2017-09-27 21:52:54 +00:00
2018-01-03 22:37:30 +00:00
vbox.Add( hbox, CC.FLAGS_EXPAND_BOTH_WAYS )
vbox.Add( buttons_hbox, CC.FLAGS_EXPAND_PERPENDICULAR )
2017-09-27 21:52:54 +00:00
self.SetSizer( vbox )
#
self._listbox.Bind( wx.EVT_LISTBOX, self.EventSelection )
2017-11-29 21:48:23 +00:00
self._listbox.Bind( wx.EVT_LISTBOX_DCLICK, self.EventEdit )
2017-09-27 21:52:54 +00:00
def _Add( self ):
( result, data ) = self._add_callable()
if result:
self._AddData( data )
def _AddData( self, data ):
pretty_data = self._data_to_pretty_callable( data )
self._listbox.Append( pretty_data, data )
def _Delete( self ):
2017-11-29 21:48:23 +00:00
indices = list( self._listbox.GetSelections() )
2017-09-27 21:52:54 +00:00
if len( indices ) == 0:
return
2017-11-29 21:48:23 +00:00
indices.sort( reverse = True )
2017-09-27 21:52:54 +00:00
import ClientGUIDialogs
with ClientGUIDialogs.DialogYesNo( self, 'Remove all selected?' ) as dlg_yn:
if dlg_yn.ShowModal() == wx.ID_YES:
for i in indices:
self._listbox.Delete( i )
2018-02-21 21:59:37 +00:00
wx.QueueEvent( self.GetEventHandler(), ListBoxEvent( -1 ) )
2017-11-29 21:48:23 +00:00
2017-09-27 21:52:54 +00:00
def _Down( self ):
2017-11-29 21:48:23 +00:00
indices = list( self._listbox.GetSelections() )
2017-09-27 21:52:54 +00:00
indices.sort( reverse = True )
for i in indices:
2017-11-29 21:48:23 +00:00
if i < self._listbox.GetCount() - 1:
2017-09-27 21:52:54 +00:00
if not self._listbox.IsSelected( i + 1 ): # is the one below not selected?
self._SwapRows( i, i + 1 )
2018-02-21 21:59:37 +00:00
wx.QueueEvent( self.GetEventHandler(), ListBoxEvent( -1 ) )
2017-11-29 21:48:23 +00:00
2017-09-27 21:52:54 +00:00
def _Edit( self ):
for i in range( self._listbox.GetCount() ):
if not self._listbox.IsSelected( i ):
continue
data = self._listbox.GetClientData( i )
( result, new_data ) = self._edit_callable( data )
if result:
self._listbox.Delete( i )
pretty_new_data = self._data_to_pretty_callable( new_data )
2017-11-29 21:48:23 +00:00
self._listbox.Insert( pretty_new_data, i, new_data )
2017-09-27 21:52:54 +00:00
else:
break
2018-02-21 21:59:37 +00:00
wx.QueueEvent( self.GetEventHandler(), ListBoxEvent( -1 ) )
2017-11-29 21:48:23 +00:00
2017-09-27 21:52:54 +00:00
def _SwapRows( self, index_a, index_b ):
2017-11-29 21:48:23 +00:00
a_was_selected = self._listbox.IsSelected( index_a )
b_was_selected = self._listbox.IsSelected( index_b )
2017-09-27 21:52:54 +00:00
data_a = self._listbox.GetClientData( index_a )
data_b = self._listbox.GetClientData( index_b )
pretty_data_a = self._data_to_pretty_callable( data_a )
pretty_data_b = self._data_to_pretty_callable( data_b )
self._listbox.Delete( index_a )
self._listbox.Insert( pretty_data_b, index_a, data_b )
self._listbox.Delete( index_b )
self._listbox.Insert( pretty_data_a, index_b, data_a )
2017-11-29 21:48:23 +00:00
if b_was_selected:
self._listbox.Select( index_a )
if a_was_selected:
self._listbox.Select( index_b )
2017-09-27 21:52:54 +00:00
def _Up( self ):
indices = self._listbox.GetSelections()
for i in indices:
if i > 0:
if not self._listbox.IsSelected( i - 1 ): # is the one above not selected?
self._SwapRows( i, i - 1 )
2018-02-21 21:59:37 +00:00
wx.QueueEvent( self.GetEventHandler(), ListBoxEvent( -1 ) )
2017-11-29 21:48:23 +00:00
2017-09-27 21:52:54 +00:00
def AddDatas( self, datas ):
for data in datas:
self._AddData( data )
2018-02-21 21:59:37 +00:00
wx.QueueEvent( self.GetEventHandler(), ListBoxEvent( -1 ) )
2017-11-29 21:48:23 +00:00
2017-09-27 21:52:54 +00:00
def Bind( self, event, handler ):
self._listbox.Bind( event, handler )
2017-11-29 21:48:23 +00:00
def EventEdit( self, event ):
self._Edit()
2017-09-27 21:52:54 +00:00
def EventSelection( self, event ):
2017-11-29 21:48:23 +00:00
if len( self._listbox.GetSelections() ) == 0:
2017-09-27 21:52:54 +00:00
self._up_button.Disable()
self._delete_button.Disable()
self._down_button.Disable()
self._edit_button.Disable()
else:
self._up_button.Enable()
self._delete_button.Enable()
self._down_button.Enable()
self._edit_button.Enable()
event.Skip()
2017-12-13 22:33:07 +00:00
def GetCount( self ):
return self._listbox.GetCount()
2017-09-27 21:52:54 +00:00
def GetData( self, only_selected = False ):
datas = []
for i in range( self._listbox.GetCount() ):
data = self._listbox.GetClientData( i )
datas.append( data )
return datas
2017-12-13 22:33:07 +00:00
def Pop( self ):
if self._listbox.GetCount() == 0:
return None
data = self._listbox.GetClientData( 0 )
self._listbox.Delete( 0 )
return data
2017-02-01 21:11:17 +00:00
class ListBox( wx.ScrolledWindow ):
TEXT_X_PADDING = 3
2017-09-06 20:18:20 +00:00
def __init__( self, parent, min_height = 150 ):
2017-02-01 21:11:17 +00:00
wx.ScrolledWindow.__init__( self, parent, style = wx.VSCROLL | wx.BORDER_DOUBLE )
self._background_colour = wx.Colour( 255, 255, 255 )
2017-03-22 22:38:15 +00:00
self._terms = set()
self._ordered_terms = []
2017-02-01 21:11:17 +00:00
self._selected_terms = set()
2017-03-22 22:38:15 +00:00
self._terms_to_texts = {}
2017-02-01 21:11:17 +00:00
self._last_hit_index = None
self._last_view_start = None
self._dirty = True
2018-01-03 22:37:30 +00:00
self._client_bmp = wx.Bitmap( 20, 20, 24 )
2017-03-22 22:38:15 +00:00
2017-02-01 21:11:17 +00:00
dc = wx.MemoryDC( self._client_bmp )
dc.SetFont( wx.SystemSettings.GetFont( wx.SYS_DEFAULT_GUI_FONT ) )
( text_x, self._text_y ) = dc.GetTextExtent( 'abcdefghijklmnopqrstuvwxyz' )
self._num_rows_per_page = 0
self.SetScrollRate( 0, self._text_y )
self.SetMinSize( ( 50, min_height ) )
self.Bind( wx.EVT_PAINT, self.EventPaint )
self.Bind( wx.EVT_SIZE, self.EventResize )
self.Bind( wx.EVT_ERASE_BACKGROUND, self.EventEraseBackground )
self.Bind( wx.EVT_LEFT_DOWN, self.EventMouseSelect )
self.Bind( wx.EVT_LEFT_DCLICK, self.EventDClick )
2017-04-19 20:58:30 +00:00
self.Bind( wx.EVT_CHAR_HOOK, self.EventCharHook )
2017-02-01 21:11:17 +00:00
def __len__( self ):
2017-03-22 22:38:15 +00:00
return len( self._ordered_terms )
2017-02-01 21:11:17 +00:00
def _Activate( self ):
2017-03-29 19:39:34 +00:00
pass
def _DeleteActivate( self ):
pass
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
def _AppendTerm( self, term ):
2017-03-29 19:39:34 +00:00
was_selected_before = term in self._selected_terms
2017-03-22 22:38:15 +00:00
if term in self._terms:
self._RemoveTerm( term )
self._terms.add( term )
self._ordered_terms.append( term )
self._terms_to_texts[ term ] = self._GetTextFromTerm( term )
2017-03-29 19:39:34 +00:00
if was_selected_before:
self._selected_terms.add( term )
2017-03-22 22:38:15 +00:00
def _Clear( self ):
self._terms = set()
self._ordered_terms = []
self._selected_terms = set()
self._terms_to_texts = {}
self._last_hit_index = None
self._last_view_start = None
self._dirty = True
def _DataHasChanged( self ):
2018-01-10 22:41:51 +00:00
self._SetVirtualSize()
2018-01-03 22:37:30 +00:00
self._SetDirty()
2017-03-22 22:38:15 +00:00
2018-02-21 21:59:37 +00:00
wx.QueueEvent( self.GetEventHandler(), ListBoxEvent( -1 ) )
2017-11-22 21:03:07 +00:00
2017-03-22 22:38:15 +00:00
2017-02-01 21:11:17 +00:00
def _Deselect( self, index ):
2017-03-22 22:38:15 +00:00
term = self._GetTerm( index )
2017-02-01 21:11:17 +00:00
self._selected_terms.discard( term )
2017-03-22 22:38:15 +00:00
def _DeselectAll( self ):
self._selected_terms = set()
2017-02-01 21:11:17 +00:00
def _GetIndexUnderMouse( self, mouse_event ):
( xUnit, yUnit ) = self.GetScrollPixelsPerUnit()
( x_scroll, y_scroll ) = self.GetViewStart()
y_offset = y_scroll * yUnit
y = mouse_event.GetY() + y_offset
row_index = ( y / self._text_y )
2017-03-22 22:38:15 +00:00
if row_index >= len( self._ordered_terms ):
2017-02-01 21:11:17 +00:00
return None
return row_index
def _GetSelectedIncludeExcludePredicates( self ):
include_predicates = []
exclude_predicates = []
for term in self._selected_terms:
if isinstance( term, ClientSearch.Predicate ):
predicate_type = term.GetType()
if predicate_type in ( HC.PREDICATE_TYPE_TAG, HC.PREDICATE_TYPE_NAMESPACE, HC.PREDICATE_TYPE_WILDCARD ):
value = term.GetValue()
include_predicates.append( ClientSearch.Predicate( predicate_type, value ) )
exclude_predicates.append( ClientSearch.Predicate( predicate_type, value, False ) )
else:
include_predicates.append( term )
else:
s = term
include_predicates.append( ClientSearch.Predicate( HC.PREDICATE_TYPE_TAG, term ) )
exclude_predicates.append( ClientSearch.Predicate( HC.PREDICATE_TYPE_TAG, term, False ) )
return ( include_predicates, exclude_predicates )
2017-03-22 22:38:15 +00:00
def _GetTerm( self, index ):
if index < 0 or index > len( self._ordered_terms ) - 1:
raise HydrusExceptions.DataMissing( 'No term for index ' + str( index ) )
return self._ordered_terms[ index ]
def _GetTextColour( self, term ):
return ( 0, 111, 250 )
2018-01-31 22:58:15 +00:00
def _GetSafeHitIndex( self, hit_index, direction = None ):
if hit_index is not None:
if hit_index == -1 or hit_index > len( self._ordered_terms ):
hit_index = len( self._ordered_terms ) - 1
elif hit_index == len( self._ordered_terms ) or hit_index < -1:
hit_index = 0
return hit_index
2017-03-22 22:38:15 +00:00
def _GetSimplifiedTextFromTerm( self, term ):
return self._GetTextFromTerm( term )
def _GetTextFromTerm( self, term ):
raise NotImplementedError()
2017-02-01 21:11:17 +00:00
def _HandleClick( self, event ):
hit_index = self._GetIndexUnderMouse( event )
shift = event.ShiftDown()
ctrl = event.CmdDown()
self._Hit( shift, ctrl, hit_index )
def _Hit( self, shift, ctrl, hit_index ):
2018-01-31 22:58:15 +00:00
hit_index = self._GetSafeHitIndex( hit_index )
2017-02-01 21:11:17 +00:00
to_select = set()
to_deselect = set()
2017-03-22 22:38:15 +00:00
deselect_all = False
2017-02-01 21:11:17 +00:00
if shift:
if hit_index is not None:
if self._last_hit_index is not None:
lower = min( hit_index, self._last_hit_index )
upper = max( hit_index, self._last_hit_index )
to_select = range( lower, upper + 1 )
else:
to_select.add( hit_index )
elif ctrl:
if hit_index is not None:
2017-03-22 22:38:15 +00:00
if self._IsSelected( hit_index ):
2017-02-01 21:11:17 +00:00
to_deselect.add( hit_index )
else:
to_select.add( hit_index )
else:
if hit_index is None:
2017-03-22 22:38:15 +00:00
deselect_all = True
2017-02-01 21:11:17 +00:00
else:
2017-03-22 22:38:15 +00:00
if not self._IsSelected( hit_index ):
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
deselect_all = True
2017-02-01 21:11:17 +00:00
to_select.add( hit_index )
2017-03-22 22:38:15 +00:00
if deselect_all:
self._DeselectAll()
2017-02-01 21:11:17 +00:00
for index in to_select:
self._Select( index )
for index in to_deselect:
self._Deselect( index )
self._last_hit_index = hit_index
if self._last_hit_index is not None:
y = self._text_y * self._last_hit_index
( start_x, start_y ) = self.GetViewStart()
( x_unit, y_unit ) = self.GetScrollPixelsPerUnit()
( width, height ) = self.GetClientSize()
if y < start_y * y_unit:
y_to_scroll_to = y / y_unit
2018-01-31 22:58:15 +00:00
#self.Scroll( -1, y_to_scroll_to )
2017-02-01 21:11:17 +00:00
2018-02-21 21:59:37 +00:00
wx.QueueEvent( self.GetEventHandler(), wx.ScrollWinEvent( wx.wxEVT_SCROLLWIN_THUMBRELEASE, pos = y_to_scroll_to ) )
2017-02-01 21:11:17 +00:00
elif y > ( start_y * y_unit ) + height - self._text_y:
y_to_scroll_to = ( y - height ) / y_unit
2018-01-31 22:58:15 +00:00
#self.Scroll( -1, y_to_scroll_to + 2 )
2017-02-01 21:11:17 +00:00
2018-02-21 21:59:37 +00:00
wx.QueueEvent( self.GetEventHandler(), wx.ScrollWinEvent( wx.wxEVT_SCROLLWIN_THUMBRELEASE, pos = y_to_scroll_to + 2 ) )
2017-02-01 21:11:17 +00:00
self._SetDirty()
2017-03-22 22:38:15 +00:00
def _IsSelected( self, index ):
try:
term = self._GetTerm( index )
except HydrusExceptions.DataMissing:
return False
return term in self._selected_terms
2017-02-01 21:11:17 +00:00
def _Redraw( self, dc ):
( xUnit, yUnit ) = self.GetScrollPixelsPerUnit()
( x_scroll, y_scroll ) = self.GetViewStart()
self._last_view_start = self.GetViewStart()
y_offset = y_scroll * yUnit
( my_width, my_height ) = self.GetClientSize()
first_visible_index = y_offset / self._text_y
last_visible_index = ( y_offset + my_height ) / self._text_y
if ( y_offset + my_height ) % self._text_y != 0:
last_visible_index += 1
2017-03-22 22:38:15 +00:00
last_visible_index = min( last_visible_index, len( self._ordered_terms ) - 1 )
2017-02-01 21:11:17 +00:00
dc.SetFont( wx.SystemSettings.GetFont( wx.SYS_DEFAULT_GUI_FONT ) )
dc.SetBackground( wx.Brush( self._background_colour ) )
dc.Clear()
for ( i, current_index ) in enumerate( range( first_visible_index, last_visible_index + 1 ) ):
2017-03-22 22:38:15 +00:00
term = self._GetTerm( current_index )
text = self._terms_to_texts[ term ]
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
( r, g, b ) = self._GetTextColour( term )
2017-02-01 21:11:17 +00:00
text_colour = wx.Colour( r, g, b )
2017-03-22 22:38:15 +00:00
if term in self._selected_terms:
2017-02-01 21:11:17 +00:00
dc.SetBrush( wx.Brush( text_colour ) )
dc.SetPen( wx.TRANSPARENT_PEN )
dc.DrawRectangle( 0, i * self._text_y, my_width, self._text_y )
text_colour = self._background_colour
dc.SetTextForeground( text_colour )
( x, y ) = ( self.TEXT_X_PADDING, i * self._text_y )
dc.DrawText( text, x, y )
self._dirty = False
2017-03-22 22:38:15 +00:00
def _RefreshTexts( self ):
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
self._terms_to_texts = { term : self._GetTextFromTerm( term ) for term in self._terms }
self._SetDirty()
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
def _RemoveSelectedTerms( self ):
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
for term in list( self._selected_terms ):
self._RemoveTerm( term )
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
def _RemoveTerm( self, term ):
if term in self._terms:
self._terms.discard( term )
self._ordered_terms.remove( term )
self._selected_terms.discard( term )
del self._terms_to_texts[ term ]
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
def _Select( self, index ):
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
term = self._GetTerm( index )
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
self._selected_terms.add( term )
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
def _SelectAll( self ):
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
self._selected_terms = set( self._terms )
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
def _SetDirty( self ):
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
self._dirty = True
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
self.Refresh()
2018-01-10 22:41:51 +00:00
def _SetVirtualSize( self ):
( my_x, my_y ) = self.GetClientSize()
ideal_virtual_size = ( my_x, max( self._text_y * len( self._ordered_terms ), my_y ) )
if ideal_virtual_size != self.GetVirtualSize():
self.SetVirtualSize( ideal_virtual_size )
2017-03-22 22:38:15 +00:00
def _SortByText( self ):
def lexicographic_key( term ):
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
return self._terms_to_texts[ term ]
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
self._ordered_terms.sort( key = lexicographic_key )
2017-02-01 21:11:17 +00:00
2017-04-19 20:58:30 +00:00
def EventCharHook( self, event ):
2017-02-01 21:11:17 +00:00
shift = event.ShiftDown()
ctrl = event.CmdDown()
key_code = event.GetKeyCode()
2017-04-05 21:16:40 +00:00
if ClientGUICommon.WindowHasFocus( self ) and key_code in CC.DELETE_KEYS:
2017-03-29 19:39:34 +00:00
self._DeleteActivate()
elif key_code in ( wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER ):
2017-02-01 21:11:17 +00:00
self._Activate()
else:
if ctrl and key_code in ( ord( 'A' ), ord( 'a' ) ):
2017-03-22 22:38:15 +00:00
self._SelectAll()
self._SetDirty()
2017-02-01 21:11:17 +00:00
else:
hit_index = None
2017-04-05 21:16:40 +00:00
if len( self._ordered_terms ) > 1:
2017-02-01 21:11:17 +00:00
2018-01-31 22:58:15 +00:00
roll_up = False
roll_down = False
2017-02-01 21:11:17 +00:00
if key_code in ( wx.WXK_HOME, wx.WXK_NUMPAD_HOME ):
hit_index = 0
elif key_code in ( wx.WXK_END, wx.WXK_NUMPAD_END ):
2017-03-22 22:38:15 +00:00
hit_index = len( self._ordered_terms ) - 1
2017-02-01 21:11:17 +00:00
2018-01-31 22:58:15 +00:00
roll_up = True
2017-02-01 21:11:17 +00:00
elif self._last_hit_index is not None:
if key_code in ( wx.WXK_UP, wx.WXK_NUMPAD_UP ):
hit_index = self._last_hit_index - 1
2018-01-31 22:58:15 +00:00
roll_up = True
2017-02-01 21:11:17 +00:00
elif key_code in ( wx.WXK_DOWN, wx.WXK_NUMPAD_DOWN ):
hit_index = self._last_hit_index + 1
2018-01-31 22:58:15 +00:00
roll_down = True
2017-02-01 21:11:17 +00:00
elif key_code in ( wx.WXK_PAGEUP, wx.WXK_NUMPAD_PAGEUP ):
hit_index = max( 0, self._last_hit_index - self._num_rows_per_page )
2018-01-31 22:58:15 +00:00
roll_up = True
2017-02-01 21:11:17 +00:00
elif key_code in ( wx.WXK_PAGEDOWN, wx.WXK_NUMPAD_PAGEDOWN ):
2017-03-22 22:38:15 +00:00
hit_index = min( len( self._ordered_terms ) - 1, self._last_hit_index + self._num_rows_per_page )
2017-02-01 21:11:17 +00:00
2018-01-31 22:58:15 +00:00
roll_down = True
2017-02-01 21:11:17 +00:00
if hit_index is None:
event.Skip()
else:
2018-01-31 22:58:15 +00:00
if roll_up:
hit_index = self._GetSafeHitIndex( hit_index, -1 )
if roll_down:
hit_index = self._GetSafeHitIndex( hit_index, 1 )
2017-02-01 21:11:17 +00:00
self._Hit( shift, ctrl, hit_index )
2017-04-19 20:58:30 +00:00
def EventDClick( self, event ):
self._Activate()
def EventEraseBackground( self, event ): pass
2017-02-01 21:11:17 +00:00
def EventMouseSelect( self, event ):
self._HandleClick( event )
event.Skip()
def EventPaint( self, event ):
( my_x, my_y ) = self.GetClientSize()
if ( my_x, my_y ) != self._client_bmp.GetSize():
2018-01-03 22:37:30 +00:00
self._client_bmp = wx.Bitmap( my_x, my_y, 24 )
2017-02-01 21:11:17 +00:00
self._dirty = True
dc = wx.BufferedPaintDC( self, self._client_bmp )
if self._dirty or self._last_view_start != self.GetViewStart():
self._Redraw( dc )
def EventResize( self, event ):
( my_x, my_y ) = self.GetClientSize()
self._num_rows_per_page = my_y / self._text_y
2018-01-10 22:41:51 +00:00
self._SetVirtualSize()
2017-02-01 21:11:17 +00:00
self._SetDirty()
2017-03-22 22:38:15 +00:00
def GetClientData( self, index = None ):
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
if index is None:
return set( self._terms )
else:
return self._GetTerm( index )
2017-02-01 21:11:17 +00:00
def GetIdealHeight( self ):
2017-03-22 22:38:15 +00:00
return self._text_y * len( self._ordered_terms ) + 20
2017-02-01 21:11:17 +00:00
2018-01-31 22:58:15 +00:00
def MoveSelectionDown( self ):
if len( self._ordered_terms ) > 1 and self._last_hit_index is not None:
self._Hit( False, False, self._last_hit_index + 1 )
def MoveSelectionUp( self ):
if len( self._ordered_terms ) > 1 and self._last_hit_index is not None:
self._Hit( False, False, self._last_hit_index - 1 )
2017-02-01 21:11:17 +00:00
class ListBoxTags( ListBox ):
has_counts = False
can_spawn_new_windows = True
def __init__( self, *args, **kwargs ):
ListBox.__init__( self, *args, **kwargs )
2017-03-22 22:38:15 +00:00
self._get_current_predicates_callable = None
2017-02-01 21:11:17 +00:00
2017-09-20 19:47:31 +00:00
self._UpdateBackgroundColour()
2017-02-01 21:11:17 +00:00
self.Bind( wx.EVT_RIGHT_DOWN, self.EventMouseRightClick )
self.Bind( wx.EVT_MIDDLE_DOWN, self.EventMouseMiddleClick )
2017-05-10 21:33:58 +00:00
HG.client_controller.sub( self, 'SiblingsHaveChanged', 'notify_new_siblings_gui' )
2017-09-20 19:47:31 +00:00
HG.client_controller.sub( self, '_UpdateBackgroundColour', 'notify_new_colourset' )
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
def _GetNamespaceColours( self ):
return HC.options[ 'namespace_colours' ]
2017-02-01 21:11:17 +00:00
def _GetAllTagsForClipboard( self, with_counts = False ):
2017-03-29 19:39:34 +00:00
texts = list( self._terms_to_texts.values() )
texts.sort()
return texts
2017-03-22 22:38:15 +00:00
def _GetNamespaceFromTerm( self, term ):
raise NotImplementedError()
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
def _GetTextColour( self, term ):
2017-02-01 21:11:17 +00:00
namespace_colours = self._GetNamespaceColours()
2017-03-22 22:38:15 +00:00
namespace = self._GetNamespaceFromTerm( term )
2017-02-08 22:27:00 +00:00
2017-03-22 22:38:15 +00:00
if namespace in namespace_colours:
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
( r, g, b ) = namespace_colours[ namespace ]
2017-02-08 22:27:00 +00:00
else:
2017-03-22 22:38:15 +00:00
( r, g, b ) = namespace_colours[ None ]
2017-02-01 21:11:17 +00:00
return ( r, g, b )
def _NewSearchPage( self ):
predicates = []
for term in self._selected_terms:
if isinstance( term, ClientSearch.Predicate ):
predicates.append( term )
else:
predicates.append( ClientSearch.Predicate( HC.PREDICATE_TYPE_TAG, term ) )
2017-05-10 21:33:58 +00:00
predicates = HG.client_controller.GetGUI().FlushOutPredicates( predicates )
2017-02-01 21:11:17 +00:00
if len( predicates ) > 0:
2017-05-10 21:33:58 +00:00
HG.client_controller.pub( 'new_page_query', CC.LOCAL_FILE_SERVICE_KEY, initial_predicates = predicates )
2017-02-01 21:11:17 +00:00
2017-09-20 19:47:31 +00:00
def _ProcessMenuCopyEvent( self, command ):
2017-02-01 21:11:17 +00:00
2017-09-20 19:47:31 +00:00
if command in ( 'copy_terms', 'copy_sub_terms' ):
2017-02-01 21:11:17 +00:00
2017-09-20 19:47:31 +00:00
texts = []
2017-02-01 21:11:17 +00:00
2017-09-20 19:47:31 +00:00
for term in self._selected_terms:
2017-02-01 21:11:17 +00:00
2017-09-20 19:47:31 +00:00
if isinstance( term, ClientSearch.Predicate ):
2017-02-01 21:11:17 +00:00
2017-09-20 19:47:31 +00:00
text = term.GetUnicode( with_count = False )
2017-02-01 21:11:17 +00:00
2017-09-20 19:47:31 +00:00
else:
2017-02-01 21:11:17 +00:00
2017-09-20 19:47:31 +00:00
text = HydrusData.ToUnicode( term )
2017-02-01 21:11:17 +00:00
2017-09-20 19:47:31 +00:00
if command == 'copy_sub_terms':
2017-02-01 21:11:17 +00:00
2017-09-20 19:47:31 +00:00
( namespace_gumpf, text ) = HydrusTags.SplitTag( text )
2017-02-01 21:11:17 +00:00
2017-09-20 19:47:31 +00:00
texts.append( text )
2017-02-01 21:11:17 +00:00
2017-09-20 19:47:31 +00:00
texts.sort()
text = os.linesep.join( texts )
elif command == 'copy_all_tags':
text = os.linesep.join( self._GetAllTagsForClipboard( with_counts = False ) )
elif command == 'copy_all_tags_with_counts':
text = os.linesep.join( self._GetAllTagsForClipboard( with_counts = True ) )
HG.client_controller.pub( 'clipboard', 'text', text )
def _ProcessMenuPredicateEvent( self, command ):
pass
def _ProcessMenuTagEvent( self, command ):
import ClientGUIDialogsManage
if command == 'censorship':
( tag, ) = self._selected_terms
with ClientGUIDialogsManage.DialogManageTagCensorship( self, tag ) as dlg:
2017-02-01 21:11:17 +00:00
2017-09-20 19:47:31 +00:00
dlg.ShowModal()
2017-02-01 21:11:17 +00:00
2017-09-20 19:47:31 +00:00
elif command == 'parent':
with ClientGUIDialogsManage.DialogManageTagParents( self, self._selected_terms ) as dlg:
2017-02-01 21:11:17 +00:00
2017-09-20 19:47:31 +00:00
dlg.ShowModal()
2017-02-01 21:11:17 +00:00
2017-09-20 19:47:31 +00:00
elif command == 'sibling':
with ClientGUIDialogsManage.DialogManageTagSiblings( self, self._selected_terms ) as dlg:
2017-02-01 21:11:17 +00:00
2017-09-20 19:47:31 +00:00
dlg.ShowModal()
2017-02-01 21:11:17 +00:00
2017-09-20 19:47:31 +00:00
def _UpdateBackgroundColour( self ):
2017-12-06 22:06:56 +00:00
new_options = HG.client_controller.new_options
2017-09-20 19:47:31 +00:00
self._background_colour = new_options.GetColour( CC.COLOUR_TAGS_BOX )
self.Refresh()
2017-02-01 21:11:17 +00:00
def EventMouseMiddleClick( self, event ):
self._HandleClick( event )
if self.can_spawn_new_windows:
self._NewSearchPage()
def EventMouseRightClick( self, event ):
self._HandleClick( event )
2017-03-22 22:38:15 +00:00
if len( self._ordered_terms ) > 0:
2017-02-01 21:11:17 +00:00
menu = wx.Menu()
if len( self._selected_terms ) > 0:
if len( self._selected_terms ) == 1:
( term, ) = self._selected_terms
if isinstance( term, ClientSearch.Predicate ):
if term.GetType() == HC.PREDICATE_TYPE_TAG:
selection_string = '"' + term.GetValue() + '"'
else:
selection_string = '"' + term.GetUnicode( with_count = False ) + '"'
else:
selection_string = '"' + HydrusData.ToUnicode( term ) + '"'
else:
selection_string = 'selected'
2017-03-22 22:38:15 +00:00
if self._get_current_predicates_callable is not None:
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
current_predicates = self._get_current_predicates_callable()
2017-02-01 21:11:17 +00:00
( include_predicates, exclude_predicates ) = self._GetSelectedIncludeExcludePredicates()
if current_predicates is not None:
if True in ( include_predicate in current_predicates for include_predicate in include_predicates ):
2017-09-20 19:47:31 +00:00
ClientGUIMenus.AppendMenuItem( self, menu, 'discard ' + selection_string + ' from current search', 'Remove the selected predicates from the current search.', self._ProcessMenuPredicateEvent, 'remove_include_predicates' )
2017-02-01 21:11:17 +00:00
if True in ( include_predicate not in current_predicates for include_predicate in include_predicates ):
2017-09-20 19:47:31 +00:00
ClientGUIMenus.AppendMenuItem( self, menu, 'require ' + selection_string + ' for current search', 'Add the selected predicates from the current search.', self._ProcessMenuPredicateEvent, 'add_include_predicates' )
2017-02-01 21:11:17 +00:00
if True in ( exclude_predicate in current_predicates for exclude_predicate in exclude_predicates ):
2017-09-20 19:47:31 +00:00
ClientGUIMenus.AppendMenuItem( self, menu, 'permit ' + selection_string + ' for current search', 'Stop disallowing the selected predicates from the current search.', self._ProcessMenuPredicateEvent, 'remove_exclude_predicates' )
2017-02-01 21:11:17 +00:00
if True in ( exclude_predicate not in current_predicates for exclude_predicate in exclude_predicates ):
2017-09-20 19:47:31 +00:00
ClientGUIMenus.AppendMenuItem( self, menu, 'exclude ' + selection_string + ' from current search', 'Disallow the selected predicates for the current search.', self._ProcessMenuPredicateEvent, 'add_exclude_predicates' )
2017-02-01 21:11:17 +00:00
2017-03-15 20:13:04 +00:00
ClientGUIMenus.AppendSeparator( menu )
2017-02-01 21:11:17 +00:00
if self.can_spawn_new_windows:
2017-09-20 19:47:31 +00:00
ClientGUIMenus.AppendMenuItem( self, menu, 'open a new search page for ' + selection_string, 'Open a new search page starting with the selected predicates.', self._NewSearchPage )
2017-02-01 21:11:17 +00:00
2017-03-15 20:13:04 +00:00
ClientGUIMenus.AppendSeparator( menu )
2017-02-01 21:11:17 +00:00
2017-09-20 19:47:31 +00:00
ClientGUIMenus.AppendMenuItem( self, menu, 'copy ' + selection_string, 'Copy the selected predicates to your clipboard.', self._ProcessMenuCopyEvent, 'copy_terms' )
2017-02-01 21:11:17 +00:00
if len( self._selected_terms ) == 1:
2017-02-08 22:27:00 +00:00
( namespace, subtag ) = HydrusTags.SplitTag( selection_string )
if namespace != '':
2017-02-01 21:11:17 +00:00
2017-02-08 22:27:00 +00:00
sub_selection_string = '"' + subtag
2017-02-01 21:11:17 +00:00
2017-09-20 19:47:31 +00:00
ClientGUIMenus.AppendMenuItem( self, menu, 'copy ' + sub_selection_string, 'Copy the selected sub-predicates to your clipboard.', self._ProcessMenuCopyEvent, 'copy_sub_terms' )
2017-02-01 21:11:17 +00:00
else:
2017-09-20 19:47:31 +00:00
ClientGUIMenus.AppendMenuItem( self, menu, 'copy selected subtags', 'Copy the selected sub-predicates to your clipboard.', self._ProcessMenuCopyEvent, 'copy_sub_terms' )
2017-02-01 21:11:17 +00:00
2017-03-15 20:13:04 +00:00
ClientGUIMenus.AppendSeparator( menu )
2017-03-22 22:38:15 +00:00
if len( self._ordered_terms ) > len( self._selected_terms ):
2017-02-01 21:11:17 +00:00
2017-09-20 19:47:31 +00:00
ClientGUIMenus.AppendMenuItem( self, menu, 'copy all tags', 'Copy all the predicates in this list to your clipboard.', self._ProcessMenuCopyEvent, 'copy_all_tags' )
if self.has_counts:
ClientGUIMenus.AppendMenuItem( self, menu, 'copy all tags with counts', 'Copy all the predicates in this list, with their counts, to your clipboard.', self._ProcessMenuCopyEvent, 'copy_all_tags_with_counts' )
2017-02-01 21:11:17 +00:00
if self.can_spawn_new_windows and len( self._selected_terms ) > 0:
term_types = [ type( term ) for term in self._selected_terms ]
if str in term_types or unicode in term_types:
2017-03-15 20:13:04 +00:00
ClientGUIMenus.AppendSeparator( menu )
2017-02-01 21:11:17 +00:00
if len( self._selected_terms ) == 1:
( tag, ) = self._selected_terms
text = tag
else:
text = 'selection'
if len( self._selected_terms ) == 1:
2017-09-20 19:47:31 +00:00
ClientGUIMenus.AppendMenuItem( self, menu, 'censor ' + text, 'Hide this tag from view in future.', self._ProcessMenuTagEvent, 'censorship' )
2017-02-01 21:11:17 +00:00
2017-09-20 19:47:31 +00:00
ClientGUIMenus.AppendMenuItem( self, menu, 'add parents to ' + text, 'Add a parent to this tag.', self._ProcessMenuTagEvent, 'parent' )
2017-09-27 21:52:54 +00:00
ClientGUIMenus.AppendMenuItem( self, menu, 'add siblings to ' + text, 'Add a sibling to this tag.', self._ProcessMenuTagEvent, 'sibling' )
2017-02-01 21:11:17 +00:00
2017-05-10 21:33:58 +00:00
HG.client_controller.PopupMenu( self, menu )
2017-02-01 21:11:17 +00:00
event.Skip()
def GetSelectedTags( self ):
2017-05-24 20:28:24 +00:00
return set( self._selected_terms )
2017-02-01 21:11:17 +00:00
def SiblingsHaveChanged( self ):
pass
2017-03-22 22:38:15 +00:00
class ListBoxTagsPredicates( ListBoxTags ):
2017-02-01 21:11:17 +00:00
has_counts = True
def _GetWithParentIndices( self, index ):
indices = [ index ]
index += 1
2017-03-22 22:38:15 +00:00
while index < len( self._ordered_terms ):
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
term = self._GetTerm( index )
2017-02-01 21:11:17 +00:00
if term.GetType() == HC.PREDICATE_TYPE_PARENT:
indices.append( index )
else:
break
index += 1
return indices
def _Deselect( self, index ):
to_deselect = self._GetWithParentIndices( index )
for index in to_deselect:
ListBoxTags._Deselect( self, index )
def _GetAllTagsForClipboard( self, with_counts = False ):
2017-03-22 22:38:15 +00:00
return [ term.GetUnicode( with_counts ) for term in self._terms ]
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
def _GetNamespaceFromTerm( self, term ):
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
predicate = term
namespace = predicate.GetNamespace()
return namespace
2018-01-31 22:58:15 +00:00
def _GetSafeHitIndex( self, hit_index, direction = None ):
hit_index = ListBox._GetSafeHitIndex( self, hit_index )
if direction is not None and hit_index is not None:
hit_term = self._GetTerm( hit_index )
while hit_term.GetType() == HC.PREDICATE_TYPE_PARENT:
hit_index += direction
if hit_index >= len( self._ordered_terms ):
hit_index = 0
hit_term = self._GetTerm( hit_index )
return hit_index
2017-03-22 22:38:15 +00:00
def _GetSimplifiedTextFromTerm( self, term ):
predicate = term
return predicate.GetUnicode( with_counts = False )
def _GetTextFromTerm( self, term ):
predicate = term
return predicate.GetUnicode()
def _HasPredicate( self, predicate ):
return predicate in self._terms
2017-02-01 21:11:17 +00:00
def _Hit( self, shift, ctrl, hit_index ):
2018-01-31 22:58:15 +00:00
hit_index = self._GetSafeHitIndex( hit_index )
if hit_index is not None and hit_index > 0:
2017-02-01 21:11:17 +00:00
2018-01-31 22:58:15 +00:00
# this realigns the hit index in the up direction, so if user clicks on parent, they get the upper child
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
while self._GetTerm( hit_index ).GetType() == HC.PREDICATE_TYPE_PARENT:
2017-02-01 21:11:17 +00:00
hit_index -= 1
ListBoxTags._Hit( self, shift, ctrl, hit_index )
def _Select( self, index ):
to_select = self._GetWithParentIndices( index )
for index in to_select:
ListBoxTags._Select( self, index )
2017-03-22 22:38:15 +00:00
def GetPredicates( self ):
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
return set( self._terms )
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
class ListBoxTagsActiveSearchPredicates( ListBoxTagsPredicates ):
has_counts = False
def __init__( self, parent, page_key, initial_predicates = None ):
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
if initial_predicates is None:
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
initial_predicates = []
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
ListBoxTagsPredicates.__init__( self, parent, min_height = 100 )
self._page_key = page_key
self._get_current_predicates_callable = self.GetPredicates
if len( initial_predicates ) > 0:
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
for predicate in initial_predicates:
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
self._AppendTerm( predicate )
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
self._DataHasChanged()
2017-02-01 21:11:17 +00:00
2017-05-10 21:33:58 +00:00
HG.client_controller.sub( self, 'EnterPredicates', 'enter_predicates' )
2017-02-01 21:11:17 +00:00
def _Activate( self ):
if len( self._selected_terms ) > 0:
2017-03-22 22:38:15 +00:00
self._EnterPredicates( set( self._selected_terms ) )
2017-02-01 21:11:17 +00:00
2017-03-29 19:39:34 +00:00
def _DeleteActivate( self ):
self._Activate()
2017-03-22 22:38:15 +00:00
def _EnterPredicates( self, predicates, permit_add = True, permit_remove = True ):
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
if len( predicates ) == 0:
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
return
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
predicates_to_be_added = set()
predicates_to_be_removed = set()
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
for predicate in predicates:
predicate = predicate.GetCountlessCopy()
if self._HasPredicate( predicate ):
if permit_remove:
predicates_to_be_removed.add( predicate )
else:
if permit_add:
predicates_to_be_added.add( predicate )
inverse_predicate = predicate.GetInverseCopy()
if self._HasPredicate( inverse_predicate ):
predicates_to_be_removed.add( inverse_predicate )
for predicate in predicates_to_be_added:
self._AppendTerm( predicate )
for predicate in predicates_to_be_removed:
self._RemoveTerm( predicate )
self._SortByText()
self._DataHasChanged()
2017-05-10 21:33:58 +00:00
HG.client_controller.pub( 'refresh_query', self._page_key )
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
def _GetTextFromTerm( self, term ):
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
predicate = term
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
return predicate.GetUnicode( render_for_user = True )
def _ProcessMenuPredicateEvent( self, command ):
( include_predicates, exclude_predicates ) = self._GetSelectedIncludeExcludePredicates()
if command == 'add_include_predicates':
self._EnterPredicates( include_predicates, permit_remove = False )
elif command == 'remove_include_predicates':
self._EnterPredicates( include_predicates, permit_add = False )
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
elif command == 'add_exclude_predicates':
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
self._EnterPredicates( exclude_predicates, permit_remove = False )
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
elif command == 'remove_exclude_predicates':
self._EnterPredicates( exclude_predicates, permit_add = False )
def EnterPredicates( self, page_key, predicates, permit_add = True, permit_remove = True ):
if page_key == self._page_key:
self._EnterPredicates( predicates, permit_add = permit_add, permit_remove = permit_remove )
class ListBoxTagsAC( ListBoxTagsPredicates ):
def __init__( self, parent, callable, service_key, **kwargs ):
ListBoxTagsPredicates.__init__( self, parent, **kwargs )
self._callable = callable
self._service_key = service_key
self._predicates = {}
def _Activate( self ):
predicates = [ term for term in self._selected_terms if term.GetType() != HC.PREDICATE_TYPE_PARENT ]
2017-05-10 21:33:58 +00:00
predicates = HG.client_controller.GetGUI().FlushOutPredicates( predicates )
2017-03-22 22:38:15 +00:00
if len( predicates ) > 0:
self._callable( predicates )
def SetPredicates( self, predicates ):
# 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 ):
for index in range( len( predicates ) ):
p_1 = predicates[ index ]
p_2 = self._predicates[ 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:
# important to make own copy, as same object originals can be altered (e.g. set non-inclusive) in cache, and we need to notice that change just above
self._predicates = [ predicate.GetCopy() for predicate in predicates ]
self._Clear()
for predicate in predicates:
self._AppendTerm( predicate )
self._DataHasChanged()
if len( predicates ) > 0:
2018-02-07 23:40:33 +00:00
hit_index = 0
if len( predicates ) > 1:
if HG.client_controller.new_options.GetBoolean( 'ac_select_first_with_count' ):
for ( index, predicate ) in enumerate( predicates ):
if predicate.GetCount() != 0:
hit_index = index
break
self._Hit( False, False, hit_index )
2017-03-22 22:38:15 +00:00
def SetTagService( self, service_key ):
self._service_key = service_key
class ListBoxTagsACRead( ListBoxTagsAC ):
def _GetTextFromTerm( self, term ):
predicate = term
return predicate.GetUnicode( render_for_user = True )
class ListBoxTagsACWrite( ListBoxTagsAC ):
def _GetTextFromTerm( self, term ):
predicate = term
return predicate.GetUnicode( sibling_service_key = self._service_key )
class ListBoxTagsCensorship( ListBoxTags ):
def _Activate( self ):
if len( self._selected_terms ) > 0:
tags = set( self._selected_terms )
for tag in tags:
self._RemoveTerm( tag )
2017-06-07 22:05:15 +00:00
self._ordered_terms.sort()
2017-03-22 22:38:15 +00:00
self._DataHasChanged()
def _GetNamespaceFromTerm( self, term ):
tag = term
if tag == ':':
return None
else:
( namespace, subtag ) = HydrusTags.SplitTag( tag )
return namespace
def _GetTextFromTerm( self, term ):
2017-05-24 20:28:24 +00:00
tag_slice = term
2017-03-22 22:38:15 +00:00
2017-05-24 20:28:24 +00:00
return ClientData.ConvertTagSliceToString( tag_slice )
2017-02-01 21:11:17 +00:00
def AddTags( self, tags ):
for tag in tags:
2017-03-22 22:38:15 +00:00
self._AppendTerm( tag )
2017-02-01 21:11:17 +00:00
2017-06-07 22:05:15 +00:00
self._ordered_terms.sort()
2017-03-22 22:38:15 +00:00
self._DataHasChanged()
2017-02-01 21:11:17 +00:00
def EnterTags( self, tags ):
for tag in tags:
2017-03-22 22:38:15 +00:00
if tag in self._terms:
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
self._RemoveTerm( tag )
2017-02-01 21:11:17 +00:00
else:
2017-03-22 22:38:15 +00:00
self._AppendTerm( tag )
2017-02-01 21:11:17 +00:00
2017-06-07 22:05:15 +00:00
self._ordered_terms.sort()
2017-03-22 22:38:15 +00:00
self._DataHasChanged()
2017-02-01 21:11:17 +00:00
2017-05-24 20:28:24 +00:00
def RemoveTags( self, tags ):
2017-02-01 21:11:17 +00:00
for tag in tags:
2017-03-22 22:38:15 +00:00
self._RemoveTerm( tag )
2017-02-01 21:11:17 +00:00
2017-06-07 22:05:15 +00:00
self._ordered_terms.sort()
2017-03-22 22:38:15 +00:00
self._DataHasChanged()
2017-02-01 21:11:17 +00:00
class ListBoxTagsColourOptions( ListBoxTags ):
2017-03-29 19:39:34 +00:00
PROTECTED_TERMS = ( None, '' )
2017-02-01 21:11:17 +00:00
can_spawn_new_windows = False
def __init__( self, parent, initial_namespace_colours ):
ListBoxTags.__init__( self, parent )
2017-03-22 22:38:15 +00:00
for ( namespace, colour ) in initial_namespace_colours.items():
2017-02-01 21:11:17 +00:00
colour = tuple( colour ) # tuple to convert from list, for oooold users who have list colours
2017-03-22 22:38:15 +00:00
self._AppendTerm( ( namespace, colour ) )
2017-02-01 21:11:17 +00:00
2017-03-29 19:39:34 +00:00
self._SortByText()
2017-03-22 22:38:15 +00:00
self._DataHasChanged()
2017-02-01 21:11:17 +00:00
def _Activate( self ):
2017-03-29 19:39:34 +00:00
namespaces = [ namespace for ( namespace, colour ) in self._selected_terms ]
2018-01-17 22:52:10 +00:00
if len( namespaces ) > 0:
import ClientGUIDialogs
with ClientGUIDialogs.DialogYesNo( self, 'Delete all selected colours?' ) as dlg:
if dlg.ShowModal() == wx.ID_YES:
self._RemoveNamespaces( namespaces )
2017-03-29 19:39:34 +00:00
def _DeleteActivate( self ):
self._Activate()
2017-03-22 22:38:15 +00:00
def _GetTextFromTerm( self, term ):
( namespace, colour ) = term
if namespace is None:
namespace_string = 'default namespace:tag'
elif namespace == '':
namespace_string = 'unnamespaced tag'
else:
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
namespace_string = namespace + ':tag'
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
return namespace_string
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
def _GetNamespaceColours( self ):
2017-03-29 19:39:34 +00:00
return dict( self._terms )
2017-03-22 22:38:15 +00:00
def _GetNamespaceFromTerm( self, term ):
( namespace, colour ) = term
return namespace
2017-02-01 21:11:17 +00:00
def _RemoveNamespaces( self, namespaces ):
2017-03-29 19:39:34 +00:00
namespaces = [ namespace for namespace in namespaces if namespace not in self.PROTECTED_TERMS ]
2017-03-22 22:38:15 +00:00
removees = [ ( existing_namespace, existing_colour ) for ( existing_namespace, existing_colour ) in self._terms if existing_namespace in namespaces ]
for removee in removees:
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
self._RemoveTerm( removee )
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
self._DataHasChanged()
2017-02-01 21:11:17 +00:00
def SetNamespaceColour( self, namespace, colour ):
2018-01-10 22:41:51 +00:00
( r, g, b, a ) = colour.Get()
colour_tuple = ( r, g, b )
2017-03-22 22:38:15 +00:00
for ( existing_namespace, existing_colour ) in self._terms:
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
if existing_namespace == namespace:
self._RemoveTerm( ( existing_namespace, existing_colour ) )
break
2017-02-01 21:11:17 +00:00
2018-01-10 22:41:51 +00:00
self._AppendTerm( ( namespace, colour_tuple ) )
2017-02-01 21:11:17 +00:00
2017-03-29 19:39:34 +00:00
self._SortByText()
2017-03-22 22:38:15 +00:00
self._DataHasChanged()
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
def GetNamespaceColours( self ):
2017-03-29 19:39:34 +00:00
return self._GetNamespaceColours()
2017-03-22 22:38:15 +00:00
2017-02-01 21:11:17 +00:00
def GetSelectedNamespaceColours( self ):
2017-03-22 22:38:15 +00:00
namespace_colours = dict( self._selected_terms )
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
return namespace_colours
2017-02-01 21:11:17 +00:00
class ListBoxTagsStrings( ListBoxTags ):
def __init__( self, parent, service_key = None, show_sibling_text = True, sort_tags = True ):
ListBoxTags.__init__( self, parent )
if service_key is not None:
service_key = CC.COMBINED_TAG_SERVICE_KEY
self._service_key = service_key
self._show_sibling_text = show_sibling_text
self._sort_tags = sort_tags
2017-03-22 22:38:15 +00:00
def _GetNamespaceFromTerm( self, term ):
tag = term
( namespace, subtag ) = HydrusTags.SplitTag( tag )
return namespace
def _GetSimplifiedTextFromTerm( self, term ):
tag = term
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
return HydrusData.ToUnicode( tag )
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
def _GetTextFromTerm( self, term ):
2017-02-01 21:11:17 +00:00
2017-05-10 21:33:58 +00:00
siblings_manager = HG.client_controller.GetManager( 'tag_siblings' )
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
tag = term
tag_string = ClientTags.RenderTag( tag, True )
if self._show_sibling_text:
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
sibling = siblings_manager.GetSibling( self._service_key, tag )
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
if sibling is not None:
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
tag_string += ' (will display as ' + ClientTags.RenderTag( sibling, True ) + ')'
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
return tag_string
def _RecalcTags( self ):
self._RefreshTexts()
2017-02-01 21:11:17 +00:00
if self._sort_tags:
2017-03-22 22:38:15 +00:00
self._SortByText()
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
self._DataHasChanged()
2017-02-01 21:11:17 +00:00
def GetTags( self ):
2017-03-22 22:38:15 +00:00
return set( self._terms )
2017-02-01 21:11:17 +00:00
def SetTags( self, tags ):
2017-03-22 22:38:15 +00:00
self._Clear()
for tag in tags:
self._AppendTerm( tag )
2017-02-01 21:11:17 +00:00
self._RecalcTags()
def SiblingsHaveChanged( self ):
self._RecalcTags()
class ListBoxTagsStringsAddRemove( ListBoxTagsStrings ):
def __init__( self, parent, service_key = None, removed_callable = None, show_sibling_text = True ):
ListBoxTagsStrings.__init__( self, parent, service_key = service_key, show_sibling_text = show_sibling_text )
self._removed_callable = removed_callable
def _Activate( self ):
if len( self._selected_terms ) > 0:
tags = set( self._selected_terms )
self._RemoveTags( tags )
def _RemoveTags( self, tags ):
for tag in tags:
2017-03-22 22:38:15 +00:00
self._RemoveTerm( tag )
2017-02-01 21:11:17 +00:00
self._RecalcTags()
if self._removed_callable is not None:
self._removed_callable( tags )
def AddTags( self, tags ):
for tag in tags:
2017-03-22 22:38:15 +00:00
self._AppendTerm( tag )
2017-02-01 21:11:17 +00:00
self._RecalcTags()
def Clear( self ):
2017-03-22 22:38:15 +00:00
self._Clear()
2017-02-01 21:11:17 +00:00
self._RecalcTags()
def EnterTags( self, tags ):
removed = set()
for tag in tags:
2017-03-22 22:38:15 +00:00
if tag in self._terms:
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
self._RemoveTerm( tag )
2017-02-01 21:11:17 +00:00
removed.add( tag )
else:
2017-03-22 22:38:15 +00:00
self._AppendTerm( tag )
2017-02-01 21:11:17 +00:00
self._RecalcTags()
if len( removed ) > 0 and self._removed_callable is not None:
self._removed_callable( removed )
2017-04-19 20:58:30 +00:00
def EventCharHook( self, event ):
2017-02-01 21:11:17 +00:00
2017-04-12 21:46:46 +00:00
( modifier, key ) = ClientData.ConvertKeyEventToSimpleTuple( event )
2017-04-05 21:16:40 +00:00
if key in CC.DELETE_KEYS:
2017-02-01 21:11:17 +00:00
self._Activate()
else:
event.Skip()
def RemoveTags( self, tags ):
self._RemoveTags( tags )
class ListBoxTagsSelection( ListBoxTags ):
2017-03-22 22:38:15 +00:00
render_for_user = True
2017-02-01 21:11:17 +00:00
has_counts = True
def __init__( self, parent, include_counts = True, collapse_siblings = False ):
ListBoxTags.__init__( self, parent, min_height = 200 )
self._sort = HC.options[ 'default_tag_sort' ]
if not include_counts and self._sort in ( CC.SORT_BY_INCIDENCE_ASC, CC.SORT_BY_INCIDENCE_DESC, CC.SORT_BY_INCIDENCE_NAMESPACE_ASC, CC.SORT_BY_INCIDENCE_NAMESPACE_DESC ):
self._sort = CC.SORT_BY_LEXICOGRAPHIC_ASC
self._last_media = set()
self._tag_service_key = CC.COMBINED_TAG_SERVICE_KEY
self._include_counts = include_counts
self._collapse_siblings = collapse_siblings
self._current_tags_to_count = collections.Counter()
self._deleted_tags_to_count = collections.Counter()
self._pending_tags_to_count = collections.Counter()
self._petitioned_tags_to_count = collections.Counter()
self._show_current = True
self._show_deleted = False
self._show_pending = True
self._show_petitioned = True
def _GetAllTagsForClipboard( self, with_counts = False ):
if with_counts:
2017-03-22 22:38:15 +00:00
return [ self._terms_to_texts[ term ] for term in self._ordered_terms ]
2017-02-01 21:11:17 +00:00
else:
2017-03-22 22:38:15 +00:00
return self._ordered_terms
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
def _GetNamespaceFromTerm( self, term ):
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
tag = term
( namespace, subtag ) = HydrusTags.SplitTag( tag )
return namespace
def _GetSimplifiedTextFromTerm( self, term ):
tag = term
return HydrusData.ToUnicode( tag )
def _GetTextFromTerm( self, term ):
tag = term
tag_string = ClientTags.RenderTag( tag, self.render_for_user )
2017-02-01 21:11:17 +00:00
if self._include_counts:
if self._show_current and tag in self._current_tags_to_count: tag_string += ' (' + HydrusData.ConvertIntToPrettyString( self._current_tags_to_count[ tag ] ) + ')'
if self._show_pending and tag in self._pending_tags_to_count: tag_string += ' (+' + HydrusData.ConvertIntToPrettyString( self._pending_tags_to_count[ tag ] ) + ')'
if self._show_petitioned and tag in self._petitioned_tags_to_count: tag_string += ' (-' + HydrusData.ConvertIntToPrettyString( self._petitioned_tags_to_count[ tag ] ) + ')'
if self._show_deleted and tag in self._deleted_tags_to_count: tag_string += ' (X' + HydrusData.ConvertIntToPrettyString( self._deleted_tags_to_count[ tag ] ) + ')'
else:
if self._show_pending and tag in self._pending_tags_to_count: tag_string += ' (+)'
if self._show_petitioned and tag in self._petitioned_tags_to_count: tag_string += ' (-)'
if self._show_deleted and tag in self._deleted_tags_to_count: tag_string += ' (X)'
if not self._collapse_siblings:
2017-05-10 21:33:58 +00:00
siblings_manager = HG.client_controller.GetManager( 'tag_siblings' )
2017-02-01 21:11:17 +00:00
sibling = siblings_manager.GetSibling( self._tag_service_key, tag )
if sibling is not None:
2017-03-22 22:38:15 +00:00
sibling = ClientTags.RenderTag( sibling, self.render_for_user )
tag_string += ' (will display as ' + sibling + ')'
2017-02-01 21:11:17 +00:00
return tag_string
def _RecalcStrings( self, limit_to_these_tags = None ):
2017-04-12 21:46:46 +00:00
previous_selected_terms = set( self._selected_terms )
2017-02-01 21:11:17 +00:00
if limit_to_these_tags is None:
2017-03-22 22:38:15 +00:00
self._Clear()
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
nonzero_tags = set()
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
if self._show_current: nonzero_tags.update( ( tag for ( tag, count ) in self._current_tags_to_count.items() if count > 0 ) )
if self._show_deleted: nonzero_tags.update( ( tag for ( tag, count ) in self._deleted_tags_to_count.items() if count > 0 ) )
if self._show_pending: nonzero_tags.update( ( tag for ( tag, count ) in self._pending_tags_to_count.items() if count > 0 ) )
if self._show_petitioned: nonzero_tags.update( ( tag for ( tag, count ) in self._petitioned_tags_to_count.items() if count > 0 ) )
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
for tag in nonzero_tags:
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
self._AppendTerm( tag )
2017-02-01 21:11:17 +00:00
else:
2017-03-22 22:38:15 +00:00
if not isinstance( limit_to_these_tags, set ):
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
limit_to_these_tags = set( limit_to_these_tags )
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
for tag in limit_to_these_tags:
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
self._RemoveTerm( tag )
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
nonzero_tags = set()
if self._show_current: nonzero_tags.update( ( tag for ( tag, count ) in self._current_tags_to_count.items() if count > 0 and tag in limit_to_these_tags ) )
if self._show_deleted: nonzero_tags.update( ( tag for ( tag, count ) in self._deleted_tags_to_count.items() if count > 0 and tag in limit_to_these_tags ) )
if self._show_pending: nonzero_tags.update( ( tag for ( tag, count ) in self._pending_tags_to_count.items() if count > 0 and tag in limit_to_these_tags ) )
if self._show_petitioned: nonzero_tags.update( ( tag for ( tag, count ) in self._petitioned_tags_to_count.items() if count > 0 and tag in limit_to_these_tags ) )
for tag in nonzero_tags:
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
self._AppendTerm( tag )
2017-02-01 21:11:17 +00:00
2017-04-12 21:46:46 +00:00
for term in previous_selected_terms:
if term in self._terms:
self._selected_terms.add( term )
2017-03-22 22:38:15 +00:00
self._SortTags()
2017-02-01 21:11:17 +00:00
def _SortTags( self ):
2017-03-22 22:38:15 +00:00
def lexicographic_key( term ):
2018-01-17 22:52:10 +00:00
tag = self._terms_to_texts[ term ]
( namespace, subtag ) = HydrusTags.SplitTag( tag )
comparable_subtag = HydrusTags.ConvertTagToSortable( subtag )
# 'cat' < 'character:rei'
# 'page:3' < 'page:20'
# '1' < 'series:eva'
# note that 'test' < ( 1, '' ) but u'test' > ( 1, '' ) wew
if namespace == '':
return ( comparable_subtag, comparable_subtag )
else:
return ( namespace, comparable_subtag )
2017-03-22 22:38:15 +00:00
def incidence_key( term ):
return tags_to_count[ term ]
def namespace_key( term ):
tag = term
( namespace, subtag ) = HydrusTags.SplitTag( tag )
if namespace == '':
namespace = '{' # '{' is above 'z' in ascii, so this works for most situations
return namespace
def namespace_lexicographic_key( term ):
tag = term
# '{' is above 'z' in ascii, so this works for most situations
( namespace, subtag ) = HydrusTags.SplitTag( tag )
if namespace == '':
2018-01-17 22:52:10 +00:00
return ( '{', HydrusTags.ConvertTagToSortable( subtag ) )
2017-03-22 22:38:15 +00:00
else:
2018-01-17 22:52:10 +00:00
return ( namespace, HydrusTags.ConvertTagToSortable( subtag ) )
2017-03-22 22:38:15 +00:00
2017-02-01 21:11:17 +00:00
if self._sort in ( CC.SORT_BY_INCIDENCE_ASC, CC.SORT_BY_INCIDENCE_DESC, CC.SORT_BY_INCIDENCE_NAMESPACE_ASC, CC.SORT_BY_INCIDENCE_NAMESPACE_DESC ):
tags_to_count = collections.Counter()
if self._show_current: tags_to_count.update( self._current_tags_to_count )
if self._show_deleted: tags_to_count.update( self._deleted_tags_to_count )
if self._show_pending: tags_to_count.update( self._pending_tags_to_count )
if self._show_petitioned: tags_to_count.update( self._petitioned_tags_to_count )
2017-03-22 22:38:15 +00:00
# let's establish a-z here for equal incidence values later
2017-02-01 21:11:17 +00:00
if self._sort in ( CC.SORT_BY_INCIDENCE_ASC, CC.SORT_BY_INCIDENCE_NAMESPACE_ASC ):
2017-03-22 22:38:15 +00:00
self._ordered_terms.sort( key = lexicographic_key, reverse = True )
2017-02-01 21:11:17 +00:00
reverse = False
elif self._sort in ( CC.SORT_BY_INCIDENCE_DESC, CC.SORT_BY_INCIDENCE_NAMESPACE_DESC ):
2017-03-22 22:38:15 +00:00
self._ordered_terms.sort( key = lexicographic_key )
2017-02-01 21:11:17 +00:00
reverse = True
2017-03-22 22:38:15 +00:00
self._ordered_terms.sort( key = incidence_key, reverse = reverse )
2017-02-01 21:11:17 +00:00
if self._sort in ( CC.SORT_BY_INCIDENCE_NAMESPACE_ASC, CC.SORT_BY_INCIDENCE_NAMESPACE_DESC ):
# python list sort is stable, so lets now sort again
if self._sort == CC.SORT_BY_INCIDENCE_NAMESPACE_ASC:
reverse = True
elif self._sort == CC.SORT_BY_INCIDENCE_NAMESPACE_DESC:
reverse = False
2017-03-22 22:38:15 +00:00
self._ordered_terms.sort( key = namespace_key, reverse = reverse )
2017-02-01 21:11:17 +00:00
else:
2017-03-22 22:38:15 +00:00
if self._sort in ( CC.SORT_BY_LEXICOGRAPHIC_DESC, CC.SORT_BY_LEXICOGRAPHIC_NAMESPACE_DESC ):
reverse = True
elif self._sort in ( CC.SORT_BY_LEXICOGRAPHIC_ASC, CC.SORT_BY_LEXICOGRAPHIC_NAMESPACE_ASC ):
reverse = False
if self._sort in ( CC.SORT_BY_LEXICOGRAPHIC_NAMESPACE_ASC, CC.SORT_BY_LEXICOGRAPHIC_NAMESPACE_DESC ):
key = namespace_lexicographic_key
elif self._sort in ( CC.SORT_BY_LEXICOGRAPHIC_ASC, CC.SORT_BY_LEXICOGRAPHIC_DESC ):
key = lexicographic_key
self._ordered_terms.sort( key = key, reverse = reverse )
2017-02-01 21:11:17 +00:00
2017-03-22 22:38:15 +00:00
self._DataHasChanged()
2017-02-01 21:11:17 +00:00
def ChangeTagService( self, service_key ):
self._tag_service_key = service_key
self.SetTagsByMedia( self._last_media, force_reload = True )
def SetSort( self, sort ):
self._sort = sort
self._SortTags()
def SetShow( self, show_type, value ):
if show_type == 'current': self._show_current = value
elif show_type == 'deleted': self._show_deleted = value
elif show_type == 'pending': self._show_pending = value
elif show_type == 'petitioned': self._show_petitioned = value
self._RecalcStrings()
def IncrementTagsByMedia( self, media ):
media = set( media )
media = media.difference( self._last_media )
( current_tags_to_count, deleted_tags_to_count, pending_tags_to_count, petitioned_tags_to_count ) = ClientData.GetMediasTagCount( media, tag_service_key = self._tag_service_key, collapse_siblings = self._collapse_siblings )
self._current_tags_to_count.update( current_tags_to_count )
self._deleted_tags_to_count.update( deleted_tags_to_count )
self._pending_tags_to_count.update( pending_tags_to_count )
self._petitioned_tags_to_count.update( petitioned_tags_to_count )
tags_changed = set()
if self._show_current: tags_changed.update( current_tags_to_count.keys() )
if self._show_deleted: tags_changed.update( deleted_tags_to_count.keys() )
if self._show_pending: tags_changed.update( pending_tags_to_count.keys() )
if self._show_petitioned: tags_changed.update( petitioned_tags_to_count.keys() )
if len( tags_changed ) > 0:
self._RecalcStrings( tags_changed )
self._last_media.update( media )
def SetTagsByMedia( self, media, force_reload = False ):
media = set( media )
if force_reload:
( current_tags_to_count, deleted_tags_to_count, pending_tags_to_count, petitioned_tags_to_count ) = ClientData.GetMediasTagCount( media, tag_service_key = self._tag_service_key, collapse_siblings = self._collapse_siblings )
self._current_tags_to_count = current_tags_to_count
self._deleted_tags_to_count = deleted_tags_to_count
self._pending_tags_to_count = pending_tags_to_count
self._petitioned_tags_to_count = petitioned_tags_to_count
self._RecalcStrings()
else:
removees = self._last_media.difference( media )
adds = media.difference( self._last_media )
( current_tags_to_count, deleted_tags_to_count, pending_tags_to_count, petitioned_tags_to_count ) = ClientData.GetMediasTagCount( removees, tag_service_key = self._tag_service_key, collapse_siblings = self._collapse_siblings )
self._current_tags_to_count.subtract( current_tags_to_count )
self._deleted_tags_to_count.subtract( deleted_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 ) = ClientData.GetMediasTagCount( adds, tag_service_key = self._tag_service_key, collapse_siblings = self._collapse_siblings )
self._current_tags_to_count.update( current_tags_to_count )
self._deleted_tags_to_count.update( deleted_tags_to_count )
self._pending_tags_to_count.update( pending_tags_to_count )
self._petitioned_tags_to_count.update( petitioned_tags_to_count )
for counter in ( self._current_tags_to_count, self._deleted_tags_to_count, self._pending_tags_to_count, self._petitioned_tags_to_count ):
tags = counter.keys()
for tag in tags:
if counter[ tag ] == 0: del counter[ tag ]
if len( removees ) == 0:
tags_changed = set()
if self._show_current: tags_changed.update( current_tags_to_count.keys() )
if self._show_deleted: tags_changed.update( deleted_tags_to_count.keys() )
if self._show_pending: tags_changed.update( pending_tags_to_count.keys() )
if self._show_petitioned: tags_changed.update( petitioned_tags_to_count.keys() )
if len( tags_changed ) > 0:
self._RecalcStrings( tags_changed )
else:
self._RecalcStrings()
self._last_media = media
2017-03-22 22:38:15 +00:00
self._DataHasChanged()
2017-02-01 21:11:17 +00:00
def SiblingsHaveChanged( self ):
self.SetTagsByMedia( self._last_media, force_reload = True )
class ListBoxTagsSelectionHoverFrame( ListBoxTagsSelection ):
def __init__( self, parent, canvas_key ):
ListBoxTagsSelection.__init__( self, parent, include_counts = False, collapse_siblings = True )
self._canvas_key = canvas_key
def _Activate( self ):
2017-05-10 21:33:58 +00:00
HG.client_controller.pub( 'canvas_manage_tags', self._canvas_key )
2017-02-01 21:11:17 +00:00
class ListBoxTagsSelectionManagementPanel( ListBoxTagsSelection ):
def __init__( self, parent, page_key, predicates_callable = None ):
ListBoxTagsSelection.__init__( self, parent, include_counts = True, collapse_siblings = True )
self._page_key = page_key
2017-03-22 22:38:15 +00:00
self._get_current_predicates_callable = predicates_callable
2017-02-01 21:11:17 +00:00
2017-05-10 21:33:58 +00:00
HG.client_controller.sub( self, 'IncrementTagsByMediaPubsub', 'increment_tags_selection' )
HG.client_controller.sub( self, 'SetTagsByMediaPubsub', 'new_tags_selection' )
HG.client_controller.sub( self, 'ChangeTagServicePubsub', 'change_tag_service' )
2017-02-01 21:11:17 +00:00
def _Activate( self ):
predicates = [ ClientSearch.Predicate( HC.PREDICATE_TYPE_TAG, term ) for term in self._selected_terms ]
if len( predicates ) > 0:
2017-05-10 21:33:58 +00:00
HG.client_controller.pub( 'enter_predicates', self._page_key, predicates )
2017-02-01 21:11:17 +00:00
def _ProcessMenuPredicateEvent( self, command ):
( include_predicates, exclude_predicates ) = self._GetSelectedIncludeExcludePredicates()
if command == 'add_include_predicates':
2017-05-10 21:33:58 +00:00
HG.client_controller.pub( 'enter_predicates', self._page_key, include_predicates, permit_remove = False )
2017-02-01 21:11:17 +00:00
elif command == 'remove_include_predicates':
2017-05-10 21:33:58 +00:00
HG.client_controller.pub( 'enter_predicates', self._page_key, include_predicates, permit_add = False )
2017-02-01 21:11:17 +00:00
elif command == 'add_exclude_predicates':
2017-05-10 21:33:58 +00:00
HG.client_controller.pub( 'enter_predicates', self._page_key, exclude_predicates, permit_remove = False )
2017-02-01 21:11:17 +00:00
elif command == 'remove_exclude_predicates':
2017-05-10 21:33:58 +00:00
HG.client_controller.pub( 'enter_predicates', self._page_key, exclude_predicates, permit_add = False )
2017-02-01 21:11:17 +00:00
def ChangeTagServicePubsub( self, page_key, service_key ):
if page_key == self._page_key:
self.ChangeTagService( service_key )
def IncrementTagsByMediaPubsub( self, page_key, media ):
if page_key == self._page_key:
self.IncrementTagsByMedia( media )
def SetTagsByMediaPubsub( self, page_key, media, force_reload = False ):
if page_key == self._page_key:
self.SetTagsByMedia( media, force_reload = force_reload )
class ListBoxTagsSelectionTagsDialog( ListBoxTagsSelection ):
2017-03-22 22:38:15 +00:00
render_for_user = False
2017-02-01 21:11:17 +00:00
2017-03-29 19:39:34 +00:00
def __init__( self, parent, add_func, delete_func ):
2017-02-01 21:11:17 +00:00
ListBoxTagsSelection.__init__( self, parent, include_counts = True, collapse_siblings = False )
2017-03-29 19:39:34 +00:00
self._add_func = add_func
self._delete_func = delete_func
2017-02-01 21:11:17 +00:00
def _Activate( self ):
if len( self._selected_terms ) > 0:
2017-04-12 21:46:46 +00:00
self._add_func( set( self._selected_terms ) )
2017-02-01 21:11:17 +00:00
2017-03-29 19:39:34 +00:00
def _DeleteActivate( self ):
if len( self._selected_terms ) > 0:
2017-04-12 21:46:46 +00:00
self._delete_func( set( self._selected_terms ) )
2017-03-29 19:39:34 +00:00