~ubuntu-branches/ubuntu/karmic/quodlibet/karmic

« back to all changes in this revision

Viewing changes to qltk/completion.py

  • Committer: Bazaar Package Importer
  • Author(s): Luca Falavigna
  • Date: 2009-01-30 23:55:34 UTC
  • mfrom: (1.1.12 upstream)
  • Revision ID: james.westby@ubuntu.com-20090130235534-l4e72ulw0vqfo17w
Tags: 2.0-1ubuntu1
* Merge from Debian experimental (LP: #276856), remaining Ubuntu changes:
  + debian/patches/40-use-music-profile.patch:
    - Use the "Music and Movies" pipeline per default.
* Refresh the above patch for new upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright 2005 Joe Wreschnig, Michael Urman
2
 
#
3
 
# This program is free software; you can redistribute it and/or modify
4
 
# it under the terms of the GNU General Public License version 2 as
5
 
# published by the Free Software Foundation
6
 
#
7
 
# $Id: completion.py 4047 2007-04-30 03:49:58Z piman $
8
 
 
9
 
import gtk
10
 
 
11
 
import formats
12
 
 
13
 
from util import copool
14
 
 
15
 
class EntryWordCompletion(gtk.EntryCompletion):
16
 
    """Entry completion for simple words, where a word boundry is
17
 
    roughly equivalent to the separators in the QL query language.
18
 
 
19
 
    You need to manually set a model containing the available words."""
20
 
 
21
 
    leftsep = ["&(", "|(", ",", ", "]
22
 
    rightsep = [" ", ")", ","]
23
 
 
24
 
    def __init__(self):
25
 
        super(EntryWordCompletion, self).__init__()
26
 
        self.set_match_func(self.__match_filter)
27
 
        self.connect('match-selected', self.__match_selected)
28
 
 
29
 
    def __match_filter(self, completion, entrytext, iter):
30
 
        model = completion.get_model()
31
 
        entry = self.get_entry()
32
 
        entrytext = entrytext.decode('utf-8')
33
 
        if entry is None: return False
34
 
        cursor = entry.get_position()
35
 
        if (cursor != len(entrytext) and not
36
 
            max([entrytext[cursor:].startswith(s) for s in self.rightsep])):
37
 
            return False
38
 
 
39
 
        # find the border to the left
40
 
        left, f = max(
41
 
            [(entrytext.rfind(c, 0, cursor), c) for c in self.leftsep])
42
 
        if left < 0: left += 1
43
 
        else: left += len(f)
44
 
 
45
 
        if left == cursor: return False
46
 
        key = entrytext[left:cursor]
47
 
 
48
 
        value = model.get_value(iter, self.get_property('text-column'))
49
 
        return bool(value and value.startswith(key))
50
 
 
51
 
    def __match_selected(self, completion, model, iter):
52
 
        value = model.get_value(iter, self.get_property('text-column'))
53
 
        entry = self.get_entry()
54
 
        cursor = entry.get_position()
55
 
 
56
 
        text = entry.get_text()
57
 
        text = text.decode('utf-8')
58
 
        left, f = max(
59
 
            [(text.rfind(c, 0, cursor), c) for c in self.leftsep])
60
 
        if left == -1: left += 1
61
 
        else: left += len(f)
62
 
        offset = cursor - left
63
 
 
64
 
        entry.insert_text(value[offset:], cursor)
65
 
        entry.set_position(left + len(value))
66
 
        return True
67
 
 
68
 
class LibraryTagCompletion(EntryWordCompletion):
69
 
    """A completion for text entries tied to a library's tag list."""
70
 
 
71
 
    def __init__(self, library):
72
 
        super(LibraryTagCompletion, self).__init__()
73
 
        try: model = self.__model
74
 
        except AttributeError:
75
 
            model = type(self).__model = gtk.ListStore(str)
76
 
            library.connect('changed', self.__refreshmodel, model)
77
 
            library.connect('added', self.__refreshmodel, model)
78
 
            library.connect('removed', self.__refreshmodel, model)
79
 
            self.__refreshmodel(library, None, model)
80
 
        self.set_model(model)
81
 
        self.set_text_column(0)
82
 
 
83
 
    @classmethod
84
 
    def __refreshmodel(klass, library, songs, model):
85
 
        copool.add(klass.__refreshmodel_real, library, model)
86
 
 
87
 
    @classmethod
88
 
    def __refreshmodel_real(klass, library, model):
89
 
        tags = set()
90
 
        model.clear()
91
 
        yield True
92
 
        # Iterate over a new list since this function and the
93
 
        # library updater are copooled with different IDs.
94
 
        for count, song in enumerate(list(library)):
95
 
            for tag in song.keys():
96
 
                if not (tag.startswith("~#") or tag in formats.MACHINE_TAGS):
97
 
                    tags.add(tag)
98
 
            if count % 1000 == 0:
99
 
                yield True
100
 
        tags.update(["~dirname", "~basename", "~people", "~format"])
101
 
        for tag in ["track", "disc", "playcount", "skipcount", "lastplayed",
102
 
                    "mtime", "added", "rating", "length"]:
103
 
            tags.add("#(" + tag)
104
 
        for tag in ["date", "bpm"]:
105
 
            if tag in tags: tags.add("#(" + tag)
106
 
        yield True
107
 
        for tag in tags:
108
 
            model.append([tag])
109
 
 
110
 
class LibraryValueCompletion(gtk.EntryCompletion):
111
 
    """Entry completion for a library value, for a specific tag."""
112
 
 
113
 
    def __init__(self, tag, library):
114
 
        super(LibraryValueCompletion, self).__init__()
115
 
        self.set_model(gtk.ListStore(str))
116
 
        self.set_text_column(0)
117
 
        self.set_tag(tag, library)
118
 
 
119
 
    def set_tag(self, tag, library):
120
 
        if tag is None:
121
 
            return
122
 
        elif tag in ("bpm date discnumber isrc originaldate recordingdate "
123
 
                     "tracknumber title").split() + formats.MACHINE_TAGS:
124
 
            return
125
 
        elif tag in formats.PEOPLE:
126
 
            tag = "~people"
127
 
        copool.add(self.__fill_tag, tag, library)
128
 
 
129
 
    def __fill_tag(self, tag, library):
130
 
        model = self.get_model()
131
 
        model.clear()
132
 
        yield True
133
 
        values = sorted(library.tag_values(tag))
134
 
        self.set_minimum_key_length(int(len(values) > 100))
135
 
        yield True
136
 
        for count, value in enumerate(values):
137
 
            model.append(row=[value])
138
 
            if count % 1000 == 0:
139
 
                yield True