hydrus/hydrus/client/gui/lists/ClientGUIListBoxesData.py

507 lines
14 KiB
Python

import collections
import typing
from hydrus.core import HydrusConstants as HC
from hydrus.core import HydrusData
from hydrus.core import HydrusExceptions
from hydrus.core import HydrusGlobals as HG
from hydrus.core import HydrusSerialisable
from hydrus.core import HydrusTags
from hydrus.client import ClientConstants as CC
from hydrus.client import ClientSearch
from hydrus.client.gui.search import ClientGUISearch
from hydrus.client.media import ClientMedia
from hydrus.client.metadata import ClientTags
class ListBoxItem( object ):
def __init__( self ):
pass
def __eq__( self, other ):
if isinstance( other, ListBoxItem ):
return self.__hash__() == other.__hash__()
return NotImplemented
def __hash__( self ):
raise NotImplementedError()
def __lt__( self, other ):
if isinstance( other, ListBoxItem ):
return self.GetCopyableText() < other.GetCopyableText()
return NotImplemented
def GetCopyableText( self, with_counts: bool = False ) -> str:
raise NotImplementedError()
def GetSearchPredicates( self ) -> typing.List[ ClientSearch.Predicate ]:
raise NotImplementedError()
def GetRowsOfPresentationTextsWithNamespaces( self, render_for_user: bool ) -> typing.List[ typing.List[ typing.Tuple[ str, str ] ] ]:
raise NotImplementedError()
def GetRowCount( self ):
return 1
def GetTags( self ) -> typing.Set[ str ]:
raise NotImplementedError()
class ListBoxItemTagSlice( ListBoxItem ):
def __init__( self, tag_slice: str ):
ListBoxItem.__init__( self )
self._tag_slice = tag_slice
def __hash__( self ):
return self._tag_slice.__hash__()
def GetCopyableText( self, with_counts: bool = False ) -> str:
return ClientTags.ConvertTagSliceToString( self._tag_slice )
def GetSearchPredicates( self ) -> typing.List[ ClientSearch.Predicate ]:
return []
def GetRowsOfPresentationTextsWithNamespaces( self, render_for_user: bool ) -> typing.List[ typing.Tuple[ str, str ] ]:
presentation_text = self.GetCopyableText()
if self._tag_slice in ( '', ':' ):
namespace = ''
else:
( namespace, subtag ) = HydrusTags.SplitTag( self._tag_slice )
return [ [ ( presentation_text, namespace ) ] ]
def GetTags( self ) -> typing.Set[ str ]:
return set()
def GetTagSlice( self ):
return self._tag_slice
class ListBoxItemNamespaceColour( ListBoxItem ):
def __init__( self, namespace: str, colour: typing.Tuple[ int, int, int ] ):
ListBoxItem.__init__( self )
self._namespace = namespace
self._colour = colour
def __hash__( self ):
return self._namespace.__hash__()
def GetCopyableText( self, with_counts: bool = False ) -> str:
if self._namespace is None:
return ClientTags.ConvertTagSliceToString( ':' )
elif self._namespace == '':
return ClientTags.ConvertTagSliceToString( '' )
else:
return ClientTags.ConvertTagSliceToString( '{}:'.format( self._namespace ) )
def GetNamespace( self ):
return self._namespace
def GetNamespaceAndColour( self ):
return ( self._namespace, self._colour )
def GetSearchPredicates( self ) -> typing.List[ ClientSearch.Predicate ]:
return []
def GetRowsOfPresentationTextsWithNamespaces( self, render_for_user: bool ) -> typing.List[ typing.List[ typing.Tuple[ str, str ] ] ]:
return [ [ ( self.GetCopyableText(), self._namespace ) ] ]
def GetTags( self ) -> typing.Set[ str ]:
return set()
class ListBoxItemTextTag( ListBoxItem ):
def __init__( self, tag: str ):
ListBoxItem.__init__( self )
self._tag = tag
self._ideal_tag = None
self._parent_tags = None
def __hash__( self ):
return self._tag.__hash__()
def _AppendIdealTagTextWithNamespace( self, texts_with_namespaces, render_for_user ):
( namespace, subtag ) = HydrusTags.SplitTag( self._ideal_tag )
ideal_text = ' (displays as {})'.format( ClientTags.RenderTag( self._ideal_tag, render_for_user ) )
texts_with_namespaces.append( ( ideal_text, namespace ) )
def _AppendParentsTextWithNamespaces( self, rows_of_texts_with_namespaces, render_for_user ):
indent = ' '
for parent in self._parent_tags:
( namespace, subtag ) = HydrusTags.SplitTag( parent )
tag_text = ClientTags.RenderTag( parent, render_for_user )
texts_with_namespaces = [ ( indent + tag_text, namespace ) ]
rows_of_texts_with_namespaces.append( texts_with_namespaces )
def GetCopyableText( self, with_counts: bool = False ) -> str:
return self._tag
def GetSearchPredicates( self ) -> typing.List[ ClientSearch.Predicate ]:
return [ ClientSearch.Predicate( ClientSearch.PREDICATE_TYPE_TAG, self._tag ) ]
def GetRowCount( self ):
if self._parent_tags is None:
return 1
else:
return 1 + len( self._parent_tags )
def GetRowsOfPresentationTextsWithNamespaces( self, render_for_user: bool ) -> typing.List[ typing.List[ typing.Tuple[ str, str ] ] ]:
# this should be with counts or whatever, but we need to think about this more lad
( namespace, subtag ) = HydrusTags.SplitTag( self._tag )
tag_text = ClientTags.RenderTag( self._tag, render_for_user )
texts_with_namespaces = [ ( tag_text, namespace ) ]
if self._ideal_tag is not None:
self._AppendIdealTagTextWithNamespace( texts_with_namespaces, render_for_user )
rows_of_texts_with_namespaces = [ texts_with_namespaces ]
if self._parent_tags is not None:
self._AppendParentsTextWithNamespaces( rows_of_texts_with_namespaces, render_for_user )
return rows_of_texts_with_namespaces
def GetSimpleSortText( self ) -> typing.Set[ str ]:
pass
def GetTag( self ) -> str:
return self._tag
def GetTags( self ) -> typing.Set[ str ]:
return { self._tag }
def SetIdealTag( self, ideal_tag ):
self._ideal_tag = ideal_tag
def SetParents( self, parents ):
self._parent_tags = parents
class ListBoxItemTextTagWithCounts( ListBoxItemTextTag ):
def __init__( self, tag: str, current_count: int, deleted_count: int, pending_count: int, petitioned_count: int, include_actual_counts: bool ):
# some have deleted and petitioned as well, so think about this
ListBoxItemTextTag.__init__( self, tag )
self._current_count = current_count
self._deleted_count = deleted_count
self._pending_count = pending_count
self._petitioned_count = petitioned_count
self._include_actual_counts = include_actual_counts
def __hash__( self ):
return self._tag.__hash__()
def GetCopyableText( self, with_counts: bool = False ) -> str:
if with_counts:
return ''.join( ( text for ( text, namespace ) in self.GetRowsOfPresentationTextsWithNamespaces( False )[0] ) )
else:
return self._tag
def GetSearchPredicates( self ) -> typing.List[ ClientSearch.Predicate ]:
# with counts? or just merge this into texttag???
return [ ClientSearch.Predicate( ClientSearch.PREDICATE_TYPE_TAG, self._tag ) ]
def GetRowsOfPresentationTextsWithNamespaces( self, render_for_user: bool ) -> typing.List[ typing.List[ typing.Tuple[ str, str ] ] ]:
# this should be with counts or whatever, but we need to think about this more lad
( namespace, subtag ) = HydrusTags.SplitTag( self._tag )
tag_text = ClientTags.RenderTag( self._tag, render_for_user )
if self._include_actual_counts:
if self._current_count > 0:
tag_text += ' ({})'.format( HydrusData.ToHumanInt( self._current_count ) )
if self._pending_count > 0:
tag_text += ' (+{})'.format( HydrusData.ToHumanInt( self._pending_count ) )
if self._petitioned_count > 0:
tag_text += ' (-{})'.format( HydrusData.ToHumanInt( self._petitioned_count ) )
if self._deleted_count > 0:
tag_text += ' (X{})'.format( HydrusData.ToHumanInt( self._deleted_count ) )
else:
if self._pending_count > 0:
tag_text += ' (+)'
if self._petitioned_count > 0:
tag_text += ' (-)'
if self._deleted_count > 0:
tag_text += ' (X)'
texts_with_namespaces = [ ( tag_text, namespace ) ]
if self._ideal_tag is not None:
self._AppendIdealTagTextWithNamespace( texts_with_namespaces, render_for_user )
rows_of_texts_with_namespaces = [ texts_with_namespaces ]
if self._parent_tags is not None:
self._AppendParentsTextWithNamespaces( rows_of_texts_with_namespaces, render_for_user )
return rows_of_texts_with_namespaces
class ListBoxItemPredicate( ListBoxItem ):
def __init__( self, predicate: ClientSearch.Predicate, show_ideal_siblings: bool ):
ListBoxItem.__init__( self )
self._predicate = predicate
self._show_ideal_siblings = show_ideal_siblings
self._i_am_an_or_under_construction = False
def __hash__( self ):
return self._predicate.__hash__()
def GetCopyableText( self, with_counts: bool = False ) -> str:
if self._predicate.GetType() == ClientSearch.PREDICATE_TYPE_NAMESPACE:
namespace = self._predicate.GetValue()
# this is useful for workflow
text = '{}:*'.format( namespace )
elif self._predicate.GetType() == ClientSearch.PREDICATE_TYPE_PARENT:
text = HydrusTags.CleanTag( self._predicate.GetValue() )
else:
text = self._predicate.ToString( with_count = with_counts )
return text
def GetSearchPredicates( self ) -> typing.List[ ClientSearch.Predicate ]:
if self._predicate.GetType() in ( ClientSearch.PREDICATE_TYPE_LABEL, ClientSearch.PREDICATE_TYPE_PARENT ):
return []
else:
return [ self._predicate ]
def GetRowCount( self ):
return 1 + len( self._predicate.GetParentPredicates() )
def GetRowsOfPresentationTextsWithNamespaces( self, render_for_user: bool ) -> typing.List[ typing.List[ typing.Tuple[ str, str ] ] ]:
rows_of_texts_and_namespaces = []
texts_and_namespaces = self._predicate.GetTextsAndNamespaces( render_for_user, or_under_construction = self._i_am_an_or_under_construction )
if self._show_ideal_siblings and self._predicate.HasIdealSibling():
ideal_sibling = self._predicate.GetIdealSibling()
( ideal_namespace, ideal_subtag ) = HydrusTags.SplitTag( ideal_sibling )
ideal_text = ' (displays as {})'.format( ClientTags.RenderTag( ideal_sibling, render_for_user ) )
texts_and_namespaces.append( ( ideal_text, ideal_namespace ) )
rows_of_texts_and_namespaces.append( texts_and_namespaces )
for parent_pred in self._predicate.GetParentPredicates():
rows_of_texts_and_namespaces.append( parent_pred.GetTextsAndNamespaces( render_for_user ) )
return rows_of_texts_and_namespaces
def GetTags( self ) -> typing.Set[ str ]:
if self._predicate.GetType() in ( ClientSearch.PREDICATE_TYPE_TAG, ClientSearch.PREDICATE_TYPE_WILDCARD ):
tag = self._predicate.GetValue()
elif self._predicate.GetType() == ClientSearch.PREDICATE_TYPE_NAMESPACE:
namespace = self._predicate.GetValue()
# this is useful for workflow
tag = '{}:*'.format( namespace )
elif self._predicate.GetType() == ClientSearch.PREDICATE_TYPE_PARENT:
tag = HydrusTags.CleanTag( self._predicate.GetValue() )
else:
return set()
return { tag }
def SetORUnderConstruction( self, value: bool ):
self._i_am_an_or_under_construction = value