~nmu-sscheel/gtg/rework-task-editor

« back to all changes in this revision

Viewing changes to GTG/gtk/tag_completion.py

  • Committer: Bertrand Rousseau
  • Date: 2012-05-09 22:33:25 UTC
  • mfrom: (1178 trunk)
  • mto: This revision was merged to the branch mainline in revision 1179.
  • Revision ID: bertrand.rousseau@gmail.com-20120509223325-a53d8nwo0x9g93bc
Merge nimit branch and trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
5
#
 
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
 
9
# version.
 
10
#
 
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
 
14
# details.
 
15
#
 
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
# -----------------------------------------------------------------------------
 
19
 
 
20
""" Tag completion which is connected to LibLarch """
 
21
 
 
22
import gtk
 
23
import unicodedata
 
24
 
 
25
FILTER_NAME = '@@TagCompletion'
 
26
 
 
27
 
 
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
 
34
    else:
 
35
        return False
 
36
 
 
37
 
 
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))
 
42
 
 
43
 
 
44
def tag_match(completion, key, iterator, column):
 
45
    """ Does key match an item in the list?
 
46
 
 
47
    Don't match any item if only artefacts (!, @) are inserted
 
48
    (don't show all tags) """
 
49
 
 
50
    key = key.lower().lstrip()
 
51
    if key in ['', '!', '@', '!@']:
 
52
        return False
 
53
 
 
54
    text = completion.get_model().get_value(iterator, column)
 
55
    text = normalize_unicode(text.lower())
 
56
 
 
57
    return text.startswith(key)
 
58
 
 
59
 
 
60
class TagCompletion(gtk.EntryCompletion):
 
61
    """ Tag completion which allows to enter 4 representation of a '@tag':
 
62
       ['@tag', '!@tag', 'tag', '!tag']
 
63
 
 
64
       The user can choose wheter write tag with or without '@',
 
65
       with or without '!' which is used for negation.
 
66
 
 
67
       The list of tasks is updated by LibLarch callbacks """
 
68
 
 
69
    def __init__(self, tree):
 
70
        """ Initialize entry completion
 
71
 
 
72
        Create a list store which is connected to a LibLarch and
 
73
        kept updated. """
 
74
        gtk.EntryCompletion.__init__(self)
 
75
 
 
76
        self.tags = gtk.ListStore(str)
 
77
 
 
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)
 
84
 
 
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)
 
91
 
 
92
    def _try_insert(self, name):
 
93
        """ Insert an item into ListStore if it is not already there.
 
94
        It keeps the list sorted. """
 
95
        position = 0
 
96
        for position, row in enumerate(self.tags, 1):
 
97
            if row[0] == name:
 
98
                # already there
 
99
                return
 
100
            elif row[0] > name:
 
101
                position -= 1
 
102
                break
 
103
        self.tags.insert(position, (name, ))
 
104
 
 
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:])
 
112
 
 
113
    def _try_delete(self, name):
 
114
        """ Delete an item if it is in the list """
 
115
        for row in self.tags:
 
116
            if row[0] == name:
 
117
                self.tags.remove(row.iter)
 
118
                break
 
119
 
 
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:])