Renaming some event handlers
[multilist] / src / libview.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 """
5 This file is part of Multilist.
6
7 Multilist is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 Multilist is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Multilist.  If not, see <http://www.gnu.org/licenses/>.
19
20 Copyright (C) 2008 Christoph Würstle
21 """
22
23 import logging
24
25 import gtk
26 import gobject
27 import pango
28
29 import gtk_toolbox
30
31
32 try:
33         _
34 except NameError:
35         _ = lambda x: x
36
37
38 _moduleLogger = logging.getLogger(__name__)
39
40
41 class CellRendererTriple(gtk.GenericCellRenderer):
42         __gproperties__ = {
43                 "status": (gobject.TYPE_STRING, "Status",
44                 "Status", "", gobject.PARAM_READWRITE),
45         }
46
47         __gsignals__ = {
48                 'status_changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_INT, gobject.TYPE_STRING)),
49         }
50
51         def __init__(self):
52                 #self.__gobject_init__()
53                 #gtk.GenericCellRenderer.__init__(self, *args, **kwargs)
54                 gtk.GenericCellRenderer.__init__(self)
55                 #self.__gobject_init__()
56                 self.status = -1
57                 self.xpad = 2
58                 self.ypad = 2
59                 self.mode = gtk.CELL_RENDERER_MODE_ACTIVATABLE
60                 self.xpad = -2
61                 self.ypad = -2
62                 self.xalign = 0.5
63                 self.yalign = 0.5
64                 self.active = 0
65                 self.widget = None
66                 self.last_cell = None
67                 self.connect('editing-started', self.on_clicked)
68
69         def do_set_property(self, property, value):
70                 setattr(self, property.name, value)
71
72         def do_get_property(self, property):
73                 return getattr(self, property.name)
74
75         def get_layout(self, widget):
76                 '''Gets the Pango layout used in the cell in a TreeView widget.'''
77
78                 layout = pango.Layout(widget.get_pango_context())
79                 layout.set_width(-1)    # Do not wrap text.
80
81                 layout.set_text('  ')
82
83                 return layout
84
85         def on_get_size(self, widget, cell_area = None):
86                 xpad = 2
87                 ypad = 2
88
89                 xalign = 0
90                 yalign = 0.5
91
92                 layout = self.get_layout(widget)
93                 width, height = layout.get_pixel_size()
94
95                 x_offset = xpad
96                 y_offset = ypad
97
98                 if cell_area:
99
100                         x_offset = xalign * (cell_area.width - width)
101                         x_offset = max(x_offset, xpad)
102                         x_offset = int(round(x_offset, 0))
103
104                         y_offset = yalign * (cell_area.height - height)
105                         y_offset = max(y_offset, ypad)
106                         y_offset = int(round(y_offset, 0))
107
108                 width  = width  + (xpad * 2)
109                 height = height + (ypad * 2)
110
111                 return x_offset, y_offset, width, height
112
113         def on_clicked(self,  widget, data):
114                 print widget, data
115
116         def clicked(self, widget, data1 = None):
117                 x, y = widget.get_pointer()
118                 widget.realize()
119
120                 path = widget.get_path_at_pos(x, y)
121
122                 #print "a", widget.get_cursor()
123                 #print path
124
125                 path = widget.get_cursor()[0]
126
127                 if path is not None:
128                         irow = path[0]  #path[0][0]-1
129                         rect = widget.get_cell_area(irow, widget.get_column(0)) #FixME 0 is hardcoded
130                         if x < rect.x+rect.width:
131                                 self.emit("status_changed", irow, self.status)
132                 else:
133                         return
134
135                         #workarround -1 means last item, because bug in treeview?!
136                         #print "not in list"
137                         rect = widget.get_visible_rect() #widget.get_cell_area(-1, widget.get_column(0))
138                         #print rect.x, rect.y, rect.width, rect.height, x, y
139                         irow = -1
140                         rect = widget.get_cell_area(0, widget.get_column(0)) #FixME 0 is hardcoded
141                         if x < rect.x+rect.width:
142                                 self.emit("status_changed", irow, "-1")
143
144         def on_render(self, window, widget, background_area, cell_area, expose_area, flags ):
145                 if (self.widget == None):
146                         #print widget
147                         self.widget = widget
148                         self.widget.connect("cursor-changed", self.clicked) #button-press-event
149
150                 self.last_cell = cell_area
151
152                 x = int(cell_area.x+(cell_area.width-2)/2-(cell_area.height-2)/2)
153                 y = int(cell_area.y+1)
154                 height = int(cell_area.height-2)
155                 width = int(height)
156
157                 if (self.status == "1"):
158                         widget.style.paint_check(window, gtk.STATE_NORMAL, gtk.SHADOW_IN, cell_area, widget, "cellradio", x, y, width, height)
159                 elif (self.status == "0"):
160                         #width = height
161                         height = height-3
162                         width = height
163
164                         widget.style.paint_flat_box(window, gtk.STATE_NORMAL, gtk.SHADOW_NONE, cell_area, widget, "cellunselected", x, y, width, height)
165
166                         widget.style.paint_hline(window, gtk.STATE_NORMAL, cell_area, widget, "cellunselected", x, x+width, y)
167                         widget.style.paint_hline(window, gtk.STATE_NORMAL, cell_area, widget, "cellunselected", x, x+width, y+height)
168                         widget.style.paint_vline(window, gtk.STATE_NORMAL, cell_area, widget, "cellunselected", y, y+height, x)
169                         widget.style.paint_vline(window, gtk.STATE_NORMAL, cell_area, widget, "cellunselected", y, y+height, x+width)
170
171                 else:
172                         widget.style.paint_diamond(window, gtk.STATE_NORMAL, gtk.SHADOW_IN, cell_area, widget, "cellunselected", x, y, width, height)
173
174                 #widget.show_all()
175                 #print "render"
176                 pass
177
178         def on_start_editing(self, event, widget, path, background_area, cell_area, flags):
179                 print "on_start_editing", path
180                 return None
181
182         def on_activate(self, event, widget, path, background_area, cell_area, flags):
183                 print "activate", path
184                 return False
185
186
187 class CellRendererCombo2(gtk.GenericCellRenderer):
188         __gproperties__ = {
189                 "text": (gobject.TYPE_STRING, "text",
190                 "Text", "", gobject.PARAM_READWRITE),
191         }
192
193         __gsignals__ = {
194                 'status_changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_INT, gobject.TYPE_STRING)),
195         }
196
197         def __init__(self):
198                 #self.__gobject_init__()
199                 #gtk.GenericCellRenderer.__init__(self, *args, **kwargs)
200                 gtk.GenericCellRenderer.__init__(self)
201                 #self.__gobject_init__()
202                 self.status = -1
203                 self.xpad = 2
204                 self.ypad = 2
205                 self.mode = gtk.CELL_RENDERER_MODE_ACTIVATABLE
206                 self.xpad = -2
207                 self.ypad = -2
208                 self.xalign = 0.5
209                 self.yalign = 0.5
210                 self.active = 0
211                 self.widget = None
212                 self.last_cell = None
213                 self.text = "(none)"
214                 self.connect('editing-started', self.on_clicked)
215
216         def do_set_property(self, property, value):
217                 #print property, value
218                 setattr(self, property.name, value)
219
220         def do_get_property(self, property):
221                 return getattr(self, property.name)
222
223         def get_layout(self, widget):
224                 '''Gets the Pango layout used in the cell in a TreeView widget.'''
225
226                 layout = pango.Layout(widget.get_pango_context())
227                 layout.set_width(-1)    # Do not wrap text.
228
229                 layout.set_text(self.text)
230
231                 return layout
232
233         def on_get_size(self, widget, cell_area = None):
234                 xpad = 2
235                 ypad = 2
236
237                 xalign = 0
238                 yalign = 0.5
239
240                 layout = self.get_layout(widget)
241                 width, height = layout.get_pixel_size()
242
243                 x_offset = xpad
244                 y_offset = ypad
245
246                 if cell_area:
247
248                         x_offset = xalign * (cell_area.width - width)
249                         x_offset = max(x_offset, xpad)
250                         x_offset = int(round(x_offset, 0))
251
252                         y_offset = yalign * (cell_area.height - height)
253                         y_offset = max(y_offset, ypad)
254                         y_offset = int(round(y_offset, 0))
255
256                 width  = width  + (xpad * 2)
257                 height = height + (ypad * 2)
258
259                 return x_offset, y_offset, width, height
260
261         @gtk_toolbox.log_exception(_moduleLogger)
262         def on_clicked(self,  widget, data):
263                 print widget, data
264
265         def clicked(self, widget, data1 = None):
266                 return
267                 x, y = widget.get_pointer()
268                 widget.realize()
269
270                 #path = widget.get_path_at_pos(x, y)
271
272                 path = widget.get_cursor()[0]
273
274                 if path is not None:
275                         irow = path[0]  #path[0][0]-1
276                         rect = widget.get_cell_area(irow, widget.get_column(0)) #FixME 0 is hardcoded
277                         if x < rect.x+rect.width:
278                                 self.emit("status_changed", irow, self.status)
279                 else:
280                         return
281
282                         #workarround -1 means last item, because bug in treeview?!
283                         #print "not in list"
284                         rect = widget.get_visible_rect() #widget.get_cell_area(-1, widget.get_column(0))
285                         #print rect.x, rect.y, rect.width, rect.height, x, y
286                         irow = -1
287                         rect = widget.get_cell_area(0, widget.get_column(0)) #FixME 0 is hardcoded
288                         if x < rect.x+rect.width:
289                                 self.emit("status_changed", irow, "-1")
290
291         def on_render(self, window, widget, background_area, cell_area, expose_area, flags ):
292                 if (self.widget == None):
293                         self.widget = widget
294                         self.widget.connect("cursor-changed", self.clicked) #button-press-event
295
296                 self.last_cell = cell_area
297
298                 x = int(cell_area.x+(cell_area.width-2)/2-(cell_area.height-2)/2)
299                 y = int(cell_area.y+1)
300                 height = int(cell_area.height-2)
301                 width = int(height)
302
303                 widget.style.paint_layout(window, gtk.STATE_NORMAL, True, cell_area, widget, "cellradio", x, y, self.get_layout(widget))
304
305                 #widget.show_all()
306
307         def on_start_editing(self, event, widget, path, background_area, cell_area, flags):
308                 print "on_start_editing", path
309                 return None
310
311         def on_activate(self, event, widget, path, background_area, cell_area, flags):
312                 print "activate", path
313                 return False
314
315
316 gobject.type_register(CellRendererCombo2)
317 gobject.type_register(CellRendererTriple)
318
319
320 class View(gtk.VBox):
321
322         def __init__(self, db, liststorehandler, parent_window):
323                 self.db = db
324                 self.parent_window = parent_window
325                 self.liststorehandler = liststorehandler
326
327                 gtk.VBox.__init__(self, homogeneous = False, spacing = 0)
328
329                 logging.info("libview, init")
330
331                 self.scrolled_window = None
332                 self.reload_view()
333
334         def loadList(self):
335                 ls = self.liststorehandler.get_liststore()
336                 self.treeview.set_model(ls)
337
338         def col_edited(self, cell, irow, new_text, icol = None):
339                 if (irow != 4):
340                         self.liststorehandler.update_row(irow, icol, new_text)
341                 else:
342                         print cell, irow, new_text, icol
343
344         def col_toggled(self, widget, irow, status ):
345                 ls = self.treeview.get_model()
346
347                 if self.liststorehandler.get_filter() == self.liststorehandler.SHOW_ACTIVE:
348                         if ls[irow][1] == "0":
349                                 self.liststorehandler.update_row(irow, 1, "1")
350                         else:
351                                 self.liststorehandler.update_row(irow, 1, "0")
352                 else:
353                         if ls[irow][1] == "1":
354                                 self.liststorehandler.update_row(irow, 1, "-1")
355                         elif ls[irow][1] == "0":
356                                 self.liststorehandler.update_row(irow, 1, "1")
357                         else:
358                                 self.liststorehandler.update_row(irow, 1, "0")
359
360         def convert(self, s):
361                 if s == "1":
362                         return 1
363                 else:
364                         return 0
365
366         def del_active_row(self):
367                 path, col = self.treeview.get_cursor()
368                 if path is not None:
369                         irow = path[0]
370                         row_iter = self.treeview.get_model().get_iter(path)
371                         self.liststorehandler.del_row(irow, row_iter)
372
373         def sort_func_function(self, model, iter1, iter2, data = None):
374                 print "sorting"
375
376         def reload_view(self):
377                 # create the TreeView using liststore
378                 self.modelsort = gtk.TreeModelSort(self.liststorehandler.get_liststore())
379                 self.modelsort.set_sort_column_id(2, gtk.SORT_ASCENDING)
380
381                 self.treeview = gtk.TreeView(self.modelsort)
382                 self.treeview.set_headers_visible(True)
383
384                 self.cell = range(self.liststorehandler.get_colcount())
385                 self.tvcolumn = range(self.liststorehandler.get_colcount())
386
387                 m = self.liststorehandler.get_unitsstore()
388
389                 for i in range(self.liststorehandler.get_colcount()):
390                         if i in [1, 2]:
391                                 default = "1"
392                         else:
393                                 default = "0"
394                         if self.db.ladeDirekt("showcol_"+str(self.liststorehandler.get_colname(i)), default) == "1":
395                                 if i in [1]:
396                                         self.cell[i] = CellRendererTriple()
397                                         self.tvcolumn[i] = gtk.TreeViewColumn("", self.cell[i])
398                                         self.cell[i].connect( 'status_changed', self.col_toggled)
399                                         self.tvcolumn[i].set_attributes( self.cell[i], status = i)
400                                 elif i in [3, 6]:
401                                         self.cell[i] = gtk.CellRendererCombo()
402                                         self.tvcolumn[i] = gtk.TreeViewColumn(self.liststorehandler.get_colname(i), self.cell[i])
403                                         self.cell[i].set_property("model", m)
404                                         self.cell[i].set_property('text-column', i)
405                                         self.cell[i].set_property('editable', True)
406                                         self.cell[i].connect("edited", self.col_edited, i)
407                                         self.tvcolumn[i].set_attributes( self.cell[i], text = i)
408                                 else:
409                                         self.cell[i] = gtk.CellRendererText()
410                                         self.tvcolumn[i] = gtk.TreeViewColumn(self.liststorehandler.get_colname(i), self.cell[i])
411                                         self.cell[i].set_property('editable', True)
412                                         self.cell[i].set_property('editable-set', True)
413                                         self.cell[i].connect("edited", self.col_edited, i)
414                                         #self.cell[i].connect("editing-canceled", self.col_edited2, i) 
415                                         self.tvcolumn[i].set_attributes(self.cell[i], text = i)
416
417                                 self.cell[i].set_property('cell-background', 'lightgray')
418                                 self.tvcolumn[i].set_sort_column_id(i)
419                                 self.tvcolumn[i].set_resizable(True)
420                                 self.treeview.append_column(self.tvcolumn[i])
421
422                 # Disable drag and drop reordering of rows
423                 self.treeview.set_reorderable(False)
424
425                 if self.scrolled_window is not None:
426                         self.scrolled_window.destroy()
427
428                 self.scrolled_window = gtk.ScrolledWindow()
429                 self.scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
430
431                 self.scrolled_window.add(self.treeview)
432                 self.pack_start(self.scrolled_window, expand = True, fill = True, padding = 0)
433                 self.loadList()
434
435                 self.show_all()