1
# Copyright 2005 Joe Wreschnig, Michael Urman
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
7
# $Id: completion.py 4047 2007-04-30 03:49:58Z piman $
13
from util import copool
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.
19
You need to manually set a model containing the available words."""
21
leftsep = ["&(", "|(", ",", ", "]
22
rightsep = [" ", ")", ","]
25
super(EntryWordCompletion, self).__init__()
26
self.set_match_func(self.__match_filter)
27
self.connect('match-selected', self.__match_selected)
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])):
39
# find the border to the left
41
[(entrytext.rfind(c, 0, cursor), c) for c in self.leftsep])
42
if left < 0: left += 1
45
if left == cursor: return False
46
key = entrytext[left:cursor]
48
value = model.get_value(iter, self.get_property('text-column'))
49
return bool(value and value.startswith(key))
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()
56
text = entry.get_text()
57
text = text.decode('utf-8')
59
[(text.rfind(c, 0, cursor), c) for c in self.leftsep])
60
if left == -1: left += 1
62
offset = cursor - left
64
entry.insert_text(value[offset:], cursor)
65
entry.set_position(left + len(value))
68
class LibraryTagCompletion(EntryWordCompletion):
69
"""A completion for text entries tied to a library's tag list."""
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)
81
self.set_text_column(0)
84
def __refreshmodel(klass, library, songs, model):
85
copool.add(klass.__refreshmodel_real, library, model)
88
def __refreshmodel_real(klass, library, model):
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):
100
tags.update(["~dirname", "~basename", "~people", "~format"])
101
for tag in ["track", "disc", "playcount", "skipcount", "lastplayed",
102
"mtime", "added", "rating", "length"]:
104
for tag in ["date", "bpm"]:
105
if tag in tags: tags.add("#(" + tag)
110
class LibraryValueCompletion(gtk.EntryCompletion):
111
"""Entry completion for a library value, for a specific tag."""
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)
119
def set_tag(self, tag, library):
122
elif tag in ("bpm date discnumber isrc originaldate recordingdate "
123
"tracknumber title").split() + formats.MACHINE_TAGS:
125
elif tag in formats.PEOPLE:
127
copool.add(self.__fill_tag, tag, library)
129
def __fill_tag(self, tag, library):
130
model = self.get_model()
133
values = sorted(library.tag_values(tag))
134
self.set_minimum_key_length(int(len(values) > 100))
136
for count, value in enumerate(values):
137
model.append(row=[value])
138
if count % 1000 == 0: