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