comparison Gtk/gui.py @ 1:2ac1551ad2ab version 0.0.0

add code
author Miguel Ángel Bárcena Rodríguez <miguelangel@obraencurso.es>
date Sun, 31 Oct 2010 20:07:33 +0100
parents
children a221c14c3c31
comparison
equal deleted inserted replaced
0:a1703c4f2990 1:2ac1551ad2ab
1 # -*- coding: utf-8 -*-
2 ## File gui.py
3 ## This file is part of pyArq-Presupuestos.
4 ##
5 ## Copyright (C) 2010 Miguel Ángel Bárcena Rodríguez
6 ## <miguelangel@obraencurso.es>
7 ##
8 ## pyArq-Presupuestos is free software: you can redistribute it and/or modify
9 ## it under the terms of the GNU General Public License as published by
10 ## the Free Software Foundation, either version 3 of the License, or
11 ## (at your option) any later version.
12 ##
13 ## pyArq-Presupuestos is distributed in the hope that it will be useful,
14 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ## GNU General Public License for more details.
17 ##
18 ## You should have received a copy of the GNU General Public License
19 ## along with this program. If not, see <http://www.gnu.org/licenses/>.
20 ##
21
22 """Gui module
23
24 The MainWindow class contain the toplevel WINDOW,
25 this window have a notebook with a page for each budget.
26 Each budget or notebook page is showed by the Page class, this class contain
27 the main widget showed in a page notebook.
28 The main widget can show the budget information in several panes.
29 This panes are ordened in gtk.Paned represented for the class Paned which can
30 have 2 viewes represented for the View class or other gtk.Paned that have other
31 viewes or more gtk.Paned.
32 The view can have diferente type of widgets to show the budget information.
33 The DecompositionList class show the decompositon list information of a record
34 The Measure class show de measure information of a record
35 The TextWindow class show the long description of a record
36 The Sheet class class show the sheet of condition information of a record
37
38 The views can send signal to the others.
39 All the viewes ordered in panes can be or not be connected to the others,
40 if there are connecteded to the others when the user change the active code in
41 one of the panes the active code change in the others.
42
43 """
44 # TODO: Config file
45
46 # Standar Modules
47 import os
48 import time
49 import pygtk
50 pygtk.require('2.0')
51 import gtk
52 import gobject
53 import weakref
54
55 # pyArq-Presupuestos Modules
56 from Gtk import importFiebdc
57 from Generic import base
58 from Generic import fiebdc
59 from Generic import durusdatabase
60 from Generic import utils
61 from Generic import globals
62 from Generic import openwith
63
64 # Load default icon
65 if os.path.exists(globals.getAppPath("ICON")):
66 icon = gtk.gdk.pixbuf_new_from_file(globals.getAppPath("ICON"))
67 gtk.window_set_default_icon_list(icon)
68 else:
69 print utils.mapping(_("The icon file does not exist. '$1'"),
70 (globals.getAppPath("ICON"),))
71
72 # Autodetect desktop
73 if globals.desktop["autodetect"] is True:
74 openwith.autodetect_desktop()
75 print utils.mapping(_("pyArq-Presupuestos running on $1"),
76 (globals.desktop["desktop"],))
77
78 class MainWindow(object):
79 """gui.MainWindow:
80
81 Description:
82 Creates and shows the main window.
83 This is the interface base class.
84 Constructor:
85 gui.MainWindow(): Returns the newly created main window instance
86 Ancestry:
87 +-- object
88 +-- MainWindow
89 Atributes:
90 "window": Main window widget ("gtk.Window" object)
91 "__budget_temp_list": Temporal list of budgets
92 "__budget_list": List of budgets ("base.Budget" objects)
93 "__page_list": List of pages ("Page" object)
94 "__notebook": Notebook widget ("gtk.Notebook" object)
95 "__general_action_group": the "General" action group
96 Methods:
97 __init__(self)
98 _main(self)
99 _addBudget(self, budget)
100 _appendPage(self)
101 _testBudgetList(self)
102 _menuitemImportFiebdc(self, widget)
103 _menuitemImportPriceDatabase(self, widget)
104 _menuitemOpenPriceDatabase(self, widget)
105 _menuitemOpen
106 _menuitemClose(self, widget)
107 _menuitemText(self, widget)
108 _delete_event(self, widget, event)
109 _destroy(self, widget)
110 """
111 # TODO:* Can choose open budget in new window
112 # TODO:* gtk.Action for menu and toolbar
113 # TODO:* Can choose show more than one notebook in the same window or
114 # TODO: can show basedata notebook in a side pane
115 __ui = '''<ui>
116 <menubar name="MenuBar">
117 <menu action="File">
118 <menuitem action="ImportFiebdc"/>
119 <menuitem action="Close"/>
120 </menu>
121 <menu action="View">
122 <menuitem action="Text"/>
123 </menu>
124 <menu action="Test">
125 <menuitem action="ImportFiebdcPriceDatabase"/>
126 <menuitem action="OpenPriceDatabase"/>
127 </menu>
128 </menubar>
129 <toolbar name="ToolBar">
130 <toolitem action="ImportFiebdc"/>
131 <separator/>
132 <toolitem action="Close"/>
133 <separator name="sep1"/>
134 </toolbar>
135 </ui>'''
136
137 def __init__(self):
138 """def __init__(self)
139
140 Initialize the atributes "__budget_list" and "__page_list" without data.
141 Creates the widgets "window" and "__notebook".
142 """
143 self.__budget_temp_list = []
144 self.__budget_list = []
145 self.__page_list = []
146 # Main window
147 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
148 self.window.set_default_size(771, 570)
149 self.window.set_title("Presupuestos")
150 self.window.set_border_width(0)
151 self.window.connect("destroy", self._destroy)
152 self.window.connect("delete_event", self._delete_event)
153 # Vertical box
154 _vbox1 = gtk.VBox(False, 0)
155 self.window.add(_vbox1)
156 _vbox1.show()
157 #Uimanager
158 _uimanager = gtk.UIManager()
159 _accelgroup = _uimanager.get_accel_group()
160 self.window.add_accel_group(_accelgroup)
161 _general_action_group = gtk.ActionGroup("General")
162 self.__general_action_group = _general_action_group
163 _general_action_group.add_actions(
164 [("File", None, _("_File"), None),
165 ("ImportFiebdc", gtk.STOCK_OPEN, _('_Import Fiebdc'), "", 'NPI',
166 self._menuitemImportFiebdc),
167 ("Close", gtk.STOCK_CLOSE, _("_Close"), None, 'NPI',
168 self._menuitemClose),
169 ("View", None, _("_View")),
170 ("Text", None, _("_Text"), None, 'NPI',
171 self._menuitemText),
172 ("Test", None, _("_Test")),
173 ('ImportFiebdcPriceDatabase', gtk.STOCK_OPEN,
174 _("Import Fiebdc _price database"), "", "NPI",
175 self._menuitemImportPriceDatabase ),
176 ("OpenPriceDatabase", gtk.STOCK_OPEN, _('_Open price database'),
177 "", 'NPI', self._menuitemOpenPriceDatabase),
178 ])
179 _uimanager.insert_action_group(_general_action_group, 0)
180 _uimanager.add_ui_from_string(self.__ui)
181 _menu_bar = _uimanager.get_widget("/MenuBar")
182 _vbox1.pack_start(_menu_bar, False, False, 0)
183 _toolbar = _uimanager.get_widget("/ToolBar")
184 _toolbar.get_settings().set_long_property("gtk-toolbar-icon-size",
185 gtk.ICON_SIZE_SMALL_TOOLBAR, "pyArq-Presupuestos:toolbar")
186 _vbox1.pack_start(_toolbar, False, False, 0)
187 # Notebook
188 self.__notebook = gtk.Notebook()
189 _vbox1.pack_start(self.__notebook, True, True, 0)
190 self.__notebook.set_tab_pos(gtk.POS_TOP)
191 self.__notebook.set_show_tabs(True)
192 self.__notebook.set_show_border(True)
193 self.__notebook.set_scrollable(True)
194 self.__notebook.show()
195 self._main()
196
197 def _main(self):
198 """def main(self)
199
200 Shows window and starts the GTK+ event processing loop.
201 """
202 self.window.show()
203 gtk.main()
204
205 def _addBudget(self, budget):
206 """def _addBudget(self, budget)
207
208 budget: "base.Budget" object
209
210 Appends a budget in the "__budget_list"
211 """
212 if budget != None:
213 _budget = budget
214 if _budget in self.__budget_temp_list:
215 self.__budget_temp_list.remove(_budget)
216 self.__budget_list.append(_budget)
217
218 def _appendPage(self):
219 """def _appendPage(self)
220
221 Creates a new page (instance of "Page class") from the last budget in
222 __budget_list, appends this page in the "__page_list" and shows the
223 page widget in the notebook widget.
224 """
225 _last_budget = self.__budget_list[-1]
226 _page = Page(_last_budget)
227 self.__notebook.append_page(_page.widget, _page.title)
228 self.__page_list.append(_page)
229
230 def _testBudgetList2(self):
231 """def _testBudgetList2(self)
232
233 Test if the number of budgets ("__budget_list") is greater
234 than the number of pages ("__page_list"), if it is greater
235 appendPage method is called to create a page to show the new budget
236 and save the budget in a durus file.
237 """
238 if len(self.__budget_list) > len(self.__page_list):
239 self._appendPage()
240 #-# in test mode
241 # TODO: It must be in a thread
242 _last_budget = self.__budget_list[-1]
243 _path = globals.getHomePath("DURUS-DATABASE")
244 _file_whit_path_bc3 = _last_budget.filename
245 _filename_bc3 = _file_whit_path_bc3.split("/")[-1]
246 _filename = _filename_bc3.split(".")[-2]
247 _file = _path + _filename + ".durus"
248 print utils.mapping(_("Saving file: $1"), (_file,))
249 _time = time.time()
250 _durus_file = durusdatabase.DurusFile(_file,True)
251 _durus_file.setBudget(_last_budget)
252 _durus_file.close()
253 print utils.mapping(_("Saving time: $1 seconds"),
254 (("%.2f" %(time.time()-_time) ),))
255 #-#
256 return False
257 return True
258
259 def _menuitemImportFiebdc(self, widget):
260 """def _menuitemImportFiebdc(self, widget)
261
262 widget: the widget where the event is emitted from
263 Callback to open a budget file.
264 Inits a timeout to test if a budgets is appended to "__budget_list"
265 calling _testBudgetList method if it is true.
266
267 Creates and shows a window to open a budget file.
268 """
269 _budget = base.Budget()
270 self.__budget_temp_list.append(_budget)
271 _budget_file = fiebdc.Read()
272 _read_method = _budget_file.readFile
273 _filename = "file"
274 _exit_method = _budget_file.cancel
275 _file_window = importFiebdc.FileSelectionWindow(self,
276 _read_method, _budget, _filename, _exit_method)
277
278 def _menuitemImportPriceDatabase(self, widget):
279 """def _menuitemImportPriceDatabase(self, widget)
280
281 widget: the widget where the event is emitted from
282 Callback to open a budget file.
283 Inits a timeout to test if a budgets is appended to "__budget_list"
284 calling _testBudgetList method if it is true.
285
286 Creates and shows a window to open a budget file.
287 """
288 #TODO: change timeout, it is deprecated
289 #TODO: the .durus file must be direted saved
290 gobject.timeout_add(100, self._testBudgetList2)
291 _budget = base.Budget()
292 self.__budget_temp_list.append(_budget)
293 _budget_file = fiebdc.Read()
294 _read_method = _budget_file.readFile
295 _filename = "file"
296 _exit_method = _budget_file.cancel
297 _file_window = importFiebdc.FileSelectionWindow(self,
298 _read_method, _budget, _filename, _exit_method)
299
300 def _menuitemOpenPriceDatabase(self, widget):
301 """def _menuitemImportPriceDatabase(self, widget)
302
303 widget: the widget where the event is emitted from
304 Callback to open a budget file.
305 Inits a timeout to test if a budgets is appended to "__budget_list"
306 calling _testBudgetList method if it is true.
307
308 Creates and shows a window to open a budget file.
309 """
310 _openDialog = OpenDurusDatabase(self._OpenDurusDatabase)
311 _openDialog.main()
312
313 def _OpenDurusDatabase(self, file):
314 """def _menuitemImportFiebdc(self, widget)
315
316 widget: the widget where the event is emitted from
317
318 Callback to open a budget file from a durus file.
319 """
320 _file = file
321 print utils.mapping(_("Loading file: $1:"), (_file,))
322 _time = time.time()
323 _durus_file = durusdatabase.DurusFile(_file,False)
324 _budget = _durus_file.getBudget()
325 _durus_file.close()
326 print utils.mapping(("Loadig time: $1 seconds"),
327 (("%.2f" %(time.time()-_time)),))
328 self.__budget_list.append(_budget)
329 _page = Page(_budget)
330 self.__notebook.append_page(_page.widget, _page.title)
331 self.__page_list.append(_page)
332
333 def _menuitemClose(self, widget):
334 """def _menuitemClose(self, widget)
335
336 widget: the widget where the event is emitted from
337
338 Callback to close a budget file.
339 """
340 _page_num = self.__notebook.get_current_page()
341 if _page_num == -1:
342 return
343 _page = self.__page_list.pop(_page_num)
344 if isinstance(_page, Page):
345 #not loading budget
346 self.__budget_list.pop(_page_num)
347 _page.clear()
348 self.__notebook.remove_page(_page_num)
349
350 def _menuitemText(self, widget):
351 """_menuitemText(self, widget)
352
353 widget: the widget where the event is emitted from
354
355 Creates and shows a window showing text description
356 using a instance of TextWindow class.
357 """
358 _page_num = self.__notebook.get_current_page()
359 if _page_num == -1:
360 return
361 _budget = self.__budget_list[_page_num]
362 _page = self.__page_list[_page_num]
363 _code = _page.getActiveCode()
364 _concepto = _budget.getRecord(_code)
365 _text = _concepto.text
366 _window = TextWindow(_code, _text)
367 _window.main()
368
369 def _delete_event(self, widget, event):
370 """_delete_event(self, widget, event)
371
372 widget: the widget where the event is emitted from
373 event: the "gtk.gdk.Event"
374
375 Method connected to "delete_event" signal of main window widget
376 This signal is emitted when a user press the close titlebar button.
377 It Returns True so the signal "destroy" is emitted.
378 """
379 for _page in self.__page_list:
380 _page.clear()
381 return False # -> destroy
382
383 def _destroy(self, widget):
384 """_destroy(self, widget)
385
386 widget: the widget where the event is emitted from
387 Method connected to "destroy" signal of main window widget
388
389 This signal is emited when the method connected to "delete_event"
390 signal returns True or when the program call the destroy() method of
391 the gtk.Window widget.
392 The window is closed and the GTK+ event processing loop is ended.
393 """
394 gtk.main_quit()
395
396 def getNotebook(self):
397 return self.__notebook
398 def getPageList(self):
399 return self.__page_list
400 def getBudgetList(self):
401 return self.__budget_list
402
403 class EmptyPage(object):
404 """
405 """
406 def __init__(self, mainWindow, readFileMethod, budget, filename,
407 cancelMethod):
408 """def __init__(self, mainWindow, readFileMethod, budget, filename,
409 cancelMethod)
410
411 """
412 self.__mainWindow = mainWindow
413 self.__readFileMethod = readFileMethod
414 self.__budget = budget
415 self.__filename = filename
416 self.__cancelMethod = cancelMethod
417 self.__children = None
418 self.__cancel = [False, False]
419 self.__progress = 0.0
420 self.__widget = gtk.VBox()
421 self.__main_item = None
422 self.__widget.show()
423 self.__throbber = gtk.Image()
424 self.__throbber.set_from_file(globals.getAppPath("THROBBER-ICON"))
425 self.__throbber.show()
426 self.__animationThobber = gtk.gdk.PixbufAnimation(
427 globals.getAppPath("THROBBER-GIF"))
428 self.__quietThobber = self.__throbber.get_pixbuf()
429 self.__budget_icon = gtk.gdk.pixbuf_new_from_file_at_size(
430 globals.getAppPath("BUDGET-ICON"), 16, 16)
431 _filename = os.path.basename(filename)
432 _rootfilename = os.path.splitext(_filename)[0]
433 if not _rootfilename == "":
434 _filename = _rootfilename
435 _titleLabel = gtk.Label(_filename)
436 _titleLabel.show()
437 self.__title = gtk.HBox()
438 self.__title.add(self.__throbber)
439 self.__title.add(_titleLabel)
440 self.__statusbar = gtk.Statusbar()
441 self.__statuscontext = self.__statusbar.get_context_id("Statusbar")
442 self.__statusbar.show()
443 _align = gtk.Alignment(0.5, 0.5, 0, 0)
444 _iconVbox = gtk.VBox()
445 _pyArqIcon = gtk.Image()
446 _pyArqIcon.set_from_file(globals.getAppPath("PYARQ-ICON"))
447 _pyArqIcon.show()
448 _iconVbox.pack_start(_pyArqIcon, True, True, 0)
449 _link = gtk.LinkButton("http://pyarq.obraencurso.es",
450 "http://pyarq.obraencurso.es")
451 _iconVbox.pack_start(_link, True, True, 0)
452 _link.show()
453 _iconVbox.show()
454 _align.add(_iconVbox)
455 _align.show()
456 self.__widget.pack_start(_align, True, True, 0)
457 _progressframe = gtk.Frame()
458 _progressframe.set_shadow_type(gtk.SHADOW_IN)
459 _progressframe.show()
460 self.__progress_bar = gtk.ProgressBar()
461 self.__progress_bar.show()
462 _progressframe.add(self.__progress_bar)
463 self.__statusbar.pack_start(_progressframe, False, False, 0)
464 self.__widget.pack_end(self.__statusbar, False, True, 0)
465 self.__main_item = None
466
467 def run(self):
468 self.__statusbar.push(self.__statuscontext, _("Time: 0s"))
469 self.__throbber.set_from_animation(self.__animationThobber)
470 self._launchChildren()
471 self._launchTimeout()
472
473 def progress(self, percent):
474 _progress = str(int(round(100 * percent,0)))
475 self.__progress = percent
476
477 def stopLoading(self):
478 self.__throbber.set_from_pixbuf(self.__budget_icon)
479 self.__progress_bar.hide()
480 self.__statusbar.pop(self.__statuscontext)
481
482 def _launchChildren(self):
483 """_launchChildren(self)
484
485 Launch the thread to read the file
486 """
487 if self.__children is None:
488 self.__children = importFiebdc.Thread(self, self.__mainWindow,
489 self.__readFileMethod, self.__budget, self.__filename,
490 self.__cancelMethod)
491 self.__children.start()
492
493 def _launchTimeout(self):
494 """def _launchTimeout(self)
495
496 Launch the timeouts:
497 1- update progress bar
498 2- update time label
499 3- If the other timetouts are stoped the window is closed
500 """
501 gobject.timeout_add(500, self._updateProgressBar)
502 gobject.timeout_add(1000, self._updateLabel, time.time())
503 self.__cancel = [False, False]
504 gobject.timeout_add(1000, self._autoClose)
505
506 def _updateProgressBar(self):
507 """def _updateProgressBar(self)
508
509 update progress bar in a timeout
510 If the thread end or is canceled the timeout is stoped
511 """
512 if self.__children is None or self.__children.isCanceled() == True:
513 self.__cancel[0] = True
514 return False
515 else:
516 self.__progress_bar.set_fraction(self.__progress)
517 _text = "%s%%" %str(int(round(100 * self.__progress,0)))
518 self.__progress_bar.set_text(_text)
519 return True
520
521 def _updateLabel(self, _time):
522 """def _updateProgressBar(self)
523
524 update time label in a timeout
525 If the thread end or is canceled the timeout is stoped
526 """
527 if self.__children is None or self.__children.isCanceled() == True:
528 self.__cancel[1] = True
529 return False
530 else:
531 _time = time.time() - _time
532 _text = utils.mapping(_("Time: $1"), ("%.0f" %_time,))
533 self.__statusbar.pop(self.__statuscontext)
534 self.__statusbar.push(self.__statuscontext, _text)
535 return True
536
537 def _autoClose(self):
538 """def _updateProgressBar(self)
539
540 If the time label and progress bar timeouts are stoped the window is
541 closed and ist tiemeout is stoped
542 """
543 if self.__cancel == [ True, True ]:
544 return False
545 else:
546 return True
547
548 def closeWindow(self):
549 """def closeWindow(self)
550
551 Sets the __children atribute to None
552 This causes that the timeouts is ended.
553 This method is called from thread when it is finished
554 TODO: it must called threadFinished or somethig
555 """
556 self.__children = None
557 self.stopLoading()
558 _page = Page(self.__budget)
559 _children = self.__widget.get_children()
560 for _child in _children:
561 self.__widget.remove(_child)
562 self.__widget.pack_start(_page.widget, True, True, 0)
563 _noteBook = self.__mainWindow.getNotebook()
564 _pageIndex = _noteBook.page_num(self.__widget)
565 self.__mainWindow.getPageList()[_pageIndex] = _page
566 def threadCanceled(self):
567 """def threadCanceled(self)
568
569 Sets the __children atribute to None
570 This causes that the timeouts is ended.
571 This method is called from thread when is canceled
572 TODO: it must called threadFinished or somethig
573 """
574 self.__children = None
575 self.stopLoading()
576
577 def clear(self):
578 """def clear(self)
579
580 Cancel thread
581 """
582 self.__children.cancel()
583
584 def getWidget(self):
585 """def getWidget(self)
586
587 Return de main widget to show in the page
588 """
589 return self.__widget
590
591 def getTitle(self):
592 """def getTtle(self)
593
594 Return the title of the page, a gtk.Label objetc
595 """
596 return self.__title
597
598 widget = property(getWidget, None, None,
599 "Main widget showed in the pane")
600 title = property(getTitle, None, None,
601 "Page Title")
602
603 class Page(object):
604 """gui.Page:
605
606 Description:
607 It creates and shows a page in the notebook from a budget object.
608 The page can show the budget information in several panes ordered
609 according to "panes_list" information.
610 Constructor:
611 gui.Page(budget, active_code=None):
612 budget: budget to be showed in this page (base.Budget object)
613 active_code: the code of the active record
614 Returns the newly created Page instance
615 Ancestry:
616 +-- object
617 +-- Page
618 Atributes:
619 "budget": Read-Write. Budget to show in the page. (base.obra object)
620 "panes_list": Read. info list for create the panes
621 ej: [ "v", pane1, pane2 ] , [ "h", pane1, pane2 ]
622 [ "v", [ "h", pane1, pane2 ], [ "h", pane1, pane2 ] ]
623 pane types:
624 * "DecompositionList": its creates a "DecompositionList" object
625 * "RecordDescription" : its creates a "Description" objetc
626 * "Measure": its creates a "Measure" objetc
627 * "FileView": its creates a "FileView" objet
628 * "CompanyView": its creates a "CompanyView" object
629 "widget": Read. Notebook page Widget. (a gtk.VBox instance)
630 "title": Read. Notebook page title (gtk.Label object)
631 "__active_path_record": The active path record
632 "__main_item": main item in the page, can be a View object or a Paned
633 object
634 Methods:
635 __init__(self, budget=None, active_code=None)
636 propagateMessageFrom(self, message, path, arg=None)
637 sendMessageTo(self, pane, message, path, arg=None)
638 clear(self)
639 getItem(self,path)
640 setMainItem(self, item)
641 itemsFactory(self, list_paned, path=(0,))
642 setActivePathRecord(self, path_record)
643 getTitle(self)
644 getWidget(self)
645 setBudget(self, budget)
646 getBudget(self)
647 getPanesList(self)
648 """
649 # TODO: * The panes can be ordered as the user wishes
650 # TODO: * Panes in windows
651 # TODO: * pane types
652 # TODO: * General budget properties (is better a dialog?)
653
654 def __init__(self, budget, path_record=(0,)):
655 """def __init__(self, budget=None, active_code=None)
656
657 budget: "base.Budget" object
658 active_code: the code of the active record
659 Sets the atributes
660 * __panes_list: info to create the panes
661 * budget (base.Budget object)
662 * active_code
663 """
664 #TODO: __panes_list should come from config file...
665 self.__widget = gtk.VBox()
666 self.__panes_list = [ "v", "DecompositionList", [ "v", "Measure",
667 "RecordDescription" ]]
668 self.__main_item = None
669 self.setBudget(budget)
670 self.setActivePathRecord(path_record)
671 self.__widget.show()
672
673 def propagateMessageFrom(self, message, path, arg=None):
674 """def propagateMessageFrom(self, message, path, arg=None)
675
676 message: string message
677 path: tuple that represents the pane path which emits the message
678 arg: arguments for the message
679 if message is "change_active" arg is the path record
680
681 The panes are connectted to this method to send messages to other panes
682 """
683 _budget = self.__budget
684 if message == "change_active" and _budget.hasPath(arg):
685 self.sendMessageTo(self.__main_item, message, path, arg)
686 elif message == "autoclose":
687 self._closeItem(path)
688 elif message == "split h":
689 self._splitItem(path, "h")
690 elif message == "split v":
691 self._splitItem(path, "v")
692
693 def sendMessageTo(self, pane, message, path, arg=None):
694 """def sendMessageTo(self, pane,message, path, arg=None)
695 pane: the receiver pane
696 message: string message
697 path: tuple that represents the pane path which emits the message
698 arg: arguments for the message
699
700 Sends a message to a pane
701 """
702 if not pane.path == path:
703 pane.runMessage(message, path, arg)
704
705 def clear(self):
706 """def clear(self)
707
708 Clear atributes
709 """
710 self.propagateMessageFrom("clear", (0,))
711
712 del self.__budget
713 del self.__panes_list
714 del self.__widget
715 del self.__title
716 del self.__active_path_record
717 del self.__main_item
718
719 def getItem(self,path):
720 """def getItem(self, path
721
722 Return the item whith the path "path", it can return a Paned instance
723 or a View instance
724 """
725 _item = self.__main_item
726 if len(path) == 1:
727 return _item
728 else:
729 return _item.getItem(path[1:])
730
731 def setMainItem(self, item):
732 """setMainItem(self,item)
733
734 Sets a new main item in the page
735 """
736 if not self.__main_item is None:
737 _old_main_widget = self.__main_item.widget
738 self.__widget.remove(_old_main_widget)
739 self.__main_item = item
740 _main_widget = self.__main_item.widget
741 _main_widget.show()
742 self.__widget.pack_start(_main_widget, True, True, 0)
743
744 def _splitItem(self, path, orientation):
745 """_splitItem(self, path, orientation)
746
747 Splits the item that is identifies by the path and the orientation
748 """
749 _item = self.getItem(path)
750 _parent = self.getItem(path[:-1])
751 _item.setPath(path+ (0,))
752 _item_clone0 = _item.getClone(path + (0,))
753 _item_clone1 = _item.getClone(path + (1,))
754 _paned = Paned(orientation, path, _item_clone0, _item_clone1)
755 if len(path) > 1:
756 _parent.setItem(path[-1], [_paned])
757 else:
758 self.setMainItem(_paned)
759
760 def _closeItem(self, path):
761 """_closeItem(self, path)
762
763 Closes the item that is identifies by the path
764 """
765 _item = self.getItem(path)
766 if len(path) > 1:
767 # There are more than one item
768 _parent = self.getItem(path[:-1])
769 _brothers = [ _brother for _brother in _parent]
770 _brothers.remove(_item)
771 _brother = _brothers[0]
772
773 _parent.widget.remove(_brother.widget)
774 _brother.path = path[:-1]
775 if len(path) > 2:
776 _grandparent = self.getItem(path[:-2])
777 _grandparent.setItem(path[-2], [_brother])
778 _parent.widget.destroy()
779 _parent.clear()
780 _item.clear()
781 else:
782 _grandparent = self
783 _grandparent.setMainItem(_brother)
784 _parent.widget.destroy()
785 _parent.clear()
786 _item.clear()
787 else:
788 # Thre is only one item in the page, it can not be closed
789 pass
790
791 def itemsFactory(self, list_paned, path=(0,)):
792 """def itemsFactory(self, list_paned, path(0,))
793
794 list_paned: list in "__panes_list" format
795 [ "v" or "h", panel1_type, panel2_type]
796 which contains the info for create the widgets.
797 panel types:
798 * "DecompositionList"
799 * "RecordDescription"
800 * "Measure"
801 * "Sheet of Conditions"
802 * "FileView"
803 * "CompanyView"
804 path: tuple that represents the item path in the page
805
806 Creates the items and widgets and returns the main item
807 """
808 if not isinstance(list_paned , list):
809 raise ValueError, _("The value must be a list")
810 if list_paned[0] == "v" or list_paned[0] == "h":
811 if len(list_paned) != 3:
812 raise ValueError, _("Incorrect len")
813 if not isinstance(list_paned[1],list):
814 list_paned[1] = [list_paned[1]]
815 if not isinstance(list_paned[2],list):
816 list_paned[2] = [list_paned[2]]
817 _item1 = self.itemsFactory(list_paned[1],path + (0,))
818 _item2 = self.itemsFactory(list_paned[2],path + (1,))
819 _item = Paned(list_paned[0], path, _item1, _item2)
820 elif list_paned[0] == "DecompositionList":
821 _item = View( "DecompositionList", self.__budget,
822 weakref.ref(self), path, self.__active_path_record)
823 elif list_paned[0] == "RecordDescription":
824 _item = View( "RecordDescription", self.__budget,weakref.ref(self),
825 path, self.__active_path_record)
826 elif list_paned[0] == "Measure":
827 _item = View( "Measure", self.__budget, weakref.ref(self), path,
828 self.__active_path_record)
829 elif list_paned[0] == "Sheet of Conditions":
830 _item = Sheet(sef.__budget, weakref.ref(self), path,
831 self.__active_path_record)
832 elif list_paned[0] == "FileView":
833 _item = FileView(sef.__budget, weakref.ref(self), path,
834 self.__active_path_record)
835 elif list_paned[0] == "CompanyView":
836 _item = CompanyView(sef.__budget, weakref.ref(self), path,
837 self.__active_path_record)
838 else:
839 _item = None
840 raise ValueError, utils.mapping(_("Incorrect item $1"),
841 (str(list_paned[0]),))
842 return _item
843
844 def setActivePathRecord(self, path_record):
845 """def setActivePathRecord(self, path_record)
846
847 path_record: the active record path
848
849 Sets the active record path
850 """
851 if self.__budget.hasPath(path_record):
852 self.__active_path_record = path_record
853 else:
854 raise ValueError, utils.mapping(_("The budget does not have the "\
855 "path record: $1"), (str(path_record),))
856
857 def getTitle(self):
858 """def getTtle(self)
859
860 Return the title of the page, a gtk.Label objetc
861 """
862 return self.__title
863
864 def getWidget(self):
865 """def getWidget(self)
866
867 Return de main widget to show in the pane
868 """
869 return self.__widget
870
871 def setBudget(self, budget):
872 """def setBudget(self, budget)
873
874 budget: a base.Budget object
875
876 Sets the budget and the active code atributes,
877 creates the page title and the widgets in the pane and
878 shows the main widget.
879 """
880 if budget is None:
881 self.clear()
882 return
883 self.__budget = budget
884 self.setActivePathRecord((0,))
885 ## Todo: change page title
886 self.__title = gtk.Label(self.__budget.getCode(
887 self.__active_path_record))
888 _panes_list = self.__panes_list
889 self.__main_item = self.itemsFactory(_panes_list)
890 _main_widget = self.__main_item.getWidget()
891 _main_widget.show()
892 self.__widget.pack_start(_main_widget, True, True, 0)
893
894 def getBudget(self):
895 """def getBudget(self)
896
897 Return de budget, a "base.Budget" object.
898 """
899 return self.__budget
900
901 def getPanesList(self):
902 """def getPanesList(self)
903
904 Return the panes list, info list for create the panes.
905 """
906 return self.__panes_list
907
908 budget = property(getBudget, setBudget, None,
909 "Budget to show, base.Budget object")
910 widget = property(getWidget, None, None,
911 "Main widget showed in the pane")
912 title = property(getTitle, None, None,
913 "Page Title")
914 panes_list = property(getPanesList, None, None,
915 "Info list for create the panes")
916
917 class View(object):
918 """gui.View:
919
920 Description:
921 It creates a view to show the budget info
922 Constructor:
923 View(view_type, budget, wr_page, path, active_path_record)
924 Ancestry:
925 +-- object
926 +-- Paned
927 Atributes:
928 "path": the tuple that identifies the view in the main notebook page
929 "widget": the main gtk widget to show in a view object,
930 a gtk.VBox object
931 "__view_type": the object type to show
932 * DecompositionList
933 * Description
934 * Measure
935 * Sheet of conditions
936 * FileView
937 * CompanyView
938 "__wr_page": weak reference to the page where the view must be showed
939 "__budget": the budget to show
940 "__view ": the object to show:
941 * DecompositionList object
942 * Description object
943 * Measure object
944 * Sheet object
945 * FileView object
946 * Comapany View
947 "__connected": boolean value, True means that the View object sends and
948 receives signals from/to others views
949 "__connected_button": a button to switch __connected True or False
950 Methods:
951 __init__(self)
952 getItem(self, path)
953 _closeItem(self, close_button)
954 _change_combo(self, combobox)
955 propagateMessgeFrom(self, message, path, arg=None)
956 runMessage(self, message, path, arg=None)
957 getWidget(self)
958 getPath(self)
959 setPath(self)
960 getClone(self, newpath)
961 clear(self)
962 """
963 def __init__(self, view_type, budget, wr_page, path, active_path_record):
964
965 """def __init__(self, view_type, budget, wr_page, path,
966 active_path_record)
967 view_type: the object type to show
968 * DecompositionList
969 * Description
970 * Measure
971 * Sheet
972 * FileView
973 * CompanyView
974 budget: the budget to show
975 wr_page: weak reference to the page where the view must be showed
976 path: the position or path of the view in the page notebook
977 active_path_record: the record path that must be showed
978
979 Creates and shows a new view
980 """
981 self.__active_path_record = active_path_record
982 self.__view_type = view_type
983 self.__wr_page = wr_page
984 self.__budget = budget
985 self.__path = path
986 self.__connected = True
987 # view_type liststore
988 _liststore = gtk.ListStore(str)
989 _liststore.append([_("Decomposition")]) #0
990 _liststore.append([_("Description")]) #1
991 _liststore.append([_("Measure")]) #2
992 _liststore.append([_("Sheet of Conditions")]) #3
993 _liststore.append([_("Files")]) #4
994 _liststore.append([_("Companies")]) #5
995 _combobox = gtk.ComboBox(_liststore)
996 _cell = gtk.CellRendererText()
997 _combobox.pack_start(_cell, True)
998 _combobox.add_attribute(_cell, 'text', 0)
999 _vbox = gtk.VBox()
1000 _vbox.show()
1001 _toolitem = gtk.ToolItem()
1002 _toolitem.set_expand(True)
1003 _toolitem.add(_vbox)
1004 _toolitem.show()
1005 self.__widget = gtk.Toolbar()
1006 self.__widget.insert(_toolitem, 0)
1007 _hbox = gtk.HBox()
1008 if view_type == "DecompositionList":
1009 self.__view = DecompositionList(budget, weakref.ref(self),
1010 path, active_path_record)
1011 _combobox.set_active(0)
1012 _view_icon = gtk.Image()
1013 _view_icon.set_from_file(globals.getAppPath("DECOMPOSITION-ICON"))
1014 elif view_type == "RecordDescription":
1015 self.__view = Description(budget, weakref.ref(self),
1016 path, active_path_record)
1017 _combobox.set_active(1)
1018 _view_icon = gtk.Image()
1019 _view_icon.set_from_file(globals.getAppPath("DESCRIPTION-ICON"))
1020 elif view_type == "Measure":
1021 self.__view = Measure(budget, weakref.ref(self),
1022 path, active_path_record)
1023 _combobox.set_active(2)
1024 _view_icon = gtk.Image()
1025 _view_icon.set_from_file(globals.getAppPath("MEASURE-ICON"))
1026 elif view_type == "Sheet of Conditions":
1027 self.__view = Sheet(budget, weakref.ref(self),
1028 path, active_path_record)
1029 _combobox.set_active(3)
1030 _view_icon = gtk.Image()
1031 _view_icon.set_from_file(globals.getAppPath("SHEET-ICON"))
1032 elif view_type == "FileView":
1033 self.__view = FileView(budget, weakref.ref(self),
1034 path, active_path_record)
1035 _combobox.set_active(4)
1036 _view_icon = gtk.Image()
1037 _view_icon.set_from_file(globals.getAppPath("SHEET-ICON"))
1038 elif view_type == "CompanyView":
1039 self.__view = CompanyView(budget, weakref.ref(self), path,
1040 active_path_record)
1041 _combobox.set_active(5)
1042 _view_icon = gtk.Image()
1043 _view_icon.set_from_file(globals.getAppPath("SHEET-ICON"))
1044
1045 else:
1046 raise ValueError, _(utils.mapping("Invalid type of View: $1",
1047 view_type))
1048 _view_icon.show()
1049 _combobox.connect("changed", self._change_combo)
1050 _combobox.show()
1051 _vbox.pack_start(_hbox,False)
1052 _vbox.pack_start(self.__view.widget, True, True)
1053 _hbox.pack_start(_view_icon, False, False,0)
1054 _hbox.pack_start(_combobox, False, False,0)
1055 _invisible = gtk.HBox()
1056 _invisible.show()
1057 _hbox.pack_start(_invisible, True, False,0)
1058 _icon_menu = gtk.Image()
1059 _icon_menu.set_from_file(globals.getAppPath("MENU-ICON"))
1060 _icon_menu.show()
1061 _menu_button = gtk.ToolButton()
1062 _menu_button.set_icon_widget(_icon_menu)
1063 _menu_button.connect("clicked", self._menu_view)
1064 _menu_button.show()
1065 _icon_connected = gtk.Image()
1066 _icon_connected.set_from_file(globals.getAppPath("CONNECTED-ICON"))
1067 _icon_connected.show()
1068 _hbox.pack_start(_menu_button, False, False, 0)
1069 self.__connected_button = gtk.ToolButton()
1070 self.__connected_button.set_icon_widget(_icon_connected)
1071 self.__connected_button.connect("clicked", self._connected)
1072 self.__connected_button.show()
1073 _hbox.pack_start(self.__connected_button, False, False, 0)
1074 _icon_close = gtk.Image()
1075 _icon_close.set_from_file(globals.getAppPath("CLOSE-ICON"))
1076 _icon_close.show()
1077 _close_button = gtk.ToolButton()
1078 _close_button.set_icon_widget(_icon_close)
1079 _close_button.connect("clicked", self._closeItem)
1080 _close_button.show()
1081 _hbox.pack_start(_close_button, False, False, 0)
1082 _hbox.show()
1083 self.__widget.show()
1084
1085 def getItem(self, path):
1086 """def getItem(self, path)
1087
1088 Return itself.
1089 """
1090 return self
1091
1092 def _closeItem(self, close_button):
1093 """_closeItem(self, widget)
1094
1095 Method connected to the "clicked" signal of the _close_button widget
1096 Send the "autoclose" message to the page to close this view
1097 """
1098 self.propagateMessageFrom( "autoclose", self.__path)
1099
1100 def _change_combo(self, combobox):
1101 """_change_combo(self, combobox)
1102
1103 Method connected to the "changed" signal of the _combobox widget
1104 It changes the view type to the type selected in the combobox
1105 """
1106 _index = combobox.get_active()
1107 _budget = self.__view.budget
1108 _wr_page = self.__view.page
1109 _path = self.__view.path
1110 _path_record = self.__view.active_path_record
1111 _toolitem = self.__widget.get_nth_item(0)
1112 _vbox= _toolitem.get_children()[0]
1113 _hbox = _vbox.get_children()[0]
1114 _combobox = _hbox.get_children()[1]
1115 _hbox.remove(_combobox)
1116 _invisible = _hbox.get_children()[1]
1117 _hbox.remove(_invisible)
1118 _menu_button = _hbox.get_children()[1]
1119 _hbox.remove(_menu_button)
1120 _connected_button = _hbox.get_children()[1]
1121 _hbox.remove(_connected_button)
1122 _close_button = _hbox.get_children()[1]
1123 _hbox.remove(_close_button)
1124 _vbox.remove(self.__view.widget)
1125 _vbox.remove(_hbox)
1126 _hbox.destroy()
1127 _view_icon = gtk.Image()
1128 if _index == 0:
1129 self.__view = DecompositionList(_budget, _wr_page, _path,
1130 _path_record)
1131
1132 _view_icon.set_from_file(globals.getAppPath("DECOMPOSITION-ICON"))
1133 self.__view_type = "DecompositionList"
1134 elif _index == 1:
1135 self.__view = Description(_budget, _wr_page, _path,
1136 _path_record)
1137 _view_icon.set_from_file(globals.getAppPath("DESCRIPTION-ICON"))
1138 self.__view_type = "RecordDescription"
1139 elif _index == 2:
1140 self.__view = Measure(_budget, _wr_page, _path,
1141 _path_record)
1142 _view_icon.set_from_file(globals.getAppPath("MEASURE-ICON"))
1143 self.__view_type = "Measure"
1144 elif _index == 3:
1145 self.__view = Sheet(_budget, _wr_page, _path,
1146 _path_record)
1147 _view_icon.set_from_file(globals.getAppPath("SHEET-ICON"))
1148 self.__view_type = "Sheet of Conditions"
1149 elif _index == 4:
1150 self.__view = FileView(_budget, _wr_page, _path,
1151 _path_record)
1152 _view_icon.set_from_file(globals.getAppPath("SHEET-ICON"))
1153 self.__view_type = "FileView"
1154 elif _index == 5:
1155 self.__view = CompanyView(_budget, _wr_page, _path,
1156 _path_record)
1157 _view_icon.set_from_file(globals.getAppPath("SHEET-ICON"))
1158 self.__view_type = "CompanyView"
1159 _view_icon.show()
1160 _hbox = gtk.HBox()
1161 _hbox.pack_start(_view_icon, False, False,0)
1162 _hbox.pack_start(_combobox, False, False,0)
1163 _hbox.pack_start(_invisible, True, False,0)
1164 _hbox.pack_start(_menu_button, False, False, 0)
1165 _hbox.pack_start(_connected_button, False, False, 0)
1166 _hbox.pack_start(_close_button, False, False, 0)
1167 _hbox.show()
1168 _vbox.pack_start(_hbox, False, False, 0)
1169 _vbox.pack_start(self.__view.widget, True, True, 0)
1170
1171 def _menu_view(self, widget):
1172 """_menu_view(self, widget)
1173
1174 Method connected to the "clicked" signal of the __connected_button
1175 It shows a popup menu with some options
1176 """
1177 _menu_view = gtk.Menu()
1178 _item_leftright = gtk.MenuItem("Split View Left/Right")
1179 _menu_view.append(_item_leftright)
1180 _item_leftright.connect_object("activate", self._split_view, "h")
1181 _item_leftright.show()
1182 _item_topbottom = gtk.MenuItem("Split View Top/Bottom")
1183 _menu_view.append(_item_topbottom)
1184 _item_topbottom.connect_object("activate", self._split_view, "v")
1185 _item_topbottom.show()
1186 _item_close = gtk.MenuItem("close view")
1187 _menu_view.append(_item_close)
1188 _item_close.connect_object("activate", self._closeItem, None)
1189 _item_close.show()
1190 _menu_view.popup(None, None, None, 0, 0)
1191
1192 def _split_view(self, orientation):
1193 """_menu_view(self, orientation)
1194
1195 orientation: orientation split, "h" or "v"
1196
1197 Method connected to the "activate" signal of the _item_leftright and
1198 _item_topbottom menu items.
1199 It sends the "split" message to the page to splits the view in the
1200 specified orientation
1201 """
1202 self.propagateMessageFrom( "split " + orientation, self.__path)
1203
1204 def _connected(self, widget):
1205 """_connected(self, widget)
1206
1207 Method connected to the "clicked" signal of the _menu_button
1208 It changes the __connected atribute to True or False, if the
1209 _connected atribute is False the view do not send and receive messages
1210 to/from others views
1211 """
1212 if self.__connected:
1213 _icon = gtk.Image()
1214 _icon.set_from_file(globals.getAppPath("DISCONNECTED-ICON"))
1215 _icon.show()
1216 self.__connected_button.set_icon_widget(_icon)
1217 self.__connected = False
1218 else:
1219 _icon = gtk.Image()
1220 _icon.set_from_file(globals.getAppPath("CONNECTED-ICON"))
1221 _icon.show()
1222 self.__connected_button.set_icon_widget(_icon)
1223 self.__connected = True
1224
1225 def propagateMessageFrom(self, message, path, arg=None):
1226 """def propagateMessageFrom(self, message, path, arg=None)
1227
1228 message: string message
1229 path: tuple that represents the pane path which emits the message
1230 arg: arguments for the message
1231 The panes are connectted to this method to send messages to other panes
1232 """
1233 if self.__connected or message == "autoclose" or \
1234 message == "split h" or message == "split v":
1235 self.__wr_page().propagateMessageFrom(message, path, arg)
1236
1237 def runMessage(self, message, path, arg=None):
1238 """def runMessage(self, message, path, arg=None)
1239
1240 message: the message type
1241 "change_active": change the active record
1242 "clear": clear instance
1243 path: tuple that identifies the pane in the notebook page
1244 arg: tuple whit two items:
1245 0: record path in the budget
1246 1: record code
1247 This method receives a message and executes its corresponding action
1248 """
1249 if self.__connected:
1250 self.__view.runMessage(message, path, arg)
1251 if message == "change_active":
1252 if self.__budget.hasPath(arg):
1253 _path_record = arg
1254 self.__active_path_record = _path_record
1255
1256 def getWidget(self):
1257 """def getWidget(self)
1258
1259 Return de pane widget
1260 """
1261 return self.__widget
1262
1263 def getPath(self):
1264 """def getPath(self)
1265
1266 return the tuple that identifies the pane in the notebook page
1267 """
1268 return self.__view.path
1269
1270 def setPath(self, path):
1271 """def setPath(self)
1272
1273 set the tuple that identifies the pane in the notebook page
1274 """
1275 self.__path = path
1276 self.__view.path = path
1277
1278 def getClone(self, new_path):
1279 """getClone(self, new_path)
1280
1281 new_path: the path that identifies the clone view in the page
1282
1283 return a clone of itself
1284 """
1285 return View(self.__view_type, self.__budget, self.__wr_page,
1286 new_path, self.__active_path_record)
1287
1288 def clear(self):
1289 """clear(self)
1290
1291 Clear the intance atributes
1292 """
1293 del self.__wr_page
1294 del self.__budget
1295 del self.__path
1296 del self.__widget
1297 del self.__view
1298 del self.__connected
1299 del self.__connected_button
1300
1301 path = property(getPath, setPath, None,
1302 "path that identifies the item in the notebook page")
1303 widget = property(getWidget, None, None, "View widget")
1304
1305 class Paned(object):
1306 """gui.Paned:
1307
1308 Description:
1309 It creates and shows gtk.Hpaned or gtk.Vpaned to show in page budget
1310 Constructor:
1311 Paned(orientation, widget1, widget2)
1312 orientation: The orientation of the pane separator, can be "v" or "h"
1313 widget1: the top or left pane widget
1314 widget2: the botton or right pane widget
1315 Returns the newly created Paned instance
1316 Ancestry:
1317 +-- object
1318 +-- Paned
1319 Atributes:
1320 "widget": Pane widget("gtk.VPaned" or "gtk.HPaned" object)
1321 "__orientation": The orientation of de gtk.Paned, can be "v" or "h"
1322 "__items": list of items showed in the paned, its can be View or Paned
1323 instances
1324 "__path": the paned path in the page
1325 Methods:
1326 __init__(self)
1327 __getitem__(self, item)
1328 getClone(self, new_path)
1329 getItem(self, path)
1330 runMessage(self, messge, path, arg=None)
1331 getWidget(self)
1332 {get/set}Path
1333 clear(self)
1334 """
1335 # TODO: *control the position paned separator. Now is always 200 pixels
1336 # TODO: can be with a float(0.0-1.0) aspect ratio
1337 # TODO: 0.0 no space for widget1
1338 # TODO: 1.0 all the space for widget1
1339 # TODO: *control the position pane separator when the size of the window
1340 # TODO: change with the same ascpect ratio
1341
1342 def __init__(self, orientation, path, item1, item2):
1343 """def __init__(self, oritentation, path, item1, item2)
1344
1345 orientation: The orientation of de gtk.Paned, can be "v" or "h"
1346 path: the paned path in the page
1347 item1: the top or left pane object
1348 item2: the bottom or right pane object
1349
1350 Creates and shows a new gtk.Paned
1351 """
1352 self.__orientation = orientation
1353 if not isinstance(item1.widget, gtk.Widget) or \
1354 not isinstance(item2.widget, gtk.Widget):
1355 raise ValueError, _("The item must be a widget object.")
1356 if orientation == "v":
1357 self.__widget = gtk.VPaned()
1358 elif orientation == "h":
1359 self.__widget = gtk.HPaned()
1360 else:
1361 raise ValueError, _("Invalid orientation.")
1362 self.__widget.pack1(item1.widget,True,False)
1363 self.__widget.pack2(item2.widget,True,False)
1364 self.__widget.set_position(200)
1365 self.__widget.show()
1366 self.__items = [item1, item2]
1367 self.__path = path
1368
1369 def __getitem__(self, item):
1370 """__getitem__(self, item)
1371
1372 Called to implement evaluation of self[key].
1373 The accepted keys should be integers 0 or 1.
1374 """
1375 return self.__items[item]
1376
1377 def getClone(self, new_path):
1378 """getClone(self, new_path)
1379
1380 Return a clone Paned instance with the path new_path
1381 """
1382 return Paned(self.__orientation, new_path,
1383 self.__items[0].getClone(new_path + (0,)),
1384 self.__items[1].getClone(new_path + (1,)))
1385
1386 def getItem(self,path):
1387 """def getItem(self, path)
1388
1389 Return the item whith the specified path.
1390 """
1391 _item = self.__items[path[0]]
1392 if len(path) == 1:
1393 return _item
1394 else:
1395 return _item.getItem(path[1:])
1396
1397 def setItem(self, path, item_list):
1398 """def setItem(self, path, item_list)
1399
1400 Sets the first item in the item_list whith the especified path and
1401 remove the old item in this position.
1402 """
1403 item = item_list[0]
1404 if path == 0 or path == 1:
1405 _old_item = self.__items[path]
1406 self.__widget.remove(_old_item.widget)
1407 self.__items[path] = item
1408 if path == 0:
1409 self.__widget.pack1(item.widget,True,False)
1410 else:
1411 self.__widget.pack2(item.widget,True,False)
1412 return True
1413 return False
1414
1415 def runMessage(self, message, path, arg=None):
1416 """def runMessage(self, message, page_path, arg=None)
1417
1418 message: the message type
1419 "change_active": change the active record
1420 "clear": clear instance
1421 page_path: tuple that identifies the pane in the notebook page
1422 arg: arguments
1423
1424 This method receives a message and send this to the items of the paned
1425 """
1426 for _item in self.__items:
1427 if not _item.path == path:
1428 _item.runMessage(message, path, arg)
1429
1430 def getWidget(self):
1431 """def getWidget(self)
1432
1433 Return de gtk.Paned widget
1434 """
1435 return self.__widget
1436
1437 def getPath(self):
1438 """def getPath(self)
1439
1440 Return de Paned path in the notebook page
1441 """
1442 return self.__path
1443
1444 def setPath(self, path):
1445 """def setPath(self)
1446
1447 sets the tuple that identifies the pane in the notebook page
1448 """
1449 self.__path = path
1450 self.__items[0].path = path + (0,)
1451 self.__items[1].path = path + (1,)
1452
1453 def clear(self):
1454 del self.__widget
1455 del self.__orientation
1456 del self.__items
1457 del self.__path
1458
1459 widget = property(getWidget, None, None, "gtk.Paned widget")
1460 path = property(getPath, setPath, None, "Pane path in the notebook page")
1461
1462 class TreeView(object):
1463 """gui.Treeviev:
1464
1465 Description:
1466 It creates the columns in a treeview, is the base class for
1467 DescompositionList and Measure classes
1468 Constructor:
1469 TreView(args)
1470 args: list of tuples, the tuple items are:
1471 0.type:
1472 * index column
1473 * float column
1474 * text column
1475 * calculated column
1476 * calculated text
1477 * type column
1478 1. clicked method
1479 2. width
1480 3. text color
1481 4. backgruound colors
1482 5. model column index
1483 Ancestry:
1484 +-- object
1485 +-- TreeView
1486 Atributes:
1487 "columns": list of columns (gtk.TreeViewColumn isntances)
1488 Methods:
1489 __init__(self)
1490 __getitem__(self, item)
1491 createColumn(self, args)
1492 createTextBaseColumn(self,args)
1493 createBaseColumn(self,args)
1494 """
1495
1496 def __init__(self, args):
1497 """__init__(self, args)
1498
1499 args: list of tuples, the tuple items are:
1500 0.type:
1501 * index column
1502 * float column
1503 * text column
1504 * calculated column
1505 * Calculated text
1506 * type column
1507 1. clicked method
1508 2. width
1509 3. text color
1510 4. backgruound colors
1511 5. model column index
1512
1513 Create the columns form the args info calling creatheColumn to create
1514 each column
1515 """
1516 self.columns = [ self.createColumn(arg) for arg in args ]
1517 self.columns.append(self.createColumn(("END",)))
1518
1519 def createColumn(self, args):
1520 """createColumn(self, args)
1521
1522 args: tuple with the args
1523 0.type:
1524 * index column
1525 * float column
1526 * text column
1527 * calculated column
1528 * calculated text
1529 * type column
1530 1. clicked method
1531 2. width
1532 3. text color
1533 4. backgruound colors
1534 5. model column index
1535
1536 Return a column created whith the arg info
1537 """
1538 if args[0] == "INDEX":
1539 _index_column = self.createBaseColumn(args)
1540 _text_index_cell = gtk.CellRendererText()
1541 _text_index_cell.set_property('foreground-gdk',
1542 gtk.gdk.color_parse(globals.color["TEXT"]))
1543 _pixbuf_index_cell = gtk.CellRendererPixbuf()
1544 _arrow_icon = gtk.gdk.pixbuf_new_from_file(
1545 globals.getAppPath("ARROW-ICON"))
1546 _pixbuf_index_cell.set_property("pixbuf", _arrow_icon)
1547 _index_column.pack_start(_text_index_cell, True)
1548 _index_column.pack_start(_pixbuf_index_cell, True)
1549 _index_column.set_cell_data_func(_text_index_cell,
1550 self.colorCell,
1551 [gtk.gdk.color_parse(globals.color["INDEX-UNEVEN"]),
1552 gtk.gdk.color_parse(globals.color["INDEX-EVEN"])])
1553 return _index_column
1554 elif args[0] == "TEXT":
1555 _column, _cell = self.createTextBaseColumn(args)
1556 _column.add_attribute(_cell, 'text', args[5])
1557 return _column
1558 elif args[0] == "FLOAT":
1559 _column, _cell = self.createTextBaseColumn(args)
1560 _column.add_attribute(_cell, 'text', args[5])
1561 _column.get_cell_renderers()[0].set_property('xalign', 1.0)
1562 return _column
1563 elif args[0] == "CALCULATED":
1564 _column, cell = self.createTextBaseColumn(args)
1565 _column.get_cell_renderers()[0].set_property('xalign', 1.0)
1566 return _column
1567 elif args[0] == "CALCULATEDTEXT":
1568 _column, cell = self.createTextBaseColumn(args)
1569 return _column
1570 elif args[0] == "TYPE":
1571 _column = self.createBaseColumn(args)
1572 _type_cell1 = gtk.CellRendererPixbuf()
1573 _type_cell2 = gtk.CellRendererText()
1574 _type_cell2.set_property('foreground-gdk', args[3])
1575 _column.pack_start(_type_cell1, True)
1576 _column.pack_start(_type_cell2, True)
1577 _column.add_attribute(_type_cell2, 'text', args[5])
1578 _column.set_cell_data_func(_type_cell1,
1579 self.colorCell, args[4])
1580 _column.set_cell_data_func(_type_cell2,
1581 self.colorCell, args[4])
1582 return _column
1583 elif args[0] == "PIXBUF":
1584 _column = self.createBaseColumn(args)
1585 _type_cell1 = gtk.CellRendererPixbuf()
1586 _column.pack_start(_type_cell1, True)
1587 _column.set_cell_data_func(_type_cell1,
1588 self.colorCell, args[4])
1589 return _column
1590 elif args[0] == "END":
1591 _end_column = gtk.TreeViewColumn()
1592 _end_column.set_clickable(False)
1593 _end_cell = gtk.CellRendererText()
1594 _end_cell.set_property('cell-background-gdk',
1595 gtk.gdk.color_parse(globals.color["UNEVEN"]))
1596 _end_column.pack_start(_end_cell, True)
1597 return _end_column
1598 return None
1599
1600 def createTextBaseColumn(self,args):
1601 """createTextBaseColumn(self,args)
1602
1603 args: tuple with the args
1604 0.type:
1605 * float column
1606 * text column
1607 * calculated column
1608 * calculated text
1609 1. clicked method
1610 2. width
1611 3. text color
1612 4. backgruound colors
1613 5. model column index
1614
1615 Return a column and its CellREndererText
1616 """
1617 _column = self.createBaseColumn(args)
1618 _cell = gtk.CellRendererText()
1619 _cell.set_property('foreground-gdk', args[3])
1620 _column.pack_start(_cell, True)
1621 _column.set_cell_data_func(_cell, self.colorCell, args[4])
1622 return _column, _cell
1623
1624 def createBaseColumn(self,args):
1625 """createBaseColumn(self,args)
1626
1627 args: tuple with the args
1628 0.type:
1629 * index column
1630 * float column
1631 * text column
1632 * calculated column
1633 * calculated text column
1634 * type column
1635 1. clicked method
1636 2. width
1637 3. text color
1638 4. backgruound colors
1639 5. model column index
1640
1641 Return a column
1642 """
1643 _column = gtk.TreeViewColumn()
1644 _column.set_clickable(True)
1645 _column.connect("clicked", args[1])
1646 _column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
1647 _column.set_fixed_width(args[2])
1648 _column.set_resizable(True)
1649 return _column
1650
1651 class DecompositionList(TreeView):
1652 """gui.DecompositionList:
1653
1654 Description:
1655 Class to show a budget Decomposition List
1656 Constructor:
1657 DecompositionList(budget, page, path)
1658 budget: budget showed ("base.Budget" object)
1659 page: weak reference from Page instance which creates this class
1660 path: tuple that represents the view path in the Page
1661 Returns the newly created DecompositionList instance
1662 Ancestry:
1663 +-- object
1664 +-- TreeView
1665 +-- DecompositionList
1666 Atributes:
1667 "budget": Budget to show, base.obra instance.
1668 "widget or __scrolled_window": Window that contains the table,
1669 (gtk.ScrolledWindow)
1670 "path": Pane page identifier
1671 "page": weak reference from Page instance which creates this class
1672 "__active_color": background color of the active cell, a
1673 gtk.gdk.Color object
1674 "__chapter_background_colors": background colors of the Code
1675 column cells when there is a chapter record,
1676 list of gtk.gdk.Color objects [even cell, uneven cell]
1677 "__methond_message": Method to send messages to the page
1678 "__liststore": list model which store the list data
1679 (gtk.ListStore object)
1680 "__treeview": widget for displaying decomposition lists (gtk.TreeView)
1681 "__index_column": Index column (gtk.TreeViewColumn object)
1682 "__code_column": Record code column (gtk.TreeViewColumn)
1683 "__unit_column": Unit of measure column (gtk.TreeViewColumn)
1684 "__description_column": record's short description column
1685 (gtk.TreeViewColumn)
1686 "__measure_column": Measure column (gtk.TreeViewColumn)
1687 "__price_column": Price column (gtk.TreeViewColumn)
1688 "__amount_column": Amount column(gtk.TreeViewColumn)
1689 "__end_column": End empty column (gtk.TreeViewColumn)
1690 "__treeselection": active selection
1691 "__selection_control": state of the selection control (True/False)
1692 "__cursor": cursor position in the table
1693 Methods:
1694 __init__(self, budget)
1695 treeviewCursorChanged(self, treeview)
1696 treeviewClickedEvent(self, widget, event)
1697 treeviewKeyPressEvent(self, widget, event)
1698 moveCursor(self, treeview, step, count)
1699 controlSelection(self, selection)
1700 selectAll(self, column)
1701 setColumnsHeaders(self)
1702 setListstoreValues(self, puntero, treeiter=None)
1703 colorCell(self, column, cell_renderer, tree_model, iter, lcolor)
1704 _claculateAmount(self, row_path, tree_model)
1705 showParentRecord(self, column)
1706 showMessageRecord(self, camino,_code):
1707 showRowRecord(self, treeview, path, column)
1708 runMessage(self, messagem path, arg=None)
1709 _clear(self)
1710 getWidget(self)
1711 {get/set}Path
1712 {get/seg}Page
1713 getBudget(self)
1714 getActivePathRecord(self)
1715 """
1716
1717 def __init__(self, budget, page, path, path_record=(0,)):
1718 """def __init__(self, budget, page, path)
1719
1720 budget: budget showed ("base.Budget" object)
1721 page: weak reference from Page instance which creates this class
1722 path: tuple that represents the path of the List in the Page
1723
1724 Sets the init atributes
1725 Creates the init list values in self.__liststore from the budget
1726 showing the top record descomposition
1727 Creates the list in self.__treeview
1728 * Creates the columns and cell
1729 * Sets te the column headers values
1730 * Sets the selection properties
1731 * Connects the events
1732 """
1733 # TODO: to group all columns in a dicctionary
1734 # Budget
1735 if not isinstance(budget, base.Budget):
1736 raise ValueError, _("Argument must be a Budget object")
1737 self.__budget = budget
1738 self.__page = page
1739 self.__path = path
1740 # ListStore
1741 self.__liststore = gtk.ListStore(object
1742 #, int, int, str, str, str, str, str,str
1743 )
1744 if path_record is None:
1745 print _("DecompositionList.__init__: Record path can not be None")
1746 path_record = (0,)
1747 self.__active_path_record = path_record
1748 self.setListstoreValues(self.__active_path_record)
1749 # Treeview
1750 self.__treeview = gtk.TreeView(self.__liststore)
1751 self.__treeview.set_enable_search(False)
1752 self.__treeview.set_reorderable(False)
1753 self.__treeview.set_headers_clickable(True)
1754 self.__treeview.show()
1755 # Scrolled_window
1756 self.__scrolled_window = gtk.ScrolledWindow()
1757 self.__scrolled_window.set_policy(gtk.POLICY_AUTOMATIC,
1758 gtk.POLICY_AUTOMATIC)
1759 self.__scrolled_window.add(self.__treeview)
1760 # colors
1761 _text_color = gtk.gdk.color_parse(globals.color["TEXT"])
1762 _background_color = [
1763 gtk.gdk.color_parse(globals.color["UNEVEN"]),
1764 gtk.gdk.color_parse(globals.color["EVEN"])]
1765 self.__chapter_background_colors = [
1766 gtk.gdk.color_parse(globals.color["CHAPTER-UNEVEN"]),
1767 gtk.gdk.color_parse(globals.color["CHAPTER-EVEN"])]
1768 super(DecompositionList,self).__init__(
1769 [("INDEX",self.selectAll,42),
1770 ("CALCULATEDTEXT", self.showParentRecord,
1771 gtk.Label("A"*10).size_request()[0] +10,
1772 _text_color, _background_color),
1773 ("PIXBUF", self.showParentRecord, 26, _text_color,
1774 _background_color),
1775 ("CALCULATEDTEXT", self.showParentRecord,
1776 gtk.Label(_("a"*4)).size_request()[0] +10,
1777 _text_color, _background_color),
1778 ("CALCULATEDTEXT", self.showParentRecord,
1779 gtk.Label("a"*30).size_request()[0] +10,
1780 _text_color, _background_color),
1781 ("CALCULATED", self.showParentRecord,
1782 gtk.Label("a"*10).size_request()[0] +10,
1783 _text_color, _background_color),
1784 ("CALCULATED", self.showParentRecord,
1785 gtk.Label("a"*10).size_request()[0] +10,
1786 _text_color, _background_color),
1787 ("CALCULATED", self.showParentRecord,
1788 gtk.Label("a"*10).size_request()[0] +10,
1789 gtk.gdk.color_parse(globals.color["CALCULATED-TEXT"]),
1790 _background_color),
1791 ])
1792 self.__index_column = self.columns[0]
1793 self.__code_column = self.columns[1]
1794 self.__type_column = self.columns[2]
1795 self.__unit_column = self.columns[3]
1796 self.__description_column = self.columns[4]
1797 self.__measure_column = self.columns[5]
1798 self.__price_column = self.columns[6]
1799 self.__amount_column = self.columns[7]
1800 self.__end_column = self.columns[8]
1801 # Index column
1802 self.__treeview.append_column(self.__index_column)
1803 # Code column
1804 self.__treeview.append_column(self.__code_column)
1805 # Type column
1806 self.__treeview.append_column(self.__type_column)
1807 self.chapter_icon = gtk.gdk.pixbuf_new_from_file(
1808 globals.getAppPath("CHAPTER-ICON"))
1809 self.unit_icon = gtk.gdk.pixbuf_new_from_file(
1810 globals.getAppPath("UNIT-ICON") )
1811 self.material_icon = gtk.gdk.pixbuf_new_from_file(
1812 globals.getAppPath("MATERIAL-ICON") )
1813 self.machinery_icon = gtk.gdk.pixbuf_new_from_file(
1814 globals.getAppPath("MACHINERY-ICON"))
1815 self.labourforce_icon = gtk.gdk.pixbuf_new_from_file(
1816 globals.getAppPath("LABOURFORCE-ICON"))
1817 self.__type_column.get_cell_renderers()[0].set_property("pixbuf",
1818 self.labourforce_icon)
1819
1820 # Unit column
1821 self.__treeview.append_column(self.__unit_column)
1822 # Description column
1823 self.__treeview.append_column(self.__description_column)
1824 # Measure Column
1825 self.__treeview.append_column(self.__measure_column)
1826 # Price column
1827 self.__treeview.append_column(self.__price_column)
1828 # Amount column
1829 self.__treeview.append_column(self.__amount_column)
1830 # End Column
1831 self.__treeview.append_column(self.__end_column)
1832 # Connect
1833 self.__treeview.connect("row-activated", self.showRowRecord)
1834 self.__treeview.connect("move-cursor", self.moveCursor)
1835 self.__treeview.connect("key-press-event", self.treeviewKeyPressEvent)
1836 self.__treeview.connect("button-press-event", self.treeviewClickedEvent)
1837 self.__treeview.connect("cursor-changed", self.treeviewCursorChanged)
1838 # control selection
1839 self.__treeselection = self.__treeview.get_selection()
1840 self.__treeselection.set_mode(gtk.SELECTION_MULTIPLE)
1841 self.__treeselection.set_select_function(self.controlSelection)
1842 self.__selection_control = True
1843 if len(self.__liststore) > 0:
1844 self.__treeview.set_cursor_on_cell((0,),self.__unit_column,
1845 self.__unit_column.get_cell_renderers()[0],True)
1846 self.__treeview.grab_focus()
1847 self.__cursor = self.__treeview.get_cursor()
1848 # Show
1849 self.setColumnsHeaders()
1850 self.__scrolled_window.show()
1851
1852 def treeviewCursorChanged(self, treeview):
1853 """def treeviewCursorChanged(self, treeview)
1854
1855 treeview: treewiew widget
1856 Method connected to "cursor-changed" signal
1857 The "cursor-changed" signal is emitted when the cursor moves or is set
1858 Sets the new cursor position in self.__cursor, it is used to avoid
1859 unnecessary changes in cursor position.
1860 """
1861 event = gtk.get_current_event()
1862 (_cursor_path, _column) = treeview.get_cursor()
1863 if event is None or event.type != gtk.gdk.BUTTON_RELEASE:
1864 if not _column is self.__index_column:
1865 self.__cursor = treeview.get_cursor()
1866
1867 def treeviewClickedEvent(self, widget, event):
1868 """def treeviewClickedEvent(self, widget, event)
1869
1870 widget: treewiew widget
1871 event: clicked event
1872 Method connected to "button-press-event" signal
1873 The "button-press-event" signal is emitted when a mouse button is
1874 pressed.
1875 Returns TRUE to stop other handlers from being invoked for the event.
1876 Returns FALSE to propagate the event further.
1877
1878 The events in end column are ignored.
1879 If the user click in a row of the index column the cursor is moved to
1880 this row but not to the index column
1881 """
1882 if event.button == 1:
1883 path_at_pos = self.__treeview.get_path_at_pos(int(event.x),
1884 int(event.y))
1885 if not path_at_pos is None:
1886 _path_cursor, _column, _x, _y = path_at_pos
1887 if _column == self.columns[-1]:
1888 return True
1889 if _column is self.columns[0]:
1890 self.__cursor[0] == _path_cursor
1891 return False
1892
1893 def treeviewKeyPressEvent(self, widget, event):
1894 """def treeviewKeyPressEvent(self, widget, event)
1895
1896 widget: treewiew widget
1897 event: Key Press event
1898 Method connected to "key-press-event" signal
1899 The "key-press-event" signal is emitted when the user presses a key
1900 on the keyboard.
1901 Returns :TRUE to stop other handlers from being invoked for the event.
1902 Returns :FALSE to propagate the event further.
1903
1904 If the user press the right cursor button and the cursor is in the
1905 amount column or pres the left cursor button and the cursor is
1906 in the code column the event is estoped, else the event is propagated.
1907 """
1908 (_cursor_path, _column) = self.__treeview.get_cursor()
1909 if (event.keyval == gtk.keysyms.Right \
1910 and _column == self.columns[-2]) \
1911 or (event.keyval == gtk.keysyms.Left \
1912 and _column == self.columns[1]):
1913 return True
1914 return False
1915
1916 def moveCursor(self, treeview, step, count):
1917 """def treeviewKeyPressEvent(self, widget, event)
1918
1919 treeview: the treeview that received the signal
1920 step: the movement step size
1921 count: the number of steps to take
1922
1923 Method connected to "move-cursor" signal
1924 The "move-cursor" signal is emitted when the user moves the cursor
1925 using the Right, Left, Up or Down arrow keys or the Page Up,
1926 Page Down, Home and End keys.
1927
1928 Returns :TRUE if the signal was handled.
1929 """
1930 return False
1931
1932 def controlSelection(self, selection):
1933 """def controlSelection(self, selection)
1934
1935 selection: treeselection
1936
1937 Method connected to set_selection_function()
1938 This method is called before any node is selected or unselected,
1939 giving some control over which nodes are selected.
1940 The selection function should return TRUE if the state
1941 of the node may be toggled, and FALSE if the state of the node should
1942 be left unchanged.
1943
1944 The selection only run if the user click in the index column, else
1945 the previous selection is erased.
1946 """
1947 _column = self.__treeview.get_cursor()[1]
1948 if _column is self.columns[0] \
1949 or self.__selection_control == False:
1950 return True
1951 else:
1952 self.__selection_control = False
1953 self.__treeselection.unselect_all()
1954 self.__selection_control = True
1955 return False
1956
1957 def selectAll(self, column):
1958 """def selectAll(self, column)
1959
1960 column: index column
1961 Method connected to "clicked" event in the index column
1962 If the user clickes in the index column header selecs or deselects
1963 all rows
1964 """
1965 (_model, _pathlist) = self.__treeselection.get_selected_rows()
1966 # it avoid to set cursor in the index column
1967 self.__treeview.set_cursor(self.__cursor[0], self.__cursor[1])
1968 self.__selection_control = False
1969 if len(_pathlist) == 0:
1970 # select all
1971 self.__treeselection.select_all()
1972 else:
1973 # unselect all
1974 self.__treeselection.unselect_all()
1975 self.__selection_control = True
1976
1977 def setColumnsHeaders(self):
1978 """def setColumnsHeaders(self)
1979
1980 Sets the headers column values
1981 """
1982 _path_record = self.__active_path_record
1983 _number = _path_record[-1]
1984 _budget = self.__budget
1985 _code = _budget.getCode(_path_record)
1986 _decomposition = _budget.getDecomposition(_path_record)
1987 _stryield = _budget.getStrYield(_decomposition.budgetMeasures[0],
1988 _budget.getRecord(_code).recordType)
1989 _record = _budget.getRecord(_code)
1990 _unit = _record.unit
1991 _description = _record.summary
1992 _price = _budget.getStrPriceFromRecord(self.budget.getActiveTitle(),
1993 _record)
1994 # TODO: round to decimal places in amount
1995 _amount = float(_stryield) * float(_price)
1996 if len(_path_record) == 1: # root record
1997 _amount = _price
1998 else:
1999 _parent_code = self.budget.getCode(self.__active_path_record[:-1])
2000 _parent_record = self.__budget.getRecord(_parent_code)
2001 _amount = _budget.getStrAmount(self.__active_path_record)
2002
2003 self.__code_column.set_title(_("Code") + chr(10) + "[" + _code + "]")
2004 self.__unit_column.set_title(_("Unit") + chr(10) + "[" + _unit + "]")
2005 self.__description_column.set_title(
2006 _("Description") + chr(10) + "[" + _description + "]")
2007 self.__measure_column.set_title(
2008 _("Measure") + chr(10) + "[" + _stryield + "]")
2009 self.__price_column.set_title(
2010 _("Price") + chr(10) + "[" + _price + "]")
2011 self.__amount_column.set_title(
2012 _("Amount") + chr(10) + "[" + str(_amount) + "]")
2013
2014
2015 def setListstoreValues(self, path_record):
2016 """def setListstoreValues(self, path_record)
2017
2018 path_record: Record path in the budget
2019 Sets the liststore record values from a path record
2020 """
2021 self.__liststore.clear()
2022 _budget = self.__budget
2023 if not _budget.hasPath(path_record):
2024 raise ValueError, _("Invalid path")
2025 else:
2026 _parent_code = _budget.getCode(path_record)
2027 for N,_code in enumerate(_budget.getchildren(_parent_code)):
2028 _decomposition = _budget.getNDecomposition(_parent_code, N)
2029 _record = _budget.getRecord(_code)
2030 _values = [_record,
2031 #_record.hierarchy,
2032 #_record.type,
2033 #_record.subtype,
2034 #_code,
2035 #_record.unit,
2036 #_record.summary,
2037 #_decomposition.yield_,
2038 #_decomposition.budget[0].yield_,
2039 #_record.prices[_budget.getActiveTitle()].prices]
2040 #_record.getPrice(_budget.getActiveTitle())
2041 ]
2042 _treeiter = self.__liststore.append(_values)
2043
2044 def colorCell(self, column, cell_renderer, tree_model, iter, lcolor):
2045 """def colorCell(self, column, cell_renderer, tree_model, iter, lcolor)
2046
2047 column: the gtk.TreeViewColumn in the treeview
2048 cell_renderer: a gtk.CellRenderer
2049 tree_model: the gtk.TreeModel
2050 iter: gtk.TreeIter pointing at the row
2051 lcolor: list with 2 gtk colors for even and uneven record
2052
2053 Method connected to "set_cell_data_func" of many column
2054 The set_cell_data_func() method sets the data function (or method)
2055 to use for the column gtk.CellRenderer specified by cell_renderer.
2056 This function (or method) is used instead of the standard attribute
2057 mappings for setting the column values, and should set the attributes
2058 of the cell renderer as appropriate. func may be None to remove the
2059 current data function. The signature of func is:
2060 -def celldatafunction(column, cell, model, iter, user_data)
2061 -def celldatamethod(self, column, cell, model, iter, user_data)
2062 where column is the gtk.TreeViewColumn in the treeview, cell is the
2063 gtk.CellRenderer for column, model is the gtk.TreeModel for the
2064 treeview and iter is the gtk.TreeIter pointing at the row.
2065
2066 The method sets cell background color and text for all columns.
2067 """
2068 _row_path = tree_model.get_path(iter)
2069 _number = _row_path[-1]
2070 _record = tree_model[_row_path][0]
2071 if column is self.__index_column:
2072 cell_renderer.set_property('text', str(_number + 1))
2073 self.__index_column.get_cell_renderers()[1].set_property(
2074 'cell-background-gdk', lcolor[_number % 2])
2075 elif column is self.__code_column:
2076 # if the record is a chapter
2077 if tree_model.get_value(iter, 0).recordType.hierarchy == 1:
2078 lcolor = self.__chapter_background_colors
2079 _code = _record.code
2080 cell_renderer.set_property('text', _code)
2081 elif column is self.__unit_column:
2082 _unit = _record.unit
2083 cell_renderer.set_property('text', _unit)
2084 elif column is self.__description_column:
2085 _summary = _record.summary
2086 cell_renderer.set_property('text', _summary)
2087 elif column is self.__measure_column:
2088 _parent_code = self.budget.getCode(self.__active_path_record)
2089 _parent_record = self.__budget.getRecord(_parent_code)
2090 _decomposition = _parent_record.children[_number]
2091 _stryield = self.__budget.getStrYield(
2092 _decomposition.budgetMeasures[0], _parent_record.recordType)
2093 cell_renderer.set_property('text', _stryield)
2094 elif column is self.__price_column:
2095 _price = self.budget.getStrPriceFromRecord(
2096 self.budget.getActiveTitle(), _record)
2097 cell_renderer.set_property('text', _price)
2098 elif column is self.__amount_column:
2099 _parent_code = self.budget.getCode(self.__active_path_record)
2100 _parent_record = self.__budget.getRecord(_parent_code)
2101 _amount = self.budget.getStrAmount(
2102 self.__active_path_record + (_number,))
2103 cell_renderer.set_property('text', str(_amount))
2104 elif column is self.__type_column:
2105 _hierarchy = tree_model[_row_path][0].recordType.hierarchy
2106 _type = tree_model[_row_path][0].recordType.type
2107 _subtype = tree_model[_row_path][0].recordType.subtype
2108 if _hierarchy == 1:
2109 cell_renderer.set_property("pixbuf",self.chapter_icon)
2110 else:
2111 if _type == 0:
2112 cell_renderer.set_property("pixbuf",self.unit_icon)
2113 elif _type == 1:
2114 cell_renderer.set_property("pixbuf",
2115 self.labourforce_icon)
2116 elif _type == 2:
2117 cell_renderer.set_property("pixbuf",
2118 self.machinery_icon)
2119 else:
2120 cell_renderer.set_property("pixbuf",self.material_icon)
2121 if self.__treeview.get_cursor() == (_row_path,column):
2122 cell_renderer.set_property('cell-background-gdk',
2123 gtk.gdk.color_parse(globals.color["ACTIVE"]))
2124 else:
2125 cell_renderer.set_property('cell-background-gdk',
2126 lcolor[_number % 2])
2127
2128 def showParentRecord(self, column):
2129 """def showParentRecord(self, column)
2130
2131 column: the column that is clicked
2132 Method connected to "clicked" event of many columns
2133 Show the parent record
2134 """
2135 _budget = self.__budget
2136 if len(self.__active_path_record) == 1:
2137 # The active record is the root record
2138 # This avoid to move the cursor to the clicked column
2139 self.__treeview.set_cursor(self.__cursor[0], self.__cursor[1])
2140 else:
2141 _path_record = self.__active_path_record[:-1]
2142 _parent = self.__active_path_record[-1]
2143 self.__active_path_record = _path_record
2144 self.setColumnsHeaders()
2145 self.setListstoreValues(self.__active_path_record)
2146 arg = ( _path_record )
2147 _page = self.__page()
2148 _page.propagateMessageFrom("change_active", self.__path, arg)
2149 self.__treeview.set_cursor(_parent, self.__cursor[1])
2150 self.__cursor = self.__treeview.get_cursor()
2151
2152 def showMessageRecord(self, record_path):
2153 """def showMessageRecord(self, record_path)
2154
2155 record_path: the path of the record to show
2156 Method connected to "change_active" message
2157 Show the record especified in the "change_active" message
2158 """
2159 _budget = self.__budget
2160 self.__active_path_record = record_path
2161 self.setColumnsHeaders()
2162 self.setListstoreValues(self.__active_path_record)
2163 self.__treeview.set_cursor((0,))
2164
2165 def showRowRecord(self, treeview, treeview_path, column):
2166 """def showRowRecord(self, treeview, treeview_path, column)
2167
2168 treeview: treview to show
2169 treeview_path: the path of the record to show
2170 code: the code of the record to show
2171
2172 Method connected to "row-activated" event
2173 The "row-activated" signal is emitted when the row_activated() method
2174 is called or the user double clicks a treeview row.
2175 "row-activated" is also emitted when a non-editable row is selected
2176 and one of the keys: Space, Shift+Space, Return or Enter is pressed.
2177 Show the especified record
2178 """
2179 if not (column is self.__end_column) and \
2180 not (column is self.__index_column):
2181 _budget = self.__budget
2182 _model = treeview.get_model()
2183 _iter = _model.get_iter(treeview_path)
2184 _code = _model.get_value(_iter, 0).code
2185 #_code = _model.get_value(_iter, 4)
2186 _path_record = self.__active_path_record + treeview_path
2187 if self.__budget.hasPath(_path_record):
2188 # if this record path is valid
2189 self.__active_path_record = _path_record
2190 self.setColumnsHeaders()
2191 self.setListstoreValues(self.__active_path_record)
2192 self.__treeview.set_cursor((0,))
2193 _arg = ( _path_record )
2194 _page = self.__page()
2195 _page.propagateMessageFrom("change_active", self.__path,
2196 _arg )
2197
2198 def runMessage(self, message, path, arg=None):
2199 """def runMessage(self, message, path, arg=None)
2200
2201 message: the message type
2202 "change_active": change the active record
2203 "clear": clear instance
2204 path: tuple that identifies the pane in the notebook page
2205 arg: tuple whit two items:
2206 0: record path in the budget
2207 1: record code
2208 This method receives a message and executes its corresponding action
2209 """
2210 _budget = self.__budget
2211 if message == "change_active":
2212 if _budget.hasPath(arg):
2213 _path_record = arg
2214 self.showMessageRecord( _path_record)
2215 elif message == "clear":
2216 self._clear()
2217
2218 def _clear(self):
2219 """def _clear(self)
2220
2221 it deletes the __budget value
2222 this would not be necessary if there were not circular references,
2223 which are pending to fix
2224 """
2225 del self.__budget
2226
2227 def getWidget(self):
2228 """def getWidget(self)
2229
2230 return the main widget (gtk.ScrolledWindow)
2231 """
2232 return self.__scrolled_window
2233
2234 def getPath(self):
2235 """def getPath(self)
2236
2237 return the tuple that identifies the pane in the notebook page
2238 """
2239 return self.__path
2240
2241 def setPath(self, path):
2242 """def setPath(self)
2243
2244 sets the tuple that identifies the pane in the notebook page
2245 """
2246 self.__path = path
2247
2248 def getPage(self):
2249 """def getPage(self)
2250
2251 return the Page
2252 """
2253 return self.__page
2254
2255 def setPage(self,page):
2256 """def setPage(self)
2257
2258 set the Page
2259 """
2260 self.__page = page
2261
2262 def getBudget(self):
2263 """def getBudget(self)
2264
2265 return the Budget objet
2266 """
2267 return self.__budget
2268
2269 def getActivePathRecord(self):
2270 """def getActivePathRecord(self)
2271
2272 return the Active Path Record
2273 """
2274 return self.__active_path_record
2275
2276 widget = property(getWidget, None, None,
2277 "Pane configuration list")
2278 path = property(getPath, setPath, None,
2279 "path that identifie the item in the page notebook")
2280 page = property(getPage, setPage, None,
2281 "weak reference from Page instance which creates this class")
2282 budget = property(getBudget, None, None,
2283 "Budget object")
2284 active_path_record = property(getActivePathRecord, None, None,
2285 "Active path record")
2286
2287 class Measure(TreeView):
2288 """gui.Measure:
2289
2290 Description:
2291 Class to show a Measure List
2292 Constructor:
2293 Measure(budget, page, path)
2294 budget: budget showed ("base.Budget" object)
2295 page: weak reference from Page instance which creates this class
2296 path: tuple that represents the path of the List in the Page
2297 Returns the newly created DecompositionList instance
2298 Ancestry:
2299 +-- object
2300 +-- TreeView
2301 +-- DecompositionList
2302 Atributes:
2303 "budget": Budget to show, base.obra instance.
2304 "__active_path_record": path of the active record in the budget
2305 "widget or __scrolled_window": Window that contains the table,
2306 (gtk.ScrolledWindow)
2307 "path": Pane page identifier
2308 "page": weak reference from Page instance which creates this class
2309 "__active_color": The background color of the active cell as a
2310 gtk.gdk.Color object
2311 "__chapter_background_colors": The background colors of the Code
2312 column cells when there is a chapter record
2313 as a list of gtk.gdk.Color objects [even cell, uneven cell]
2314 "__methond_message": Method to send messages to the page
2315 "__liststore": list model which store the list data
2316 (gtk.ListStore object)
2317 "__treeview": widget for displaying decomposition lists (gtk.TreeView)
2318 "__index_column": Index column (gtk.TreeViewColumn object)
2319 "__code_column": Record code column (gtk.TreeViewColumn)
2320 "__unit_column": Unit of measure column (gtk.TreeViewColumn)
2321 "__description_column": record's short description column
2322 (gtk.TreeViewColumn)
2323 "__measure_column": Measure column (gtk.TreeViewColumn)
2324 "__price_column": Price column (gtk.TreeViewColumn)
2325 "__amount_column": Amount column(gtk.TreeViewColumn)
2326 "__end_column": End empty column (gtk.TreeViewColumn)
2327 "__treeselection": active selection
2328 "__selection_control": state of the selection control (True/False)
2329 "__cursor": Situation of the cursor in the table
2330 Methods:
2331 __init__(self, budget, page, path, path_record=(0,))
2332 setListstoreValues(self, path_record)
2333 setColumnsHeaders(self)
2334 controlSelection(self, selection)
2335 showMessageRecord(self, record_path)
2336 treeviewCursorChanged(self, treeview)
2337 moveCursor(self, treeview, step, count)
2338 treeviewClickedEvent(self, widget, event)
2339 treeviewKeyPressEvent(self, widget, event)
2340 runMessage(self, message, path, arg=None)
2341 selectAll(self, column)
2342 colorCell(self, column, cell_renderer, tree_model, iter, lcolor)
2343 _clear(self)
2344 getWidget(self)
2345 {get/set}Path
2346 {get/set}Page
2347 getBudget(self)
2348 getActivePathRecord(self)
2349 """
2350
2351 def __init__(self, budget, page, path, path_record=(0,)):
2352 """def __init__(self, budget, page, path, path_record=(0,))
2353
2354 budget: budget: budget showed ("base.Budget" object)
2355 page: weak reference from Page instance which creates this class
2356 path: tuple that represents the path of the List in the Page
2357 path_record: path of the active record in the budget
2358
2359 Sets the init atributes
2360 Creates the init list values in self.__liststore from the budget
2361 showing the top record from the record with path path_record
2362 Creates the list in self.__treeview
2363 * Creates the columns and cell
2364 * Sets te the column headers values
2365 * Sets the selection properties
2366 * Connects the events
2367 """
2368 # Seting init args
2369 if not isinstance(budget, base.Budget):
2370 raise ValueError, _("Argument must be a Budget object")
2371 self.__budget = budget
2372 self.__page = page
2373 self.__path = path
2374 if not isinstance(path_record, tuple):
2375 print _("Record path must be a tuple")
2376 path_record = (0,)
2377 self.__active_path_record = path_record
2378 # ListStore
2379 self.__liststore = gtk.ListStore(object)
2380 self.setListstoreValues(self.__active_path_record)
2381 # Treeview
2382 self.__treeview = gtk.TreeView(self.__liststore)
2383 self.__treeview.set_enable_search(False)
2384 self.__treeview.set_reorderable(False)
2385 self.__treeview.set_headers_clickable(True)
2386 self.__treeview.show()
2387 # Scrolled_window
2388 self.__scrolled_window = gtk.ScrolledWindow()
2389 self.__scrolled_window.set_policy(gtk.POLICY_AUTOMATIC,
2390 gtk.POLICY_AUTOMATIC)
2391 self.__scrolled_window.add(self.__treeview)
2392 # colors
2393 _text_color = gtk.gdk.color_parse(globals.color["TEXT"])
2394 _calculated_text =gtk.gdk.color_parse(globals.color["CALCULATED-TEXT"])
2395 _background_color = [
2396 gtk.gdk.color_parse(globals.color["UNEVEN"]),
2397 gtk.gdk.color_parse(globals.color["EVEN"])]
2398 self.__chapter_background_colors = [
2399 gtk.gdk.color_parse(globals.color["CHAPTER-UNEVEN"]),
2400 gtk.gdk.color_parse(globals.color["CHAPTER-EVEN"])]
2401 super(Measure,self).__init__(
2402 [("INDEX",self.selectAll,42),
2403 ("PIXBUF", self.passMethod,
2404 gtk.Label("A"*4).size_request()[0] +10,
2405 _text_color, _background_color),
2406 ("CALCULATEDTEXT", self.passMethod,
2407 gtk.Label("A"*12).size_request()[0] +10,
2408 _text_color, _background_color),
2409 ("CALCULATED", self.passMethod,
2410 gtk.Label("A"*5).size_request()[0] +10,
2411 _text_color, _background_color),
2412 ("CALCULATED", self.passMethod,
2413 gtk.Label("A"*7).size_request()[0] +10,
2414 _text_color, _background_color),
2415 ("CALCULATED", self.passMethod,
2416 gtk.Label("A"*7).size_request()[0] +10,
2417 _text_color, _background_color),
2418 ("CALCULATED", self.passMethod,
2419 gtk.Label("A"*7).size_request()[0] +10,
2420 _text_color, _background_color),
2421 ("CALCULATEDTEXT", self.passMethod,
2422 gtk.Label("A"*12).size_request()[0] +10,
2423 _text_color, _background_color),
2424 ("CALCULATED", self.passMethod,
2425 gtk.Label("A"*7).size_request()[0] +10,
2426 _calculated_text, _background_color),
2427 ("CALCULATED", self.passMethod,
2428 gtk.Label("A"*7).size_request()[0] +10,
2429 _calculated_text, _background_color),
2430 ])
2431 self.__index_column = self.columns[0]
2432 self.__linetype_column = self.columns[1]
2433 self.__comment_column = self.columns[2]
2434 self.__units_column = self.columns[3]
2435 self.__length_column = self.columns[4]
2436 self.__width_column = self.columns[5]
2437 self.__height_column = self.columns[6]
2438 self.__formula_column = self.columns[7]
2439 self.__parcial_column = self.columns[8]
2440 self.__subtotal_column = self.columns[9]
2441 self.__end_column = self.columns[10]
2442 # Index column
2443 self.__treeview.append_column(self.__index_column)
2444 # Linetype column
2445 self.__treeview.append_column(self.__linetype_column)
2446 self.calculatedline_icon = gtk.gdk.pixbuf_new_from_file(
2447 globals.getAppPath("CALCULATEDLINE-ICON"))
2448 self.normalline_icon = gtk.gdk.pixbuf_new_from_file(
2449 globals.getAppPath("NORMALLINE-ICON") )
2450 self.parcialline_icon = gtk.gdk.pixbuf_new_from_file(
2451 globals.getAppPath("PARCIALLINE-ICON") )
2452 self.acumulatedline_icon = gtk.gdk.pixbuf_new_from_file(
2453 globals.getAppPath("ACUMULATEDLINE-ICON"))
2454 # Comment column
2455 self.__treeview.append_column(self.__comment_column)
2456 # Units column
2457 self.__treeview.append_column(self.__units_column)
2458 # Length column
2459 self.__treeview.append_column(self.__length_column)
2460 # Width_column
2461 self.__treeview.append_column(self.__width_column)
2462 # Height column
2463 self.__treeview.append_column(self.__height_column)
2464 # Formula column
2465 self.__treeview.append_column(self.__formula_column)
2466 # Parcial column
2467 self.__treeview.append_column(self.__parcial_column)
2468 # Subtotal column
2469 self.__treeview.append_column(self.__subtotal_column)
2470 # End Column
2471 self.__treeview.append_column(self.__end_column)
2472 # Connect
2473 self.__treeview.connect("move-cursor", self.moveCursor)
2474 self.__treeview.connect("key-press-event", self.treeviewKeyPressEvent)
2475 self.__treeview.connect("button-press-event", self.treeviewClickedEvent)
2476 self.__treeview.connect("cursor-changed", self.treeviewCursorChanged)
2477 # control selection
2478 self.__treeselection = self.__treeview.get_selection()
2479 self.__treeselection.set_mode(gtk.SELECTION_MULTIPLE)
2480 self.__treeselection.set_select_function(self.controlSelection)
2481 self.__selection_control = True
2482 self.__treeview.set_cursor_on_cell((1,), self.columns[1],
2483 self.columns[1].get_cell_renderers()[0],True)
2484 self.__treeview.grab_focus()
2485 self.__cursor = self.__treeview.get_cursor()
2486 # Show
2487 self.setColumnsHeaders()
2488 self.__scrolled_window.show()
2489
2490 def passMethod(self, args):
2491 pass
2492
2493 def setListstoreValues(self, path_record):
2494 """def setListstoreValues(self, path_record)
2495
2496 path_record: Record path in the budget
2497 Sets the liststore record values from a path record
2498 """
2499 self.__liststore.clear()
2500 _budget = self.__budget
2501 if not _budget.hasPath(path_record):
2502 raise ValueError, _("Invalid path")
2503 else:
2504 _measure = _budget.getMeasure(path_record)
2505 if isinstance(_measure, base.Measure):
2506 _lines = _measure.lines
2507 for _line in _lines:
2508 _values = [
2509 _line,
2510 ## _line.type,
2511 ## _line.comment,
2512 ## _line.units,
2513 ## _line.length,
2514 ## _line.width,
2515 ## _line.height
2516 ]
2517 _treeiter = self.__liststore.append(_values)
2518 else:
2519 raise ValueError, utils.mapping(_("measure must be a Measure "\
2520 "object. Type: $1"), (type(_measure),))
2521 def setColumnsHeaders(self):
2522 """def setColumnsHeaders(self)
2523
2524 Sets the headers column values
2525 """
2526 _measure = self.__budget.getMeasure(self.__active_path_record)
2527 _DS = self.__budget.getDecimals("DS")
2528 _total = _measure.measure
2529 _total_str = ("%." + str(_DS) + "f" ) % _total
2530 self.columns[1].set_title(_("Type")) # Σ parcial Σ total
2531 self.columns[2].set_title(_("Comment"))
2532 self.columns[3].set_title(_("N\n(a)"))
2533 self.columns[4].set_title(_("Length\n(b)"))
2534 self.columns[5].set_title(_("Width\n(c)"))
2535 self.columns[6].set_title(_("Height\n(d)"))
2536 self.columns[7].set_title(_("Formula"))
2537 self.columns[8].set_title(_("Parcial\n[%s]" % _total_str))
2538 self.columns[9].set_title(_("Subtotal"))
2539 def controlSelection(self, selection):
2540 """def controlSelection(self, selection)
2541
2542 selection: treeselection
2543
2544 Method connected to set_selection_function()
2545 This method is called before any node is selected or unselected,
2546 giving some control over which nodes are selected.
2547 The selection function should return TRUE if the state
2548 of the node may be toggled, and FALSE if the state of the node should
2549 be left unchanged.
2550
2551 The selection only run if the user click in the index column, else
2552 the previous selection is erased.
2553 """
2554 _column = self.__treeview.get_cursor()[1]
2555 if _column is self.columns[0] \
2556 or self.__selection_control == False:
2557 return True
2558 else:
2559 self.__selection_control = False
2560 self.__treeselection.unselect_all()
2561 self.__selection_control = True
2562 return False
2563
2564 def showMessageRecord(self, record_path):
2565 """def showMessageRecord(self, record_path)
2566
2567 record_path: the path of the record to show
2568 Method connected to "change_active" message
2569 Show the record especified in the "change_active" message
2570 """
2571 _budget = self.__budget
2572 self.__active_path_record = record_path
2573 self.setColumnsHeaders()
2574 self.setListstoreValues(self.__active_path_record)
2575 self.__treeview.set_cursor((0,))
2576
2577 def treeviewCursorChanged(self, treeview):
2578 """def treeviewCursorChanged(self, treeview)
2579
2580 treeview: treewiew widget
2581 Method connected to "cursor-changed" signal
2582 The "cursor-changed" signal is emitted when the cursor moves or is set
2583 Sets the new cursor position in self.__cursor, it is used to avoid
2584 unnecessary changes in cursor position.
2585 """
2586 event = gtk.get_current_event()
2587 (_cursor_path, _column) = treeview.get_cursor()
2588 if event is None or event.type != gtk.gdk.BUTTON_RELEASE:
2589 if not _column is self.__index_column:
2590 self.__cursor = treeview.get_cursor()
2591
2592 def moveCursor(self, treeview, step, count):
2593 """def treeviewKeyPressEvent(self, widget, event)
2594
2595 treeview: the treeview that received the signal
2596 step: the movement step size
2597 count: the number of steps to take
2598
2599 Method connected to "move-cursor" signal
2600 The "move-cursor" signal is emitted when the user moves the cursor
2601 using the Right, Left, Up or Down arrow keys or the Page Up,
2602 Page Down, Home and End keys.
2603
2604 Returns :TRUE if the signal was handled.
2605 """
2606 return False
2607
2608 def treeviewClickedEvent(self, widget, event):
2609 """def treeviewClickedEvent(self, widget, event)
2610
2611 widget: treewiew widget
2612 event: clicked event
2613 Method connected to "button-press-event" signal
2614 The "button-press-event" signal is emitted when a mouse button is
2615 pressed.
2616 Returns TRUE to stop other handlers from being invoked for the event.
2617 Returns FALSE to propagate the event further.
2618
2619 The events in end column are ignored.
2620 If the user click in a row of the index column the cursor is moved to
2621 this row but not to the index column
2622 """
2623 if event.button == 1:
2624 path_at_pos = self.__treeview.get_path_at_pos(int(event.x),
2625 int(event.y))
2626 if not path_at_pos is None:
2627 _path_cursor, _column, _x, _y = path_at_pos
2628 if _column == self.columns[-1]:
2629 return True
2630 if _column is self.columns[0]:
2631 self.__cursor[0] == _path_cursor
2632 return False
2633
2634 def treeviewKeyPressEvent(self, widget, event):
2635 """def treeviewKeyPressEvent(self, widget, event)
2636
2637 widget: treewiew widget
2638 event: Key Press event
2639 Method connected to "key-press-event" signal
2640 The "key-press-event" signal is emitted when the user presses a key
2641 on the keyboard.
2642 Returns :TRUE to stop other handlers from being invoked for the event.
2643 Returns :FALSE to propagate the event further.
2644
2645 If the user press the right cursor button and the cursor is in the
2646 amount column or pres the left cursor button and the cursor is
2647 in the code column the event is estoped, else the event is propagated.
2648 """
2649 (_cursor_path, _column) = self.__treeview.get_cursor()
2650 if (event.keyval == gtk.keysyms.Right \
2651 and _column == self.columns[-2]) \
2652 or (event.keyval == gtk.keysyms.Left \
2653 and _column == self.columns[1]):
2654 return True
2655 return False
2656
2657 def runMessage(self, message, path, arg=None):
2658 """def runMessage(self, message, path, arg=None)
2659
2660 message: the message type
2661 "change_active": change the active record
2662 "clear": clear instance
2663 path: tuple that identifies the pane in the notebook page
2664 arg: tuple whit two items:
2665 0: record path in the budget
2666 1: record code
2667 This method receives a message and executes its corresponding action
2668 """
2669 _budget = self.__budget
2670 if message == "change_active":
2671 if _budget.hasPath(arg):
2672 _path_record = arg
2673 self.showMessageRecord( _path_record)
2674 elif message == "clear":
2675 self._clear()
2676
2677 def selectAll(self, column):
2678 """def selectAll(self, column)
2679
2680 column: index column
2681 Method connected to "clicked" event in the index column
2682 If the user clickes in the index column header selecs or deselects
2683 all rows
2684 """
2685 (_model, _pathlist) = self.__treeselection.get_selected_rows()
2686 # it avoid to set cursor in the index column
2687 self.__treeview.set_cursor(self.__cursor[0], self.__cursor[1])
2688 self.__selection_control = False
2689 if len(_pathlist) == 0:
2690 # select all
2691 self.__treeselection.select_all()
2692 else:
2693 # unselect all
2694 self.__treeselection.unselect_all()
2695 self.__selection_control = True
2696
2697 def colorCell(self, column, cell_renderer, tree_model, iter, lcolor):
2698 """def colorCell(self, column, cell_renderer, tree_model, iter, lcolor)
2699
2700 column: the gtk.TreeViewColumn in the treeview
2701 cell_renderer: a gtk.CellRenderer
2702 tree_model: the gtk.TreeModel
2703 iter: gtk.TreeIter pointing at the row
2704 lcolor: list with 2 gtk colors for even and uneven record
2705
2706 Method connected to "set_cell_data_func" of many column
2707 The set_cell_data_func() method sets the data function (or method)
2708 to use for the column gtk.CellRenderer specified by cell_renderer.
2709 This function (or method) is used instead of the standard attribute
2710 mappings for setting the column values, and should set the attributes
2711 of the cell renderer as appropriate. func may be None to remove the
2712 current data function. The signature of func is:
2713 -def celldatafunction(column, cell, model, iter, user_data)
2714 -def celldatamethod(self, column, cell, model, iter, user_data)
2715 where column is the gtk.TreeViewColumn in the treeview, cell is the
2716 gtk.CellRenderer for column, model is the gtk.TreeModel for the
2717 treeview and iter is the gtk.TreeIter pointing at the row.
2718
2719 The method sets cell background color for all columns
2720 and text for index and amount columns.
2721 """
2722 _row_path = tree_model.get_path(iter)
2723 _number = _row_path[-1]
2724 if column is self.__index_column:
2725 cell_renderer.set_property('text', str(_number + 1))
2726 self.__index_column.get_cell_renderers()[1].set_property(
2727 'cell-background-gdk', lcolor[_number % 2])
2728 elif column is self.__linetype_column:
2729 _measure = tree_model[_row_path][0]
2730 _type = _measure.lineType
2731 if _type == 0:
2732 cell_renderer.set_property("pixbuf",self.normalline_icon)
2733 elif _type == 1:
2734 cell_renderer.set_property("pixbuf",self.parcialline_icon)
2735 elif _type == 2:
2736 cell_renderer.set_property("pixbuf",
2737 self.acumulatedline_icon)
2738 else: #elif _type == 3:
2739 cell_renderer.set_property("pixbuf",
2740 self.calculatedline_icon)
2741
2742 elif column is self.__comment_column:
2743 _measure = tree_model[_row_path][0]
2744 _comment = str(_measure.comment)
2745 cell_renderer.set_property('text', _comment)
2746 elif column is self.__units_column:
2747 _measure = tree_model[_row_path][0]
2748 _units = _measure.units
2749 if isinstance(_units, float):
2750 _DN = self.__budget.getDecimals("DN")
2751 _units = ("%." + str(_DN) + "f" ) % _units
2752 cell_renderer.set_property('text', _units)
2753 elif column is self.__length_column:
2754 _measure = tree_model[_row_path][0]
2755 _length = _measure.length
2756 if isinstance(_length, float):
2757 _DD = self.__budget.getDecimals("DD")
2758 _length = ("%." + str(_DD) + "f" ) % _length
2759 cell_renderer.set_property('text', _length)
2760 elif column is self.__width_column:
2761 _measure = tree_model[_row_path][0]
2762 _width = _measure.width
2763 if isinstance(_width, float):
2764 _DD = self.__budget.getDecimals("DD")
2765 _width = ("%." + str(_DD) + "f" ) % _width
2766 cell_renderer.set_property('text', _width)
2767 elif column is self.__height_column:
2768 _measure = tree_model[_row_path][0]
2769 _height = _measure.height
2770 if isinstance(_height, float):
2771 _DD = self.__budget.getDecimals("DD")
2772 _height = ("%." + str(_DD) + "f" ) % _height
2773 cell_renderer.set_property('text', _height)
2774 elif column is self.__formula_column:
2775 _measure = tree_model[_row_path][0]
2776 _formula = _measure.formula
2777 cell_renderer.set_property('text', _formula)
2778 elif column is self.__parcial_column:
2779 _measure_line = tree_model[_row_path][0]
2780 _parcial = _measure_line.parcial
2781 _type = _measure_line.lineType
2782 if _type == 1 or _type == 2:
2783 _parcial = ""
2784 else:
2785 if isinstance(_parcial, float):
2786 _DS = self.__budget.getDecimals("DS")
2787 _parcial = ("%." + str(_DS) + "f" ) % _parcial
2788 cell_renderer.set_property('text', _parcial)
2789 elif column is self.__subtotal_column:
2790 _measure_line = tree_model[_row_path][0]
2791 _type = _measure_line.lineType
2792 if _type == 1 or _type == 2:
2793 if _type == 1:
2794 _color = gtk.gdk.color_parse(
2795 globals.color["SUBTOTAL-PARCIAL"])
2796 _subtotal = _measure_line.parcial_subtotal
2797 else: #elif _type == 2:
2798 _color = gtk.gdk.color_parse(globals.color["SUBTOTAL"])
2799 _subtotal = _measure_line.acumulated_subtotal
2800 lcolor = [_color, _color]
2801 if isinstance(_subtotal, float):
2802 _DS = self.__budget.getDecimals("DS")
2803 _subtotal= ("%." + str(_DS) + "f" ) % _subtotal
2804 cell_renderer.set_property('text', _subtotal)
2805 else:
2806 cell_renderer.set_property('text', "")
2807
2808 if self.__treeview.get_cursor() == (_row_path,column):
2809 cell_renderer.set_property('cell-background-gdk',
2810 gtk.gdk.color_parse(globals.color["ACTIVE"]))
2811 else:
2812 cell_renderer.set_property('cell-background-gdk',
2813 lcolor[_number % 2])
2814
2815 def _clear(self):
2816 """def _clear(self)
2817
2818 it deletes the __budget value
2819 this would not be necessary if there were not circular references,
2820 which are pending to fix
2821 """
2822 del self.__budget
2823
2824 def getWidget(self):
2825 """def getWidget(self)
2826
2827 return the main widget (gtk.ScrolledWindow)
2828 """
2829 return self.__scrolled_window
2830
2831 def getPath(self):
2832 """def getPath(self)
2833
2834 return the tuple that identifies the pane in the notebook page
2835 """
2836 return self.__path
2837
2838 def setPath(self, path):
2839 """def setPath(self)
2840
2841 sets the tuple that identifies the pane in the notebook page
2842 """
2843 self.__path = path
2844 def getPage(self):
2845 """def getPage(self)
2846
2847 return the Page
2848 """
2849 return self.__page
2850
2851 def setPage(self,page):
2852 """def setPage(self)
2853
2854 set the Page
2855 """
2856 self.__page = page
2857
2858 def getBudget(self):
2859 """def getBudget(self)
2860
2861 return the Budget objet
2862 """
2863 return self.__budget
2864
2865 def getActivePathRecord(self):
2866 """def getActivePathRecord(self)
2867
2868 return the Active Path Record
2869 """
2870 return self.__active_path_record
2871
2872 widget = property(getWidget, None, None,
2873 "Pane configuration list")
2874 path = property(getPath, setPath, None,
2875 "Path that identifies the item in the page notebook")
2876 page = property(getPage, setPage, None,
2877 "Weak reference from Page instance which creates this class")
2878 budget = property(getBudget, None, None,
2879 "Budget object")
2880 active_path_record = property(getActivePathRecord, None, None,
2881 "Active Code")
2882
2883 class Description(object):
2884 """gui.Description
2885
2886 Description:
2887 Class to show a description text of a record in a pane
2888 Constructor:
2889 Description(budget, code)
2890 budget: budget
2891 code: code record
2892 Ancestry:
2893 +-- object
2894 +-- Description
2895 Atributes:
2896 "widget": the main widget (gtk.ScrolledWindow object)
2897 "path": the tuple that identifies the pane in the notebook page
2898 TODO
2899 "budget": The budget (base.obra objetc)
2900 "active_code": The active code of the record
2901 "__textbuffer": The textbuffer of the textview that contain
2902 the record text.
2903 "__label": The gtk.label with the title of the pane
2904 Methods:
2905 __init__(self, budget, code)
2906 setActiveCode(self, code)
2907 runMessage(self, message, nt, arg=None)
2908 _clear(self)
2909 getWidget(self)
2910 {get/set}Path
2911 {get/seg}Page
2912 getBudget(self)
2913 getActviCode(self)
2914 """
2915 # TODO: make standar: "DecompositonList and Description"
2916 def __init__(self, budget, page, path, path_record=(0,)):
2917 """def __init__(self, budget, page, path, path_record=(0,))
2918
2919 budget: the budget (base.obra object)
2920 page: weak reference from Page instance which creates this class
2921 path: the path position of the description in the page
2922 path_record: the path of the active record
2923
2924 Creates an shows the scroledwindow that contain the description text
2925 of the record to be showed in a pane.
2926 """
2927 self.__budget = budget
2928 self.__page = page
2929 self.__path = path
2930 self.__active_path_record = path_record
2931 _budget = budget
2932 _text = _budget.getRecord(self.__budget.getCode(
2933 self.__active_path_record)).text
2934 _scrollwindow = gtk.ScrolledWindow()
2935 _scrollwindow.set_policy(gtk.POLICY_AUTOMATIC,
2936 gtk.POLICY_AUTOMATIC)
2937 _textview = gtk.TextView()
2938 _textview.set_wrap_mode(gtk.WRAP_WORD)
2939 self.__textbuffer = _textview.get_buffer()
2940 self.__textbuffer.set_text(_text)
2941 _textview.show()
2942 _hbox = gtk.HBox()
2943 _hbox.pack_start(_textview, True, True, 5)
2944 _hbox.show()
2945 _vbox = gtk.VBox()
2946 self.__label = gtk.Label(utils.mapping(_("Description text of the "\
2947 "record $1"), (self.__budget.getCode(
2948 self.__active_path_record),)))
2949 self.__label.set_alignment(0, 0)
2950 self.__label.show()
2951 _vbox.pack_start(self.__label, False, False, 5)
2952 _vbox.pack_start(_hbox, True, True, 5)
2953 _vbox.show()
2954 _scrollwindow.add_with_viewport(_vbox)
2955 _scrollwindow.show()
2956 self.__widget = _scrollwindow
2957
2958
2959 def setActivePathRecord(self, path_record):
2960 """def setActivePathRecord(self, path_record))
2961
2962 path_record: active path record
2963 Set the new path code to show its description text.
2964 """
2965 _budget = self.__budget
2966 self.__active_path_record = path_record
2967 _code = _budget.getCode(self.__active_path_record)
2968 self.__label.set_text(utils.mapping(_("Description text of the record "\
2969 "$1"), (_code,)))
2970 _text = _budget.getRecord(_code).text
2971 self.__textbuffer.set_text(_text)
2972
2973 def runMessage(self, message, path, arg=None):
2974 """def runMessage(self, message, path, arg=None)
2975
2976 message: the message type
2977 "change_active": change the active record
2978 "clear": clear instance
2979 path: tuple that identifies the pane in the notebook page
2980 arg: tuple whit two items:
2981 0: record path in the budget
2982 1: record code
2983 This method receives a message and executes its corresponding action
2984 """
2985 _budget = self.__budget
2986 if message == "change_active":
2987 if _budget.hasPath(arg):
2988 self.setActivePathRecord(arg)
2989 elif message == "clear":
2990 self._clear()
2991
2992 def _clear(self):
2993 """def _clear(self)
2994
2995 Delete all instance atributes
2996 """
2997 del self.__widget
2998 del self.__path
2999 del self.__budget
3000 del self.__active_code
3001 del self.__textbuffer
3002 del self.__label
3003
3004 def getWidget(self):
3005 """def getWidget(self)
3006
3007 return the main widget (gtk.ScrolledWindow)
3008 """
3009 return self.__widget
3010
3011 def getPath(self):
3012 """def getPath(self)
3013
3014 return the tuple that identifies the pane in the notebook page
3015 """
3016 return self.__path
3017
3018 def setPath(self, path):
3019 """def setPath(self)
3020
3021 sets the tuple that identifies the pane in the notebook page
3022 """
3023 self.__path = path
3024
3025 def getPage(self):
3026 """def getPage(self)
3027
3028 return the weak reference from Page instance
3029 """
3030 return self.__page
3031
3032 def setPage(self, page):
3033 """def setPage(self)
3034
3035 set the weak reference from Page instance
3036 """
3037 self.__page = page
3038
3039 def getBudget(self):
3040 """def getBudget(self)
3041
3042 return the budget object
3043 """
3044 return self.__budget
3045
3046 def getActivePathRecord(self):
3047 """def getActivePathRecord(self)
3048
3049 return the Active Path Record
3050 """
3051 return self.__active_path_record
3052
3053 path = property(getPath, setPath, None,
3054 "Path that identifie the item in the page notebook")
3055 widget = property(getWidget, None, None,
3056 "The main widget (gtk.ScrolledWindow)")
3057 page = property(getPage, setPage, None,
3058 "Weak reference from Page instance which creates this class")
3059 budget = property(getBudget, None, None,
3060 "Budget object")
3061 active_path_record = property(getActivePathRecord, None, None,
3062 "Active Path Record")
3063
3064 class Sheet(object):
3065 """gui.Sheet
3066
3067 Description:
3068 Class to show a sheeet of conditions text of a record in a pane
3069 Constructor:
3070 Sheet(budget, code)
3071 budget: budget object
3072 code: code record
3073 Ancestry:
3074 +-- object
3075 +-- Sheet
3076 Atributes:
3077 "widget": the main widget (gtk.ScrolledWindow object)
3078 "path": the tuple that identifies the pane in the notebook page
3079 "budget": The budget (base.obra objetc)
3080 "active_path_record": The active path record
3081 "page": weak reference from Page instance which creates this class
3082
3083 "__textbuffer": The textbuffer of the textview that contain
3084 the record text.
3085 "__label": The gtk.label with the title of the pane
3086 "__field_liststore": the field liststore
3087 "__field_treeview": the field treeview
3088 "__field_selection": the field selected in field treview
3089 "__section_liststore": the section liststore
3090 "__section_treeview": the section treeview
3091 "__section_selection": the section selected in the section treeview
3092 Methods:
3093 __init__(self, budget, code)
3094 setFields(self)
3095 setSection(self)
3096 setText(self)
3097 field_controlSelection(self, selection)
3098 section_controlSelection(self, selection)
3099 runMessage(self, message, nt, arg=None)
3100 _clear(self)
3101 getWidget(self)
3102 {get/set}Path
3103 {get/set}Page
3104 getBudget(self)
3105 getActviPathRecord(self)
3106 """
3107 def __init__(self, budget, page, path, path_record=(0,)):
3108 """def __init__(self, budget, page, path, path_record=(0,))
3109
3110 budget: the budget (base.obra object)
3111 page: weak reference from Page instance which creates this class
3112 path: the path position of the description in the page
3113 path_record: the path of the active record
3114 Creates an shows the scroledwindow that contain the description text
3115 of the record to be showed in a pane.
3116 """
3117 self.__budget = budget
3118 self.__page = page
3119 self.__path = path
3120 self.__active_path_record = path_record
3121 _budget = budget
3122
3123 _main_box = gtk.VBox()
3124
3125 self.__label = gtk.Label(utils.mapping(_("Sheet of Conditions of the "\
3126 "record $1"), (self.__budget.getCode(
3127 self.__active_path_record),)))
3128 self.__label.set_alignment(0, 0)
3129 self.__label.show()
3130
3131 _frame = gtk.Frame()
3132 _frame.set_shadow_type(gtk.SHADOW_IN)
3133 _frame_box = gtk.VBox()
3134 _list_box = gtk.HBox()
3135
3136 self.__field_liststore = gtk.ListStore(str, str)
3137 self.__field_treeview = gtk.TreeView(self.__field_liststore)
3138 _field_treeselection = self.__field_treeview.get_selection()
3139 _field_treeselection.set_mode(gtk.SELECTION_SINGLE)
3140 self.__field_selection = None
3141 _field_treeselection.set_select_function(
3142 self.field_controlSelection)
3143 self.__field_treeview.show()
3144 _fieldcode_cell = gtk.CellRendererText()
3145 _field_column = gtk.TreeViewColumn(_("Field"))
3146 _field_column.pack_start(_fieldcode_cell, False)
3147 _field_cell = gtk.CellRendererText()
3148 _field_column.pack_end(_field_cell, True)
3149 _field_column.add_attribute(_fieldcode_cell, "text", 0)
3150 _field_column.add_attribute(_field_cell, "text", 1)
3151 self.__field_treeview.append_column(_field_column)
3152 _field_scrollwindow = gtk.ScrolledWindow()
3153 _field_scrollwindow.set_policy(gtk.POLICY_AUTOMATIC,
3154 gtk.POLICY_AUTOMATIC)
3155 _field_scrollwindow.add(self.__field_treeview)
3156 _field_scrollwindow.show()
3157
3158 self.__section_liststore = gtk.ListStore(str, str)
3159 self.__section_treeview = gtk.TreeView(self.__section_liststore)
3160 _section_treeselection = self.__section_treeview.get_selection()
3161 _section_treeselection.set_mode(gtk.SELECTION_SINGLE)
3162 self.__section_selection = None
3163 _section_treeselection.set_select_function(
3164 self.section_controlSelection)
3165 self.__section_treeview.show()
3166 _sectioncode_cell = gtk.CellRendererText()
3167 _section_column = gtk.TreeViewColumn(_("Section"))
3168 _section_column.pack_start(_sectioncode_cell, False)
3169 _section_column.add_attribute(_sectioncode_cell, "text", 0)
3170 _section_cell = gtk.CellRendererText()
3171 _section_column.pack_end(_section_cell, True)
3172 _section_column.add_attribute(_section_cell, "text", 1)
3173 self.__section_treeview.append_column(_section_column)
3174 _section_scrollwindow = gtk.ScrolledWindow()
3175 _section_scrollwindow.set_policy(gtk.POLICY_AUTOMATIC,
3176 gtk.POLICY_AUTOMATIC)
3177 _section_scrollwindow.add(self.__section_treeview)
3178 _section_scrollwindow.show()
3179
3180 _list_box.pack_start(_field_scrollwindow, True, True, 5)
3181 _list_box.pack_start(_section_scrollwindow, True, True, 5)
3182 _list_box.show()
3183
3184 _scrollwindow = gtk.ScrolledWindow()
3185 _scrollwindow.set_policy(gtk.POLICY_AUTOMATIC,
3186 gtk.POLICY_AUTOMATIC)
3187 _textview = gtk.TextView()
3188 _textview.set_wrap_mode(gtk.WRAP_WORD)
3189 self.__textbuffer = _textview.get_buffer()
3190 _textview.show()
3191 _hbox = gtk.HBox()
3192 _hbox.pack_start(_textview, True, True, 5)
3193 _hbox.show()
3194
3195 _frame_box.pack_start(self.__label, False, False, 5)
3196 _frame_box.pack_start(_list_box, False, False, 5)
3197 _frame_box.show()
3198 _frame.add(_frame_box)
3199 _frame.show()
3200 _main_box.pack_start(_frame, False)
3201
3202
3203 _vbox = gtk.VBox()
3204 _vbox.pack_start(_hbox, True, True, 5)
3205 _vbox.show()
3206 _main_box.pack_start(_scrollwindow, True, True, 5)
3207 _main_box.show()
3208
3209 _scrollwindow.add_with_viewport(_vbox)
3210 _scrollwindow.show()
3211 self.__widget = _main_box
3212
3213 self.setFields()
3214
3215 def setFields(self):
3216 """setFields(self)
3217
3218 Set the fields items in the field treeview
3219 """
3220 _record = self.__budget.getRecord(self.__budget.getCode(
3221 self.__active_path_record))
3222 _sheet = _record.getSheet()
3223 _field_list = _sheet.getFields()
3224 self.__field_liststore.clear()
3225 for _field in _field_list:
3226 _field_text = self.__budget.getSheetField(_field)
3227 _iter = self.__field_liststore.append([_field, _field_text])
3228 _treeselection = self.__field_treeview.get_selection()
3229 _treeselection.select_path(0)
3230
3231 def setSection(self):
3232 """setSection(self)
3233
3234 Set the section items in the section treeview
3235 """
3236 self.__section_liststore.clear()
3237 if not self.__field_selection is None:
3238 _record = self.__budget.getRecord(self.__budget.getCode(
3239 self.__active_path_record))
3240 _sheet = _record.getSheet()
3241 _section_list = _sheet.getSections(self.__field_selection)
3242 for _section in _section_list:
3243 _section_text = self.__budget.getSheetSection(_section)
3244 _iter = self.__section_liststore.append([_section, _section_text])
3245 _treeselection = self.__section_treeview.get_selection()
3246 _treeselection.select_path(0)
3247
3248 def setText(self):
3249 """setText(self)
3250
3251 Set the text in the textview
3252 """
3253 if not self.__section_selection is None and\
3254 not self.__field_selection is None:
3255 _record = self.__budget.getRecord(self.__budget.getCode(
3256 self.__active_path_record))
3257 _sheet = _record.getSheet()
3258 _paragraph_code = _sheet.getParagraph(self.__field_selection,
3259 self.__section_selection)
3260 _paragraph = self.__budget.getSheetParagraph(_paragraph_code)
3261 self.__textbuffer.set_text(_paragraph)
3262 else:
3263 self.__textbuffer.set_text("")
3264
3265 def field_controlSelection(self, selection):
3266 """def controlSelection(self, selection)
3267
3268 selection: treeselection
3269
3270 Method connected to set_selection_function() in field treeview
3271 This method is called before any node is selected or unselected,
3272 giving some control over which nodes are selected.
3273 The selection function should return TRUE if the state
3274 of the node may be toggled, and FALSE if the state of the node should
3275 be left unchanged.
3276
3277 When a user select a row in the field treeview the section treeview is
3278 reloaded to show the sections of this field and already the text sheet.
3279 """
3280 _treeiter = self.__field_liststore.get_iter(selection)
3281 self.__field_selection = self.__field_liststore.get_value(_treeiter, 0)
3282 self.setSection()
3283 return True
3284
3285 def section_controlSelection(self, selection):
3286 """def controlSelection(self, selection)
3287
3288 selection: treeselection
3289
3290 Method connected to set_selection_function() in sector treeview
3291 This method is called before any node is selected or unselected,
3292 giving some control over which nodes are selected.
3293 The selection function should return TRUE if the state
3294 of the node may be toggled, and FALSE if the state of the node should
3295 be left unchanged.
3296
3297 When a user select a row in the field treeview the text sheet for this
3298 section in showed
3299 """
3300 _treeiter = self.__section_liststore.get_iter(selection)
3301 self.__section_selection = self.__section_liststore.get_value(_treeiter, 0)
3302 self.setText()
3303 return True
3304
3305 def setActivePathRecord(self, path_record):
3306 """def setActivePathRecord(self, path_record))
3307
3308 path_record: active path record
3309
3310 Set the new path code to show its sheet of condition text.
3311 """
3312 self.__field_selection = None
3313 self.__field_liststore.clear()
3314 self.__section_selection = None
3315 self.__section_liststore.clear()
3316 self.__textbuffer.set_text("")
3317 _budget = self.__budget
3318 self.__active_path_record = path_record
3319 _code = _budget.getCode(self.__active_path_record)
3320 self.__label.set_text(utils.mapping(_("Sheet2 of Conditions of the "\
3321 "record $1"), (_code,)))
3322 self.setFields()
3323
3324 def runMessage(self, message, path, arg=None):
3325 """def runMessage(self, message, path, arg=None)
3326
3327 message: the message type
3328 "change_active": change the active record
3329 "clear": clear instance
3330 path: tuple that identifies the pane in the notebook page
3331 arg: tuple whit two items:
3332 0: record path in the budget
3333 1: record code
3334 This method receives a message and executes its corresponding action
3335 """
3336 _budget = self.__budget
3337 if message == "change_active":
3338 if _budget.hasPath(arg):
3339 self.setActivePathRecord(arg)
3340 elif message == "clear":
3341 self._clear()
3342
3343 def _clear(self):
3344 """def _clear(self)
3345
3346 Deletes all the instance atributes
3347 """
3348 del self.__page
3349 del self.__widget
3350 del self.__path
3351 del self.__budget
3352 del self.__active_code
3353 del self.__textbuffer
3354 del self.__label
3355 del self.__textbuffer
3356 del self.__label
3357 del self.__field_liststore
3358 del self.__field_treeview
3359 del self.__field_selection
3360 del self.__section_liststore
3361 del self.__section_treeview
3362 del self.__section_selection
3363
3364 def getWidget(self):
3365 """def getWidget(self)
3366
3367 return the main widget (gtk.ScrolledWindow)
3368 """
3369 return self.__widget
3370
3371 def getPath(self):
3372 """def getPath(self)
3373
3374 return the tuple that identifies the pane in the notebook page
3375 """
3376 return self.__page
3377
3378 def setPath(self, path):
3379 """def setPath(self)
3380
3381 sets the tuple that identifies the pane in the notebook page
3382 """
3383 self.__path = path
3384
3385 def getPage(self):
3386 """def getPage(self)
3387
3388 return the weak reference from Page instance
3389 """
3390 return self.__page
3391
3392 def setPage(self, page):
3393 """def setPage(self)
3394
3395 set the weak reference from Page instance
3396 """
3397 self.__page = page
3398
3399 def getBudget(self):
3400 """def getBudget(self)
3401
3402 return the budget object
3403 """
3404 return self.__budget
3405
3406 def getActivePathRecord(self):
3407 """def getActivePathRecord(self)
3408
3409 return the Active Path Record
3410 """
3411 return self.__active_path_record
3412
3413 path = property(getPath, setPath, None,
3414 "Path that identifie the item in the page notebook")
3415 widget = property(getWidget, None, None,
3416 "Lista de configuracion de vistas")
3417 page = property(getPage, setPage, None,
3418 "Weak reference from Page instance which creates this class")
3419 budget = property(getBudget, None, None,
3420 "Budget object")
3421 active_path_record = property(getActivePathRecord, None, None,
3422 "Active Path Record")
3423
3424 class FileView(object):
3425 """gui.FileView
3426
3427 Description:
3428 Class to show the file icons of a record in a pane
3429 Constructor:
3430 Description(budget, code)
3431 budget: budget
3432 code: code record
3433 Ancestry:
3434 +-- object
3435 +-- Description
3436 Atributes:
3437 "widget": the main widget (gtk.ScrolledWindow object)
3438 "__icon_box": the box that contains the icon
3439 "path": the tuple that identifies the pane in the notebook page
3440 "budget": The budget (base.obra objetc)
3441 "active_code": The active code of the record
3442 Methods:
3443 __init__(self, budget, code)
3444 setActiveCode(self, code)
3445 runMessage(self, message, nt, arg=None)
3446 _clear(self)
3447 getWidget(self)
3448 {get/set}Path
3449 {get/seg}Page
3450 getBudget(self)
3451 getActviCode(self)
3452 """
3453
3454 def __init__(self, budget, page, path, path_record=(0,)):
3455 """def __init__(self, budget, page, path, path_record=(0,))
3456
3457 budget: the budget (base.obra object)
3458 page: weak reference from Page instance which creates this class
3459 path: the path position of the description in the page
3460 path_record: the path of the active record
3461
3462 Creates an shows the scroledwindow that contain icon files
3463 of the record to be showed in a pane.
3464 """
3465 self.__budget = budget
3466 self.__page = page
3467 self.__path = path
3468 self.__active_path_record = path_record
3469 self.__active_code = budget.getCode(self.__active_path_record)
3470 _budget = budget
3471 _record = self.__budget.getRecord(self.__budget.getCode(
3472 self.__active_path_record))
3473
3474 self.__icon_box = self.getIconBox(_record)
3475 _scrollwindow = gtk.ScrolledWindow()
3476 _scrollwindow.set_policy(gtk.POLICY_ALWAYS,
3477 gtk.POLICY_NEVER)
3478
3479 self.__icon_box.show()
3480 _scrollwindow.add_with_viewport(self.__icon_box)
3481 _scrollwindow.show()
3482 self.__widget = _scrollwindow
3483
3484 def getIconBox(self, record):
3485 """getIconBox(self, record)
3486
3487 record: the active record object
3488
3489 Creates and returns the box whith te icon files of the active record.
3490 """
3491 ## TODO: add others filetypes: avi, pdf, ppt...
3492 _files = record.getFiles()
3493 _hbox = gtk.HBox()
3494 _frame = gtk.Frame()
3495 _frame.set_shadow_type(gtk.SHADOW_IN)
3496 for _file in _files:
3497 _path = os.path.dirname(self.__budget.filename)
3498 _file_path = os.path.join(_path, _file.name)
3499 _filetype = utils.getFiletype(_file_path)
3500 _box = gtk.VBox()
3501 if _filetype == "image":
3502 _event_box = gtk.EventBox()
3503 try:
3504 _image_pixbuf = gtk.gdk.pixbuf_new_from_file(_file_path)
3505 _image_pixbuf = _image_pixbuf.scale_simple(64, 64,
3506 gtk.gdk.INTERP_BILINEAR)
3507 except:
3508 _image_pixbuf = gtk.gdk.pixbuf_new_from_file(
3509 globals.getAppPath("IMAGE-ICON"))
3510 _image_pixbuf = _image_pixbuf.scale_simple(64, 64,
3511 gtk.gdk.INTERP_BILINEAR)
3512 _image_icon = gtk.Image()
3513 _image_icon.set_from_pixbuf(_image_pixbuf)
3514 _image_icon.show()
3515 _event_box.add(_image_icon)
3516 _box.pack_start(_event_box, False, False, 5)
3517 _event_box.connect("button-press-event", self.launchFile,
3518 "image", _file_path)
3519 _event_box.show()
3520
3521 elif _filetype == "dxf":
3522 _event_box = gtk.EventBox()
3523 _dxf_icon = gtk.Image()
3524 _dxf_pixbuf = gtk.gdk.pixbuf_new_from_file(
3525 globals.getAppPath("DXF-ICON"))
3526 _dxf_pixbuf = _dxf_pixbuf.scale_simple(64, 64,
3527 gtk.gdk.INTERP_BILINEAR)
3528 _dxf_icon.set_from_pixbuf(_dxf_pixbuf)
3529 _dxf_icon.show()
3530 _event_box.add(_dxf_icon)
3531 _box.pack_start(_event_box, False, False, 5)
3532 _event_box.connect("button-press-event", self.launchFile,
3533 "dxf", _file_path)
3534 _event_box.show()
3535 _label_event_box = gtk.EventBox()
3536 _label = gtk.Label(_file.name)
3537 _label_event_box.add(_label)
3538 _label_event_box.show()
3539 _label.show()
3540 _box.pack_start(_label_event_box, False, False, 5)
3541 _box.show()
3542 _hbox.pack_start(_box, False, False, 5)
3543 _hbox.show()
3544 _frame.add(_hbox)
3545 return _frame
3546
3547 def launchFile(self, widget, event, kind, file_path):
3548 """launchFile(self, widget, event, kind, file_path)
3549
3550 widget: the widget that emit the signal
3551 event: the event that emit the signal
3552 king: kind of file
3553 file_path: the path file to be launch
3554
3555 Launch the file if a double click emit the signal.
3556 Method connected to "button-press-event" signal in images event box
3557 """
3558 if event.type is gtk.gdk._2BUTTON_PRESS:
3559 openwith.launch_file(kind, file_path)
3560
3561 def setActivePathRecord(self, path_record):
3562 """def setActivePathRecord(self, path_record))
3563
3564 path_record: active path record
3565 Set the new path code to show its description text.
3566 """
3567 _budget = self.__budget
3568 self.__active_path_record = path_record
3569 _code = _budget.getCode(self.__active_path_record)
3570 _record = self.__budget.getRecord(_code)
3571 self.__icon_box.destroy()
3572 self.__icon_box = self.getIconBox(_record)
3573 self.__icon_box.show()
3574 self.__widget.add_with_viewport(self.__icon_box)
3575
3576 def runMessage(self, message, path, arg=None):
3577 """def runMessage(self, message, path, arg=None)
3578
3579 message: the message type
3580 "change_active": change the active record
3581 "clear": clear instance
3582 path: tuple that identifies the pane in the notebook page
3583 arg: tuple whit two items:
3584 0: record path in the budget
3585 1: record code
3586 This method receives a message and executes its corresponding action
3587 """
3588 _budget = self.__budget
3589 if message == "change_active":
3590 if _budget.hasPath(arg):
3591 self.setActivePathRecord(arg)
3592 elif message == "clear":
3593 self._clear()
3594
3595 def _clear(self):
3596 """def _clear(self)
3597
3598 Delete all instance atributes
3599 """
3600 del self.__hbox
3601 del self.__widget
3602 del self.__path
3603 del self.__budget
3604 del self.__active_code
3605
3606 def getWidget(self):
3607 """def getWidget(self)
3608
3609 return the main widget (gtk.ScrolledWindow)
3610 """
3611 return self.__widget
3612
3613 def getPath(self):
3614 """def getPath(self)
3615
3616 return the tuple that identifies the pane in the notebook page
3617 """
3618 return self.__path
3619
3620 def setPath(self, path):
3621 """def setPath(self)
3622
3623 sets the tuple that identifies the pane in the notebook page
3624 """
3625 self.__path = path
3626
3627 def getPage(self):
3628 """def getPage(self)
3629
3630 return the weak reference from Page instance
3631 """
3632 return self.__page
3633
3634 def setPage(self, page):
3635 """def setPage(self)
3636
3637 set the weak reference from Page instance
3638 """
3639 self.__page = page
3640
3641 def getBudget(self):
3642 """def getBudget(self)
3643
3644 return the budget object
3645 """
3646 return self.__budget
3647
3648 def getActivePathRecord(self):
3649 """def getActivePathRecord(self)
3650
3651 return the Active Path Record
3652 """
3653 return self.__active_path_record
3654
3655 path = property(getPath, setPath, None,
3656 "Path that identifie the item in the page notebook")
3657 widget = property(getWidget, None, None,
3658 "The main widget (gtk.ScrolledWindow)")
3659 page = property(getPage, setPage, None,
3660 "Weak reference from Page instance which creates this class")
3661 budget = property(getBudget, None, None,
3662 "Budget object")
3663 active_path_record = property(getActivePathRecord, None, None,
3664 "Active Path Record")
3665
3666
3667 class TextWindow(object):
3668 """gui.TextWindow
3669
3670 Description:
3671 Class to show a description text of a record in a new gtk window
3672 Constructor:
3673 TextWindow(code, text)
3674 code: code of the record
3675 text: description text of the record
3676 Ancestry:
3677 +-- object
3678 +-- TextWindow
3679 Atributes:
3680 Methods:
3681 __init__(self, code, text)
3682 main(self)
3683 destroy(self, widget)
3684 """
3685
3686 def __init__(self, code, text):
3687 """def __init__(self, code, text)
3688
3689 code: code of the record
3690 text: description text of the record
3691 Creates an shows the window.
3692 """
3693 _window = gtk.Window(gtk.WINDOW_TOPLEVEL)
3694 _window.set_resizable(True)
3695 _window.set_default_size(700, 300)
3696 _window.set_title(utils.mapping(_("$1 text"), (code,)))
3697 _window.set_border_width(0)
3698 _box1 = gtk.VBox(False, 0)
3699 _window.add(_box1)
3700 _box1.show()
3701 _sw = gtk.ScrolledWindow()
3702 _sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
3703 _textview = gtk.TextView()
3704 _textview.set_wrap_mode(gtk.WRAP_WORD)
3705 _textbuffer = _textview.get_buffer()
3706 _sw.add(_textview)
3707 _sw.show()
3708 _textview.show()
3709 _box1.pack_start(_sw)
3710 _textbuffer.set_text(text)
3711 _window.connect("destroy", self.destroy)
3712 _window.show()
3713
3714 def main(self):
3715 """def main(self)
3716
3717 Starts the GTK+ event processing loop.
3718 """
3719 gtk.main()
3720
3721 def destroy(self, widget):
3722 """destroy(self, widget)
3723 widget: the widget where the event is emitted from
3724 Method connected to "destroy" signal of window widget
3725 This signal is emited when the method connected to "delete_event"
3726 signal returns True or when the program call the destroy() method of
3727 the gtk.Window widget.
3728 The window is closed and the GTK+ event processing loop is ended.
3729 """
3730 gtk.main_quit()
3731
3732 class CompanyView(object):
3733 """gui.CompanyView:
3734
3735 Description:
3736 Class to show the company records of a budget
3737 Constructor:
3738 CompanyView(budget, page, path)
3739 budget: budget showed ("base.Budget" object)
3740 page: weak reference from Page instance which creates this class
3741 path: tuple that represents the path of the List in the Page
3742 Returns the newly created CompanyView instance
3743 Ancestry:
3744 +-- object
3745 +-- CompanyView
3746 Atributes:
3747 "budget": Budget to show, base.obra instance.
3748 "active_path_record"
3749 "widget": Window that contains the main widget,
3750 (gtk.ScrolledWindow)
3751 "path": Pane page identifier
3752 "page": weak reference from Page instance which creates this class
3753 "__methond_message": Method to send messages to the page
3754 Methods:
3755 __init__(self, budget, page, path, path_record=(0,))
3756 runMessage(self, message, path, arg=None)
3757 _clear(self)
3758 getWidget(self)
3759 {get/set}Path
3760 {get/set}Page
3761 getBudget(self)
3762 getActivePathRecord(self)
3763 """
3764
3765 def __init__(self, budget, page, path, path_record=(0,)):
3766 """def __init__(self, budget, page, path, path_record=(0,))
3767
3768 budget: budget: budget showed ("base.Budget" object)
3769 page: weak reference from Page instance which creates this class
3770 path: tuple that represents the path of the List in the Page
3771 path_record: path of the active record in the budget
3772
3773 Sets the init atributes
3774 Creates the
3775
3776 """
3777 self.__selection = None
3778 # Seting init args
3779 if not isinstance(budget, base.Budget):
3780 raise ValueError, _("Argument must be a Budget object")
3781 self.__budget = budget
3782 self.__page = page
3783 self.__path = path
3784 self.__active_path_record = path_record
3785 # HVox
3786 self.__hbox = gtk.HPaned()
3787 self.__hbox.set_position(230)
3788 # TreeStore
3789 self.__treestore = gtk.TreeStore(str, str)
3790 self.setTreeStoreValues()
3791 # Select Treeview
3792 self.__select_treeview = gtk.TreeView(self.__treestore)
3793 self.__select_treeview.set_enable_search(False)
3794 self.__select_treeview.set_reorderable(False)
3795 self.__select_treeview.set_headers_visible(False)
3796 self.__select_treeview.show()
3797 # Scrolled_window
3798 self.__scrolled_window = gtk.ScrolledWindow()
3799 self.__scrolled_window.set_policy(gtk.POLICY_AUTOMATIC,
3800 gtk.POLICY_AUTOMATIC)
3801 self.__scrolled_window.add(self.__select_treeview)
3802 # colors
3803 _text_color = gtk.gdk.color_parse(globals.color["TEXT"])
3804 _background_color = [
3805 gtk.gdk.color_parse(globals.color["UNEVEN"]),
3806 gtk.gdk.color_parse(globals.color["EVEN"])]
3807 self.__code_column = gtk.TreeViewColumn()
3808 self.__code_column.set_clickable(True)
3809 self.__code_column.set_fixed_width(200)
3810 _code_cell = gtk.CellRendererText()
3811 _code_cell.set_property('foreground-gdk', _text_color)
3812 self.__code_column.pack_start(_code_cell, True)
3813 self.__code_column.add_attribute(_code_cell, 'text', 0)
3814 _summary_cell = gtk.CellRendererText()
3815 _summary_cell.set_property('foreground-gdk', _text_color)
3816 self.__code_column.pack_start(_summary_cell, True)
3817 self.__code_column.add_attribute(_summary_cell, 'text', 1)
3818 # Index column
3819 self.__select_treeview.append_column(self.__code_column)
3820 # control selection
3821 self.__treeselection = self.__select_treeview.get_selection()
3822 self.__treeselection.set_mode(gtk.SELECTION_SINGLE)
3823 self.__treeselection.set_select_function(self.controlSelection)
3824 # Show
3825 self.setColumnsHeaders()
3826 self.__scrolled_window.show()
3827 # Option View
3828 self.__option_View = OptionView("")
3829 # Selection
3830 self.__select_treeview.set_cursor((0,), None, False)
3831 self.__select_treeview.grab_focus()
3832 #
3833 self.__hbox.add1(self.__scrolled_window)
3834 self.__hbox.add2(self.__option_View.widget)
3835 self.__hbox.show()
3836 self.__widget = self.__hbox
3837
3838 def setOptions(self, type):
3839 if type == "company":
3840 _options = [("code", _("Code"), "string",
3841 _("""Code that define the company""")),
3842 ("summary", _("Summary"), "string",
3843 _("""Summary of the company name""")),
3844 ("name", _("Name"), "string",
3845 _("""Complete name""")),
3846 ("cif", _("CIF"), "string",
3847 _("""Fiscal identifier number""")),
3848 ("web", _("Web"), "string",
3849 _("""Company web page""")),
3850 ("email", _("Email"), "string",
3851 _("""Company email""")),
3852 ]
3853 self.__option_View.setOptions(_options)
3854 elif type == "office":
3855 _options = [("type", _("Type"), "string",
3856 _("""Type of Office:
3857 C: Central office
3858 D: Local office
3859 R: Performer""")),
3860 ("subname", _("Name"), "string",
3861 _("Office name")),
3862 ("address", _("Address"), "string",""),
3863 ("postal code", _("Postal code"), "string",""),
3864 ("town", _("Town"), "string",""),
3865 ("province", _("Province"), "string",""),
3866 ("country", _("Country"), "string",""),
3867 ("phone", _("Phone"), "list",
3868 _("Phone numbers of the office")),
3869 ("fax", _("Fax"), "list",
3870 _("Fax numbers of the office")),
3871 ("contact person", _("Contact person"), "string",
3872 _("Contact persons in the office")),
3873 ]
3874 self.__option_View.setOptions(_options)
3875 else:
3876 print _("Unknow Option Type")
3877 def setOptionValues(self, company_key):
3878 self.__option_View.setValues(_values)
3879
3880 def setTreeStoreValues(self):
3881 """def setListstoreValues(self)
3882
3883 Sets the treestore values from the budget
3884 """
3885 _budget = self.__budget
3886 _company_keys = _budget.getCompanyKeys()
3887 for _company_key in _company_keys:
3888 _company = _budget.getCompany(_company_key)
3889 _values = [_company_key, _company.summary]
3890 _treeiter = self.__treestore.append(None, _values)
3891 _offices = _company.offices
3892 for _office in _offices:
3893 # TODO: Test offices
3894 _values = [_office.officeType, _office.subname]
3895 self.__treestore.append(_treeiter, _values)
3896
3897 def setColumnsHeaders(self):
3898 """def setColumnsHeaders(self)
3899
3900 Sets the headers column values
3901 """
3902 #self.columns[1].set_title(_("Type")) # Σ parcial Σ total
3903 #self.columns[2].set_title(_("Comment"))
3904 #self.columns[3].set_title(_("N"))
3905 #self.columns[4].set_title(_("Length"))
3906 #self.columns[5].set_title(_("Width"))
3907 #self.columns[6].set_title(_("Height"))
3908 pass
3909
3910 def controlSelection(self, selection):
3911 """def controlSelection(self, selection)
3912
3913 selection: selection
3914
3915 Method connected to set_selection_function()
3916 This method is called before any node is selected or unselected,
3917 giving some control over which nodes are selected.
3918 The selection function should return TRUE if the state
3919 of the node may be toggled, and FALSE if the state of the node should
3920 be left unchanged.
3921
3922 The selection changes the company/office in the option treeview
3923 """
3924 if len(selection) == 1:
3925 # The selection is a company
3926 _company_key = self.__treestore[selection][0]
3927 _company = self.__budget.getCompany(_company_key)
3928 _selection = "company"
3929 _values = _company.values
3930 else:
3931 # The selection is a office
3932 _company_key = self.__treestore[selection[:1]][0]
3933 _company = self.__budget.getCompany(_company_key)
3934 _selection = "office"
3935 _office = _company.offices[selection[1]]
3936 _values = _office.values
3937 if not self.__selection == _selection:
3938 self.__selection = _selection
3939 self.setOptions(_selection)
3940 self.__option_View.setValues(_values)
3941
3942 return True
3943
3944 def showMessageRecord(self, record_path):
3945 """def showMessageRecord(self, record_path)
3946
3947 record_path: the path of the record to show
3948 Method connected to "change_active" message
3949 Show the record especified in the "change_active" message
3950 """
3951 self.__active_path_record = record_path
3952
3953 def runMessage(self, message, path, arg=None):
3954 """def runMessage(self, message, path, arg=None)
3955
3956 message: the message type
3957 "change_active": change the active record
3958 "clear": clear instance
3959 path: tuple that identifies the pane in the notebook page
3960 arg: tuple whit two items:
3961 0: record path in the budget
3962 1: record code
3963 This method receives a message and executes its corresponding action
3964 """
3965 _budget = self.__budget
3966 if message == "change_active":
3967 if _budget.hasPath(arg):
3968 _path_record = arg
3969 self.showMessageRecord( _path_record)
3970 pass
3971 elif message == "clear":
3972 self._clear()
3973
3974 def colorCell(self, column, cell_renderer, tree_model, iter, lcolor):
3975 """def colorCell(self, column, cell_renderer, tree_model, iter, lcolor)
3976
3977 column: the gtk.TreeViewColumn in the treeview
3978 cell_renderer: a gtk.CellRenderer
3979 tree_model: the gtk.TreeModel
3980 iter: gtk.TreeIter pointing at the row
3981 lcolor: list with 2 gtk colors for even and uneven record
3982
3983 Method connected to "set_cell_data_func" of many column
3984 The set_cell_data_func() method sets the data function (or method)
3985 to use for the column gtk.CellRenderer specified by cell_renderer.
3986 This function (or method) is used instead of the standard attribute
3987 mappings for setting the column values, and should set the attributes
3988 of the cell renderer as appropriate. func may be None to remove the
3989 current data function. The signature of func is:
3990 -def celldatafunction(column, cell, model, iter, user_data)
3991 -def celldatamethod(self, column, cell, model, iter, user_data)
3992 where column is the gtk.TreeViewColumn in the treeview, cell is the
3993 gtk.CellRenderer for column, model is the gtk.TreeModel for the
3994 treeview and iter is the gtk.TreeIter pointing at the row.
3995
3996 The method sets cell background color for all columns
3997 and text for index and amount columns.
3998 """
3999 _row_path = tree_model.get_path(iter)
4000 _number = _row_path[-1]
4001 if column is self.__index_column:
4002 cell_renderer.set_property('text', str(_number + 1))
4003 self.__index_column.get_cell_renderers()[1].set_property(
4004 'cell-background-gdk', lcolor[_number % 2])
4005 if self.__treeview.get_cursor() == (_row_path,column):
4006 cell_renderer.set_property('cell-background-gdk',
4007 gtk.gdk.color_parse(globals.color["ACTIVE"]))
4008 else:
4009 cell_renderer.set_property('cell-background-gdk',
4010 lcolor[_number % 2])
4011
4012 def _clear(self):
4013 """def _clear(self)
4014
4015 it deletes the __budget value
4016 this would not be necessary if there were not circular references,
4017 which are pending to fix
4018 """
4019 del self.__budget
4020
4021 def getWidget(self):
4022 """def getWidget(self)
4023
4024 return the main widget (gtk.ScrolledWindow)
4025 """
4026 return self.__widget
4027
4028 def getPath(self):
4029 """def getPath(self)
4030
4031 return the tuple that identifies the pane in the notebook page
4032 """
4033 return self.__path
4034
4035 def setPath(self, path):
4036 """def setPath(self)
4037
4038 sets the tuple that identifies the pane in the notebook page
4039 """
4040 self.__path = path
4041 def getPage(self):
4042 """def getPage(self)
4043
4044 return the Page
4045 """
4046 return self.__page
4047
4048 def setPage(self,page):
4049 """def setPage(self)
4050
4051 set the Page
4052 """
4053 self.__page = page
4054
4055 def getBudget(self):
4056 """def getBudget(self)
4057
4058 return the Budget objet
4059 """
4060 return self.__budget
4061
4062 def getActivePathRecord(self):
4063 """def getActivePathRecord(self)
4064
4065 return the Active Path Record
4066 """
4067 return self.__active_path_record
4068
4069 active_path_record = property(getActivePathRecord, None, None,
4070 "Active path record")
4071 widget = property(getWidget, None, None,
4072 "main widget")
4073 path = property(getPath, setPath, None,
4074 "Path that identifies the item in the page notebook")
4075 page = property(getPage, setPage, None,
4076 "Weak reference from Page instance which creates this class")
4077 budget = property(getBudget, None, None,
4078 "Budget object")
4079
4080
4081 class OptionView(object):
4082 """gui.OptionView:
4083
4084 Description:
4085 It creates a treeview whith the column "Option Name" "Value"
4086 and "Type" to show and edit Options
4087 Constructor:
4088 OptionView(option_list)
4089 option_list: list of options
4090 (option_name, type)
4091 Ancestry:
4092 +-- object
4093 +-- OptionView
4094 Atributes:
4095 "__liststore"
4096 "__treeview"
4097 "__option_column"
4098 "__value_column"
4099 "__type_column"
4100 "__treeselection"
4101 "__widget": Main windget
4102 "__option_list"
4103 "__option_dict"
4104 "__description_label"
4105 "option_types"
4106 "widget": __widget
4107 Methods:
4108 __init__(self, option_list)
4109 createColumn(self, args)
4110 createTextBaseColumn(self,args)
4111 createBaseColumn(self,args)
4112 """
4113
4114 def __init__(self, option_list):
4115 """__init__(self, option_list)
4116
4117 """
4118 self.__option_dict = {}
4119 self.__option_list = []
4120 self.option_types = {"boolean" : _("Boolean"),
4121 "integer": _("Integer"),
4122 "string": _("Text"),
4123 "color" : _("Color"),
4124 "list" : _("List")}
4125 # ListStore
4126 self.__liststore = gtk.ListStore(str, str, str, str, str)
4127 # Treeview
4128 self.__treeview = gtk.TreeView(self.__liststore)
4129 self.__treeview.set_enable_search(False)
4130 self.__treeview.set_reorderable(False)
4131 self.__treeview.set_headers_clickable(False)
4132 # vbox
4133 _vbox = gtk.VBox()
4134 # Scrolled_window
4135 _scrolled_window = gtk.ScrolledWindow()
4136 _scrolled_window.set_policy(gtk.POLICY_AUTOMATIC,
4137 gtk.POLICY_AUTOMATIC)
4138 _scrolled_window.add(self.__treeview)
4139 _scrolled_window.show()
4140 _vbox.pack_start(_scrolled_window)
4141 # colors
4142 _text_color = gtk.gdk.color_parse(globals.color["TEXT"])
4143 _background_color = [
4144 gtk.gdk.color_parse(globals.color["UNEVEN"]),
4145 gtk.gdk.color_parse(globals.color["EVEN"])]
4146 # Option Column
4147 self.__option_column = gtk.TreeViewColumn()
4148 self.__option_column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
4149 self.__option_column.set_fixed_width(150)
4150 self.__option_column.set_resizable(True)
4151 _option_cell = gtk.CellRendererText()
4152 _option_cell.set_property('foreground-gdk', _text_color)
4153 self.__option_column.pack_start(_option_cell, True)
4154 self.__option_column.set_cell_data_func(_option_cell, self.colorCell,
4155 _background_color)
4156 self.__option_column.set_title(_("Option name"))
4157 self.__option_column.add_attribute(_option_cell, 'text', 1)
4158 self.__treeview.append_column(self.__option_column)
4159 # Value Column
4160 self.__value_column = gtk.TreeViewColumn()
4161 self.__value_column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
4162 self.__value_column.set_fixed_width(275)
4163 self.__value_column.set_resizable(True)
4164 _value_cell = gtk.CellRendererText()
4165 _value_cell.set_property('foreground-gdk', _text_color)
4166 self.__value_column.pack_start(_value_cell, True)
4167 self.__value_column.set_cell_data_func(_value_cell, self.colorCell,
4168 _background_color)
4169 self.__value_column.set_title(_("Value"))
4170 self.__value_column.add_attribute(_value_cell, 'text', 2)
4171 self.__treeview.append_column(self.__value_column)
4172 # Type Column
4173 self.__type_column = gtk.TreeViewColumn()
4174 self.__type_column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED)
4175 self.__type_column.set_fixed_width(70)
4176 self.__type_column.set_resizable(True)
4177 _type_cell = gtk.CellRendererText()
4178 _type_cell.set_property('foreground-gdk', _text_color)
4179 self.__type_column.pack_start(_type_cell, True)
4180 self.__type_column.set_cell_data_func(_type_cell, self.colorCell,
4181 _background_color)
4182 self.__type_column.set_title(_("Type"))
4183 self.__treeview.append_column(self.__type_column)
4184 # End Column
4185 _end_column = gtk.TreeViewColumn()
4186 _end_column.set_clickable(False)
4187 _end_cell = gtk.CellRendererText()
4188 _end_cell.set_property('cell-background-gdk',
4189 gtk.gdk.color_parse(globals.color["UNEVEN"]))
4190 _end_column.pack_start(_end_cell, True)
4191 self.__treeview.append_column(_end_column)
4192 # Connect
4193 self.__treeview.connect("key-press-event", self.treeviewKeyPressEvent)
4194 self.__treeview.connect("button-press-event", self.treeviewClickedEvent)
4195 # control selection
4196 self.__treeselection = self.__treeview.get_selection()
4197 self.__treeselection.set_mode(gtk.SELECTION_MULTIPLE)
4198 self.__treeselection.set_select_function(self.controlSelection)
4199 # labels
4200 _frame = gtk.Frame()
4201 _frame.set_shadow_type(gtk.SHADOW_OUT)
4202 _vbox2 = gtk.VBox()
4203 _frame.add(_vbox2)
4204 _alignement = gtk.Alignment(xalign=0, yalign=0, xscale=0, yscale=0)
4205 _alignement.set_padding(0, 0, 12, 0)
4206 _label = gtk.Label()
4207 _label.set_markup("<b>" + _("Description:") + "</b>")
4208 _label.show()
4209 _alignement.add(_label)
4210 _alignement.show()
4211 _alignement2 = gtk.Alignment(xalign=0, yalign=0, xscale=0, yscale=0)
4212 _alignement2.set_padding(0, 0, 24, 0)
4213 self.__description_label = gtk.Label()
4214 self.__description_label.show()
4215 _alignement2.add(self.__description_label)
4216 _alignement2.show()
4217 _vbox2.pack_start(_alignement, False)
4218 _vbox2.pack_start(_alignement2, False)
4219 _vbox2.show()
4220 _frame.show()
4221 _vbox.pack_start(_frame, False)
4222 # Show
4223 self.__treeview.show()
4224 _vbox.show()
4225 self.__widget = _vbox
4226
4227 def treeviewKeyPressEvent(self, widget, event):
4228 """def treeviewKeyPressEvent(self, widget, event)
4229
4230 widget: treewiew widget
4231 event: Key Press event
4232 Method connected to "key-press-event" signal
4233 The "key-press-event" signal is emitted when the user presses a key
4234 on the keyboard.
4235 Returns :TRUE to stop other handlers from being invoked for the event.
4236 Returns :FALSE to propagate the event further.
4237
4238 If the user press the right cursor button and the cursor is in the
4239 value column or pres the left cursor button and the cursor is
4240 in the value column the event is estoped, else the event is propagated.
4241 """
4242 (_cursor_path, _column) = self.__treeview.get_cursor()
4243 if (event.keyval == gtk.keysyms.Right \
4244 and _column == self.__value_column) \
4245 or (event.keyval == gtk.keysyms.Left \
4246 and _column == self.__value_column):
4247 return True
4248 else:
4249 _description = self.__liststore[_cursor_path][4]
4250 self.__description_label.set_text(_description)
4251 return False
4252
4253 def treeviewClickedEvent(self, widget, event):
4254 """def treeviewClickedEvent(self, widget, event)
4255
4256 widget: treewiew widget
4257 event: clicked event
4258 Method connected to "button-press-event" signal
4259 The "button-press-event" signal is emitted when a mouse button is
4260 pressed.
4261 Returns TRUE to stop other handlers from being invoked for the event.
4262 Returns FALSE to propagate the event further.
4263
4264 The cursos is moved to value column.
4265 """
4266 path_at_pos = self.__treeview.get_path_at_pos(int(event.x),
4267 int(event.y))
4268 if not path_at_pos is None:
4269 _path_cursor, _column, _x, _y = path_at_pos
4270 _description = self.__liststore[_path_cursor][4]
4271 self.__description_label.set_text(_description)
4272 if _column == self.__value_column:
4273 return False
4274 else:
4275 self.__treeview.set_cursor(_path_cursor,self.__value_column,
4276 True)
4277 self.__treeview.grab_focus()
4278 return True
4279 return True
4280
4281 def controlSelection(self, selection):
4282 """def controlSelection(self, selection)
4283
4284 selection: treeselection
4285
4286 Method connected to set_selection_function()
4287 This method is called before any node is selected or unselected,
4288 giving some control over which nodes are selected.
4289 The selection function should return TRUE if the state
4290 of the node may be toggled, and FALSE if the state of the node should
4291 be left unchanged.
4292
4293 Return False so none row is selected
4294 """
4295 return False
4296
4297
4298 def colorCell(self, column, cell_renderer, tree_model, iter, lcolor):
4299 """def colorCell(self, column, cell_renderer, tree_model, iter, lcolor)
4300
4301 column: the gtk.TreeViewColumn in the treeview
4302 cell_renderer: a gtk.CellRenderer
4303 tree_model: the gtk.TreeModel
4304 iter: gtk.TreeIter pointing at the row
4305 lcolor: list with 2 gtk colors for even and uneven record
4306
4307 Method connected to "set_cell_data_func" of the column
4308 The set_cell_data_func() method sets the data function (or method)
4309 to use for the column gtk.CellRenderer specified by cell_renderer.
4310 This function (or method) is used instead of the standard attribute
4311 mappings for setting the column values, and should set the attributes
4312 of the cell renderer as appropriate. func may be None to remove the
4313 current data function. The signature of func is:
4314 -def celldatafunction(column, cell, model, iter, user_data)
4315 -def celldatamethod(self, column, cell, model, iter, user_data)
4316 where column is the gtk.TreeViewColumn in the treeview, cell is the
4317 gtk.CellRenderer for column, model is the gtk.TreeModel for the
4318 treeview and iter is the gtk.TreeIter pointing at the row.
4319
4320 The method sets cell background color for all columns
4321 and text for type column.
4322 """
4323 _row_path = tree_model.get_path(iter)
4324 _number = _row_path[-1]
4325 if self.__treeview.get_cursor() == (_row_path,column):
4326 cell_renderer.set_property('cell-background-gdk',
4327 gtk.gdk.color_parse(globals.color["ACTIVE"]))
4328 else:
4329 cell_renderer.set_property('cell-background-gdk',
4330 lcolor[_number % 2])
4331 if column is self.__type_column:
4332 _type = self.option_types[tree_model[_row_path][3]]
4333 cell_renderer.set_property('text', _type)
4334
4335 def setOptions(self, option_list):
4336 """setOptions(self, option_list)
4337
4338 option_list: list of tuples
4339 (option, option name, type)
4340 option: option identifier
4341 option name: a string with the option name
4342 Description: a string with the option description
4343 type: can be "boolean"
4344 "integer"
4345 "string"
4346 "color"
4347 Sets the Options in the treeview rows
4348 """
4349 self.__option_dict = {}
4350 self.__option_list = []
4351 self.__liststore.clear()
4352 if isinstance(option_list, list):
4353 for _option in option_list:
4354 if isinstance(_option, tuple) and len(_option) == 4:
4355 _option_key = _option[0]
4356 _option_name = _option[1]
4357 _option_type = _option[2]
4358 _option_description = _option[3]
4359 if isinstance(_option_key, str) and \
4360 (isinstance(_option_name, str) or\
4361 isinstance(_option_name, unicode))and \
4362 _option_type in self.option_types.keys():
4363 self.__liststore.append([_option_key, _option_name, "",
4364 _option_type, _option_description])
4365 self.__option_dict[_option_key] = [_option_name, "",
4366 _option_type, _option_description]
4367 self.__option_list.append(_option_key)
4368 else:
4369 print _("Option values must be strings")
4370 else:
4371 print _("Option must be a tuple with 4 items")
4372 else:
4373 print _("Option list must be a list")
4374 return
4375 def setValues(self, values):
4376 """setValues(self, values)
4377
4378 values: dictionary {option : value}
4379
4380 Sets the Options values
4381 """
4382 if isinstance(values, dict):
4383 for _option, _value in values.iteritems():
4384 if _option in self.__option_dict:
4385 _type = self.__option_dict[_option][2]
4386 if _type == "boolean":
4387 if isinstance(_value, bool):
4388 _num = self.__option_list.index(_option)
4389 _iter = self.__liststore.get_iter((_num,))
4390 self.__liststore.set_value(_iter, 2, _value)
4391 self.__option_dict[_option][1] = _value
4392 else:
4393 print _("Icorrect type, must be boolean")
4394 elif _type == "integer":
4395 try:
4396 _value = int(_value)
4397 except ValueError:
4398 print _("Icorrect type, must be integer")
4399 else:
4400 _num = self.__option_list.index(_option)
4401 _iter = self.__liststore.get_iter((_num,))
4402 self.__liststore.set_value(_iter, 2, _value)
4403 self.__option_dict[_option][1] = _value
4404 elif _type == "string":
4405 if isinstance(_value, str):
4406 _num = self.__option_list.index(_option)
4407 _iter = self.__liststore.get_iter((_num,))
4408 self.__liststore.set_value(_iter, 2, _value)
4409 self.__option_dict[_option][1] = _value
4410 else:
4411 print _("Icorrect type, must be string")
4412 elif _type == "list":
4413 if isinstance(_value, list):
4414 _num = self.__option_list.index(_option)
4415 _iter = self.__liststore.get_iter((_num,))
4416 _str_value = ""
4417 for _item_value in _value:
4418 _str_value = _str_value + _item_value + ","
4419 if _str_value[-1] == ",":
4420 _str_value = _str_value[:-1]
4421 self.__liststore.set_value(_iter, 2, _str_value)
4422 self.__option_dict[_option][1] = _value
4423 else:
4424 print _("Icorrect type, must be list")
4425 elif _type == "color":
4426 if isinstance(_value, str):
4427 try:
4428 _color = gtk.gdk.color_parse(_value)
4429 except ValueError:
4430 print _("Icorrect type, must be a parseable " \
4431 "color")
4432 else:
4433 _num = self.__option_list.index(_option)
4434 _iter = self.__liststore.get_iter((_num,))
4435 self.__liststore.set_value(_iter, 2, _value)
4436 self.__option_dict[_option][1] = _value
4437 else:
4438 print _("Type must be boolean, integer, string or "\
4439 "color")
4440 else:
4441 print _("Value must be in the option dict")
4442 else:
4443 print _("Values must be a dict")
4444 self.__treeview.set_cursor((0),self.__value_column, False)
4445 self.__treeview.grab_focus()
4446 (_cursor_path, _column) = self.__treeview.get_cursor()
4447 _description = self.__liststore[_cursor_path][4]
4448 self.__description_label.set_text(_description)
4449
4450 def getWidget(self):
4451 """def getWidget(self)
4452
4453 return the main widget (gtk.ScrolledWindow)
4454 """
4455 return self.__widget
4456 widget = property(getWidget, None, None,
4457 "The main widget (gtk.ScrolledWindow)")
4458
4459
4460 class OpenDurusDatabase(object):
4461 """gui.OpenFiebdc
4462
4463 Description:
4464 Class to show a dialog to open a durus price database
4465 Constructor:
4466 OpenDurusDatabase()
4467 Ancestry:
4468 +-- object
4469 +-- OpenDurusDatabase
4470 Atributes:
4471 "_openMethod": The method to open the file
4472 "__file": the filename to open
4473 "__window": the File Selection window
4474 Methods:
4475 __init__(self)
4476 setActiveCode(self, code)
4477 """
4478 def __init__(self, openMethod):
4479 self.__openMethod = openMethod
4480 self.__file = None
4481 self.__window = gtk.FileSelection("Abrir Archivo")
4482 self.__window.connect("destroy", self.destroy)
4483 self.__window.ok_button.connect("clicked", self._openFile)
4484 self.__window.cancel_button.connect("clicked",
4485 lambda w: self.__window.destroy())
4486 self.__window.set_filename(globals.getHomePath("DURUS-DATABASE"))
4487 self.__window.show()
4488
4489 def destroy(self, widget):
4490 gtk.main_quit()
4491
4492 def main(self):
4493 gtk.main()
4494
4495 def _openFile(self, w):
4496 self.__file = self.__window.get_filename()
4497 _filename = os.path.basename(self.__file)
4498 _filename_list = _filename.split(".")
4499 _filename_ext = _filename_list[-1]
4500 if _filename == "":
4501 print _("No file selected")
4502 elif len(_filename_list) < 2 or _filename_ext != "durus":
4503 print _("The filename must have durus extension")
4504 else:
4505 try:
4506 self.__openMethod(self.__window.get_filename())
4507 self.__window.destroy()
4508 except IOError:
4509 print utils.mapping("IOError, $1", (self.__file,))