Mercurial > pyarq-presupuestos
view Gtk/gui.py @ 13:ff04584f66e4
windows icon
author | Miguel Ángel Bárcena Rodríguez <miguelangel@obraencurso.es> |
---|---|
date | Sat, 01 Jan 2011 19:50:30 +0100 |
parents | fe9c55f86698 |
children | 60bc5117926c |
line wrap: on
line source
# -*- coding: utf-8 -*- ## File gui.py ## This file is part of pyArq-Presupuestos. ## ## Copyright (C) 2010 Miguel Ángel Bárcena Rodríguez ## <miguelangel@obraencurso.es> ## ## pyArq-Presupuestos is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## pyArq-Presupuestos is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program. If not, see <http://www.gnu.org/licenses/>. ## """Gui module The MainWindow class contain the toplevel WINDOW, this window have a notebook with a page for each budget. Each budget or notebook page is showed by the Page class, this class contain the main widget showed in a page notebook. The main widget can show the budget information in several panes. This panes are ordened in gtk.Paned represented for the class Paned which can have 2 viewes represented for the View class or other gtk.Paned that have other viewes or more gtk.Paned. The view can have diferente type of widgets to show the budget information. The DecompositionList class show the decompositon list information of a record The Measure class show the measure information of a record The Sheet class class show the sheet of condition information of a record The views can send signal to the others. All the viewes ordered in panes can be or not be connected to the others, if there are connecteded to the others when the user change the active code in one of the panes the active code change in the others. """ # TODO: Config file # Standar Modules import os import time import pygtk pygtk.require('2.0') import gtk import gobject import weakref # pyArq-Presupuestos Modules from Gtk import importFiebdc from Generic import base from Generic import fiebdc from Generic import durusdatabase from Generic import utils from Generic import globalVars from Generic import openwith # Load default icon if os.path.exists(globalVars.getAppPath("ICON")): icon = gtk.gdk.pixbuf_new_from_file(globalVars.getAppPath("ICON")) gtk.window_set_default_icon_list(icon) else: print utils.mapping(_("The icon file does not exist. '$1'"), (globalVars.getAppPath("ICON"),)) # Autodetect desktop if globalVars.desktop["autodetect"]: openwith.autodetect_desktop() print utils.mapping(_("pyArq-Presupuestos running on $1"), (globalVars.desktop["desktop"],)) # Add MenutoolButton to Uimanager class MenuToolAction(gtk.Action): __gtype_name__ = "MenuToolAction" gobject.type_register(MenuToolAction) MenuToolAction.set_tool_item_type(gtk.MenuToolButton) class MainWindow(object): """gui.MainWindow: Description: Creates and shows the main window. This is the interface base class. Constructor: gui.MainWindow() Ancestry: +-- object +-- MainWindow Atributes: Methods: changeHistorySignal changeActiveSignal appendEmptyPage updatePage closePage """ # TODO:* Can choose open budget in new window # TODO:* Can choose show more than one notebook in the same window or # TODO: can show basedata notebook in a side pane __ui = '''<ui> <menubar name="MenuBar"> <menu action="File"> <menuitem action="ImportFiebdc"/> <menuitem action="Close"/> </menu> <menu action="View"> </menu> <menu action="Go"> <menuitem action="GoPrevious"/> <menuitem action="GoPosterior"/> <menuitem action="GoUp"/> <menuitem action="GoToRoot"/> </menu> <menu action="Test"> <menuitem action="ImportFiebdcPriceDatabase"/> <menuitem action="OpenPriceDatabase"/> </menu> </menubar> <toolbar name="ToolBar"> <toolitem action="ImportFiebdc"/> <toolitem action="Close"/> <separator name="sep1"/> <toolitem action="GoPrevMenu"/> <toolitem action="GoPostMenu"/> <toolitem action="GoUp"/> <toolitem action="GoToRoot"/> </toolbar> </ui>''' def __init__(self): """__init__() Initialize the atributes self.__page_list without data. Creates the widgets "window" and "__notebook". self.__window: gtk.Window object self.__uimanager: gtk.UIManager object self.__page_list: List of pages ("Page" object) self.__notebook: Notebook widget ("gtk.Notebook" object) self.__general_action_group: "General" action group self.__navigation_action_group: "Navigation" action group """ self.__page_list = [] # Main window self.__window = gtk.Window(gtk.WINDOW_TOPLEVEL) self.__window.set_default_size(771, 570) self.__window.set_title("Presupuestos") self.__window.set_border_width(0) self.__window.connect("destroy", self._destroy) self.__window.connect("delete_event", self._delete_event) # Vertical box _vbox1 = gtk.VBox(False, 0) self.__window.add(_vbox1) _vbox1.show() #Uimanager self.__uimanager = gtk.UIManager() _accelgroup = self.__uimanager.get_accel_group() self.__window.add_accel_group(_accelgroup) self.__general_action_group = gtk.ActionGroup("General") self.__general_action_group.add_actions( [("File", None, _("_File"), None), ("ImportFiebdc", gtk.STOCK_OPEN, _('_Import Fiebdc'), "", _('Import FIEBDC'), self._menuitemImportFiebdc), ("Close", gtk.STOCK_CLOSE, _("_Close"), None, _('Close'), self._menuitemClose), ("View", None, _("_View")), ("Go", None, _("_Go")), ("Test", None, _("_Test")), ('ImportFiebdcPriceDatabase', gtk.STOCK_OPEN, _("Import Fiebdc _price database"), "", _("Import database"), self._menuitemImportPriceDatabase ), ("OpenPriceDatabase", gtk.STOCK_OPEN, _('_Open price database'), "", _('Open Database'), self._menuitemOpenPriceDatabase), ]) self.__navigation_action_group = gtk.ActionGroup("Navigation") self.__navigation_action_group.add_actions( [("Go", None, _("_Go")), ("GoPrevious", gtk.STOCK_GO_BACK, _("_Back"),"", _("Go to the previous visited item"), self._menuitemGoPrevious), ("GoPosterior", gtk.STOCK_GO_FORWARD, _("_Forward"),"", _("Go to the next visited item"), self._menuitemGoPosterior), ("GoUp", gtk.STOCK_GO_UP, _("_Up Item"),"", _("Go up item"), self._menuitemGoUp), ("GoToRoot", gtk.STOCK_GOTO_TOP, _("_Root"),"", _("Go to root"), self._menuitemGoToRoot), ]) self.__navigation_action_group.add_action( MenuToolAction("GoPrevMenu", None , _("Go to the previous visited item"), gtk.STOCK_GO_BACK)) self.__navigation_action_group.add_action( MenuToolAction("GoPostMenu", None , _("Go to the next visited item"), gtk.STOCK_GO_FORWARD)) self.__navigation_action_group.set_sensitive(False) self.__navigation_action_group.get_action("GoPostMenu").set_sensitive( False) self.__navigation_action_group.get_action("GoPrevMenu").set_sensitive( False) self.__uimanager.insert_action_group(self.__general_action_group, 0) self.__uimanager.insert_action_group(self.__navigation_action_group, 1) self.__uimanager.add_ui_from_string(self.__ui) _menu_bar = self.__uimanager.get_widget("/MenuBar") _vbox1.pack_start(_menu_bar, False, False, 0) _toolbar = self.__uimanager.get_widget("/ToolBar") _toolbar.get_settings().set_long_property("gtk-toolbar-icon-size", gtk.ICON_SIZE_SMALL_TOOLBAR, "pyArq-Presupuestos:toolbar") _vbox1.pack_start(_toolbar, False, False, 0) # menuToolButton go prev _go_prev_button = self.__uimanager.get_widget( "/ToolBar/GoPrevMenu") _go_prev_button.set_arrow_tooltip_text(_("Back history")) _go_prev_button.connect('clicked', self._menuitemGoPrevious) # menuToolButton go pos _go_post_button = self.__uimanager.get_widget( "/ToolBar/GoPostMenu") _go_post_button.set_arrow_tooltip_text(_("Forward history")) _go_post_button.connect('clicked', self._menuitemGoPosterior) # Notebook self.__notebook = gtk.Notebook() _vbox1.pack_start(self.__notebook, True, True, 0) self.__notebook.set_tab_pos(gtk.POS_TOP) self.__notebook.set_show_tabs(True) self.__notebook.set_show_border(True) self.__notebook.set_scrollable(True) self.__notebook.connect("switch-page", self._switch_page) self.__notebook.show() self._main() #TODO: create budget object in mainwindow? def changeHistorySignal(self): """changeHistorySignal() A pane emit the updateHistory signal. Nothing to do now """ pass def changeActiveSignal(self): """changeActiveSignal() A pane emit the change-active signal. Chech buttons sensitive """ self._checkButtonsSensitive(self.__notebook.get_current_page()) def _checkButtonsSensitive(self, page_num): """_checkButtonsSensitive(page_num) page_num: page number in notebook Check and if necessary update the sensitive state of the navigation buttons. """ _page = self.__page_list[page_num] if isinstance(_page, Page) and \ self.__navigation_action_group.get_sensitive(): # GoToRoot and GoUp actions _goto_root = self.__navigation_action_group.get_action("GoToRoot") _go_up = self.__navigation_action_group.get_action("GoUp") if len(_page.activePathRecord) == 1 and \ _goto_root.get_sensitive(): _goto_root.set_sensitive(False) _go_up.set_sensitive(False) elif len(_page.activePathRecord) != 1 and \ not _goto_root.get_sensitive(): _goto_root.set_sensitive(True) _go_up.set_sensitive(True) # GoPrevMenu action _go_Previous = self.__navigation_action_group.get_action( "GoPrevious") _go_prev = self.__navigation_action_group.get_action("GoPrevMenu") if _page.previousPathRecord is None: if _go_prev.get_sensitive(): _go_prev.set_sensitive(False) _go_Previous .set_sensitive(False) else: if not _go_prev.get_sensitive(): _go_prev.set_sensitive(True) _go_Previous.set_sensitive(True) # GoPostMenu action _go_Posterior = self.__navigation_action_group.get_action( "GoPosterior") _go_post = self.__navigation_action_group.get_action("GoPostMenu") if _page.posteriorPathRecord is None: if _go_post.get_sensitive(): _go_post.set_sensitive(False) _go_Posterior.set_sensitive(False) else: if not _go_post.get_sensitive(): _go_post.set_sensitive(True) _go_Posterior.set_sensitive(True) def _switch_page(self, notebook, page, page_num,): """_switch_page(notebook, page, page_num) Method connected to the "switch-page" signal of the notebook widget It changes the sensitive state of the navigation action group """ _page = self.__page_list[page_num] if isinstance(_page, EmptyPage) and \ self.__navigation_action_group.get_sensitive(): self.__navigation_action_group.set_sensitive(False) elif isinstance(_page, Page): if not self.__navigation_action_group.get_sensitive(): self.__navigation_action_group.set_sensitive(True) self._checkButtonsSensitive(page_num) _go_prev = self.__uimanager.get_widget("/ToolBar/GoPrevMenu") _go_prev.set_menu(_page.back_menu) _go_post = self.__uimanager.get_widget("/ToolBar/GoPostMenu") _go_post.set_menu(_page.forward_menu) def _main(self): """main() Shows window and starts the GTK+ event processing loop. """ self.__window.show() gtk.main() def appendEmptyPage(self, emptyPage): """appendEmptyPage(widget, label) Append a empty page to the notebook. """ self.__page_list.append(emptyPage) self.__notebook.append_page(emptyPage.widget, emptyPage.title) # TODO: reordenable and detachable Pages #self.__notebook.set_tab_reorderable(emptyPage.widget, True) #self.__notebook.set_tab_detachable(emptyPage.widget, True) def updatePage(self, empty_page, page): """updatePage(page) Update emptyPage to Page. """ _page_num = self.__notebook.page_num(empty_page.widget) self.__page_list[_page_num] = page if self.__notebook.get_current_page() == _page_num: _go_prev = self.__uimanager.get_widget("/ToolBar/GoPrevMenu") _go_prev.set_menu(page.back_menu) _go_post = self.__uimanager.get_widget("/ToolBar/GoPostMenu") _go_post.set_menu(page.forward_menu) if not self.__navigation_action_group.get_sensitive(): self.__navigation_action_group.set_sensitive(True) self._checkButtonsSensitive(_page_num) def _menuitemImportFiebdc(self, widget): """_menuitemImportFiebdc(widget) widget: the widget where the event is emitted from Callback to open a budget file. Creates and shows a file selection window to open a budget file. """ _budget = base.Budget() _budget_file = fiebdc.Read() _read_method = _budget_file.readFile _filename = "file" _filetype = "budget" _exit_method = _budget_file.cancel _file_window = importFiebdc.FileSelectionWindow(self, _read_method, _budget, _filename, _exit_method, _filetype) def _menuitemImportPriceDatabase(self, widget): """_menuitemImportPriceDatabase(widget) widget: the widget where the event is emitted from Callback to open a price database file. Creates and shows a file selection window to open a price database file. """ _budget = base.Budget() _budget_file = fiebdc.Read() _read_method = _budget_file.readFile _filename = "file" _filetype = "database" _exit_method = _budget_file.cancel _file_window = importFiebdc.FileSelectionWindow(self, _read_method, _budget, _filename, _exit_method, _filetype) def _menuitemOpenPriceDatabase(self, widget): """_menuitemOpenPriceDatabase(widget) widget: the widget where the event is emitted from Callback to open a price database from a durus file. Creates and shows a file selection window to open a durus database """ _budget = None _budget_file = durusdatabase.Read() _read_method = _budget_file.readFile _filename = "file" _filetype = "durus" _exit_method = _budget_file.cancel _file_window = importFiebdc.FileSelectionWindow(self, _read_method, _budget, _filename, _exit_method, _filetype) def _menuitemClose(self, widget): """_menuitemClose(widget) widget: the widget where the event is emitted from Callback to close a budget file. """ _page_num = self.__notebook.get_current_page() if _page_num != -1: _page = self.__page_list[_page_num] if isinstance(_page, EmptyPage) and _page.filetype == "durus": print _("Cancel reading Durus database has not been " "implemented.") else: _page.close() def closePage(self, page): """closePage(page) page: EmptyPage or Page object Removes a page from notebook and page_list. Hide navigation action group if necessary """ if page in self.__page_list: _page_num = self.__page_list.index(page) self.__page_list.pop(_page_num) page.clear() self.__notebook.remove_page(_page_num) if len(self.__page_list) == 0: self.__navigation_action_group.set_sensitive(False) else: raise IndexError, _("The page is not in the page list") def _menuitemGoToRoot(self, widget): """_menuitemGoToRoot(widget) widget: the widget where the event is emitted from Callback to go to root record. """ _page_num = self.__notebook.get_current_page() if _page_num == -1: return _page = self.__page_list[_page_num] if isinstance(_page, Page): #not loading budget _page.propagateMessageFrom("change_active", (-1,), (0,)) def _menuitemGoUp(self, widget): """_menuitemGoUp(widget) widget: the widget where the event is emitted from Callback to go to up record. """ _page_num = self.__notebook.get_current_page() if _page_num != -1: _page = self.__page_list[_page_num] if isinstance(_page, Page): #not loading budget _active_path = _page.activePathRecord if len(_active_path) > 1: _budget = _page.budget _up_path = _active_path[:-1] if _budget.hasPath(_up_path): _page.propagateMessageFrom("change_active", (-1,), _up_path) def _menuitemGoPrevious(self, widget): """_menuitemGoPrevious(widget) widget: the widget where the event is emitted from Callback to go to previous record. """ _page_num = self.__notebook.get_current_page() if _page_num != -1: _page = self.__page_list[_page_num] if isinstance(_page, Page): #not loading budget _previous_path = _page.previousPathRecord if _previous_path is not None: _budget = _page.budget if _budget.hasPath(_previous_path): _page.propagateMessageFrom("change_active", (-1,), _previous_path) def _menuitemGoPosterior(self, widget): """_menuitemPosterior(widget) widget: the widget where the event is emitted from Callback to go to posterior record. """ _page_num = self.__notebook.get_current_page() if _page_num != -1: _page = self.__page_list[_page_num] if isinstance(_page, Page): #not loading budget _posterior_path = _page.posteriorPathRecord if _posterior_path is not None: _budget = _page.budget if _budget.hasPath(_posterior_path): _page.propagateMessageFrom("change_active", (-1,), _posterior_path) def _delete_event(self, widget, event): """_delete_event(widget, event) widget: the widget where the event is emitted from event: the "gtk.gdk.Event" Method connected to "delete_event" signal of main window widget This signal is emitted when a user press the close titlebar button. It Returns True so the signal "destroy" is emitted. """ for _page in self.__page_list: _page.clear() return False # -> destroy def _destroy(self, widget): """_destroy(widget) widget: the widget where the event is emitted from Method connected to "destroy" signal of main window widget This signal is emited when the method connected to "delete_event" signal returns True or when the program call the destroy() method of the gtk.Window widget. The window is closed and the GTK+ event processing loop is ended. """ gtk.main_quit() class EmptyPage(object): """gui.EmptyPage: Description: It creates and shows a page in the notebook while a budget is loaded. The page show the pyarq logo, loading time and a progress bar. Constructor: gui.EmptyPage(mainWindow, readFileMethod, budget, filename, cancelMethod, filetype): mainWindow: gui.Mainwindow object readFileMethod: Method to read the selected file budget: base.Budget object filename: "file" cancelMethod: Method to cancel the read method filetype: "budget", "database" or "durus" Ancestry: +-- object +-- EmptyPage Atributes: widget: Read. Main widget showed in the pane title: Read. Page Title filetype: Read. budget, basedata or durus Methods: run progress stopLoading threadFinishedSignal threadCanceled close clear """ def __init__(self, mainWindow, readFileMethod, budget, filename, cancelMethod, filetype): """__init__(mainWindow, readFileMethod, budget, filename, cancelMethod, filetype) mainWindow: gui.Mainwindow object readFileMethod: Method to read the selected file budget: base.Budget object filename: "file" cancelMethod: Method to cancel the read method filetype: "budget", "database" or "durus" self.__mainWindow: gui.Mainwindow object self.__readFileMethod: Method to read the selected file self.__budget: base.Budget object self.__filename: "file" self.__cancelMethod: Method to cancel the read method self.__filetype: "budget", "database" or "durus" self.__children: the read thread self.__progress: 0 to 1 progress self.__widget: main widget, a gtk.VBox object self.__main_item: None self.__throbber: a gtk.Image self.__animationThobber: a gtk.gdk.PixbufAnimation self.__quietThobber: a pixbuf self.__budget_icon: a gtk.gdk.pixbuf self.__title: a gtk.HBox self.__statusbar: a gtk.Statusbar self.__statuscontext: the statusbar context self.__progress_bar: a gtk.ProgressBar """ self.__mainWindow = mainWindow self.__readFileMethod = readFileMethod self.__budget = budget self.__filename = filename self.__filetype = filetype self.__cancelMethod = cancelMethod self.__children = None self.__cancel = [False, False] self.__progress = 0.0 self.__widget = gtk.VBox() self.__main_item = None self.__widget.show() self.__throbber = gtk.Image() self.__throbber.set_from_file(globalVars.getAppPath("THROBBER-ICON")) self.__throbber.show() self.__animationThobber = gtk.gdk.PixbufAnimation( globalVars.getAppPath("THROBBER-GIF")) self.__quietThobber = self.__throbber.get_pixbuf() self.__budget_icon = gtk.gdk.pixbuf_new_from_file( globalVars.getAppPath("BUDGET-ICON")) _filename = os.path.basename(filename) _rootfilename = os.path.splitext(_filename)[0] if not _rootfilename == "": _filename = _rootfilename _titleLabel = gtk.Label(_filename) _titleLabel.show() self.__title = gtk.HBox() self.__title.add(self.__throbber) self.__title.add(_titleLabel) self.__statusbar = gtk.Statusbar() self.__statuscontext = self.__statusbar.get_context_id("Statusbar") self.__statusbar.show() _align = gtk.Alignment(0.5, 0.5, 0, 0) _iconVbox = gtk.VBox() _pyArqIcon = gtk.Image() _pyArqIcon.set_from_file(globalVars.getAppPath("PYARQ-ICON")) _pyArqIcon.show() _iconVbox.pack_start(_pyArqIcon, True, True, 0) _link = gtk.LinkButton("http://pyarq.obraencurso.es", "http://pyarq.obraencurso.es") _iconVbox.pack_start(_link, True, True, 0) _link.show() _iconVbox.show() _align.add(_iconVbox) _align.show() self.__widget.pack_start(_align, True, True, 0) _progressframe = gtk.Frame() _progressframe.set_shadow_type(gtk.SHADOW_IN) _progressframe.show() self.__progress_bar = gtk.ProgressBar() if self.__filetype != "durus": self.__progress_bar.show() _progressframe.add(self.__progress_bar) self.__statusbar.pack_start(_progressframe, False, False, 0) self.__widget.pack_end(self.__statusbar, False, True, 0) self.__main_item = None def run(self): """run() Launch clildren and timeouts """ self.__statusbar.push(self.__statuscontext, _("Time: 0s")) self.__throbber.set_from_animation(self.__animationThobber) self._launchChildren() self._launchTimeout() def progress(self, percent): """progress(percent) percent: Percentage executed. Sets progress """ _progress = str(int(round(100 * percent,0))) self.__progress = percent def stopLoading(self): """stopLoading() Stop progressbar """ self.__throbber.set_from_pixbuf(self.__budget_icon) self.__progress_bar.hide() self.__statusbar.pop(self.__statuscontext) def _launchChildren(self): """_launchChildren() Launch the thread to read the file """ if self.__children is None: self.__children = importFiebdc.Thread(self, self.__mainWindow, self.__readFileMethod, self.__budget, self.__filename, self.__cancelMethod, self.__filetype) self.__children.start() def _launchTimeout(self): """_launchTimeout() Launch the timeouts: 1- update progress bar 2- update time label 3- If the other timetouts are stoped the window is closed """ gobject.timeout_add(1000, self._updateLabel, time.time()) if self.__filetype != "durus": gobject.timeout_add(500, self._updateProgressBar) self.__cancel = [False, False] else: self.__cancel = [True, False] gobject.timeout_add(1000, self._autoClose) def _updateProgressBar(self): """_updateProgressBar() update progress bar in a timeout If the thread end or is canceled the timeout is stoped """ if self.__children is None or self.__children.isCanceled() == True: self.__cancel[0] = True return False else: self.__progress_bar.set_fraction(self.__progress) _text = "%s%%" %str(int(round(100 * self.__progress,0))) self.__progress_bar.set_text(_text) return True def _updateLabel(self, _time): """_updateProgressBar(_time) update time label in a timeout If the thread end or is canceled the timeout is stoped """ if self.__children is None or self.__children.isCanceled() == True: self.__cancel[1] = True return False else: _time = time.time() - _time _text = utils.mapping(_("Time: $1"), ("%.0f" %_time,)) self.__statusbar.pop(self.__statuscontext) self.__statusbar.push(self.__statuscontext, _text) return True def _autoClose(self): """_updateProgressBar() If the time label and progress bar timeouts are stoped the window is closed and ist tiemeout is stoped """ if self.__cancel == [ True, True ]: return False else: return True def threadFinishedSignal(self, budget): """threadFinishedSignal(budget) Sets the self.__children to None This causes that the timeouts is ended. This method is called from thread when it finish """ self.__budget = budget self.__children = None self.stopLoading() _page = Page(self.__mainWindow, self.__budget) _children = self.__widget.get_children() for _child in _children: self.__widget.remove(_child) self.__widget.pack_start(_page.widget, True, True, 0) self.__mainWindow.updatePage(self, _page) def threadCanceled(self): """threadCanceled() Sets the __children atribute to None This causes that the timeouts is ended. This method is called from thread when is canceled """ self.__children = None self.stopLoading() self.__mainWindow.closePage(self) def close(self): """close() Close page canceling children """ self.__children.cancel() def clear(self): """clear() clear vars """ pass def _getWidget(self): """_getWidget() Return de main widget to show in the page """ return self.__widget def _getTitle(self): """_getTitle() Return the title of the page, a gtk.Label objetc """ return self.__title def _getFiletype(self): """_getFiletipe() Return the title of the page, a gtk.Label objetc """ return self.__filetype widget = property(_getWidget, None, None, "Main widget showed in the pane") title = property(_getTitle, None, None, "Page Title") filetype = property(_getFiletype, None, None, "Filetype: budget, basedata or durus") class Page(object): """gui.Page: Description: It creates and shows a page in the notebook from a budget object. The page can show the budget information in several panes ordered according to "panes_list" information. Constructor: gui.Page(mainWindow, budget, active_code=None) mainwindow: MainWindow object budget: base.Budget object active_code: Active record code Ancestry: +-- object +-- Page Atributes: widget: Read. Notebook page Widget. (a gtk.VBox instance) budget: Read-Write. Budget to show in the page. (base.obra object) panes_list: Read. info list for create the panes ej: [ "v", pane1, pane2 ] , [ "h", pane1, pane2 ] [ "v", [ "h", pane1, pane2 ], [ "h", pane1, pane2 ] ] pane types: * "DecompositionList": its creates a "DecompositionList" object * "RecordDescription" : its creates a "Description" objetc * "Measure": its creates a "Measure" objetc * "FileView": its creates a "FileView" objet * "CompanyView": its creates a "CompanyView" object title: Read. Notebook page title (gtk.Label object) activePathRecord: Read. The active path record previousPathRecord: Read. The previous path record posteriorPathRecord Read. The posterior path record back_menu: back menu to show in menutoolbutton forward_menu: forward menu to show in menutoolbutton Methods: propagateMessageFrom sendMessageTo close clear getItem """ # TODO: * The panes can be ordered as the user wishes # TODO: * Panes in windows # TODO: * pane types # TODO: * General budget properties (is better a dialog?) def __init__(self, mainWindow, budget, path_record=(0,)): """__init__(mainWindow, budget, path_record=(0,)) mainWindow: MainWindow object budget: "base.Budget" object path_record: the active path record self.__mainWindow: MainWindow object self.__widget: a gtk.VBox self.__panes_list: self.__main_item: self.__active_path_record: self.__history_back: self.__history_forward: self.__back_menu: a gtk.Menu self.__forward_menu: a gtk.Menu """ #TODO: __panes_list should come from config file... self.__mainWindow = mainWindow self.__widget = gtk.VBox() self.__panes_list = [ "v", "DecompositionList", [ "v", "Measure", "RecordDescription" ]] self.__main_item = None self.__active_path_record = () self.__history_back = [] self.__history_forward = [] self.__back_menu = gtk.Menu() self.__back_menu.show() self.__forward_menu = gtk.Menu() self.__forward_menu.show() self.budget = budget self._setActivePathRecord(path_record) self.__widget.show() self.__budget_icon = gtk.gdk.pixbuf_new_from_file( globalVars.getAppPath("BUDGET-ICON")) self.__chapter_icon = gtk.gdk.pixbuf_new_from_file( globalVars.getAppPath("CHAPTER-ICON")) self.__unit_icon = gtk.gdk.pixbuf_new_from_file( globalVars.getAppPath("UNIT-ICON") ) self.__material_icon = gtk.gdk.pixbuf_new_from_file( globalVars.getAppPath("MATERIAL-ICON") ) self.__machinery_icon = gtk.gdk.pixbuf_new_from_file( globalVars.getAppPath("MACHINERY-ICON")) self.__labourforce_icon = gtk.gdk.pixbuf_new_from_file( globalVars.getAppPath("LABOURFORCE-ICON")) def propagateMessageFrom(self, message, pane_path, arg=None): """propagateMessageFrom(message, pane_path, arg=None) message: string message * "change_active": change active code * "autoclose" * "split h" * "split v" pane_path: tuple that represents the pane path which emits the message arg: arguments for the message if message is "change_active" arg is the path record The panes are connectted to this method to send messages to other panes """ _budget = self.__budget if message == "change_active" and _budget.hasPath(arg): self.sendMessageTo(self.__main_item, message, pane_path, arg) self._setActivePathRecord(arg) self.__mainWindow.changeActiveSignal() elif message == "autoclose": self._closeItem(pane_path) elif message == "split h": self._splitItem(pane_path, "h") elif message == "split v": self._splitItem(pane_path, "v") def sendMessageTo(self, pane, message, pane_path, arg=None): """sendMessageTo(pane, message, pane_path, arg=None) pane: the receiver pane message: string message pane_path: tuple that represents the pane pane_path which emits the message arg: arguments for the message Sends a message to a pane """ if not pane.pane_path == pane_path: pane.runMessage(message, pane_path, arg) def close(self): """close() Close Page """ self.__mainWindow.closePage(self) def clear(self): """clear() Clear atributes """ self.propagateMessageFrom("clear", (0,)) del self.__budget del self.__panes_list del self.__widget del self.__title del self.__active_path_record del self.__main_item def getItem(self, pane_path): """getItem(pane_path) Return the item whith the path "pane_path", it can return a Paned instance or a View instance """ _item = self.__main_item if len(pane_path) == 1: return _item else: return _item.getItem(pane_path[1:]) def _setMainItem(self, item): """_setMainItem(item) Sets a new main item in the page """ if not self.__main_item is None: _old_main_widget = self.__main_item.widget self.__widget.remove(_old_main_widget) self.__main_item = item _main_widget = self.__main_item.widget _main_widget.show() self.__widget.pack_start(_main_widget, True, True, 0) def _splitItem(self, pane_path, orientation): """_splitItem(pane_path, orientation) Splits the item that is identifies by the pane_path and the orientation """ _item = self.getItem(pane_path) _parent = self.getItem(pane_path[:-1]) _item.pane_path = pane_path + (0,) _item_clone0 = _item.getClone(pane_path + (0,)) _item_clone1 = _item.getClone(pane_path + (1,)) _paned = Paned(orientation, pane_path, _item_clone0, _item_clone1) if len(pane_path) > 1: _parent.setItem(pane_path[-1], [_paned]) else: self._setMainItem(_paned) def _closeItem(self, pane_path): """_closeItem(pane_path) Closes the item that is identifies by the pane_path """ _item = self.getItem(pane_path) if len(pane_path) > 1: # There are more than one item _parent = self.getItem(pane_path[:-1]) _brothers = [ _brother for _brother in _parent] _brothers.remove(_item) _brother = _brothers[0] _parent.widget.remove(_brother.widget) _brother.pane_path = pane_path[:-1] if len(pane_path) > 2: _grandparent = self.getItem(pane_path[:-2]) _grandparent.setItem(pane_path[-2], [_brother]) _parent.widget.destroy() _parent.clear() _item.clear() else: _grandparent = self _grandparent._setMainItem(_brother) _parent.widget.destroy() _parent.clear() _item.clear() else: # Thre is only one item in the page, it can not be closed pass def _itemsFactory(self, list_paned, pane_path=(0,)): """_itemsFactory(list_paned, pane_path(0,)) list_paned: list in "__panes_list" format [ "v" or "h", panel1_type, panel2_type] which contains the info for create the widgets. panel types: * "DecompositionList" * "RecordDescription" * "Measure" * "Sheet of Conditions" * "FileView" * "CompanyView" pane_path: tuple that represents the item path in the page Creates the items and widgets and returns the main item """ if not isinstance(list_paned , list): raise ValueError, _("The value must be a list") if list_paned[0] == "v" or list_paned[0] == "h": if len(list_paned) != 3: raise ValueError, _("Incorrect len") if not isinstance(list_paned[1],list): list_paned[1] = [list_paned[1]] if not isinstance(list_paned[2],list): list_paned[2] = [list_paned[2]] _item1 = self._itemsFactory(list_paned[1],pane_path + (0,)) _item2 = self._itemsFactory(list_paned[2],pane_path + (1,)) _item = Paned(list_paned[0], pane_path, _item1, _item2) elif list_paned[0] == "DecompositionList": _item = View( "DecompositionList", self.__budget, weakref.ref(self), pane_path, self.__active_path_record) elif list_paned[0] == "RecordDescription": _item = View( "RecordDescription", self.__budget,weakref.ref(self), pane_path, self.__active_path_record) elif list_paned[0] == "Measure": _item = View( "Measure", self.__budget, weakref.ref(self), pane_path, self.__active_path_record) elif list_paned[0] == "Sheet of Conditions": _item = Sheet(sef.__budget, weakref.ref(self), pane_path, self.__active_path_record) elif list_paned[0] == "FileView": _item = FileView(sef.__budget, weakref.ref(self), pane_path, self.__active_path_record) elif list_paned[0] == "CompanyView": _item = CompanyView(sef.__budget, weakref.ref(self), pane_path, self.__active_path_record) else: _item = None raise ValueError, utils.mapping(_("Incorrect item $1"), (str(list_paned[0]),)) return _item def _setActivePathRecord(self, path_record): """_setActivePathRecord(path_record) path_record: the active record path Sets the active record path """ if path_record != self.__active_path_record: if self.__budget.hasPath(path_record): self.__active_path_record = path_record self._appendHistory(path_record) else: raise ValueError, utils.mapping(_("The budget does not have "\ "the path record: $1"), (str(path_record),)) def _appendHistory(self, path): """_appendHistory(path)) path: the new active path record Append the new active path record to history lists and update menus """ if len(self.__history_back) > 1 and path in self.__history_back[:-1]: # the new active record is in back history list # then append forward history and pop back history _items_num = len(self.__history_back) - \ self.__history_back.index(path) -1 for _item in range(_items_num): _record_path = self.__history_back.pop() _first_menuitem = self.__back_menu.get_children()[0] self.__back_menu.remove(_first_menuitem) self.__history_forward.append(_record_path) _menuitem = self._menuItemFactory(_record_path) _menuitem.connect_object("activate", self._menuHistoryForward, _record_path, _menuitem) self.__forward_menu.prepend(_menuitem) while len(self.__history_forward) > 100: # list too long self.__history_forward.pop(0) _last_menuitem = self.__forward_menu.get_children()[-1] self.__forward_menu.remove(_last_menuitem) else: # the new active record not is in back history list if len(self.__history_forward) > 1 and \ path in self.__history_forward: # the new active record is in history forward list # then append back history and pop forward history _items_num = len(self.__history_forward) - \ self.__history_forward.index(path) for _item in range(_items_num): _record_path = self.__history_forward.pop() _first_menuitem = self.__forward_menu.get_children()[0] self.__forward_menu.remove(_first_menuitem) self.__history_back.append(_record_path) if len(self.__history_back) > 1: _menuitem = self._menuItemFactory( self.__history_back[-2]) _menuitem.connect_object("activate", self._menuHistoryBack, self.__history_back[-2], _menuitem) self.__back_menu.prepend(_menuitem) else: # the new active record not is in history forward list # then append back history and clear forward history self.__history_forward[:] = [] for _child in self.__forward_menu.get_children(): self.__forward_menu.remove(_child) self.__history_back.append(path) if len(self.__history_back) > 1: _menuitem = self._menuItemFactory(self.__history_back[-2]) _menuitem.connect_object("activate", self._menuHistoryBack, self.__history_back[-2], _menuitem) self.__back_menu.prepend(_menuitem) while len(self.__history_back) > 100: # list too long self.__history_back.pop(0) _last_menuitem = self.__back_menu.get_children()[-1] self.__back_menu.remove(_last_menuitem) self.__mainWindow.changeHistorySignal() def _getImage(self, record): """_getImage(record) record: record object Returns an image depending on the type of record """ _hierarchy = record.recordType.hierarchy _type = record.recordType.type _subtype = record.recordType.subtype if _hierarchy == 0: _icon = self.__budget_icon elif _hierarchy == 1: _icon = self.__chapter_icon else: if _type == 0: _icon = self.__unit_icon elif _type == 1: _icon = self.__labourforce_icon elif _type == 2: _icon = self.__machinery_icon else: _icon = self.__material_icon _image = gtk.Image() _image.set_from_pixbuf(_icon) return _image def _menuFactory(self): """_menuFactory() record: record object Creates menus for history back an history forward tool buttons """ # Back Menu # clear menu for _child in self.__back_menu.get_children(): self.__back_menu.remove(_child) # pupulate menu if len(self.__history_back) > 1: for _record_path in self.__history_back[:-1]: _menuitem = self._menuItemFactory(_record_path) _menuitem.connect_object("activate", self._menuHistoryBack, _record_path, _menuitem) self.__back_menu.prepend(_menuitem) # Forward Menu # clear menu for _child in self.__forward_menu.get_children(): self.__forward_menu.remove(_child) # pupulate menu if len(self.__history_forward) > 0: for _record_path in self.__history_forward[:]: _menuitem = self._menuItemFactory(_record_path) _menuitem.connect_object("activate", self._menuHistoryForward, _record_path, _menuitem) self.__forward_menu.prepend(_menuitem) def _menuItemFactory(self, record_path): """_menuItemFactory(record_path): record_path: record path Creates and return a menuItem to go to the record """ _code = self.budget.getCode(record_path) _record = self.budget.getRecord(_code) _summary = _record.summary _text = _code + " " + _summary if len(_text) > 30: _text = _text[:27] + "..." _image = self._getImage(_record) _menuitem = gtk.ImageMenuItem(_text) _menuitem.set_image(_image) _menuitem.show() return _menuitem def _menuHistoryBack(self, record_path, menu_item): """_menuHistoryBack(record_path, menu_item) Go to the record selected in History Back menu """ if self.budget.hasPath(record_path): self.propagateMessageFrom("change_active", (-1,), record_path) def _menuHistoryForward(self, record_path, menu_item): """_menuHistoryForward(record_path, menu_item) Go to the record selected in History Forward menu """ if self.budget.hasPath(record_path): self.propagateMessageFrom("change_active", (-1,), record_path) def _getActivePathRecord(self): """_getActivePathRecord() Return the Active Path Record """ return self.__active_path_record def _getPreviousPathRecord(self): """_getPreviousPathRecord() Return the Previous Path Record """ if len(self.__history_back) > 1: return self.__history_back[-2] else: return None def _getPosteriorPathRecord(self): """_getPosteriorPathRecord() Return the Posterior Path Record """ if len(self.__history_forward) > 0: return self.__history_forward[-1] else: return None def _getBackMenu(self): """_getBackMenu() Return the Back Menu """ return self.__back_menu def _getForwardMenu(self): """_getForwardMenu() Return the Forward Menu """ return self.__forward_menu def _getTitle(self): """_getTitle() Return the page title, a gtk.Label objetc """ return self.__title def _getWidget(self): """_getWidget() Return de main widget to show in the pane """ return self.__widget def _setBudget(self, budget): """_setBudget(budget) budget: a base.Budget object Sets the budget and the active code atributes, creates the page title and the widgets in the pane and shows the main widget. """ if budget is None: self.clear() return self.__budget = budget self._setActivePathRecord((0,)) # Todo: change page title self.__title = gtk.Label(self.__budget.getCode( self.__active_path_record)) _panes_list = self.__panes_list self.__main_item = self._itemsFactory(_panes_list) _main_widget = self.__main_item.widget _main_widget.show() self.__widget.pack_start(_main_widget, True, True, 0) def _getBudget(self): """_getBudget() Return de budget, a "base.Budget" object. """ return self.__budget def _getPanesList(self): """_getPanesList() Return the panes list, info list for create the panes. """ return self.__panes_list budget = property(_getBudget, _setBudget, None, "Budget to show, base.Budget object") widget = property(_getWidget, None, None, "Main widget showed in the pane") title = property(_getTitle, None, None, "Page Title") panes_list = property(_getPanesList, None, None, "Info list for create the panes") activePathRecord = property(_getActivePathRecord, None, None, "Active Path Record") previousPathRecord = property(_getPreviousPathRecord, None, None, "Previous Active Path Record") posteriorPathRecord = property(_getPosteriorPathRecord, None, None, "Posterior Active Path Record") back_menu = property(_getBackMenu, None, None, "Back Menu") forward_menu = property(_getForwardMenu, None, None, "Forward Menu") class View(object): """gui.View: Description: It creates a view to show the budget info Constructor: View(view_type, budget, wr_page, pane_path, active_path_record) view_type: the object type to show * DecompositionList * Description * Measure * Sheet * FileView * CompanyView budget: the budget to show wr_page: weak reference to the page where the view must be showed pane_path: the position or path of the view in the page notebook active_path_record: the record path that must be showed Ancestry: +-- object +-- View Atributes: pane_path: Read-Write. The tuple that identifies the view in the main notebook page widget: Read. the main gtk widget to show in a view object, a gtk.VBox object Methods: getItem propagateMessgeFrom runMessage getClone clear """ def __init__(self, view_type, budget, wr_page, pane_path, active_path_record): """__init__(view_type, budget, wr_page, pane_path, active_path_record) view_type: the object type to show * DecompositionList * Description * Measure * Sheet * FileView * CompanyView budget: the budget to show wr_page: weak reference to the page where the view must be showed pane_path: the position or path of the view in the page notebook active_path_record: the record path that must be showed self.__active_path_record: the record path that must be showed self.__view_type: the object type to show * DecompositionList * Description * Measure * Sheet of conditions * FileView * CompanyView self.__wr_page: weak reference to the page where the view must be showed self.__budget: the budget to show self.__pane_path: the position or path of the view in the page notebook self.__connected: boolean value, True means that the View object sends and receives signals from/to others views self.__widget: main widget. a gtk.VBox self.__view: the object to show: * DecompositionList object * Description object * Measure object * Sheet object * FileView object * Comapany View self.__connected_button: a button to switch self.__connected True or False Creates and shows a new view """ self.__active_path_record = active_path_record self.__view_type = view_type self.__wr_page = wr_page self.__budget = budget self.__pane_path = pane_path self.__connected = True # view_type liststore _liststore = gtk.ListStore(str) _liststore.append([_("Decomposition")]) #0 _liststore.append([_("Description")]) #1 _liststore.append([_("Measure")]) #2 _liststore.append([_("Sheet of Conditions")]) #3 _liststore.append([_("Files")]) #4 _liststore.append([_("Companies")]) #5 _combobox = gtk.ComboBox(_liststore) _cell = gtk.CellRendererText() _combobox.pack_start(_cell, True) _combobox.add_attribute(_cell, 'text', 0) self.__widget = gtk.VBox() _hbox = gtk.HBox() if view_type == "DecompositionList": self.__view = DecompositionList(budget, weakref.ref(self), pane_path, active_path_record) _combobox.set_active(0) _view_icon = gtk.Image() _view_icon.set_from_file(globalVars.getAppPath( "DECOMPOSITION-ICON")) elif view_type == "RecordDescription": self.__view = Description(budget, weakref.ref(self), pane_path, active_path_record) _combobox.set_active(1) _view_icon = gtk.Image() _view_icon.set_from_file(globalVars.getAppPath( "DESCRIPTION-ICON")) elif view_type == "Measure": self.__view = Measure(budget, weakref.ref(self), pane_path, active_path_record) _combobox.set_active(2) _view_icon = gtk.Image() _view_icon.set_from_file(globalVars.getAppPath("MEASURE-ICON")) elif view_type == "Sheet of Conditions": self.__view = Sheet(budget, weakref.ref(self), pane_path, active_path_record) _combobox.set_active(3) _view_icon = gtk.Image() _view_icon.set_from_file(globalVars.getAppPath("SHEET-ICON")) elif view_type == "FileView": self.__view = FileView(budget, weakref.ref(self), pane_path, active_path_record) _combobox.set_active(4) _view_icon = gtk.Image() _view_icon.set_from_file(globalVars.getAppPath("SHEET-ICON")) elif view_type == "CompanyView": self.__view = CompanyView(budget, weakref.ref(self), pane_path, active_path_record) _combobox.set_active(5) _view_icon = gtk.Image() _view_icon.set_from_file(globalVars.getAppPath("SHEET-ICON")) else: raise ValueError, _(utils.mapping("Invalid type of View: $1", view_type)) _view_icon.show() _combobox.connect("changed", self._change_combo) _combobox.show() self.__widget.pack_start(_hbox,False) self.__widget.pack_start(self.__view.widget, True, True) _hbox.pack_start(_view_icon, False, False,0) _hbox.pack_start(_combobox, False, False,0) _invisible = gtk.HBox() _invisible.show() _hbox.pack_start(_invisible, True, False,0) _icon_menu = gtk.Image() _icon_menu.set_from_file(globalVars.getAppPath("MENU-ICON")) _icon_menu.show() _menu_button = gtk.ToolButton() _menu_button.set_icon_widget(_icon_menu) _menu_button.connect("clicked", self._menu_view) _menu_button.show() _icon_connected = gtk.Image() _icon_connected.set_from_file(globalVars.getAppPath("CONNECTED-ICON")) _icon_connected.show() _hbox.pack_start(_menu_button, False, False, 0) self.__connected_button = gtk.ToolButton() self.__connected_button.set_icon_widget(_icon_connected) self.__connected_button.connect("clicked", self._connected) self.__connected_button.show() _hbox.pack_start(self.__connected_button, False, False, 0) _icon_close = gtk.Image() _icon_close.set_from_file(globalVars.getAppPath("CLOSE-ICON")) _icon_close.show() _close_button = gtk.ToolButton() _close_button.set_icon_widget(_icon_close) _close_button.connect("clicked", self._closeItem) _close_button.show() _hbox.pack_start(_close_button, False, False, 0) _hbox.show() self.__widget.show() def getItem(self, pane_path): """getItem(pane_path) Return itself. """ return self def _closeItem(self, close_button): """_closeItem(close_button) Method connected to the "clicked" signal of the _close_button widget Send the "autoclose" message to the page to close this view """ self.propagateMessageFrom("autoclose", self.__pane_path) def _change_combo(self, combobox): """_change_combo(combobox) Method connected to the "changed" signal of the _combobox widget It changes the view type to the type selected in the combobox """ _index = combobox.get_active() _budget = self.__view.budget _wr_page = self.__view.page _pane_path = self.__view.pane_path _path_record = self.__view.active_path_record _hbox = self.__widget.get_children()[0] _combobox = _hbox.get_children()[1] _hbox.remove(_combobox) _invisible = _hbox.get_children()[1] _hbox.remove(_invisible) _menu_button = _hbox.get_children()[1] _hbox.remove(_menu_button) _connected_button = _hbox.get_children()[1] _hbox.remove(_connected_button) _close_button = _hbox.get_children()[1] _hbox.remove(_close_button) self.__widget.remove(self.__view.widget) self.__widget.remove(_hbox) _hbox.destroy() _view_icon = gtk.Image() if _index == 0: self.__view = DecompositionList(_budget, _wr_page, _pane_path, _path_record) _view_icon.set_from_file(globalVars.getAppPath( "DECOMPOSITION-ICON")) self.__view_type = "DecompositionList" elif _index == 1: self.__view = Description(_budget, _wr_page, _pane_path, _path_record) _view_icon.set_from_file(globalVars.getAppPath("DESCRIPTION-ICON")) self.__view_type = "RecordDescription" elif _index == 2: self.__view = Measure(_budget, _wr_page, _pane_path, _path_record) _view_icon.set_from_file(globalVars.getAppPath("MEASURE-ICON")) self.__view_type = "Measure" elif _index == 3: self.__view = Sheet(_budget, _wr_page, _pane_path, _path_record) _view_icon.set_from_file(globalVars.getAppPath("SHEET-ICON")) self.__view_type = "Sheet of Conditions" elif _index == 4: self.__view = FileView(_budget, _wr_page, _pane_path, _path_record) _view_icon.set_from_file(globalVars.getAppPath("SHEET-ICON")) self.__view_type = "FileView" elif _index == 5: self.__view = CompanyView(_budget, _wr_page, _pane_path, _path_record) _view_icon.set_from_file(globalVars.getAppPath("SHEET-ICON")) self.__view_type = "CompanyView" _view_icon.show() _hbox = gtk.HBox() _hbox.pack_start(_view_icon, False, False,0) _hbox.pack_start(_combobox, False, False,0) _hbox.pack_start(_invisible, True, False,0) _hbox.pack_start(_menu_button, False, False, 0) _hbox.pack_start(_connected_button, False, False, 0) _hbox.pack_start(_close_button, False, False, 0) _hbox.show() self.__widget.pack_start(_hbox, False, False, 0) self.__widget.pack_start(self.__view.widget, True, True, 0) def _menu_view(self, widget): """_menu_view(widget) Method connected to the "clicked" signal of the __connected_button It shows a popup menu with some options """ _menu_view = gtk.Menu() _item_leftright = gtk.MenuItem(_("Split View Left/Right")) _menu_view.append(_item_leftright) _item_leftright.connect_object("activate", self._split_view, "h") _item_leftright.show() _item_topbottom = gtk.MenuItem(_("Split View Top/Bottom")) _menu_view.append(_item_topbottom) _item_topbottom.connect_object("activate", self._split_view, "v") _item_topbottom.show() _item_close = gtk.MenuItem(_("Close view")) _menu_view.append(_item_close) _item_close.connect_object("activate", self._closeItem, None) _item_close.show() _menu_view.popup(None, None, None, 0, 0) def _split_view(self, orientation): """_menu_view(orientation) orientation: orientation split, "h" or "v" Method connected to the "activate" signal of the _item_leftright and _item_topbottom menu items. It sends the "split" message to the page to splits the view in the specified orientation """ self.propagateMessageFrom( "split " + orientation, self.__pane_path) def _connected(self, widget): """_connected(widget) Method connected to the "clicked" signal of the _menu_button It changes the __connected atribute to True or False, if the _connected atribute is False the view do not send and receive messages to/from others views """ if self.__connected: _icon = gtk.Image() _icon.set_from_file(globalVars.getAppPath("DISCONNECTED-ICON")) _icon.show() self.__connected_button.set_icon_widget(_icon) self.__connected = False else: _icon = gtk.Image() _icon.set_from_file(globalVars.getAppPath("CONNECTED-ICON")) _icon.show() self.__connected_button.set_icon_widget(_icon) self.__connected = True def propagateMessageFrom(self, message, pane_path, arg=None): """propagateMessageFrom(message, pane_path, arg=None) message: string message pane_path: tuple that represents the pane path which emits the message arg: arguments for the message The panes are connectted to this method to send messages to other panes """ if self.__connected or message == "autoclose" or \ message == "split h" or message == "split v": self.__wr_page().propagateMessageFrom(message, pane_path, arg) def runMessage(self, message, pane_path, arg=None): """runMessage(message, pane_path, arg=None) message: the message type "change_active": change the active record "clear": clear instance pane_path: tuple that identifies the pane in the notebook page arg: tuple whit two items: 0: record path in the budget 1: record code This method receives a message and executes its corresponding action """ if self.__connected: self.__view.runMessage(message, pane_path, arg) if message == "change_active": if self.__budget.hasPath(arg): _path_record = arg self.__active_path_record = _path_record def _getWidget(self): """_getWidget() Return de pane widget """ return self.__widget def _getPanePath(self): """_getPanePath() return the tuple that identifies the pane in the notebook page """ return self.__view.pane_path def _setPanePath(self, pane_path): """_setPanePath() set the tuple that identifies the pane in the notebook page """ self.__pane_path = pane_path self.__view.pane_path = pane_path def getClone(self, new_pane_path): """getClone(new_pane_path) new_pane_path: the path that identifies the clone view in the page return a clone of itself """ return View(self.__view_type, self.__budget, self.__wr_page, new_pane_path, self.__active_path_record) def clear(self): """clear() Clear the intance atributes """ del self.__wr_page del self.__budget del self.__pane_path del self.__widget del self.__view del self.__connected del self.__connected_button pane_path = property(_getPanePath, _setPanePath, None, "path that identifies the item in the notebook page") widget = property(_getWidget, None, None, "View widget") class Paned(object): """gui.Paned: Description: It creates and shows gtk.Hpaned or gtk.Vpaned to show in page budget Constructor: Paned(orientation, widget1, widget2) orientation: The orientation of the pane separator, can be "v" or "h" widget1: the top or left pane widget widget2: the botton or right pane widget Ancestry: +-- object +-- Paned Atributes: widget: Read. Pane widget("gtk.VPaned" or "gtk.HPaned" object) pane_path: Read-Write. The paned path in the page Methods: getClone getItem setItem runMessage clear(self) """ # TODO: *control the position paned separator. Now is always in the middle # TODO: can be with a float(0.0-1.0) aspect ratio # TODO: 0.0 no space for widget1 # TODO: 1.0 all the space for widget1 def __init__(self, orientation, pane_path, item1, item2): """__init__(oritentation, pane_path, item1, item2) orientation: The orientation of de gtk.Paned, can be "v" or "h" pane_path: the paned path in the page item1: the top or left pane object item2: the bottom or right pane object self.__orientation: The orientation of de gtk.Paned, can be "v" or "h" self.__widget: Main widget, a gtk.VPaned o gtk.HPaned self.__items: list of items showed in the paned, its can be View or Paned instances self.__pane_path: the paned path in the page Creates and shows a new gtk.Paned """ self.__orientation = orientation if not isinstance(item1.widget, gtk.Widget) or \ not isinstance(item2.widget, gtk.Widget): raise ValueError, _("The item must be a widget object.") if orientation == "v": self.__widget = gtk.VPaned() elif orientation == "h": self.__widget = gtk.HPaned() else: raise ValueError, _("Invalid orientation.") self.__widget.pack1(item1.widget,True,False) self.__widget.pack2(item2.widget,True,False) self.__widget.show() self.__items = [item1, item2] self.__pane_path = pane_path def __getitem__(self, item): """__getitem__(item) Called to implement evaluation of self[key]. The accepted keys should be integers 0 or 1. """ return self.__items[item] def getClone(self, new_pane_path): """getClone(new_pane_path) Return a clone Paned instance with the path new_path """ return Paned(self.__orientation, new_pane_path, self.__items[0].getClone(new_pane_path + (0,)), self.__items[1].getClone(new_pane_path + (1,))) def getItem(self,pane_path): """getItem(pane_path) Return the item whith the specified path. """ _item = self.__items[pane_path[0]] if len(pane_path) == 1: return _item else: return _item.getItem(pane_path[1:]) def setItem(self, pane_path, item_list): """setItem(pane_path, item_list) Sets the first item in the item_list whith the especified path and remove the old item in this position. """ item = item_list[0] if pane_path == 0 or pane_path == 1: _old_item = self.__items[pane_path] self.__widget.remove(_old_item.widget) self.__items[pane_path] = item if pane_path == 0: self.__widget.pack1(item.widget,True,False) else: self.__widget.pack2(item.widget,True,False) return True return False def runMessage(self, message, pane_path, arg=None): """runMessage(message, pane_path, arg=None) message: the message type "change_active": change the active record "clear": clear instance pane_path: tuple that identifies the pane in the notebook page arg: arguments This method receives a message and send this to the items of the paned """ for _item in self.__items: if not _item.pane_path == pane_path: _item.runMessage(message, pane_path, arg) def _getWidget(self): """_getWidget() Return de gtk.Paned widget """ return self.__widget def _getPanePath(self): """_getPanePath() Return de Paned path in the notebook page """ return self.__pane_path def _setPanePath(self, pane_path): """_setPanePath() sets the tuple that identifies the pane in the notebook page """ self.__pane_path = pane_path self.__items[0].pane_path = pane_path + (0,) self.__items[1].pane_path = pane_path + (1,) def clear(self): """clear() Delete atributes """ del self.__widget del self.__orientation del self.__items del self.__pane_path widget = property(_getWidget, None, None, "gtk.Paned widget") pane_path = property(_getPanePath, _setPanePath, None, "Pane path in the notebook page") class TreeView(object): """gui.Treeviev: Description: It creates the columns in a treeview, is the base class for DescompositionList and Measure classes Constructor: TreView(args) args: list of tuples, the tuple items are: 0.type: * index column * float column * text column * calculated column * calculated text * type column 1. clicked method 2. width 3. text color 4. backgruound colors 5. model column index Ancestry: +-- object +-- TreeView Atributes: columns: list of columns (gtk.TreeViewColumn objects) Methods: createColumn createTextBaseColumn createBaseColumn """ def __init__(self, args): """__init__(args) args: list of tuples, the tuple items are: 0.type: * index column * float column * text column * calculated column * Calculated text * type column 1. clicked method 2. width 3. text color 4. backgruound colors 5. model column index Create the columns form the args info calling creatheColumn to create each column """ self.columns = [ self.createColumn(arg) for arg in args ] self.columns.append(self.createColumn(("END",))) def createColumn(self, args): """createColumn(args) args: tuple with the args 0.type: * index column * float column * text column * calculated column * calculated text * type column 1. clicked method 2. width 3. text color 4. backgruound colors 5. model column index Return a column created whith the arg info """ if args[0] == "INDEX": _index_column = self.createBaseColumn(args) _text_index_cell = gtk.CellRendererText() _text_index_cell.set_property('foreground-gdk', gtk.gdk.color_parse(globalVars.color["TEXT"])) _pixbuf_index_cell = gtk.CellRendererPixbuf() _arrow_icon = gtk.gdk.pixbuf_new_from_file( globalVars.getAppPath("ARROW-ICON")) _pixbuf_index_cell.set_property("pixbuf", _arrow_icon) _index_column.pack_start(_text_index_cell, True) _index_column.pack_start(_pixbuf_index_cell, True) _index_column.set_cell_data_func(_text_index_cell, self._colorCell, [gtk.gdk.color_parse(globalVars.color["INDEX-UNEVEN"]), gtk.gdk.color_parse(globalVars.color["INDEX-EVEN"])]) return _index_column elif args[0] == "TEXT": _column, _cell = self.createTextBaseColumn(args) _column.add_attribute(_cell, 'text', args[5]) return _column elif args[0] == "FLOAT": _column, _cell = self.createTextBaseColumn(args) _column.add_attribute(_cell, 'text', args[5]) _column.get_cell_renderers()[0].set_property('xalign', 1.0) return _column elif args[0] == "CALCULATED": _column, cell = self.createTextBaseColumn(args) _column.get_cell_renderers()[0].set_property('xalign', 1.0) return _column elif args[0] == "CALCULATEDTEXT": _column, cell = self.createTextBaseColumn(args) return _column elif args[0] == "TYPE": _column = self.createBaseColumn(args) _type_cell1 = gtk.CellRendererPixbuf() _type_cell2 = gtk.CellRendererText() _type_cell2.set_property('foreground-gdk', args[3]) _column.pack_start(_type_cell1, True) _column.pack_start(_type_cell2, True) _column.add_attribute(_type_cell2, 'text', args[5]) _column.set_cell_data_func(_type_cell1, self._colorCell, args[4]) _column.set_cell_data_func(_type_cell2, self._colorCell, args[4]) return _column elif args[0] == "PIXBUF": _column = self.createBaseColumn(args) _type_cell1 = gtk.CellRendererPixbuf() _column.pack_start(_type_cell1, True) _column.set_cell_data_func(_type_cell1, self._colorCell, args[4]) return _column elif args[0] == "END": _end_column = gtk.TreeViewColumn() _end_column.set_clickable(False) _end_cell = gtk.CellRendererText() _end_cell.set_property('cell-background-gdk', gtk.gdk.color_parse(globalVars.color["UNEVEN"])) _end_column.pack_start(_end_cell, True) return _end_column return None def createTextBaseColumn(self, args): """createTextBaseColumn(args) args: tuple with the args 0.type: * float column * text column * calculated column * calculated text 1. clicked method 2. width 3. text color 4. backgruound colors 5. model column index Return a column and its CellREndererText """ _column = self.createBaseColumn(args) _cell = gtk.CellRendererText() _cell.set_property('foreground-gdk', args[3]) _column.pack_start(_cell, True) _column.set_cell_data_func(_cell, self._colorCell, args[4]) return _column, _cell def createBaseColumn(self, args): """createBaseColumn(args) args: tuple with the args 0.type: * index column * float column * text column * calculated column * calculated text column * type column 1. clicked method 2. width 3. text color 4. backgruound colors 5. model column index Return a column """ _column = gtk.TreeViewColumn() _column.set_clickable(True) _column.connect("clicked", args[1]) _column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) _column.set_fixed_width(args[2]) _column.set_resizable(True) return _column class DecompositionList(TreeView): """gui.DecompositionList: Description: Class to show a budget Decomposition List Constructor: DecompositionList(budget, page, pane_path, path_record=(0,)) budget: budget showed ("base.Budget" object) page: weak reference from Page instance which creates this class pane_path: tuple that represents the view path in the Page path_record: the record path that must be showed Returns the newly created DecompositionList instance Ancestry: +-- object +-- TreeView +-- DecompositionList Atributes: budget: Read. Budget to show, base.obra object. widget: Read. Window that contains the table, gtk.ScrolledWindow pane_path: Read-Write. Pane page identifier page: Read-Write. weak ref from Page object which creates this class active_path_record: Read. Active path record Methods: runMessage """ def __init__(self, budget, page, pane_path, path_record=(0,)): """__init__(budget, page, pane_path, path_record=(0,)) budget: budget showed ("base.Budget" object) page: weak reference from Page instance which creates this class pane_path: tuple that represents the path of the List in the Page path_record: the record path that must be showed self.__budget: budget showed ("base.Budget" object) self.__page: weak reference from Page instance which creates this class self.__pane_path: tuple that represents the path of the List in the Page self.__liststore: list model which store the list data (gtk.ListStore object) self.__active_path_record: the record path that must be showed self.__treeview: widget for displaying decomposition lists (gtk.TreeView) self.__scrolled_window: widget to contain the treeview object self.__chapter_background_colors: background colors of the Code column cells when there is a chapter record, list of gtk.gdk.Color objects [even cell, uneven cell] self.__chapter_background_colors self.__index_column: Index column (gtk.TreeViewColumn object) self.__code_column: Record code column (gtk.TreeViewColumn) self.__type_column: Record Type column (gtk.TreeViewColumn) self.__unit_column: Unit of measure column (gtk.TreeViewColumn) self.__description_column: record's short description column (gtk.TreeViewColumn) self.__measure_column: Measure column (gtk.TreeViewColumn) self.__price_column: Price column (gtk.TreeViewColumn) self.__amount_column: Amount column(gtk.TreeViewColumn) self.__end_column: End empty column (gtk.TreeViewColumn) self.__chapter_icon: a gtk.gdk.pixbuf self.__unit_icon: a gtk.gdk.pixbuf self.__material_icon: a gtk.gdk.pixbuf self.__machinery_icon: a gtk.gdk.pixbuf self.__labourforce_icon: a gtk.gdk.pixbuf self.__treeselection: active selection self.__selection_control: state of the selection control (True/False) self.__cursor: cursor position in the table Sets the init atributes Creates the init list values in self.__liststore from the budget showing the top record descomposition Creates the list in self.__treeview * Creates the columns and cell * Sets te the column headers values * Sets the selection properties * Connects the events """ # TODO: to group all columns in a dicctionary # Budget if not isinstance(budget, base.Budget): raise ValueError, _("Argument must be a Budget object") self.__budget = budget self.__page = page self.__pane_path = pane_path # ListStore self.__liststore = gtk.ListStore(object #, int, int, str, str, str, str, str,str ) if path_record is None: print _("Record path can not be None") path_record = (0,) self.__active_path_record = path_record self._setListstoreValues(self.__active_path_record) # Treeview self.__treeview = gtk.TreeView(self.__liststore) self.__treeview.set_enable_search(False) self.__treeview.set_reorderable(False) self.__treeview.set_headers_clickable(True) self.__treeview.show() # Scrolled_window self.__scrolled_window = gtk.ScrolledWindow() self.__scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) self.__scrolled_window.add(self.__treeview) # colors _text_color = gtk.gdk.color_parse(globalVars.color["TEXT"]) _background_color = [ gtk.gdk.color_parse(globalVars.color["UNEVEN"]), gtk.gdk.color_parse(globalVars.color["EVEN"])] self.__chapter_background_colors = [ gtk.gdk.color_parse(globalVars.color["CHAPTER-UNEVEN"]), gtk.gdk.color_parse(globalVars.color["CHAPTER-EVEN"])] super(DecompositionList,self).__init__( [("INDEX",self._selectAll,42), ("CALCULATEDTEXT", self._showParentRecord, gtk.Label("A"*10).size_request()[0] +10, _text_color, _background_color), ("PIXBUF", self._showParentRecord, 26, _text_color, _background_color), ("CALCULATEDTEXT", self._showParentRecord, gtk.Label(_("a"*4)).size_request()[0] +10, _text_color, _background_color), ("CALCULATEDTEXT", self._showParentRecord, gtk.Label("a"*30).size_request()[0] +10, _text_color, _background_color), ("CALCULATED", self._showParentRecord, gtk.Label("a"*10).size_request()[0] +10, _text_color, _background_color), ("CALCULATED", self._showParentRecord, gtk.Label("a"*10).size_request()[0] +10, _text_color, _background_color), ("CALCULATED", self._showParentRecord, gtk.Label("a"*10).size_request()[0] +10, gtk.gdk.color_parse(globalVars.color["CALCULATED-TEXT"]), _background_color), ]) self.__index_column = self.columns[0] self.__code_column = self.columns[1] self.__type_column = self.columns[2] self.__unit_column = self.columns[3] self.__description_column = self.columns[4] self.__measure_column = self.columns[5] self.__price_column = self.columns[6] self.__amount_column = self.columns[7] self.__end_column = self.columns[8] # Index column self.__treeview.append_column(self.__index_column) # Code column self.__treeview.append_column(self.__code_column) # Type column self.__treeview.append_column(self.__type_column) self.__chapter_icon = gtk.gdk.pixbuf_new_from_file( globalVars.getAppPath("CHAPTER-ICON")) self.__unit_icon = gtk.gdk.pixbuf_new_from_file( globalVars.getAppPath("UNIT-ICON") ) self.__material_icon = gtk.gdk.pixbuf_new_from_file( globalVars.getAppPath("MATERIAL-ICON") ) self.__machinery_icon = gtk.gdk.pixbuf_new_from_file( globalVars.getAppPath("MACHINERY-ICON")) self.__labourforce_icon = gtk.gdk.pixbuf_new_from_file( globalVars.getAppPath("LABOURFORCE-ICON")) self.__type_column.get_cell_renderers()[0].set_property("pixbuf", self.__labourforce_icon) # Unit column self.__treeview.append_column(self.__unit_column) # Description column self.__treeview.append_column(self.__description_column) # Measure Column self.__treeview.append_column(self.__measure_column) # Price column self.__treeview.append_column(self.__price_column) # Amount column self.__treeview.append_column(self.__amount_column) # End Column self.__treeview.append_column(self.__end_column) # Connect self.__treeview.connect("row-activated", self._showRowRecord) self.__treeview.connect("move-cursor", self._moveCursor) self.__treeview.connect("key-press-event", self._treeviewKeyPressEvent) self.__treeview.connect("button-press-event", self._treeviewClickedEvent) self.__treeview.connect("cursor-changed", self._treeviewCursorChanged) # control selection self.__treeselection = self.__treeview.get_selection() self.__treeselection.set_mode(gtk.SELECTION_MULTIPLE) self.__treeselection.set_select_function(self._controlSelection) self.__selection_control = True if len(self.__liststore) > 0: self.__treeview.set_cursor_on_cell((0,),self.__unit_column, self.__unit_column.get_cell_renderers()[0],True) self.__treeview.grab_focus() self.__cursor = self.__treeview.get_cursor() # Show self._setColumnsHeaders() self.__scrolled_window.show() def _treeviewCursorChanged(self, treeview): """_treeviewCursorChanged(treeview) treeview: treewiew widget Method connected to "cursor-changed" signal The "cursor-changed" signal is emitted when the cursor moves or is set Sets the new cursor position in self.__cursor, it is used to avoid unnecessary changes in cursor position. """ event = gtk.get_current_event() (_cursor_path, _column) = treeview.get_cursor() if event is None or event.type != gtk.gdk.BUTTON_RELEASE: if not _column is self.__index_column: self.__cursor = treeview.get_cursor() def _treeviewClickedEvent(self, widget, event): """_treeviewClickedEvent(widget, event) widget: treewiew widget event: clicked event Method connected to "button-press-event" signal The "button-press-event" signal is emitted when a mouse button is pressed. Returns TRUE to stop other handlers from being invoked for the event. Returns FALSE to propagate the event further. The events in end column are ignored. If the user click in a row of the index column the cursor is moved to this row but not to the index column """ if event.button == 1: path_at_pos = self.__treeview.get_path_at_pos(int(event.x), int(event.y)) if not path_at_pos is None: _path_cursor, _column, _x, _y = path_at_pos if _column == self.columns[-1]: return True if _column is self.columns[0]: self.__cursor[0] == _path_cursor return False def _treeviewKeyPressEvent(self, widget, event): """_treeviewKeyPressEvent(widget, event) widget: treewiew widget event: Key Press event Method connected to "key-press-event" signal The "key-press-event" signal is emitted when the user presses a key on the keyboard. Returns :TRUE to stop other handlers from being invoked for the event. Returns :FALSE to propagate the event further. If the user press the right cursor button and the cursor is in the amount column or pres the left cursor button and the cursor is in the code column the event is estoped, else the event is propagated. """ (_cursor_path, _column) = self.__treeview.get_cursor() if (event.keyval == gtk.keysyms.Right \ and _column == self.columns[-2]) \ or (event.keyval == gtk.keysyms.Left \ and _column == self.columns[1]): return True return False def _moveCursor(self, treeview, step, count): """_moveCursor(treeview, step, count) treeview: the treeview that received the signal step: the movement step size count: the number of steps to take Method connected to "move-cursor" signal The "move-cursor" signal is emitted when the user moves the cursor using the Right, Left, Up or Down arrow keys or the Page Up, Page Down, Home and End keys. Returns :TRUE if the signal was handled. """ return False def _controlSelection(self, selection): """_controlSelection(selection) selection: treeselection Method connected to set_selection_function() This method is called before any node is selected or unselected, giving some control over which nodes are selected. The selection function should return TRUE if the state of the node may be toggled, and FALSE if the state of the node should be left unchanged. The selection only run if the user click in the index column, else the previous selection is erased. """ _column = self.__treeview.get_cursor()[1] if _column is self.columns[0] \ or self.__selection_control == False: return True else: self.__selection_control = False self.__treeselection.unselect_all() self.__selection_control = True return False def _selectAll(self, column): """_selectAll(column) column: index column Method connected to "clicked" event in the index column If the user clickes in the index column header selecs or deselects all rows """ (_model, _pathlist) = self.__treeselection.get_selected_rows() # it avoid to set cursor in the index column self.__treeview.set_cursor(self.__cursor[0], self.__cursor[1]) self.__selection_control = False if len(_pathlist) == 0: # select all self.__treeselection.select_all() else: # unselect all self.__treeselection.unselect_all() self.__selection_control = True def _setColumnsHeaders(self): """_setColumnsHeaders() Sets the headers column values """ _path_record = self.__active_path_record _number = _path_record[-1] _budget = self.__budget _code = _budget.getCode(_path_record) _decomposition = _budget.getDecomposition(_path_record) _stryield = _budget.getStrYield(_decomposition.budgetMeasures[0], _budget.getRecord(_code).recordType) _record = _budget.getRecord(_code) _unit = _record.unit _description = _record.summary _price = _budget.getStrPriceFromRecord(self.budget.getActiveTitle(), _record) # TODO: round to decimal places in amount _amount = float(_stryield) * float(_price) if len(_path_record) == 1: # root record _amount = _price else: _parent_code = self.budget.getCode(self.__active_path_record[:-1]) _parent_record = self.__budget.getRecord(_parent_code) _amount = _budget.getStrAmount(self.__active_path_record) self.__code_column.set_title(_("Code") + chr(10) + "[" + _code + "]") self.__unit_column.set_title(_("Unit") + chr(10) + "[" + _unit + "]") self.__description_column.set_title( _("Description") + chr(10) + "[" + _description + "]") self.__measure_column.set_title( _("Measure") + chr(10) + "[" + _stryield + "]") self.__price_column.set_title( _("Price") + chr(10) + "[" + _price + "]") self.__amount_column.set_title( _("Amount") + chr(10) + "[" + str(_amount) + "]") def _setListstoreValues(self, path_record): """_setListstoreValues(path_record) path_record: Record path in the budget Sets the liststore record values from a path record """ self.__liststore.clear() _budget = self.__budget if not _budget.hasPath(path_record): raise ValueError, _("Invalid path") else: _parent_code = _budget.getCode(path_record) for N,_code in enumerate(_budget.getchildren(_parent_code)): _decomposition = _budget.getNDecomposition(_parent_code, N) _record = _budget.getRecord(_code) _values = [_record, #_record.hierarchy, #_record.type, #_record.subtype, #_code, #_record.unit, #_record.summary, #_decomposition.yield_, #_decomposition.budget[0].yield_, #_record.prices[_budget.getActiveTitle()].prices] #_record.getPrice(_budget.getActiveTitle()) ] _treeiter = self.__liststore.append(_values) def _colorCell(self, column, cell_renderer, tree_model, iter, lcolor): """_colorCell(column, cell_renderer, tree_model, iter, lcolor) column: the gtk.TreeViewColumn in the treeview cell_renderer: a gtk.CellRenderer tree_model: the gtk.TreeModel iter: gtk.TreeIter pointing at the row lcolor: list with 2 gtk colors for even and uneven record Method connected to "set_cell_data_func" of many column The set_cell_data_func() method sets the data function (or method) to use for the column gtk.CellRenderer specified by cell_renderer. This function (or method) is used instead of the standard attribute mappings for setting the column values, and should set the attributes of the cell renderer as appropriate. func may be None to remove the current data function. The signature of func is: -def celldatafunction(column, cell, model, iter, user_data) -def celldatamethod(self, column, cell, model, iter, user_data) where column is the gtk.TreeViewColumn in the treeview, cell is the gtk.CellRenderer for column, model is the gtk.TreeModel for the treeview and iter is the gtk.TreeIter pointing at the row. The method sets cell background color and text for all columns. """ _row_path = tree_model.get_path(iter) _number = _row_path[-1] _record = tree_model[_row_path][0] if column is self.__index_column: cell_renderer.set_property('text', str(_number + 1)) self.__index_column.get_cell_renderers()[1].set_property( 'cell-background-gdk', lcolor[_number % 2]) elif column is self.__code_column: # if the record is a chapter if tree_model.get_value(iter, 0).recordType.hierarchy == 1: lcolor = self.__chapter_background_colors _code = _record.code cell_renderer.set_property('text', _code) elif column is self.__unit_column: _unit = _record.unit cell_renderer.set_property('text', _unit) elif column is self.__description_column: _summary = _record.summary cell_renderer.set_property('text', _summary) elif column is self.__measure_column: _parent_code = self.budget.getCode(self.__active_path_record) _parent_record = self.__budget.getRecord(_parent_code) _decomposition = _parent_record.children[_number] _stryield = self.__budget.getStrYield( _decomposition.budgetMeasures[0], _parent_record.recordType) cell_renderer.set_property('text', _stryield) elif column is self.__price_column: _price = self.budget.getStrPriceFromRecord( self.budget.getActiveTitle(), _record) cell_renderer.set_property('text', _price) elif column is self.__amount_column: _parent_code = self.budget.getCode(self.__active_path_record) _parent_record = self.__budget.getRecord(_parent_code) _amount = self.budget.getStrAmount( self.__active_path_record + (_number,)) cell_renderer.set_property('text', str(_amount)) elif column is self.__type_column: _hierarchy = tree_model[_row_path][0].recordType.hierarchy _type = tree_model[_row_path][0].recordType.type _subtype = tree_model[_row_path][0].recordType.subtype if _hierarchy == 1: cell_renderer.set_property("pixbuf",self.__chapter_icon) else: if _type == 0: cell_renderer.set_property("pixbuf",self.__unit_icon) elif _type == 1: cell_renderer.set_property("pixbuf", self.__labourforce_icon) elif _type == 2: cell_renderer.set_property("pixbuf", self.__machinery_icon) else: cell_renderer.set_property("pixbuf",self.__material_icon) if self.__treeview.get_cursor() == (_row_path,column): cell_renderer.set_property('cell-background-gdk', gtk.gdk.color_parse(globalVars.color["ACTIVE"])) else: cell_renderer.set_property('cell-background-gdk', lcolor[_number % 2]) def _showParentRecord(self, column): """_showParentRecord(column) column: the column that is clicked Method connected to "clicked" event of many columns Show the parent record """ _budget = self.__budget if len(self.__active_path_record) == 1: # The active record is the root record # This avoid to move the cursor to the clicked column self.__treeview.set_cursor(self.__cursor[0], self.__cursor[1]) else: _path_record = self.__active_path_record[:-1] _parent = self.__active_path_record[-1] self.__active_path_record = _path_record self._setColumnsHeaders() self._setListstoreValues(self.__active_path_record) arg = ( _path_record ) _page = self.__page() _page.propagateMessageFrom("change_active", self.__pane_path, arg) self.__treeview.set_cursor(_parent, self.__cursor[1]) self.__cursor = self.__treeview.get_cursor() def _showMessageRecord(self, record_path): """_showMessageRecord(record_path) record_path: the path of the record to show Method connected to "change_active" message Show the record especified in the "change_active" message """ _budget = self.__budget self.__active_path_record = record_path self._setColumnsHeaders() self._setListstoreValues(self.__active_path_record) self.__treeview.set_cursor((0,)) def _showRowRecord(self, treeview, treeview_path, column): """_showRowRecord(treeview, treeview_path, column) treeview: treview to show treeview_path: the path of the record to show code: the code of the record to show Method connected to "row-activated" event The "row-activated" signal is emitted when the row_activated() method is called or the user double clicks a treeview row. "row-activated" is also emitted when a non-editable row is selected and one of the keys: Space, Shift+Space, Return or Enter is pressed. Show the especified record """ if not (column is self.__end_column) and \ not (column is self.__index_column): _budget = self.__budget _model = treeview.get_model() _iter = _model.get_iter(treeview_path) _code = _model.get_value(_iter, 0).code #_code = _model.get_value(_iter, 4) _path_record = self.__active_path_record + treeview_path if self.__budget.hasPath(_path_record): # if this record path is valid self.__active_path_record = _path_record self._setColumnsHeaders() self._setListstoreValues(self.__active_path_record) self.__treeview.set_cursor((0,)) _arg = ( _path_record ) _page = self.__page() _page.propagateMessageFrom("change_active", self.__pane_path, _arg ) def runMessage(self, message, pane_path, arg=None): """runMessage(message, pane_path, arg=None) message: the message type "change_active": change the active record "clear": clear instance pane_path: tuple that identifies the pane in the notebook page arg: tuple whit two items: 0: record path in the budget 1: record code This method receives a message and executes its corresponding action """ _budget = self.__budget if message == "change_active": if _budget.hasPath(arg): _path_record = arg self._showMessageRecord( _path_record) elif message == "clear": self._clear() def _clear(self): """_clear() it deletes the __budget reference """ del self.__budget def _getWidget(self): """_getWidget() return the main widget (gtk.ScrolledWindow) """ return self.__scrolled_window def _getPanePath(self): """_getPanePath() return the tuple that identifies the pane in the notebook page """ return self.__pane_path def _setPanePath(self, pane_path): """_setPanePath() sets the tuple that identifies the pane in the notebook page """ self.__pane_path = pane_path def _getPage(self): """_getPage() return the Page """ return self.__page def _setPage(self,page): """_setPage() set the Page """ self.__page = page def _getBudget(self): """_getBudget() return the Budget objet """ return self.__budget def _getActivePathRecord(self): """_getActivePathRecord() return the Active Path Record """ return self.__active_path_record widget = property(_getWidget, None, None, "Pane configuration list") pane_path = property(_getPanePath, _setPanePath, None, "path that identifie the item in the page notebook") page = property(_getPage, _setPage, None, "weak reference from Page instance which creates this class") budget = property(_getBudget, None, None, "Budget object") active_path_record = property(_getActivePathRecord, None, None, "Active path record") class Measure(TreeView): """gui.Measure: Description: Class to show a Measure List Constructor: Measure(budget, page, pane_path, path_record=(0,) budget: budget showed ("base.Budget" object) page: weak reference from Page instance which creates this class pane_path: tuple that represents the path of the List in the Page path_record: path of the active record in the budget Ancestry: +-- object +-- TreeView +-- DecompositionList Atributes: budget: Read. Budget to show, base.obra instance. widget: Read. Window that contains the table, gtk.ScrolledWindow pane_path: Read-Write. Pane page identifier page: Read-Write. weak reference from Page instance which creates this class active_path_record: Read. Path of the active record in the budget Methods: runMessage """ def __init__(self, budget, page, pane_path, path_record=(0,)): """__init__(budget, page, pane_path, path_record=(0,)) budget: budget: budget showed ("base.Budget" object) page: weak reference from Page instance which creates this class pane_path: tuple that represents the path of the List in the Page path_record: path of the active record in the budget self.__budget: budget showed ("base.Budget" object) self.__page: weak reference from Page instance which creates this class self.__pane_path: tuple that represents the path of the List in the Page self.__active_path_record: path of the active record in the budget self.__liststore: list model which store the list data (gtk.ListStore object) self.__treeview: widget to display decomposition lists (gtk.TreeView) self.__scrolled_window: widget to scroll the treeview gtk.ScrolledWindow() self.__chapter_background_colors: The background colors of the Code column cells when there is a chapter record as a list of gtk.gdk.Color objects [even cell, uneven cell] self.__index_column: Index column (gtk.TreeViewColumn object) self.__linetype_column: Linetype column (gtk.TreeViewColumn object) self.__comment_column: Comment column (gtk.TreeViewColumn) self.__unit_column: Unit column (gtk.TreeViewColumn) self.__length_column: Legth column (gtk.TreeViewColumn) self.__width_column: With column (gtk.TreeViewColumn) self.__height_column: Height column (gtk.TreeViewColumn) self.__formula_column: Formula column (gtk.TreeViewColumn) self.__parcial_column: Parcial column (gtk.TreeViewColumn) self.__subtotal_column: Subtotal column (gtk.TreeViewColumn) self.__end_column: End empty column (gtk.TreeViewColumn self.__calculatedline_icon: gtk.gdk.pixbuf self.__normalline_icon: gtk.gdk.pixbuf self.__parcialline_icon: gtk.gdk.pixbuf self.__acumulatedline_icon: gtk.gdk.pixbuf self.__treeselection: active selection self.__selection_control: state of the selection control (True/False) self.__cursor: Situation of the cursor in the table Sets the init atributes Creates the init list values in self.__liststore from the budget showing the top record from the record with path path_record Creates the list in self.__treeview * Creates the columns and cell * Sets te the column headers values * Sets the selection properties * Connects the events """ # Seting init args if not isinstance(budget, base.Budget): raise ValueError, _("Argument must be a Budget object") self.__budget = budget self.__page = page self.__pane_path = pane_path if not isinstance(path_record, tuple): print _("Record path must be a tuple") path_record = (0,) self.__active_path_record = path_record # ListStore self.__liststore = gtk.ListStore(object) self._setListstoreValues(self.__active_path_record) # Treeview self.__treeview = gtk.TreeView(self.__liststore) self.__treeview.set_enable_search(False) self.__treeview.set_reorderable(False) self.__treeview.set_headers_clickable(True) self.__treeview.show() # Scrolled_window self.__scrolled_window = gtk.ScrolledWindow() self.__scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) self.__scrolled_window.add(self.__treeview) # colors _text_color = gtk.gdk.color_parse(globalVars.color["TEXT"]) _calculated_text =gtk.gdk.color_parse(globalVars.color["CALCULATED-TEXT"]) _background_color = [ gtk.gdk.color_parse(globalVars.color["UNEVEN"]), gtk.gdk.color_parse(globalVars.color["EVEN"])] self.__chapter_background_colors = [ gtk.gdk.color_parse(globalVars.color["CHAPTER-UNEVEN"]), gtk.gdk.color_parse(globalVars.color["CHAPTER-EVEN"])] super(Measure,self).__init__( [("INDEX",self._selectAll,42), ("PIXBUF", self._passMethod, gtk.Label("A"*4).size_request()[0] +10, _text_color, _background_color), ("CALCULATEDTEXT", self._passMethod, gtk.Label("A"*12).size_request()[0] +10, _text_color, _background_color), ("CALCULATED", self._passMethod, gtk.Label("A"*5).size_request()[0] +10, _text_color, _background_color), ("CALCULATED", self._passMethod, gtk.Label("A"*7).size_request()[0] +10, _text_color, _background_color), ("CALCULATED", self._passMethod, gtk.Label("A"*7).size_request()[0] +10, _text_color, _background_color), ("CALCULATED", self._passMethod, gtk.Label("A"*7).size_request()[0] +10, _text_color, _background_color), ("CALCULATEDTEXT", self._passMethod, gtk.Label("A"*12).size_request()[0] +10, _text_color, _background_color), ("CALCULATED", self._passMethod, gtk.Label("A"*7).size_request()[0] +10, _calculated_text, _background_color), ("CALCULATED", self._passMethod, gtk.Label("A"*7).size_request()[0] +10, _calculated_text, _background_color), ]) # Colums self.__index_column = self.columns[0] self.__linetype_column = self.columns[1] self.__comment_column = self.columns[2] self.__units_column = self.columns[3] self.__length_column = self.columns[4] self.__width_column = self.columns[5] self.__height_column = self.columns[6] self.__formula_column = self.columns[7] self.__parcial_column = self.columns[8] self.__subtotal_column = self.columns[9] self.__end_column = self.columns[10] # Index column self.__treeview.append_column(self.__index_column) # Linetype column self.__treeview.append_column(self.__linetype_column) self.__calculatedline_icon = gtk.gdk.pixbuf_new_from_file( globalVars.getAppPath("CALCULATEDLINE-ICON")) self.__normalline_icon = gtk.gdk.pixbuf_new_from_file( globalVars.getAppPath("NORMALLINE-ICON") ) self.__parcialline_icon = gtk.gdk.pixbuf_new_from_file( globalVars.getAppPath("PARCIALLINE-ICON") ) self.__acumulatedline_icon = gtk.gdk.pixbuf_new_from_file( globalVars.getAppPath("ACUMULATEDLINE-ICON")) # Comment column self.__treeview.append_column(self.__comment_column) # Units column self.__treeview.append_column(self.__units_column) # Length column self.__treeview.append_column(self.__length_column) # Width_column self.__treeview.append_column(self.__width_column) # Height column self.__treeview.append_column(self.__height_column) # Formula column self.__treeview.append_column(self.__formula_column) # Parcial column self.__treeview.append_column(self.__parcial_column) # Subtotal column self.__treeview.append_column(self.__subtotal_column) # End Column self.__treeview.append_column(self.__end_column) # Connect self.__treeview.connect("move-cursor", self._moveCursor) self.__treeview.connect("key-press-event", self._treeviewKeyPressEvent) self.__treeview.connect("button-press-event", self._treeviewClickedEvent) self.__treeview.connect("cursor-changed", self._treeviewCursorChanged) # control selection self.__treeselection = self.__treeview.get_selection() self.__treeselection.set_mode(gtk.SELECTION_MULTIPLE) self.__treeselection.set_select_function(self._controlSelection) self.__selection_control = True self.__treeview.set_cursor_on_cell((1,), self.columns[1], self.columns[1].get_cell_renderers()[0],True) self.__treeview.grab_focus() self.__cursor = self.__treeview.get_cursor() # Show self._setColumnsHeaders() self.__scrolled_window.show() def _passMethod(self, column): """_passMethod(column) column: the column that is clicked Method connected to "clicked" event of many columns Do nothing """ pass def _setListstoreValues(self, path_record): """_setListstoreValues(path_record) path_record: Record path in the budget Sets the liststore record values from a path record """ self.__liststore.clear() _budget = self.__budget if not _budget.hasPath(path_record): raise ValueError, _("Invalid path") else: _measure = _budget.getMeasure(path_record) if isinstance(_measure, base.Measure): _lines = _measure.lines for _line in _lines: _values = [ _line ] _treeiter = self.__liststore.append(_values) else: raise ValueError, utils.mapping(_("measure must be a Measure "\ "object. Type: $1"), (type(_measure),)) def _setColumnsHeaders(self): """_setColumnsHeaders() Sets the headers column values """ _measure = self.__budget.getMeasure(self.__active_path_record) _DS = self.__budget.getDecimals("DS") _total = _measure.measure _total_str = ("%." + str(_DS) + "f" ) % _total self.columns[1].set_title(_("Type")) # Σ parcial Σ total self.columns[2].set_title(_("Comment")) self.columns[3].set_title(_("N\n(a)")) self.columns[4].set_title(_("Length\n(b)")) self.columns[5].set_title(_("Width\n(c)")) self.columns[6].set_title(_("Height\n(d)")) self.columns[7].set_title(_("Formula")) self.columns[8].set_title(_("Parcial\n[%s]" % _total_str)) self.columns[9].set_title(_("Subtotal")) def _controlSelection(self, selection): """_controlSelection(selection) selection: treeselection Method connected to set_selection_function() This method is called before any node is selected or unselected, giving some control over which nodes are selected. The selection function should return TRUE if the state of the node may be toggled, and FALSE if the state of the node should be left unchanged. The selection only run if the user click in the index column, else the previous selection is erased. """ _column = self.__treeview.get_cursor()[1] if _column is self.columns[0] \ or self.__selection_control == False: return True else: self.__selection_control = False self.__treeselection.unselect_all() self.__selection_control = True return False def _showMessageRecord(self, record_path): """_showMessageRecord(record_path) record_path: the path of the record to show Method connected to "change_active" message Show the record especified in the "change_active" message """ _budget = self.__budget self.__active_path_record = record_path self._setColumnsHeaders() self._setListstoreValues(self.__active_path_record) self.__treeview.set_cursor((0,)) def _treeviewCursorChanged(self, treeview): """_treeviewCursorChanged(treeview) treeview: treewiew widget Method connected to "cursor-changed" signal The "cursor-changed" signal is emitted when the cursor moves or is set Sets the new cursor position in self.__cursor, it is used to avoid unnecessary changes in cursor position. """ event = gtk.get_current_event() (_cursor_path, _column) = treeview.get_cursor() if event is None or event.type != gtk.gdk.BUTTON_RELEASE: if not _column is self.__index_column: self.__cursor = treeview.get_cursor() def _moveCursor(self, treeview, step, count): """moveCursor(treeview, step, count) treeview: the treeview that received the signal step: the movement step size count: the number of steps to take Method connected to "move-cursor" signal The "move-cursor" signal is emitted when the user moves the cursor using the Right, Left, Up or Down arrow keys or the Page Up, Page Down, Home and End keys. Returns :TRUE if the signal was handled. """ return False def _treeviewClickedEvent(self, widget, event): """_treeviewClickedEvent(widget, event) widget: treewiew widget event: clicked event Method connected to "button-press-event" signal The "button-press-event" signal is emitted when a mouse button is pressed. Returns TRUE to stop other handlers from being invoked for the event. Returns FALSE to propagate the event further. The events in end column are ignored. If the user click in a row of the index column the cursor is moved to this row but not to the index column """ if event.button == 1: path_at_pos = self.__treeview.get_path_at_pos(int(event.x), int(event.y)) if not path_at_pos is None: _path_cursor, _column, _x, _y = path_at_pos if _column == self.columns[-1]: return True if _column is self.columns[0]: self.__cursor[0] == _path_cursor return False def _treeviewKeyPressEvent(self, widget, event): """_treeviewKeyPressEvent(widget, event) widget: treewiew widget event: Key Press event Method connected to "key-press-event" signal The "key-press-event" signal is emitted when the user presses a key on the keyboard. Returns :TRUE to stop other handlers from being invoked for the event. Returns :FALSE to propagate the event further. If the user press the right cursor button and the cursor is in the amount column or pres the left cursor button and the cursor is in the code column the event is estoped, else the event is propagated. """ (_cursor_path, _column) = self.__treeview.get_cursor() if (event.keyval == gtk.keysyms.Right \ and _column == self.columns[-2]) \ or (event.keyval == gtk.keysyms.Left \ and _column == self.columns[1]): return True return False def runMessage(self, message, pane_path, arg=None): """runMessage(message, pane_path, arg=None) message: the message type "change_active": change the active record "clear": clear instance pane_path: tuple that identifies the pane in the notebook page arg: tuple whit two items: 0: record path in the budget 1: record code This method receives a message and executes its corresponding action """ _budget = self.__budget if message == "change_active": if _budget.hasPath(arg): _path_record = arg self._showMessageRecord( _path_record) elif message == "clear": self._clear() def _selectAll(self, column): """_selectAll(column) column: index column Method connected to "clicked" event in the index column If the user clickes in the index column header selecs or deselects all rows """ (_model, _pathlist) = self.__treeselection.get_selected_rows() # it avoid to set cursor in the index column self.__treeview.set_cursor(self.__cursor[0], self.__cursor[1]) self.__selection_control = False if len(_pathlist) == 0: # select all self.__treeselection.select_all() else: # unselect all self.__treeselection.unselect_all() self.__selection_control = True def _colorCell(self, column, cell_renderer, tree_model, iter, lcolor): """_colorCell(column, cell_renderer, tree_model, iter, lcolor) column: the gtk.TreeViewColumn in the treeview cell_renderer: a gtk.CellRenderer tree_model: the gtk.TreeModel iter: gtk.TreeIter pointing at the row lcolor: list with 2 gtk colors for even and uneven record Method connected to "set_cell_data_func" of many column The set_cell_data_func() method sets the data function (or method) to use for the column gtk.CellRenderer specified by cell_renderer. This function (or method) is used instead of the standard attribute mappings for setting the column values, and should set the attributes of the cell renderer as appropriate. func may be None to remove the current data function. The signature of func is: -def celldatafunction(column, cell, model, iter, user_data) -def celldatamethod(self, column, cell, model, iter, user_data) where column is the gtk.TreeViewColumn in the treeview, cell is the gtk.CellRenderer for column, model is the gtk.TreeModel for the treeview and iter is the gtk.TreeIter pointing at the row. The method sets cell background color for all columns and text for index and amount columns. """ _row_path = tree_model.get_path(iter) _number = _row_path[-1] if column is self.__index_column: cell_renderer.set_property('text', str(_number + 1)) self.__index_column.get_cell_renderers()[1].set_property( 'cell-background-gdk', lcolor[_number % 2]) elif column is self.__linetype_column: _measure = tree_model[_row_path][0] _type = _measure.lineType if _type == 0: cell_renderer.set_property("pixbuf",self.__normalline_icon) elif _type == 1: cell_renderer.set_property("pixbuf",self.__parcialline_icon) elif _type == 2: cell_renderer.set_property("pixbuf", self.__acumulatedline_icon) else: #elif _type == 3: cell_renderer.set_property("pixbuf", self.__calculatedline_icon) elif column is self.__comment_column: _measure = tree_model[_row_path][0] _comment = str(_measure.comment) cell_renderer.set_property('text', _comment) elif column is self.__units_column: _measure = tree_model[_row_path][0] _units = _measure.units if isinstance(_units, float): _DN = self.__budget.getDecimals("DN") _units = ("%." + str(_DN) + "f" ) % _units cell_renderer.set_property('text', _units) elif column is self.__length_column: _measure = tree_model[_row_path][0] _length = _measure.length if isinstance(_length, float): _DD = self.__budget.getDecimals("DD") _length = ("%." + str(_DD) + "f" ) % _length cell_renderer.set_property('text', _length) elif column is self.__width_column: _measure = tree_model[_row_path][0] _width = _measure.width if isinstance(_width, float): _DD = self.__budget.getDecimals("DD") _width = ("%." + str(_DD) + "f" ) % _width cell_renderer.set_property('text', _width) elif column is self.__height_column: _measure = tree_model[_row_path][0] _height = _measure.height if isinstance(_height, float): _DD = self.__budget.getDecimals("DD") _height = ("%." + str(_DD) + "f" ) % _height cell_renderer.set_property('text', _height) elif column is self.__formula_column: _measure = tree_model[_row_path][0] _formula = _measure.formula cell_renderer.set_property('text', _formula) elif column is self.__parcial_column: _measure_line = tree_model[_row_path][0] _parcial = _measure_line.parcial _type = _measure_line.lineType if _type == 1 or _type == 2: _parcial = "" else: if isinstance(_parcial, float): _DS = self.__budget.getDecimals("DS") _parcial = ("%." + str(_DS) + "f" ) % _parcial cell_renderer.set_property('text', _parcial) elif column is self.__subtotal_column: _measure_line = tree_model[_row_path][0] _type = _measure_line.lineType if _type == 1 or _type == 2: if _type == 1: _color = gtk.gdk.color_parse( globalVars.color["SUBTOTAL-PARCIAL"]) _subtotal = _measure_line.parcial_subtotal else: #elif _type == 2: _color = gtk.gdk.color_parse(globalVars.color["SUBTOTAL"]) _subtotal = _measure_line.acumulated_subtotal lcolor = [_color, _color] if isinstance(_subtotal, float): _DS = self.__budget.getDecimals("DS") _subtotal= ("%." + str(_DS) + "f" ) % _subtotal cell_renderer.set_property('text', _subtotal) else: cell_renderer.set_property('text', "") if self.__treeview.get_cursor() == (_row_path,column): cell_renderer.set_property('cell-background-gdk', gtk.gdk.color_parse(globalVars.color["ACTIVE"])) else: cell_renderer.set_property('cell-background-gdk', lcolor[_number % 2]) def _clear(self): """_clear() it deletes the __budget value """ del self.__budget def _getWidget(self): """_getWidget() return the main widget (gtk.ScrolledWindow) """ return self.__scrolled_window def _getPanePath(self): """_getPanePath() return the tuple that identifies the pane in the notebook page """ return self.__pane_path def _setPanePath(self, pane_path): """_setPanePath() sets the tuple that identifies the pane in the notebook page """ self.__pane_path = pane_path def _getPage(self): """_getPage() return the Page """ return self.__page def _setPage(self,page): """_setPage() set the Page """ self.__page = page def _getBudget(self): """_getBudget() return the Budget objet """ return self.__budget def _getActivePathRecord(self): """getActivePathRecord() return the Active Path Record """ return self.__active_path_record widget = property(_getWidget, None, None, "Pane configuration list") pane_path = property(_getPanePath, _setPanePath, None, "Path that identifies the item in the page notebook") page = property(_getPage, _setPage, None, "Weak reference from Page instance which creates this class") budget = property(_getBudget, None, None, "Budget object") active_path_record = property(_getActivePathRecord, None, None, "Active Code") class Description(object): """gui.Description Description: Class to show a description text of a record in a pane Constructor: Description(budget, code) budget: base.Budget object code: record code Ancestry: +-- object +-- Description Atributes: widget: the main widget (gtk.ScrolledWindow object) pane_path: the tuple that identifies the pane in the notebook page budget: The budget (base.obra objetc) active_path_record: The active path record Methods: runMessage """ # TODO: make standar: "DecompositonList and Description" def __init__(self, budget, page, pane_path, path_record=(0,)): """__init__(budget, page, pane_path, path_record=(0,)) budget: the budget (base.obra object) page: weak reference from Page instance which creates this class pane_path: the path position of the description in the page path_record: the path of the active record self.__budget: the budget (base.obra object) self.__page: weak reference from Page instance which creates this class self.__pane_path: the path position of the description in the page self.__active_path_recordthe path of the active record self.__textbuffer: The textbuffer of the textview that contain the record text. self.__label: The gtk.label with the title of the pane self.__widget: the main pane widget, a gtk.ScrolledWindow() Creates an shows the scroledwindow that contain the description text of the record to be showed in a pane. """ self.__budget = budget self.__page = page self.__pane_path = pane_path self.__active_path_record = path_record _budget = budget _text = _budget.getRecord(self.__budget.getCode( self.__active_path_record)).text _scrollwindow = gtk.ScrolledWindow() _scrollwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) _textview = gtk.TextView() _textview.set_wrap_mode(gtk.WRAP_WORD) self.__textbuffer = _textview.get_buffer() self.__textbuffer.set_text(_text) _textview.show() _hbox = gtk.HBox() _hbox.pack_start(_textview, True, True, 5) _hbox.show() _vbox = gtk.VBox() self.__label = gtk.Label(utils.mapping(_("Description text of the "\ "record $1"), (self.__budget.getCode( self.__active_path_record),))) self.__label.set_alignment(0, 0) self.__label.show() _vbox.pack_start(self.__label, False, False, 5) _vbox.pack_start(_hbox, True, True, 5) _vbox.show() _scrollwindow.add_with_viewport(_vbox) _scrollwindow.show() self.__widget = _scrollwindow def _setActivePathRecord(self, path_record): """_setActivePathRecord(path_record)) path_record: active path record Set the new path code to show its description text. """ _budget = self.__budget self.__active_path_record = path_record _code = _budget.getCode(self.__active_path_record) self.__label.set_text(utils.mapping(_("Description text of the record "\ "$1"), (_code,))) _text = _budget.getRecord(_code).text self.__textbuffer.set_text(_text) def runMessage(self, message, pane_path, arg=None): """runMessage(message, pane_path, arg=None) message: the message type "change_active": change the active record "clear": clear instance pane_path: tuple that identifies the pane in the notebook page arg: tuple whit two items: 0: record path in the budget 1: record code This method receives a message and executes its corresponding action """ _budget = self.__budget if message == "change_active": if _budget.hasPath(arg): self._setActivePathRecord(arg) elif message == "clear": self._clear() def _clear(self): """_clear() Delete all instance atributes """ del self.__widget del self.__pane_path del self.__budget del self.__active_code del self.__textbuffer del self.__label def _getWidget(self): """_getWidget() return the main widget (gtk.ScrolledWindow) """ return self.__widget def _getPanePath(self): """_getPanePath() return the tuple that identifies the pane in the notebook page """ return self.__pane_path def _setPanePath(self, pane_path): """_setPanePath() sets the tuple that identifies the pane in the notebook page """ self.__pane_path = pane_path def _getPage(self): """_getPage() return the weak reference from Page instance """ return self.__page def _setPage(self, page): """_setPage() set the weak reference from Page instance """ self.__page = page def _getBudget(self): """_getBudget() return the budget object """ return self.__budget def _getActivePathRecord(self): """_getActivePathRecord() return the Active Path Record """ return self.__active_path_record pane_path = property(_getPanePath, _setPanePath, None, "Path that identifie the item in the page notebook") widget = property(_getWidget, None, None, "The main widget (gtk.ScrolledWindow)") page = property(_getPage, _setPage, None, "Weak reference from Page instance which creates this class") budget = property(_getBudget, None, None, "Budget object") active_path_record = property(_getActivePathRecord, None, None, "Active Path Record") class Sheet(object): """gui.Sheet Description: Class to show a sheeet of conditions text of a record in a pane Constructor: Sheet(budget, code) budget: budget object code: code record Ancestry: +-- object +-- Sheet Atributes: widget: the main widget (gtk.VBox() object) pane_path: the tuple that identifies the pane in the notebook page page: weak reference from Page instance which creates this class budget: The budget (base.obra objetc) active_path_record: The active path record Methods: runMessage """ def __init__(self, budget, page, pane_path, path_record=(0,)): """__init__(budget, page, pane_path, path_record=(0,)) budget: the budget (base.obra object) page: weak reference from Page instance which creates this class pane_path: the path position of the description in the page path_record: the path of the active record self.__budget: the budget (base.obra object) self.__page: weak reference from Page instance which creates this class self.__pane_path: the path position of the description in the page self.__active_path_record: the path of the active record self.__label: The gtk.label with the title of the pane self.__field_liststore: the field liststore self.__field_treeview: the field treeview self.__field_selection: the field selected in field treview self.__section_liststore: the section liststore self.__section_treeview: the section treeview self.__section_selection: the section selected in the section treeview self.__textbuffer: The textbuffer of the textview that contain the record text. self.__widget: main widget, a gtk.VBox() Creates an shows the scroledwindow that contain the description text of the record to be showed in a pane. """ self.__budget = budget self.__page = page self.__pane_path = pane_path self.__active_path_record = path_record _budget = budget _main_box = gtk.VBox() self.__label = gtk.Label(utils.mapping(_("Sheet of Conditions of the "\ "record $1"), (self.__budget.getCode( self.__active_path_record),))) self.__label.set_alignment(0, 0) self.__label.show() _frame = gtk.Frame() _frame.set_shadow_type(gtk.SHADOW_IN) _frame_box = gtk.VBox() _list_box = gtk.HBox() self.__field_liststore = gtk.ListStore(str, str) self.__field_treeview = gtk.TreeView(self.__field_liststore) _field_treeselection = self.__field_treeview.get_selection() _field_treeselection.set_mode(gtk.SELECTION_SINGLE) self.__field_selection = None _field_treeselection.set_select_function( self._field_controlSelection) self.__field_treeview.show() _fieldcode_cell = gtk.CellRendererText() _field_column = gtk.TreeViewColumn(_("Field")) _field_column.pack_start(_fieldcode_cell, False) _field_cell = gtk.CellRendererText() _field_column.pack_end(_field_cell, True) _field_column.add_attribute(_fieldcode_cell, "text", 0) _field_column.add_attribute(_field_cell, "text", 1) self.__field_treeview.append_column(_field_column) _field_scrollwindow = gtk.ScrolledWindow() _field_scrollwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) _field_scrollwindow.add(self.__field_treeview) _field_scrollwindow.show() self.__section_liststore = gtk.ListStore(str, str) self.__section_treeview = gtk.TreeView(self.__section_liststore) _section_treeselection = self.__section_treeview.get_selection() _section_treeselection.set_mode(gtk.SELECTION_SINGLE) self.__section_selection = None _section_treeselection.set_select_function( self._section_controlSelection) self.__section_treeview.show() _sectioncode_cell = gtk.CellRendererText() _section_column = gtk.TreeViewColumn(_("Section")) _section_column.pack_start(_sectioncode_cell, False) _section_column.add_attribute(_sectioncode_cell, "text", 0) _section_cell = gtk.CellRendererText() _section_column.pack_end(_section_cell, True) _section_column.add_attribute(_section_cell, "text", 1) self.__section_treeview.append_column(_section_column) _section_scrollwindow = gtk.ScrolledWindow() _section_scrollwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) _section_scrollwindow.add(self.__section_treeview) _section_scrollwindow.show() _list_box.pack_start(_field_scrollwindow, True, True, 5) _list_box.pack_start(_section_scrollwindow, True, True, 5) _list_box.show() _scrollwindow = gtk.ScrolledWindow() _scrollwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) _textview = gtk.TextView() _textview.set_wrap_mode(gtk.WRAP_WORD) self.__textbuffer = _textview.get_buffer() _textview.show() _hbox = gtk.HBox() _hbox.pack_start(_textview, True, True, 5) _hbox.show() _frame_box.pack_start(self.__label, False, False, 5) _frame_box.pack_start(_list_box, False, False, 5) _frame_box.show() _frame.add(_frame_box) _frame.show() _main_box.pack_start(_frame, False) _vbox = gtk.VBox() _vbox.pack_start(_hbox, True, True, 5) _vbox.show() _main_box.pack_start(_scrollwindow, True, True, 5) _main_box.show() _scrollwindow.add_with_viewport(_vbox) _scrollwindow.show() self.__widget = _main_box self._setFields() def _setFields(self): """_setFields() Set the fields items in the field treeview """ _record = self.__budget.getRecord(self.__budget.getCode( self.__active_path_record)) _sheet = _record.getSheet() _field_list = _sheet.getFields() self.__field_liststore.clear() for _field in _field_list: _field_text = self.__budget.getSheetField(_field) _iter = self.__field_liststore.append([_field, _field_text]) _treeselection = self.__field_treeview.get_selection() _treeselection.select_path(0) def _setSection(self): """_setSection() Set the section items in the section treeview """ self.__section_liststore.clear() if not self.__field_selection is None: _record = self.__budget.getRecord(self.__budget.getCode( self.__active_path_record)) _sheet = _record.getSheet() _section_list = _sheet.getSections(self.__field_selection) for _section in _section_list: _section_text = self.__budget.getSheetSection(_section) _iter = self.__section_liststore.append([_section, _section_text]) _treeselection = self.__section_treeview.get_selection() _treeselection.select_path(0) def _setText(self): """_setText() Set the text in the textview """ if not self.__section_selection is None and\ not self.__field_selection is None: _record = self.__budget.getRecord(self.__budget.getCode( self.__active_path_record)) _sheet = _record.getSheet() _paragraph_code = _sheet.getParagraph(self.__field_selection, self.__section_selection) _paragraph = self.__budget.getSheetParagraph(_paragraph_code) self.__textbuffer.set_text(_paragraph) else: self.__textbuffer.set_text("") def _field_controlSelection(self, selection): """_controlSelection(selection) selection: treeselection Method connected to set_selection_function() in field treeview This method is called before any node is selected or unselected, giving some control over which nodes are selected. The selection function should return TRUE if the state of the node may be toggled, and FALSE if the state of the node should be left unchanged. When a user select a row in the field treeview the section treeview is reloaded to show the sections of this field and already the text sheet. """ _treeiter = self.__field_liststore.get_iter(selection) self.__field_selection = self.__field_liststore.get_value(_treeiter, 0) self._setSection() return True def _section_controlSelection(self, selection): """_section_controlSelection(selection) selection: treeselection Method connected to set_selection_function() in sector treeview This method is called before any node is selected or unselected, giving some control over which nodes are selected. The selection function should return TRUE if the state of the node may be toggled, and FALSE if the state of the node should be left unchanged. When a user select a row in the field treeview the text sheet for this section in showed """ _treeiter = self.__section_liststore.get_iter(selection) self.__section_selection = self.__section_liststore.get_value(_treeiter, 0) self._setText() return True def _setActivePathRecord(self, path_record): """_setActivePathRecord(path_record)) path_record: active path record Set the new path code to show its sheet of condition text. """ self.__field_selection = None self.__field_liststore.clear() self.__section_selection = None self.__section_liststore.clear() self.__textbuffer.set_text("") _budget = self.__budget self.__active_path_record = path_record _code = _budget.getCode(self.__active_path_record) self.__label.set_text(utils.mapping(_("Sheet2 of Conditions of the "\ "record $1"), (_code,))) self._setFields() def runMessage(self, message, pane_path, arg=None): """runMessage(message, pane_path, arg=None) message: the message type "change_active": change the active record "clear": clear instance pane_path: tuple that identifies the pane in the notebook page arg: tuple whit two items: 0: record path in the budget 1: record code This method receives a message and executes its corresponding action """ _budget = self.__budget if message == "change_active": if _budget.hasPath(arg): self._setActivePathRecord(arg) elif message == "clear": self._clear() def _clear(self): """_clear() Deletes all the instance atributes """ del self.__page del self.__widget del self.__pane_path del self.__budget del self.__active_code del self.__textbuffer del self.__label del self.__textbuffer del self.__label del self.__field_liststore del self.__field_treeview del self.__field_selection del self.__section_liststore del self.__section_treeview del self.__section_selection def _getWidget(self): """_getWidget() return the main widget (gtk.ScrolledWindow) """ return self.__widget def _getPanePath(self): """_getPanePath() return the tuple that identifies the pane in the notebook page """ return self.__pane_path def _setPanePath(self, pane_path): """_setPanePath() sets the tuple that identifies the pane in the notebook page """ self.__pane_path = pane_path def _getPage(self): """_getPage() return the weak reference from Page instance """ return self.__page def _setPage(self, page): """_setPage() set the weak reference from Page instance """ self.__page = page def _getBudget(self): """_getBudget() return the budget object """ return self.__budget def _getActivePathRecord(self): """_getActivePathRecord() return the Active Path Record """ return self.__active_path_record pane_path = property(_getPanePath, _setPanePath, None, "Path that identifie the item in the page notebook") widget = property(_getWidget, None, None, "Lista de configuracion de vistas") page = property(_getPage, _setPage, None, "Weak reference from Page instance which creates this class") budget = property(_getBudget, None, None, "Budget object") active_path_record = property(_getActivePathRecord, None, None, "Active Path Record") class FileView(object): """gui.FileView Description: Class to show the file icons of a record in a pane Constructor: Description(budget, page, pane_path, path_record=(0,)) budget: the budget (base.obra object) page: weak reference from Page instance which creates this class pane_path: the path position of the description in the page path_record: the path of the active record Ancestry: +-- object +-- FileView Atributes: widget: the main widget (gtk.ScrolledWindow object) pane_path: the tuple that identifies the pane in the notebook page budget: The budget (base.obra objetc) active_code: The active code of the record Methods: runMessage """ def __init__(self, budget, page, pane_path, path_record=(0,)): """__init__(budget, page, pane_path, path_record=(0,)) budget: the budget (base.obra object) page: weak reference from Page instance which creates this class pane_path: the path position of the description in the page path_record: the path of the active record self.__budget: the budget (base.obra object) self.__page: weak reference from Page instance which creates this class self.__pane_path: the path position of the description in the page self.__active_path_record: the path of the active record self.__active_code: the code of the active record self.__icon_box: the box that contains the icon self.__widget: main widget, a gtk.ScrolledWindow Creates an shows the scroledwindow that contain icon files of the record to be showed in a pane. """ self.__budget = budget self.__page = page self.__pane_path = pane_path self.__active_path_record = path_record self.__active_code = budget.getCode(self.__active_path_record) _budget = budget _record = self.__budget.getRecord(self.__budget.getCode( self.__active_path_record)) self.__icon_box = self._getIconBox(_record) _scrollwindow = gtk.ScrolledWindow() _scrollwindow.set_policy(gtk.POLICY_ALWAYS, gtk.POLICY_NEVER) self.__icon_box.show() _scrollwindow.add_with_viewport(self.__icon_box) _scrollwindow.show() self.__widget = _scrollwindow def _getIconBox(self, record): """_getIconBox(record) record: the active record object Creates and returns the box whith te icon files of the active record. """ ## TODO: add others filetypes: avi, pdf, ppt... _files = record.getFiles() _hbox = gtk.HBox() _frame = gtk.Frame() _frame.set_shadow_type(gtk.SHADOW_IN) for _file in _files: _path = os.path.dirname(self.__budget.filename) _file_path = os.path.join(_path, _file.name) _filetype = utils.getFiletype(_file_path) _box = gtk.VBox() if _filetype == "image": _event_box = gtk.EventBox() try: _image_pixbuf = gtk.gdk.pixbuf_new_from_file(_file_path) _image_pixbuf = _image_pixbuf.scale_simple(64, 64, gtk.gdk.INTERP_BILINEAR) except: _image_pixbuf = gtk.gdk.pixbuf_new_from_file( globalVars.getAppPath("IMAGE-ICON")) _image_pixbuf = _image_pixbuf.scale_simple(64, 64, gtk.gdk.INTERP_BILINEAR) _image_icon = gtk.Image() _image_icon.set_from_pixbuf(_image_pixbuf) _image_icon.show() _event_box.add(_image_icon) _box.pack_start(_event_box, False, False, 5) _event_box.connect("button-press-event", self._launchFile, "image", _file_path) _event_box.show() elif _filetype == "dxf": _event_box = gtk.EventBox() _dxf_icon = gtk.Image() _dxf_pixbuf = gtk.gdk.pixbuf_new_from_file( globalVars.getAppPath("DXF-ICON")) _dxf_pixbuf = _dxf_pixbuf.scale_simple(64, 64, gtk.gdk.INTERP_BILINEAR) _dxf_icon.set_from_pixbuf(_dxf_pixbuf) _dxf_icon.show() _event_box.add(_dxf_icon) _box.pack_start(_event_box, False, False, 5) _event_box.connect("button-press-event", self._launchFile, "dxf", _file_path) _event_box.show() _label_event_box = gtk.EventBox() _label = gtk.Label(_file.name) _label_event_box.add(_label) _label_event_box.show() _label.show() _box.pack_start(_label_event_box, False, False, 5) _box.show() _hbox.pack_start(_box, False, False, 5) _hbox.show() _frame.add(_hbox) return _frame def _launchFile(self, widget, event, kind, file_path): """_launchFile(widget, event, kind, file_path) widget: the widget that emit the signal event: the event that emit the signal king: kind of file file_path: the path file to be launch Launch the file if a double click emit the signal. Method connected to "button-press-event" signal in images event box """ if event.type is gtk.gdk._2BUTTON_PRESS: openwith.launch_file(kind, file_path) def _setActivePathRecord(self, path_record): """_setActivePathRecord(path_record)) path_record: active path record Set the new path code to show its description text. """ _budget = self.__budget self.__active_path_record = path_record _code = _budget.getCode(self.__active_path_record) _record = self.__budget.getRecord(_code) self.__icon_box.destroy() self.__icon_box = self._getIconBox(_record) self.__icon_box.show() self.__widget.add_with_viewport(self.__icon_box) def runMessage(self, message, pane_path, arg=None): """runMessage(message, pane_path, arg=None) message: the message type "change_active": change the active record "clear": clear instance pane_path: tuple that identifies the pane in the notebook page arg: tuple whit two items: 0: record path in the budget 1: record code This method receives a message and executes its corresponding action """ _budget = self.__budget if message == "change_active": if _budget.hasPath(arg): self._setActivePathRecord(arg) elif message == "clear": self._clear() def _clear(self): """_clear() Delete all instance atributes """ del self.__widget del self.__pane_path del self.__budget del self.__active_code def _getWidget(self): """_getWidget() return the main widget (gtk.ScrolledWindow) """ return self.__widget def _getPanePath(self): """_getPanePath() return the tuple that identifies the pane in the notebook page """ return self.__pane_path def _setPanePath(self, pane_path): """_setPanePath() sets the tuple that identifies the pane in the notebook page """ self.__pane_path = pane_path def _getPage(self): """_getPage() return the weak reference from Page instance """ return self.__page def _setPage(self, page): """setPage() set the weak reference from Page instance """ self.__page = page def _getBudget(self): """getBudget() return the budget object """ return self.__budget def _getActivePathRecord(self): """_getActivePathRecord() return the Active Path Record """ return self.__active_path_record pane_path = property(_getPanePath, _setPanePath, None, "Path that identifie the item in the page notebook") widget = property(_getWidget, None, None, "The main widget (gtk.ScrolledWindow)") page = property(_getPage, _setPage, None, "Weak reference from Page instance which creates this class") budget = property(_getBudget, None, None, "Budget object") active_path_record = property(_getActivePathRecord, None, None, "Active Path Record") class CompanyView(object): """gui.CompanyView: Description: Class to show the company records of a budget Constructor: CompanyView(budget, page, pane_path, path_record=(0,)) budget: budget showed ("base.Budget" object) page: weak reference from Page instance which creates this class pane_path: tuple that represents the path of the List in the Page path_record: path of the active record in the budget Ancestry: +-- object +-- CompanyView Atributes: active_path_record: Read. Path of the active record in the budget widget: Read. Window that contains the main widget, a gtk.HPaned pane_path: Read-Write. Pane page identifier page: Read-Write. weak reference from Page instance which creates this class budget: Read. Budget to show, base.budget instance. Methods: runMessage """ def __init__(self, budget, page, pane_path, path_record=(0,)): """__init__(budget, page, pane_path, path_record=(0,)) budget: budget: budget showed ("base.Budget" object) page: weak reference from Page instance which creates this class pane_path: tuple that represents the path of the List in the Page path_record: path of the active record in the budget self.__selection: self.__budget: budget: budget showed ("base.Budget" object) self.__page: weak reference from Page instance which creates this class self.__pane_path: tuple that represents the path of the List in the Page self.__active_path_record: path of the active record in the budget self.__widget: main widget, a gtk.HPaned self.__treestore: to store companys data self.__option_View: OptionView object Creates an shows the scroledwindow that contain the company data. """ self.__selection = None # Seting init args if not isinstance(budget, base.Budget): raise ValueError, _("Argument must be a Budget object") self.__budget = budget self.__page = page self.__pane_path = pane_path self.__active_path_record = path_record # main widget self.__widget = gtk.HPaned() self.__widget.set_position(230) # TreeStore self.__treestore = gtk.TreeStore(str, str) self._setTreeStoreValues() # Select Treeview _select_treeview = gtk.TreeView(self.__treestore) _select_treeview.set_enable_search(False) _select_treeview.set_reorderable(False) _select_treeview.set_headers_visible(False) _select_treeview.show() # Scrolled_window _scrolled_window = gtk.ScrolledWindow() _scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) _scrolled_window.add(_select_treeview) # colors _text_color = gtk.gdk.color_parse(globalVars.color["TEXT"]) _background_color = [ gtk.gdk.color_parse(globalVars.color["UNEVEN"]), gtk.gdk.color_parse(globalVars.color["EVEN"])] _code_column = gtk.TreeViewColumn() _code_column.set_clickable(True) _code_column.set_fixed_width(200) _code_cell = gtk.CellRendererText() _code_cell.set_property('foreground-gdk', _text_color) _code_column.pack_start(_code_cell, True) _code_column.add_attribute(_code_cell, 'text', 0) _summary_cell = gtk.CellRendererText() _summary_cell.set_property('foreground-gdk', _text_color) _code_column.pack_start(_summary_cell, True) _code_column.add_attribute(_summary_cell, 'text', 1) # Index column _select_treeview.append_column(_code_column) # control selection _treeselection = _select_treeview.get_selection() _treeselection.set_mode(gtk.SELECTION_SINGLE) _treeselection.set_select_function(self._controlSelection) # Show _scrolled_window.show() # Option View self.__option_View = OptionView("") # Selection _select_treeview.set_cursor((0,), None, False) _select_treeview.grab_focus() # self.__widget.add1(_scrolled_window) self.__widget.add2(self.__option_View.widget) self.__widget.show() def _setOptions(self, type): """_setOptions(type) type: "company" or "office" Sets the Options in the OptionView """ if type == "company": _options = [("code", _("Code"), "string", _("""Code that define the company""")), ("summary", _("Summary"), "string", _("""Summary of the company name""")), ("name", _("Name"), "string", _("""Complete name""")), ("cif", _("CIF"), "string", _("""Fiscal identifier number""")), ("web", _("Web"), "string", _("""Company web page""")), ("email", _("Email"), "string", _("""Company email""")), ] self.__option_View.options = _options elif type == "office": _options = [("type", _("Type"), "string", _("""Type of Office: C: Central office D: Local office R: Performer""")), ("subname", _("Name"), "string", _("Office name")), ("address", _("Address"), "string",""), ("postal code", _("Postal code"), "string",""), ("town", _("Town"), "string",""), ("province", _("Province"), "string",""), ("country", _("Country"), "string",""), ("phone", _("Phone"), "list", _("Phone numbers of the office")), ("fax", _("Fax"), "list", _("Fax numbers of the office")), ("contact person", _("Contact person"), "string", _("Contact persons in the office")), ] self.__option_View.options = _options else: print _("Unknow Option Type") def _setTreeStoreValues(self): """_setTreeStoreValues() Sets the treestore values from the budget """ _budget = self.__budget _company_keys = _budget.getCompanyKeys() for _company_key in _company_keys: _company = _budget.getCompany(_company_key) _values = [_company_key, _company.summary] _treeiter = self.__treestore.append(None, _values) _offices = _company.offices for _office in _offices: # TODO: Test offices _values = [_office.officeType, _office.subname] self.__treestore.append(_treeiter, _values) def _controlSelection(self, selection): """_controlSelection(selection) selection: selection Method connected to set_selection_function() This method is called before any node is selected or unselected, giving some control over which nodes are selected. The selection function should return TRUE if the state of the node may be toggled, and FALSE if the state of the node should be left unchanged. The selection changes the company/office in the option treeview """ if len(selection) == 1: # The selection is a company _company_key = self.__treestore[selection][0] _company = self.__budget.getCompany(_company_key) _selection = "company" _values = _company.values else: # The selection is a office _company_key = self.__treestore[selection[:1]][0] _company = self.__budget.getCompany(_company_key) _selection = "office" _office = _company.offices[selection[1]] _values = _office.values if not self.__selection == _selection: self.__selection = _selection self.options = _selection self.__option_View.values = _values return True def _showMessageRecord(self, record_path): """_showMessageRecord(record_path) record_path: the path of the record to show Method connected to "change_active" message Show the record especified in the "change_active" message """ self.__active_path_record = record_path def runMessage(self, message, pane_path, arg=None): """runMessage(message, pane_path, arg=None) message: the message type "change_active": change the active record "clear": clear instance pane_path: tuple that identifies the pane in the notebook page arg: tuple whit two items: 0: record path in the budget 1: record code This method receives a message and executes its corresponding action """ _budget = self.__budget if message == "change_active": if _budget.hasPath(arg): _path_record = arg self._showMessageRecord( _path_record) pass elif message == "clear": self._clear() def _colorCell(self, column, cell_renderer, tree_model, iter, lcolor): """_colorCell(column, cell_renderer, tree_model, iter, lcolor) column: the gtk.TreeViewColumn in the treeview cell_renderer: a gtk.CellRenderer tree_model: the gtk.TreeModel iter: gtk.TreeIter pointing at the row lcolor: list with 2 gtk colors for even and uneven record Method connected to "set_cell_data_func" of many column The set_cell_data_func() method sets the data function (or method) to use for the column gtk.CellRenderer specified by cell_renderer. This function (or method) is used instead of the standard attribute mappings for setting the column values, and should set the attributes of the cell renderer as appropriate. func may be None to remove the current data function. The signature of func is: -def celldatafunction(column, cell, model, iter, user_data) -def celldatamethod(self, column, cell, model, iter, user_data) where column is the gtk.TreeViewColumn in the treeview, cell is the gtk.CellRenderer for column, model is the gtk.TreeModel for the treeview and iter is the gtk.TreeIter pointing at the row. The method sets cell background color for all columns and text for index and amount columns. """ _row_path = tree_model.get_path(iter) _number = _row_path[-1] if column is self.__index_column: cell_renderer.set_property('text', str(_number + 1)) self.__index_column.get_cell_renderers()[1].set_property( 'cell-background-gdk', lcolor[_number % 2]) if self.__treeview.get_cursor() == (_row_path,column): cell_renderer.set_property('cell-background-gdk', gtk.gdk.color_parse(globalVars.color["ACTIVE"])) else: cell_renderer.set_property('cell-background-gdk', lcolor[_number % 2]) def _clear(self): """_clear() it deletes the self.__budget value """ del self.__budget def _getWidget(self): """_getWidget() return the main widget (gtk.ScrolledWindow) """ return self.__widget def _getPanePath(self): """_getPanePath() return the tuple that identifies the pane in the notebook page """ return self.__pane_path def _setPanePath(self, pane_path): """_setPanePath() sets the tuple that identifies the pane in the notebook page """ self.__pane_path = pane_path def _getPage(self): """_getPage() return the Page """ return self.__page def _setPage(self,page): """_setPage() set the Page """ self.__page = page def _getBudget(self): """_getBudget() return the Budget objet """ return self.__budget def _getActivePathRecord(self): """_getActivePathRecord() return the Active Path Record """ return self.__active_path_record active_path_record = property(_getActivePathRecord, None, None, "Active path record") widget = property(_getWidget, None, None, "main widget") pane_path = property(_getPanePath, _setPanePath, None, "Path that identifies the item in the page notebook") page = property(_getPage, _setPage, None, "Weak reference from Page instance which creates this class") budget = property(_getBudget, None, None, "Budget object") class OptionView(object): """gui.OptionView: Description: It creates a treeview whith the column "Option Name" "Value" and "Type" to show and edit Options Constructor: OptionView(option_list) option_list: list of options (option_name, type) Ancestry: +-- object +-- OptionView Atributes: widget: Read. Main widget options: Write values: Write Methods: """ def __init__(self, option_list): """__init__(option_list) self.__option_dict: {"option key" : ["option name", "value", "option type", "option_description"]} self.__option_list: option keys list self.__option_types: valid option types list self.__liststore: gtk.ListStore self.__treeview: gtk.TreeView self.__option_column: option column self.__value_column: value column self.__type_column: type column self.__description_label: gtk.Label self.__widget: Main widget Creates an shows the widget that contain the option data. """ self.__option_dict = {} self.__option_list = [] self.__option_types = {"boolean" : _("Boolean"), "integer": _("Integer"), "string": _("Text"), "color" : _("Color"), "list" : _("List")} # ListStore self.__liststore = gtk.ListStore(str, str, str, str, str) # Treeview self.__treeview = gtk.TreeView(self.__liststore) self.__treeview.set_enable_search(False) self.__treeview.set_reorderable(False) self.__treeview.set_headers_clickable(False) # vbox _vbox = gtk.VBox() # Scrolled_window _scrolled_window = gtk.ScrolledWindow() _scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) _scrolled_window.add(self.__treeview) _scrolled_window.show() _vbox.pack_start(_scrolled_window) # colors _text_color = gtk.gdk.color_parse(globalVars.color["TEXT"]) _background_color = [ gtk.gdk.color_parse(globalVars.color["UNEVEN"]), gtk.gdk.color_parse(globalVars.color["EVEN"])] # Option Column self.__option_column = gtk.TreeViewColumn() self.__option_column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) self.__option_column.set_fixed_width(150) self.__option_column.set_resizable(True) _option_cell = gtk.CellRendererText() _option_cell.set_property('foreground-gdk', _text_color) self.__option_column.pack_start(_option_cell, True) self.__option_column.set_cell_data_func(_option_cell, self._colorCell, _background_color) self.__option_column.set_title(_("Option name")) self.__option_column.add_attribute(_option_cell, 'text', 1) self.__treeview.append_column(self.__option_column) # Value Column self.__value_column = gtk.TreeViewColumn() self.__value_column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) self.__value_column.set_fixed_width(275) self.__value_column.set_resizable(True) _value_cell = gtk.CellRendererText() _value_cell.set_property('foreground-gdk', _text_color) self.__value_column.pack_start(_value_cell, True) self.__value_column.set_cell_data_func(_value_cell, self._colorCell, _background_color) self.__value_column.set_title(_("Value")) self.__value_column.add_attribute(_value_cell, 'text', 2) self.__treeview.append_column(self.__value_column) # Type Column self.__type_column = gtk.TreeViewColumn() self.__type_column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) self.__type_column.set_fixed_width(70) self.__type_column.set_resizable(True) _type_cell = gtk.CellRendererText() _type_cell.set_property('foreground-gdk', _text_color) self.__type_column.pack_start(_type_cell, True) self.__type_column.set_cell_data_func(_type_cell, self._colorCell, _background_color) self.__type_column.set_title(_("Type")) self.__treeview.append_column(self.__type_column) # End Column _end_column = gtk.TreeViewColumn() _end_column.set_clickable(False) _end_cell = gtk.CellRendererText() _end_cell.set_property('cell-background-gdk', gtk.gdk.color_parse(globalVars.color["UNEVEN"])) _end_column.pack_start(_end_cell, True) self.__treeview.append_column(_end_column) # Connect self.__treeview.connect("key-press-event", self._treeviewKeyPressEvent) self.__treeview.connect("button-press-event", self._treeviewClickedEvent) # control selection _treeselection = self.__treeview.get_selection() _treeselection.set_mode(gtk.SELECTION_MULTIPLE) _treeselection.set_select_function(self._controlSelection) # labels _frame = gtk.Frame() _frame.set_shadow_type(gtk.SHADOW_OUT) _vbox2 = gtk.VBox() _frame.add(_vbox2) _alignement = gtk.Alignment(xalign=0, yalign=0, xscale=0, yscale=0) _alignement.set_padding(0, 0, 12, 0) _label = gtk.Label() _label.set_markup("<b>" + _("Description:") + "</b>") _label.show() _alignement.add(_label) _alignement.show() _alignement2 = gtk.Alignment(xalign=0, yalign=0, xscale=0, yscale=0) _alignement2.set_padding(0, 0, 24, 0) self.__description_label = gtk.Label() self.__description_label.show() _alignement2.add(self.__description_label) _alignement2.show() _vbox2.pack_start(_alignement, False) _vbox2.pack_start(_alignement2, False) _vbox2.show() _frame.show() _vbox.pack_start(_frame, False) # Show self.__treeview.show() _vbox.show() self.__widget = _vbox def _treeviewKeyPressEvent(self, widget, event): """_treeviewKeyPressEvent(widget, event) widget: treewiew widget event: Key Press event Method connected to "key-press-event" signal The "key-press-event" signal is emitted when the user presses a key on the keyboard. Returns :TRUE to stop other handlers from being invoked for the event. Returns :FALSE to propagate the event further. If the user press the right cursor button and the cursor is in the value column or pres the left cursor button and the cursor is in the value column the event is estoped, else the event is propagated. """ (_cursor_path, _column) = self.__treeview.get_cursor() if (event.keyval == gtk.keysyms.Right \ and _column == self.__value_column) \ or (event.keyval == gtk.keysyms.Left \ and _column == self.__value_column): return True else: _description = self.__liststore[_cursor_path][4] self.__description_label.set_text(_description) return False def _treeviewClickedEvent(self, widget, event): """_treeviewClickedEvent(widget, event) widget: treewiew widget event: clicked event Method connected to "button-press-event" signal The "button-press-event" signal is emitted when a mouse button is pressed. Returns TRUE to stop other handlers from being invoked for the event. Returns FALSE to propagate the event further. The cursos is moved to value column. """ path_at_pos = self.__treeview.get_path_at_pos(int(event.x), int(event.y)) if not path_at_pos is None: _path_cursor, _column, _x, _y = path_at_pos _description = self.__liststore[_path_cursor][4] self.__description_label.set_text(_description) if _column == self.__value_column: return False else: self.__treeview.set_cursor(_path_cursor,self.__value_column, True) self.__treeview.grab_focus() return True return True def _controlSelection(self, selection): """_controlSelection(selection) selection: treeselection Method connected to set_selection_function() This method is called before any node is selected or unselected, giving some control over which nodes are selected. The selection function should return TRUE if the state of the node may be toggled, and FALSE if the state of the node should be left unchanged. Return False so none row is selected """ return False def _colorCell(self, column, cell_renderer, tree_model, iter, lcolor): """_colorCell(column, cell_renderer, tree_model, iter, lcolor) column: the gtk.TreeViewColumn in the treeview cell_renderer: a gtk.CellRenderer tree_model: the gtk.TreeModel iter: gtk.TreeIter pointing at the row lcolor: list with 2 gtk colors for even and uneven record Method connected to "set_cell_data_func" of the column The set_cell_data_func() method sets the data function (or method) to use for the column gtk.CellRenderer specified by cell_renderer. This function (or method) is used instead of the standard attribute mappings for setting the column values, and should set the attributes of the cell renderer as appropriate. func may be None to remove the current data function. The signature of func is: -def celldatafunction(column, cell, model, iter, user_data) -def celldatamethod(self, column, cell, model, iter, user_data) where column is the gtk.TreeViewColumn in the treeview, cell is the gtk.CellRenderer for column, model is the gtk.TreeModel for the treeview and iter is the gtk.TreeIter pointing at the row. The method sets cell background color for all columns and text for type column. """ _row_path = tree_model.get_path(iter) _number = _row_path[-1] if self.__treeview.get_cursor() == (_row_path,column): cell_renderer.set_property('cell-background-gdk', gtk.gdk.color_parse(globalVars.color["ACTIVE"])) else: cell_renderer.set_property('cell-background-gdk', lcolor[_number % 2]) if column is self.__type_column: _type = self.__option_types[tree_model[_row_path][3]] cell_renderer.set_property('text', _type) def _setOptions(self, option_list): """_setOptions(option_list) option_list: list of tuples (option, option name, type) option: option identifier option name: a string with the option name Description: a string with the option description type: can be "boolean" "integer" "string" "color" Sets the Options in the treeview rows """ self.__option_dict = {} self.__option_list = [] self.__liststore.clear() if isinstance(option_list, list): for _option in option_list: if isinstance(_option, tuple) and len(_option) == 4: _option_key = _option[0] _option_name = _option[1] _option_type = _option[2] _option_description = _option[3] if isinstance(_option_key, str) and \ (isinstance(_option_name, str) or\ isinstance(_option_name, unicode))and \ _option_type in self.__option_types.keys(): self.__liststore.append([_option_key, _option_name, "", _option_type, _option_description]) self.__option_dict[_option_key] = [_option_name, "", _option_type, _option_description] self.__option_list.append(_option_key) else: print _("Option values must be strings") else: print _("Option must be a tuple with 4 items") else: print _("Option list must be a list") def _setValues(self, values): """_setValues(values) values: dictionary {option : value} Sets the Options values """ if isinstance(values, dict): for _option, _value in values.iteritems(): if _option in self.__option_dict: _type = self.__option_dict[_option][2] if _type == "boolean": if isinstance(_value, bool): _num = self.__option_list.index(_option) _iter = self.__liststore.get_iter((_num,)) self.__liststore.set_value(_iter, 2, _value) self.__option_dict[_option][1] = _value else: print _("Icorrect type, must be boolean") elif _type == "integer": try: _value = int(_value) except ValueError: print _("Icorrect type, must be integer") else: _num = self.__option_list.index(_option) _iter = self.__liststore.get_iter((_num,)) self.__liststore.set_value(_iter, 2, _value) self.__option_dict[_option][1] = _value elif _type == "string": if isinstance(_value, str): _num = self.__option_list.index(_option) _iter = self.__liststore.get_iter((_num,)) self.__liststore.set_value(_iter, 2, _value) self.__option_dict[_option][1] = _value else: print _("Icorrect type, must be string") elif _type == "list": if isinstance(_value, list): _num = self.__option_list.index(_option) _iter = self.__liststore.get_iter((_num,)) _str_value = "" for _item_value in _value: _str_value = _str_value + _item_value + "," if _str_value[-1] == ",": _str_value = _str_value[:-1] self.__liststore.set_value(_iter, 2, _str_value) self.__option_dict[_option][1] = _value else: print _("Icorrect type, must be list") elif _type == "color": if isinstance(_value, str): try: _color = gtk.gdk.color_parse(_value) except ValueError: print _("Icorrect type, must be a parseable " \ "color") else: _num = self.__option_list.index(_option) _iter = self.__liststore.get_iter((_num,)) self.__liststore.set_value(_iter, 2, _value) self.__option_dict[_option][1] = _value else: print _("Type must be boolean, integer, string or "\ "color") else: print _("Value must be in the option dict") else: print _("Values must be a dict") self.__treeview.set_cursor((0),self.__value_column, False) self.__treeview.grab_focus() (_cursor_path, _column) = self.__treeview.get_cursor() _description = self.__liststore[_cursor_path][4] self.__description_label.set_text(_description) def _getWidget(self): """_getWidget() return the main widget (gtk.ScrolledWindow) """ return self.__widget widget = property(_getWidget, None, None, "main widget") values = property(None, _setValues, None, "values") options = property(None, _setOptions, None, "options")