Source code for tagit.controller.filter

"""Filter controller.

Part of the tagit module.
A copy of the license is provided with the project.
Author: Matthias Baumgartner, 2016

"""
# IMPORTS
import json
import re

# INNER-MODULE IMPORTS
from controller import DataController
from ..basics import unique, split, string_types
from ..bindings import Binding
from browser import TAGS_SEPERATOR
from ..token import Token_Tag, Token_Include, Token_Exclude, token_factory

# EXPORTS
__all__ = ('CFilter', 'CFilterToken')


## CODE ##

class CFilterToken(DataController): pass # Just for get_root and parent

[docs]class CFilter(DataController): def __init__(self, widget, model, settings, parent=None): super(CFilter, self).__init__(widget, model, settings, parent) self.active = [] self.inactive = [] # Database update self.parent.bind(on_images_change=self.apply) self.parent.bind(on_show_selected=self.selected_show) self.parent.bind(on_remove_selected=self.selected_remove) # Keyboard bindings self.get_root().bind(on_keyboard=self.on_keyboard) def __del__(self): # Release bindings self.get_root().unbind(on_keyboard=self.on_keyboard) self.parent.unbind(on_images_change=self.apply) self.parent.unbind(on_show_selected=self.selected_show) self.parent.unbind(on_remove_selected=self.selected_remove)
[docs] def save(self, path): """Save the current filter to *path*. """ import json fh = open(path, 'w') json.dump((self.active, self.inactive), fh)
[docs] def load(self, path): """Load the filter from *path*. """ import json self.active, self.inactive = json.load(open(path)) self.redraw() self.apply()
def num_tokens(self): return len(self.active) ########################################################################### # WIDGET CONTROL # ###########################################################################
[docs] def redraw(self): """Update the widget.""" tokens_raw = self.active + self.inactive self.widget.redraw(tokens_raw, len(self.active)) ########################################################################### # GETTERS # ###########################################################################
def get_tokens(self): return self.active def get_tags(self): return filter(Token_Tag.match, self.active)
[docs] def apply(self): """Run the filter. """ # query the filter from the database query_result = self.model.query(self.active) # Propagate the result via the parent self.parent.dispatch('on_results_change', self, query_result) return False # Don't prevent other listeners to run. ########################################################################### # OPERATIONS # ###########################################################################
[docs] def go_back(self, nSteps=1): """Remove the last *nSteps* tokens. """ self.inactive = self.active[-nSteps:] + self.inactive self.active = self.active[:-nSteps] self.redraw() self.apply()
[docs] def go_forth(self, nSteps=1): """Re-add the next *nSteps* tokens. """ self.active = self.active + self.inactive[:nSteps] self.inactive = self.inactive[nSteps:] self.redraw() self.apply()
[docs] def remove_token(self, token): """Remove a *token* from the token list. """ if token in self.active: self.active.remove(token) self.redraw() self.apply() if token in self.inactive: self.inactive.remove(token) self.redraw()
[docs] def add_token_tag(self, text): """Add a token for tag *text*.""" self.add_token(Token_Tag(text))
[docs] def add_variable_token(self, text): """Add a token and allow its type to be specified.""" parts = re.match('^!\s*(\w+)\s*:\s*(.*)$', text) if parts is not None: type_, args = parts.groups() token = token_factory(type_, args) self.add_token(token) else: self.add_token_tag(text)
[docs] def add_token(self, token): """Add a token *text*. """ if token not in self.active: self.active.append(token) self.inactive = [] self.redraw() self.apply()
[docs] def edit_token(self, token, data): """Change *token* to *text*. """ if token in self.active: if token.from_string(data) not in self.active: # add to active token.update(data) # delete from inactive if token in self.inactive: self.inactive.remove(token) self.redraw() self.apply() elif token in self.inactive: if token.from_string(data) not in self.inactive: # add to inactive token.update(data) # delete from active post = lambda: True if token in self.active: self.active.remove(token) post = self.apply self.redraw() post() ########################################################################### # EVENTS # ###########################################################################
def selected_show(self, selection): self.add_token(Token_Include(selection)) def selected_remove(self, selection): self.add_token(Token_Exclude(selection)) ########################################################################### # KEYBINDINGS # ###########################################################################
[docs] def on_keyboard(self, wx, evt): """Handle filter keyboard events. """ if Binding.check(evt, self.settings.trace('bindings', 'filter', 'redraw ', Binding.simple(286))): # F5 self.apply() return True elif Binding.check(evt, self.settings.trace('bindings', 'filter', 'add_token ', Binding.simple(107, Binding.CTRL, Binding.REST))): # Ctrl + k return self.request_add_token() elif Binding.check(evt, self.settings.trace('bindings', 'filter', 'edit_filter', Binding.simple(108, Binding.CTRL, Binding.REST))): # Ctrl + l return self.request_editor() elif Binding.check(evt, self.settings.trace('bindings', 'filter', 'go_back ', Binding.multi((Binding.BACKSPACE, Binding.CTRL, Binding.REST), (Binding.LEFT, Binding.ALT, Binding.REST)))): self.go_back(1) return True elif Binding.check(evt, self.settings.trace('bindings', 'filter', 'go_forth ', Binding.simple(Binding.RIGHT, Binding.ALT, Binding.REST))): self.go_forth(1) return True return False ########################################################################### # MOUSE EVENTS # ###########################################################################
[docs] def request_apply(self): """Apply the filter. """ self.apply() return True
[docs] def request_add_token(self): """Add a token. """ self.widget.token_dialogue('', self.add_variable_token) return True
[docs] def request_remove_token(self, token): """Remove token *token*. """ if token in self.active + self.inactive: self.remove_token(token) return True return False
[docs] def request_edit_token(self, token, newtext=''): """Change *token*. If *newtext* is empty, a dialogue will be requested. Otherwise, *token* is changed to *newtext*. """ if token not in self.active + self.inactive: return False if newtext != '': self.edit_token(token, newtext) else: self.widget.token_dialogue(token.edit(), lambda txt: self.edit_token(token, txt)) return True
def request_editor(self): active, inactive = self.active, self.inactive active = filter(Token_Tag.match, active) inactive = filter(Token_Tag.match, inactive) def on_ok(text): # Remove tag tokens for tok in active: self.active.remove(tok) for tok in inactive: self.inactive.remove(tok) # Add new tokens to the rear for tok in text.split(TAGS_SEPERATOR): tok = tok.strip() if len(tok) > 0: self.add_token_tag(tok) def on_cancel(text): self.redraw() self.widget.show_editor((TAGS_SEPERATOR + ' ').join(map(lambda t: t.edit(), active)), on_ok, on_cancel) ## EOF ##