1
# -*- coding: utf-8 -*-
2
# -----------------------------------------------------------------------------
3
# Gettings Things Gnome! - a personal organizer for the GNOME desktop
4
# Copyright (c) 2008-2012 - Lionel Dricot & Bertrand Rousseau
6
# This program is free software: you can redistribute it and/or modify it under
7
# the terms of the GNU General Public License as published by the Free Software
8
# Foundation, either version 3 of the License, or (at your option) any later
11
# This program is distributed in the hope that it will be useful, but WITHOUT
12
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
16
# You should have received a copy of the GNU General Public License along with
17
# this program. If not, see <http://www.gnu.org/licenses/>.
18
# -----------------------------------------------------------------------------
20
""" Tag completion which is connected to LibLarch """
25
FILTER_NAME = '@@TagCompletion'
28
def tag_filter(tag, parameters=None):
29
""" Show only regular tags which has some active tasks or the user has
30
changed an attribute (e.g. color, workview) => only important tags """
31
if tag.get_id().startswith('@'):
32
has_attributes = len(tag.get_all_attributes(butname=True)) > 0
33
return has_attributes or tag.get_active_tasks_count() > 0
38
def normalize_unicode(string):
39
""" Unicode characters with diacritic could have more than just one
40
representation. We force them to be in just one of them."""
41
return unicodedata.normalize('NFC', unicode(string))
44
def tag_match(completion, key, iterator, column):
45
""" Does key match an item in the list?
47
Don't match any item if only artefacts (!, @) are inserted
48
(don't show all tags) """
50
key = key.lower().lstrip()
51
if key in ['', '!', '@', '!@']:
54
text = completion.get_model().get_value(iterator, column)
55
text = normalize_unicode(text.lower())
57
return text.startswith(key)
60
class TagCompletion(gtk.EntryCompletion):
61
""" Tag completion which allows to enter 4 representation of a '@tag':
62
['@tag', '!@tag', 'tag', '!tag']
64
The user can choose wheter write tag with or without '@',
65
with or without '!' which is used for negation.
67
The list of tasks is updated by LibLarch callbacks """
69
def __init__(self, tree):
70
""" Initialize entry completion
72
Create a list store which is connected to a LibLarch and
74
gtk.EntryCompletion.__init__(self)
76
self.tags = gtk.ListStore(str)
78
tree = tree.get_basetree()
79
tree.add_filter(FILTER_NAME, tag_filter, {'flat': True})
80
tag_tree = tree.get_viewtree('tag_completion', False)
81
tag_tree.register_cllbck('node-added-inview', self._on_tag_added)
82
tag_tree.register_cllbck('node-deleted-inview', self._on_tag_deleted)
83
tag_tree.apply_filter(FILTER_NAME)
85
self.set_model(self.tags)
86
self.set_text_column(0)
87
self.set_match_func(tag_match, 0)
88
self.set_inline_completion(True)
89
self.set_inline_selection(True)
90
self.set_popup_single_match(False)
92
def _try_insert(self, name):
93
""" Insert an item into ListStore if it is not already there.
94
It keeps the list sorted. """
96
for position, row in enumerate(self.tags, 1):
103
self.tags.insert(position, (name, ))
105
def _on_tag_added(self, tag, path):
106
""" Add all variants of tag """
107
tag = normalize_unicode(tag)
108
self._try_insert(tag)
109
self._try_insert('!' + tag)
110
self._try_insert(tag[1:])
111
self._try_insert('!' + tag[1:])
113
def _try_delete(self, name):
114
""" Delete an item if it is in the list """
115
for row in self.tags:
117
self.tags.remove(row.iter)
120
def _on_tag_deleted(self, tag, path):
121
""" Delete all variants of tag """
122
tag = normalize_unicode(tag)
123
self._try_delete(tag)
124
self._try_delete('!' + tag)
125
self._try_delete(tag[1:])
126
self._try_delete('!' + tag[1:])