69
71
# Set up a pango.Layout for the category title
70
72
cat_layout = ctx.create_layout ()
71
cat_layout.set_text (self.get_property("category-header"))
72
73
cat_layout.set_font_description (self.header_font_desc)
75
cat_layout.set_markup("...")
76
cat_layout_width, cat_layout_height = cat_layout.get_pixel_size()
77
ellipsise_size = cat_layout_width
79
cat_text = self.get_property("category-header")
80
cat_layout.set_markup(cat_text)
81
cat_layout_width, cat_layout_height = cat_layout.get_pixel_size()
74
83
# Set up a pango.Layout for the hit count
75
84
count_layout = ctx.create_layout ()
76
85
count_layout.set_text ("(" + str(self.get_property("match-count")) + ")")
77
86
count_layout.set_font_description (self.header_font_desc)
79
# Position and draw the layouts
80
ctx.move_to (18, background_area.y + 6)
81
ctx.show_layout (cat_layout)
82
w, h = count_layout.get_pixel_size()
83
ctx.move_to (background_area.width - w + 10, background_area.y + 6)
84
ctx.show_layout (count_layout)
86
# Draw a line in the normal background color in the top of the header,
87
# to separate rows a bit.
88
ctx.set_source_color (self.header_bg)
89
ctx.move_to (0, background_area.y + 1)
90
ctx.line_to (background_area.width + 100, background_area.y + 1) #FIXME: This 100 should really be the icon column width
88
count_layout_width, count_layout_height = count_layout.get_pixel_size()
90
max_cat_layout_width = cell_area.width - count_layout_width - 10
92
if cat_layout_width > max_cat_layout_width:
93
ratio = float(max_cat_layout_width - ellipsise_size)/cat_layout_width;
94
characters = int( ratio * len(cat_text) )
95
while (cat_layout_width > max_cat_layout_width):
97
cat_layout.set_markup( cat_text[0:characters].strip() + "..." )
99
cat_layout_width, cat_layout_height = cat_layout.get_pixel_size()
101
cat_layout.set_markup(cat_text.strip())
104
state = self.renderer_state_to_widget_state(flag)
105
main_gc = widget.get_style().text_gc[state]
107
window.draw_layout(main_gc,
109
cell_area.y + ( (cell_area.height - cat_layout_height) / 2) + 1,
112
mod_gc = widget.get_style().text_gc[state]
113
window.draw_layout(mod_gc,
114
(cell_area.x + cell_area.width) - count_layout_width - 2,
115
cell_area.y + ( (cell_area.height - count_layout_height) / 2 ) + 1,
118
def renderer_state_to_widget_state(self, flags):
119
state = gtk.STATE_NORMAL
120
if (gtk.CELL_RENDERER_SELECTED & flags) == gtk.CELL_RENDERER_SELECTED:
121
state = gtk.STATE_SELECTED
93
124
def do_get_property(self, property):
94
125
if property.name == 'category-header':
115
146
activation_keys = [65293] # Enter - Space makes a mess when users type in queries with spaces
118
"match-selected" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, [gobject.TYPE_PYOBJECT]),
149
"match-selected" : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, [gobject.TYPE_STRING, gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT]),
121
152
def __init__ (self, model):
122
153
gtk.TreeView.__init__ (self, model)
124
155
icon = gtk.CellRendererPixbuf ()
156
icon.set_property("xpad", 10)
125
157
hit_title = CellRendererCuemiacCategory ()
126
158
hit_title.set_property ("ellipsize", pango.ELLIPSIZE_END)
127
hit_title.set_property ("width-chars", 50) #FIXME: Pick width according to screen size
128
160
hits = gtk.TreeViewColumn ("Hits")
129
hits.pack_start (icon)
161
hits.pack_start (icon, expand=False)
130
162
hits.pack_start (hit_title)
131
163
hits.set_cell_data_func(hit_title, self.__get_match_title_for_cell)
132
164
hits.set_cell_data_func(icon, self.__get_match_icon_for_cell)
135
167
self.connect ("cursor-changed", self.__on_cursor_changed)
136
168
self.set_property ("headers-visible", False)
138
self.connect ("row-activated", self.__on_activated)
170
self.connect ("row-activated", self.__on_activated) # Used activate result if enter in entry has been pressed
139
171
self.connect ("button-press-event", self.__on_button_press)
140
172
self.connect ("key-press-event", self.__on_key_press)
145
177
# gtkTreeView does not use normal gtk DnD api.
146
178
# it uses the api from hell
148
# Stuff to handle persistant expansion states.
149
# A category will be expanded if it's in __collapsed_rows
150
self.__collapsed_rows = deskbar.GCONF_CLIENT.get_list(deskbar.GCONF_COLLAPSED_CAT, gconf.VALUE_STRING)
151
deskbar.GCONF_CLIENT.notify_add(deskbar.GCONF_COLLAPSED_CAT, lambda x, y, z, a: self.__on_config_expanded_cat(z.value))
153
self.connect ("row-expanded", self.__on_row_expanded, model)
154
self.connect ("row-collapsed", self.__on_row_collapsed, model)
155
model.connect ("category-added", self.__on_category_added)
159
180
def is_ready (self):
160
181
""" Returns True if the view is ready for user interaction """
161
182
num_children = self.get_model().iter_n_children (None)
254
272
model = self.get_model ()
255
273
match = model[model.get_iter(path)][model.MATCHES]
256
274
if match.__class__ != CuemiacCategory:
257
self.emit ("row-activated", path, col)
258
#self.emit ("match-selected", match)
260
def __on_config_expanded_cat (self, value):
261
if value != None and value.type == gconf.VALUE_LIST:
262
self.__collapsed_rows = [h.get_string() for h in value.get_list()]
264
def __on_row_expanded (self, widget, iter, path, model):
265
idx = model[iter][model.MATCHES].get_id ()
266
if idx in self.__collapsed_rows:
267
self.__collapsed_rows.remove (idx)
268
deskbar.GCONF_CLIENT.set_list(deskbar.GCONF_COLLAPSED_CAT, gconf.VALUE_STRING, self.__collapsed_rows)
270
def __on_row_collapsed (self, widget, iter, path, model):
271
idx = model[iter][model.MATCHES].get_id ()
272
self.__collapsed_rows.append (idx)
273
deskbar.GCONF_CLIENT.set_list(deskbar.GCONF_COLLAPSED_CAT, gconf.VALUE_STRING, self.__collapsed_rows)
275
def __on_category_added (self, widget, cat, path):
276
if cat.get_id() not in self.__collapsed_rows:
277
self.expand_row (path, False)
275
self.__on_activated(treeview, path, col, event)
277
# def __on_config_expanded_cat (self, value):
278
# if value != None and value.type == gconf.VALUE_LIST:
279
# self.__collapsed_rows = [h.get_string() for h in value.get_list()]
279
281
def __on_cursor_changed (self, view):
280
282
model, iter = self.get_selection().get_selected()
287
289
if match.__class__ == CuemiacCategory:
288
290
cell.set_property ("pixbuf", None)
291
cell.set_property ("visible", True)
289
292
cell.set_property ("cell-background-gdk", self.style.bg[gtk.STATE_NORMAL])
291
elif match.__class__== tuple:
292
cell.set_property ("cell-background-gdk", self.style.base[gtk.STATE_NORMAL])
293
qstring, match_obj = match
294
cell.set_property ("pixbuf", match_obj.get_icon())
296
print "ERROR:See bug 359251 and report this output: Match object of unexpected type: %r - %r" % (match.__class__, match)
297
294
cell.set_property ("cell-background-gdk", self.style.base[gtk.STATE_NORMAL])
298
cell.set_property ("pixbuf", None)
295
if isinstance(match, Match):
296
cell.set_property ("pixbuf", match.get_icon())
297
cell.set_property ("visible", True)
299
logging.error("See bug 359251 and report this output: Match object of unexpected type: %r - %r" % (match.__class__, match))
300
cell.set_property ("pixbuf", None)
301
cell.set_property ("visible", False)
302
303
def __get_match_title_for_cell (self, column, cell, model, iter, data=None):
318
319
cell.set_property ("markup", model[iter][model.ACTIONS])
320
def __on_activated (self, treeview, path, col):
321
def __on_activated (self, treeview, path, col, event=None):
321
322
model = self.get_model()
322
323
iter = model.get_iter (path)
323
324
match = model[iter][model.MATCHES]
325
qstring = model[iter][model.QUERY]
325
327
# Check if this s really a match and not just
327
if match.__class__ == CuemiacCategory:
329
if isinstance(match, CuemiacCategory):
330
# So we have a Match, tell the world
331
self.emit ("match-selected", match)
332
# So we have a Match, tell the world
333
self.emit ("match-selected", qstring, match, event)
334
335
def __on_key_press (self, widget, event):
335
336
# FIXME: In the future we should check for ctrl being pressed to create shortcuts