Minor cleanup
[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 Columns_dialog(gtk.VBox):
42
43         def __init__(self, db, liststorehandler):
44                 gtk.VBox.__init__(self, homogeneous = False, spacing = 0)
45
46                 self.db = db
47                 self.liststorehandler = liststorehandler
48
49                 #serverbutton = gtk.ToggleButton("SyncServer starten")
50                 #serverbutton.connect("clicked", self.startServer, (None, ))
51                 #self.pack_start(serverbutton, expand = False, fill = True, padding = 1)
52                 #print "x1"
53
54                 frame = gtk.Frame(_("Columns"))
55                 self.framebox = gtk.VBox(homogeneous = False, spacing = 0)
56
57                 self.scrolled_window = gtk.ScrolledWindow()
58                 self.scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
59
60                 self.scrolled_window.add_with_viewport(self.framebox)
61
62                 i = 1 #uid can not be shown
63                 while self.liststorehandler.get_colname(i) is not None:
64                         name = str(self.liststorehandler.get_colname(i))
65                         checkbutton = gtk.CheckButton(name)
66                         if self.db.ladeDirekt("showcol_"+name) == "1":
67                                 checkbutton.set_active(True)
68
69                         self.framebox.pack_start(checkbutton)
70                         i = i+1
71
72                 frame.add(self.scrolled_window)
73                 self.pack_start(frame, expand = True, fill = True, padding = 1)
74
75         def is_col_selected(self, icol):
76                 children = self.framebox.get_children()
77                 if icol < len(children):
78                         return children[icol].get_active()
79                 else:
80                         return None
81
82         def save_column_setting(self):
83                 i = 1 #uid can not be shown
84                 while self.liststorehandler.get_colname(i) is not None:
85                         name = str(self.liststorehandler.get_colname(i))
86                         if self.is_col_selected(i-1) == True:
87                                 self.db.speichereDirekt("showcol_"+name, "1")
88                         else:
89                                 self.db.speichereDirekt("showcol_"+name, "0")
90                         i += 1
91
92
93 class CellRendererTriple(gtk.GenericCellRenderer):
94         __gproperties__ = {
95                 "status": (gobject.TYPE_STRING, "Status",
96                 "Status", "", gobject.PARAM_READWRITE),
97         }
98
99         __gsignals__ = {
100                 'status_changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_INT, gobject.TYPE_STRING)),
101         }
102
103         def __init__(self):
104                 #self.__gobject_init__()
105                 #gtk.GenericCellRenderer.__init__(self, *args, **kwargs)
106                 gtk.GenericCellRenderer.__init__(self)
107                 #self.__gobject_init__()
108                 self.status = -1
109                 self.xpad = 2
110                 self.ypad = 2
111                 self.mode = gtk.CELL_RENDERER_MODE_ACTIVATABLE
112                 self.xpad = -2
113                 self.ypad = -2
114                 self.xalign = 0.5
115                 self.yalign = 0.5
116                 self.active = 0
117                 self.widget = None
118                 self.last_cell = None
119                 self.connect('editing-started', self.on_clicked)
120
121         def do_set_property(self, property, value):
122                 setattr(self, property.name, value)
123
124         def do_get_property(self, property):
125                 return getattr(self, property.name)
126
127         def get_layout(self, widget):
128                 '''Gets the Pango layout used in the cell in a TreeView widget.'''
129
130                 layout = pango.Layout(widget.get_pango_context())
131                 layout.set_width(-1)    # Do not wrap text.
132
133                 layout.set_text('  ')
134
135                 return layout
136
137         def on_get_size(self, widget, cell_area = None):
138                 xpad = 2
139                 ypad = 2
140
141                 xalign = 0
142                 yalign = 0.5
143
144                 layout = self.get_layout(widget)
145                 width, height = layout.get_pixel_size()
146
147                 x_offset = xpad
148                 y_offset = ypad
149
150                 if cell_area:
151
152                         x_offset = xalign * (cell_area.width - width)
153                         x_offset = max(x_offset, xpad)
154                         x_offset = int(round(x_offset, 0))
155
156                         y_offset = yalign * (cell_area.height - height)
157                         y_offset = max(y_offset, ypad)
158                         y_offset = int(round(y_offset, 0))
159
160                 width  = width  + (xpad * 2)
161                 height = height + (ypad * 2)
162
163                 return x_offset, y_offset, width, height
164
165         def on_clicked(self,  widget, data):
166                 print widget, data
167
168         def clicked(self, widget, data1 = None):
169                 x, y = widget.get_pointer()
170                 widget.realize()
171
172                 path = widget.get_path_at_pos(x, y)
173
174                 #print "a", widget.get_cursor()
175                 #print path
176
177                 path = widget.get_cursor()[0]
178
179                 if path is not None:
180                         irow = path[0]  #path[0][0]-1
181                         rect = widget.get_cell_area(irow, widget.get_column(0)) #FixME 0 is hardcoded
182                         if x < rect.x+rect.width:
183                                 self.emit("status_changed", irow, self.status)
184                 else:
185                         return
186
187                         #workarround -1 means last item, because bug in treeview?!
188                         #print "not in list"
189                         rect = widget.get_visible_rect() #widget.get_cell_area(-1, widget.get_column(0))
190                         #print rect.x, rect.y, rect.width, rect.height, x, y
191                         irow = -1
192                         rect = widget.get_cell_area(0, widget.get_column(0)) #FixME 0 is hardcoded
193                         if x < rect.x+rect.width:
194                                 self.emit("status_changed", irow, "-1")
195
196         def on_render(self, window, widget, background_area, cell_area, expose_area, flags ):
197                 if (self.widget == None):
198                         #print widget
199                         self.widget = widget
200                         self.widget.connect("cursor-changed", self.clicked) #button-press-event
201
202                 self.last_cell = cell_area
203
204                 x = int(cell_area.x+(cell_area.width-2)/2-(cell_area.height-2)/2)
205                 y = int(cell_area.y+1)
206                 height = int(cell_area.height-2)
207                 width = int(height)
208
209                 if (self.status == "1"):
210                         widget.style.paint_check(window, gtk.STATE_NORMAL, gtk.SHADOW_IN, cell_area, widget, "cellradio", x, y, width, height)
211                 elif (self.status == "0"):
212                         #width = height
213                         height = height-3
214                         width = height
215
216                         widget.style.paint_flat_box(window, gtk.STATE_NORMAL, gtk.SHADOW_NONE, cell_area, widget, "cellunselected", x, y, width, height)
217
218                         widget.style.paint_hline(window, gtk.STATE_NORMAL, cell_area, widget, "cellunselected", x, x+width, y)
219                         widget.style.paint_hline(window, gtk.STATE_NORMAL, cell_area, widget, "cellunselected", x, x+width, y+height)
220                         widget.style.paint_vline(window, gtk.STATE_NORMAL, cell_area, widget, "cellunselected", y, y+height, x)
221                         widget.style.paint_vline(window, gtk.STATE_NORMAL, cell_area, widget, "cellunselected", y, y+height, x+width)
222
223                 else:
224                         widget.style.paint_diamond(window, gtk.STATE_NORMAL, gtk.SHADOW_IN, cell_area, widget, "cellunselected", x, y, width, height)
225
226                 #widget.show_all()
227                 #print "render"
228                 pass
229
230         def on_start_editing(self, event, widget, path, background_area, cell_area, flags):
231                 print "on_start_editing", path
232                 return None
233
234         def on_activate(self, event, widget, path, background_area, cell_area, flags):
235                 print "activate", path
236                 return False
237
238
239 class CellRendererCombo2(gtk.GenericCellRenderer):
240         __gproperties__ = {
241                 "text": (gobject.TYPE_STRING, "text",
242                 "Text", "", gobject.PARAM_READWRITE),
243         }
244
245         __gsignals__ = {
246                 'status_changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_INT, gobject.TYPE_STRING)),
247         }
248
249         def __init__(self):
250                 #self.__gobject_init__()
251                 #gtk.GenericCellRenderer.__init__(self, *args, **kwargs)
252                 gtk.GenericCellRenderer.__init__(self)
253                 #self.__gobject_init__()
254                 self.status = -1
255                 self.xpad = 2
256                 self.ypad = 2
257                 self.mode = gtk.CELL_RENDERER_MODE_ACTIVATABLE
258                 self.xpad = -2
259                 self.ypad = -2
260                 self.xalign = 0.5
261                 self.yalign = 0.5
262                 self.active = 0
263                 self.widget = None
264                 self.last_cell = None
265                 self.text = "(none)"
266                 self.connect('editing-started', self.on_clicked)
267
268         def do_set_property(self, property, value):
269                 #print property, value
270                 setattr(self, property.name, value)
271
272         def do_get_property(self, property):
273                 return getattr(self, property.name)
274
275         def get_layout(self, widget):
276                 '''Gets the Pango layout used in the cell in a TreeView widget.'''
277
278                 layout = pango.Layout(widget.get_pango_context())
279                 layout.set_width(-1)    # Do not wrap text.
280
281                 layout.set_text(self.text)
282
283                 return layout
284
285         def on_get_size(self, widget, cell_area = None):
286                 xpad = 2
287                 ypad = 2
288
289                 xalign = 0
290                 yalign = 0.5
291
292                 layout = self.get_layout(widget)
293                 width, height = layout.get_pixel_size()
294
295                 x_offset = xpad
296                 y_offset = ypad
297
298                 if cell_area:
299
300                         x_offset = xalign * (cell_area.width - width)
301                         x_offset = max(x_offset, xpad)
302                         x_offset = int(round(x_offset, 0))
303
304                         y_offset = yalign * (cell_area.height - height)
305                         y_offset = max(y_offset, ypad)
306                         y_offset = int(round(y_offset, 0))
307
308                 width  = width  + (xpad * 2)
309                 height = height + (ypad * 2)
310
311                 return x_offset, y_offset, width, height
312
313         @gtk_toolbox.log_exception(_moduleLogger)
314         def on_clicked(self,  widget, data):
315                 print widget, data
316
317         def clicked(self, widget, data1 = None):
318                 return
319                 x, y = widget.get_pointer()
320                 widget.realize()
321
322                 #path = widget.get_path_at_pos(x, y)
323
324                 path = widget.get_cursor()[0]
325
326                 if path is not None:
327                         irow = path[0]  #path[0][0]-1
328                         rect = widget.get_cell_area(irow, widget.get_column(0)) #FixME 0 is hardcoded
329                         if x < rect.x+rect.width:
330                                 self.emit("status_changed", irow, self.status)
331                 else:
332                         return
333
334                         #workarround -1 means last item, because bug in treeview?!
335                         #print "not in list"
336                         rect = widget.get_visible_rect() #widget.get_cell_area(-1, widget.get_column(0))
337                         #print rect.x, rect.y, rect.width, rect.height, x, y
338                         irow = -1
339                         rect = widget.get_cell_area(0, widget.get_column(0)) #FixME 0 is hardcoded
340                         if x < rect.x+rect.width:
341                                 self.emit("status_changed", irow, "-1")
342
343         def on_render(self, window, widget, background_area, cell_area, expose_area, flags ):
344                 if (self.widget == None):
345                         self.widget = widget
346                         self.widget.connect("cursor-changed", self.clicked) #button-press-event
347
348                 self.last_cell = cell_area
349
350                 x = int(cell_area.x+(cell_area.width-2)/2-(cell_area.height-2)/2)
351                 y = int(cell_area.y+1)
352                 height = int(cell_area.height-2)
353                 width = int(height)
354
355                 widget.style.paint_layout(window, gtk.STATE_NORMAL, True, cell_area, widget, "cellradio", x, y, self.get_layout(widget))
356
357                 #widget.show_all()
358
359         def on_start_editing(self, event, widget, path, background_area, cell_area, flags):
360                 print "on_start_editing", path
361                 return None
362
363         def on_activate(self, event, widget, path, background_area, cell_area, flags):
364                 print "activate", path
365                 return False
366
367
368 gobject.type_register(CellRendererCombo2)
369 gobject.type_register(CellRendererTriple)
370
371
372 class View(gtk.VBox):
373
374         def __init__(self, db, liststorehandler, parent_window):
375                 self.db = db
376                 self.parent_window = parent_window
377                 self.liststorehandler = liststorehandler
378
379                 gtk.VBox.__init__(self, homogeneous = False, spacing = 0)
380
381                 logging.info("libview, init")
382
383                 self.scrolled_window = None
384                 self.reload_view()
385
386         def loadList(self):
387                 ls = self.liststorehandler.get_liststore()
388                 self.treeview.set_model(ls)
389
390         def col_edited(self, cell, irow, new_text, icol = None):
391                 if (irow != 4):
392                         self.liststorehandler.update_row(irow, icol, new_text)
393                 else:
394                         print cell, irow, new_text, icol
395
396         def col_toggled(self, widget, irow, status ):
397                 ls = self.treeview.get_model()
398
399                 if self.liststorehandler.get_filter() == self.liststorehandler.SHOW_ACTIVE:
400                         if ls[irow][1] == "0":
401                                 self.liststorehandler.update_row(irow, 1, "1")
402                         else:
403                                 self.liststorehandler.update_row(irow, 1, "0")
404                 else:
405                         if ls[irow][1] == "1":
406                                 self.liststorehandler.update_row(irow, 1, "-1")
407                         elif ls[irow][1] == "0":
408                                 self.liststorehandler.update_row(irow, 1, "1")
409                         else:
410                                 self.liststorehandler.update_row(irow, 1, "0")
411
412         def convert(self, s):
413                 if s == "1":
414                         return 1
415                 else:
416                         return 0
417
418         def del_active_row(self):
419                 path, col = self.treeview.get_cursor()
420                 if path is not None:
421                         irow = path[0]
422                         row_iter = self.treeview.get_model().get_iter(path)
423                         self.liststorehandler.del_row(irow, row_iter)
424
425         def sort_func_function(self, model, iter1, iter2, data = None):
426                 print "sorting"
427
428         def reload_view(self):
429                 # create the TreeView using liststore
430                 self.modelsort = gtk.TreeModelSort(self.liststorehandler.get_liststore())
431                 self.modelsort.set_sort_column_id(2, gtk.SORT_ASCENDING)
432
433                 self.treeview = gtk.TreeView(self.modelsort)
434                 self.treeview.set_headers_visible(True)
435
436                 self.cell = range(self.liststorehandler.get_colcount())
437                 self.tvcolumn = range(self.liststorehandler.get_colcount())
438
439                 m = self.liststorehandler.get_unitsstore()
440
441                 for i in range(self.liststorehandler.get_colcount()):
442                         if 5 < i:
443                                 default = "0"
444                         else:
445                                 default = "1"
446                         if self.db.ladeDirekt("showcol_"+str(self.liststorehandler.get_colname(i)), default) == "1":
447                                 if (i == 1):
448                                         self.cell[i] = CellRendererTriple()
449                                         self.tvcolumn[i] =      gtk.TreeViewColumn("", self.cell[i])
450                                         self.cell[i].connect( 'status_changed', self.col_toggled)
451                                         self.tvcolumn[i].set_attributes( self.cell[i], status = i)
452                                 elif (i == 3)or(i == 4)or(i == 6):
453                                         self.cell[i] = gtk.CellRendererCombo()
454                                         self.tvcolumn[i] =      gtk.TreeViewColumn(self.liststorehandler.get_colname(i), self.cell[i])
455                                         self.cell[i].set_property("model", m)
456                                         self.cell[i].set_property('text-column', i)
457                                         self.cell[i].set_property('editable', True)
458                                         self.cell[i].connect("edited", self.col_edited, i) 
459                                         self.tvcolumn[i].set_attributes( self.cell[i], text = i)
460                                 else:
461                                         self.cell[i] = gtk.CellRendererText()
462                                         self.tvcolumn[i] = gtk.TreeViewColumn(self.liststorehandler.get_colname(i), self.cell[i])
463                                         self.cell[i].set_property('editable', True)
464                                         self.cell[i].set_property('editable-set', True)
465                                         self.cell[i].connect("edited", self.col_edited, i)
466                                         #self.cell[i].connect("editing-canceled", self.col_edited2, i) 
467                                         self.tvcolumn[i].set_attributes(self.cell[i], text = i)
468
469                                 self.cell[i].set_property('cell-background', 'lightgray')
470                                 self.tvcolumn[i].set_sort_column_id(i)
471                                 self.tvcolumn[i].set_resizable(True)
472
473                                 if (i>0):
474                                         self.treeview.append_column(self.tvcolumn[i])
475
476                 # Allow NOT drag and drop reordering of rows
477                 self.treeview.set_reorderable(False)
478
479                 if self.scrolled_window is not None:
480                         self.scrolled_window.destroy()
481
482                 self.scrolled_window = gtk.ScrolledWindow()
483                 self.scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
484
485                 self.scrolled_window.add(self.treeview)
486                 self.pack_start(self.scrolled_window, expand = True, fill = True, padding = 0)
487                 self.loadList()
488
489                 self.show_all()