Mercurial > pyarq-presupuestos
view Gtk/gui.py @ 7:0359329a1c26
Navigation buttons. Version of the data structure.
author | Miguel Ángel Bárcena Rodríguez <miguelangel@obraencurso.es> |
---|---|
date | Thu, 11 Nov 2010 23:22:35 +0100 |
parents | 2fc6b47dbe70 |
children | 55df0b15706b |
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 TextWindow class show the long description 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"],)) 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: "window": Main window widget ("gtk.Window" object) Methods: removePage getNotebook getPageList getBudgetList """ # TODO:* Can choose open budget in new window # TODO:* gtk.Action for menu and toolbar # 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="GoUp"/> <menuitem action="GoDown"/> <menuitem action="GoPrevious"/> <menuitem action="GoPosterior"/> <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="GoUp"/> <toolitem action="GoDown"/> <toolitem action="GoPrevious"/> <toolitem action="GoPosterior"/> <toolitem action="GoToRoot"/> </toolbar> </ui>''' def __init__(self): """def __init__(self) Initialize the atributes "__budget_list" and "__page_list" without data. Creates the widgets "window" and "__notebook". self.__budget_temp_list: Temporal list of budgets self.__budget_list: List of budgets ("base.Budget" objects) self.__page_list: List of pages ("Page" object) self.__notebook: Notebook widget ("gtk.Notebook" object) self.__general_action_group: "General" action group """ #TODO: action group for Navigation buttons self.__budget_temp_list = [] self.__budget_list = [] 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 _uimanager = gtk.UIManager() _accelgroup = _uimanager.get_accel_group() self.window.add_accel_group(_accelgroup) _general_action_group = gtk.ActionGroup("General") self.__general_action_group = _general_action_group _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")), ("GoUp", gtk.STOCK_GO_UP, _("_Up Record"),"", _("Go up record"), self._menuitemGoUp), ("GoDown", gtk.STOCK_GO_DOWN, _("_Down Record"),"", _("Go down record"), self._menuitemGoDown), ("GoPrevious", gtk.STOCK_GO_BACK, _("_Previous Record"),"", _("Go Previous record"), self._menuitemGoPrevious), ("GoPosterior", gtk.STOCK_GO_FORWARD, _("_Posterior Record"),"", _("Go posterior record"), self._menuitemGoPosterior), ("GoToRoot", gtk.STOCK_GOTO_TOP, _("_Root"),"", _("Go to root"), self._menuitemGoToRoot), ("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), ]) _uimanager.insert_action_group(_general_action_group, 0) _uimanager.add_ui_from_string(self.__ui) _menu_bar = _uimanager.get_widget("/MenuBar") _vbox1.pack_start(_menu_bar, False, False, 0) _toolbar = _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) # 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.show() self._main() def _main(self): """def main(self) Shows window and starts the GTK+ event processing loop. """ self.window.show() gtk.main() def _addBudget(self, budget): """def _addBudget(self, budget) budget: "base.Budget" object Appends a budget in the "__budget_list" """ if not budget is None: _budget = budget if _budget in self.__budget_temp_list: self.__budget_temp_list.remove(_budget) self.__budget_list.append(_budget) def _appendPage(self): """def _appendPage(self) Creates a new page (instance of "Page class") from the last budget in __budget_list, appends this page in the "__page_list" and shows the page widget in the notebook widget. """ _last_budget = self.__budget_list[-1] _page = Page(self, _last_budget) self.__notebook.append_page(_page.widget, _page.title) self.__page_list.append(_page) def _menuitemImportFiebdc(self, widget): """def _menuitemImportFiebdc(self, 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() self.__budget_temp_list.append(_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): """def _menuitemImportPriceDatabase(self, 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() self.__budget_temp_list.append(_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): """def _menuitemOpenPriceDatabase(self, 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 self.__budget_temp_list.append(_budget) _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): """def _menuitemClose(self, 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 removePage(self, page_num): """def removePage(self, page_num) page_num: The number Page to be removed Removes a page from notebook and page_list. Removes the budget from the budget_list if necessary. """ _page = self.__page_list[page_num] if isinstance(_page, Page): #not loading budget self.__budget_list.pop(page_num) self.__page_list.pop(page_num) _page.clear() self.__notebook.remove_page(page_num) def _menuitemGoToRoot(self, widget): """def _menuitemGoToRoot(self, 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): """def _menuitemGoUp(self, 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 and _active_path[-1] > 0: _budget = self.__budget_list[_page_num] _up_path = _active_path[:-1] + (_active_path[-1] - 1,) if _budget.hasPath(_up_path): _page.propagateMessageFrom("change_active", (-1,), _up_path) def _menuitemGoDown(self, widget): """def _menuitemGoToDown(self, widget) widget: the widget where the event is emitted from Callback to go to down 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 = self.__budget_list[_page_num] _up_path = _active_path[:-1] + (_active_path[-1] + 1,) if _budget.hasPath(_up_path): _page.propagateMessageFrom("change_active", (-1,), _up_path) def _menuitemGoPrevious(self, widget): """def _menuitemGoPrevious(self, 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 = self.__budget_list[_page_num] if _budget.hasPath(_previous_path): _page.propagateMessageFrom("change_active", (-1,), _previous_path) def _menuitemGoPosterior(self, widget): """def _menuitemPosterior(self, 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 = self.__budget_list[_page_num] if _budget.hasPath(_posterior_path): _page.propagateMessageFrom("change_active", (-1,), _posterior_path) def _delete_event(self, widget, event): """_delete_event(self, 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(self, 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() def getNotebook(self): """def getNotebook(self) Return the notebook widget """ return self.__notebook def getPageList(self): """def getPageList(self) Return the page list """ return self.__page_list def getBudgetList(self): """def getBudgetList(self) Return the budget list """ return self.__budget_list 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(self, mainWindow, readFileMethod, budget, filename, cancelMethod, filetype): Ancestry: +-- object +-- EmptyPage Atributes: __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" __children: the read thread __progress: 0 to 1 progress __widget: main widget, a gtk.VBox object __main_item: None __throbber: a gtk.Image __animationThobber: a gtk.gdk.PixbufAnimation __quietThobber: a pixbuf __budget_icon: a gtk.gdk.pixbuf __title: a gtk.HBox __statusbar: a gtk.Statusbar __statuscontext: the statusbar context __progress_bar: a gtk.ProgressBar Methods: __init__ run progress stopLoading _launchChildren _launchTimeout _updateProgressBar _updateLabel _autoClose threadFinishedSignal threadCanceled close clear getWidget getTitle getFiletype """ def __init__(self, mainWindow, readFileMethod, budget, filename, cancelMethod, filetype): """def __init__(self, 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 = 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_at_size( globalVars.getAppPath("BUDGET-ICON"), 16, 16) _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): self.__statusbar.push(self.__statuscontext, _("Time: 0s")) self.__throbber.set_from_animation(self.__animationThobber) self._launchChildren() self._launchTimeout() def progress(self, percent): _progress = str(int(round(100 * percent,0))) self.__progress = percent def stopLoading(self): self.__throbber.set_from_pixbuf(self.__budget_icon) self.__progress_bar.hide() self.__statusbar.pop(self.__statuscontext) def _launchChildren(self): """_launchChildren(self) 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): """def _launchTimeout(self) 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): """def _updateProgressBar(self) 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): """def _updateProgressBar(self) 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): """def _updateProgressBar(self) 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): """def closeWindow(self) Sets the __children atribute to None This causes that the timeouts is ended. This method is called from thread when it is finished """ 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) _noteBook = self.__mainWindow.getNotebook() _pageIndex = _noteBook.page_num(self.__widget) self.__mainWindow.getPageList()[_pageIndex] = _page def threadCanceled(self): """def threadCanceled(self) Sets the __children atribute to None This causes that the timeouts is ended. This method is called from thread when is canceled TODO: it must called threadFinished or somethig """ self.__children = None self.stopLoading() _page_num = self.__mainWindow.getNotebook().page_num(self.widget) self.__mainWindow.removePage(_page_num) def close(self): """def close(self) Clos page canceling children """ self.__children.cancel() def clear(self): """def clear(self) clear vars """ pass def getWidget(self): """def getWidget(self) Return de main widget to show in the page """ return self.__widget def getTitle(self): """def getTitle(self) Return the title of the page, a gtk.Label objetc """ return self.__title def getFiletype(self): """def getFiletipe(self) 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 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,)): """def __init__(self, budget=None, active_code=None) mainWindow: MainWindow object budget: "base.Budget" object path_record: the active path record """ #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.setBudget(budget) self._setActivePathRecord(path_record) self.__widget.show() def propagateMessageFrom(self, message, pane_path, arg=None): """def propagateMessageFrom(self, 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) 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): """def sendMessageTo(self, 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.path == pane_path: pane.runMessage(message, pane_path, arg) def close(self): """def close(self) Close Page """ _page_list = self.__mainWindow.getPageList() if self in _page_list: _page_num = _page_list.index(self) self.__mainWindow.removePage(_page_num) else: raise IndexError, _("The page is not in the page list") def clear(self): """def clear(self) 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): """def getItem(self, 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(self,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(self, 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.setPath(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(self, 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,)): """def _itemsFactory(self, 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): """def _setActivePathRecord(self, 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): """def _appendHistory(self, path)) path: the old active path record Sets the old active path record """ if len(self.__history_back) > 1 and self.__history_back[-2] == path: # append forward history and pop back history _path = self.__history_back.pop() self.__history_forward.append(_path) if len(self.__history_forward) > 1000: self.__history_forward.pop(0) else: # append back history and pop or delete forward history if len(self.__history_forward) > 1 and \ self.__history_forward[-1] == path: self.__history_forward.pop() else: self.__history_forward[:] = [] self.__history_back.append(path) if len(self.__history_back) > 1000: self.__history_back.pop(0) def getActivePathRecord(self): """def getActivePathRecord(self) Return the Active Path Record """ return self.__active_path_record def getPreviousPathRecord(self): """def getPreviousPathRecord(self) Return the Previous Path Record """ if len(self.__history_back) > 1: return self.__history_back[-2] else: return None def getPosteriorPathRecord(self): """def getPosteriorPathRecord(self) Return the Posterior Path Record """ if len(self.__history_forward) > 0: return self.__history_forward[-1] else: return None def getTitle(self): """def getTitle(self) Return the page title, a gtk.Label objetc """ return self.__title def getWidget(self): """def getWidget(self) Return de main widget to show in the pane """ return self.__widget def setBudget(self, budget): """def setBudget(self, 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.getWidget() _main_widget.show() self.__widget.pack_start(_main_widget, True, True, 0) def getBudget(self): """def getBudget(self) Return de budget, a "base.Budget" object. """ return self.__budget def getPanesList(self): """def getPanesList(self) 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") class View(object): """gui.View: Description: It creates a view to show the budget info Constructor: View(view_type, budget, wr_page, path, active_path_record) Ancestry: +-- object +-- Paned Atributes: "path": the tuple that identifies the view in the main notebook page "widget": the main gtk widget to show in a view object, a gtk.VBox object "__view_type": the object type to show * DecompositionList * Description * Measure * Sheet of conditions * FileView * CompanyView "__wr_page": weak reference to the page where the view must be showed "__budget": the budget to show "__view ": the object to show: * DecompositionList object * Description object * Measure object * Sheet object * FileView object * Comapany View "__connected": boolean value, True means that the View object sends and receives signals from/to others views "__connected_button": a button to switch __connected True or False Methods: __init__(self) getItem(self, path) _closeItem(self, close_button) _change_combo(self, combobox) propagateMessgeFrom(self, message, path, arg=None) runMessage(self, message, path, arg=None) getWidget(self) getPath(self) setPath(self) getClone(self, newpath) clear(self) """ def __init__(self, view_type, budget, wr_page, path, active_path_record): """def __init__(self, view_type, budget, wr_page, 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 path: the position or path of the view in the page notebook active_path_record: the record path that must be showed 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.__path = 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) _vbox = gtk.VBox() _vbox.show() _toolitem = gtk.ToolItem() _toolitem.set_expand(True) _toolitem.add(_vbox) _toolitem.show() self.__widget = gtk.Toolbar() self.__widget.insert(_toolitem, 0) _hbox = gtk.HBox() if view_type == "DecompositionList": self.__view = DecompositionList(budget, weakref.ref(self), 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), 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), 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), 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), 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), 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() _vbox.pack_start(_hbox,False) _vbox.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, path): """def getItem(self, path) Return itself. """ return self def _closeItem(self, close_button): """_closeItem(self, widget) 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.__path) def _change_combo(self, combobox): """_change_combo(self, 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 _path = self.__view.path _path_record = self.__view.active_path_record _toolitem = self.__widget.get_nth_item(0) _vbox= _toolitem.get_children()[0] _hbox = _vbox.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) _vbox.remove(self.__view.widget) _vbox.remove(_hbox) _hbox.destroy() _view_icon = gtk.Image() if _index == 0: self.__view = DecompositionList(_budget, _wr_page, _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, _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, _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, _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, _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, _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() _vbox.pack_start(_hbox, False, False, 0) _vbox.pack_start(self.__view.widget, True, True, 0) def _menu_view(self, widget): """_menu_view(self, 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(self, 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.__path) def _connected(self, widget): """_connected(self, 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, path, arg=None): """def propagateMessageFrom(self, message, path, arg=None) message: string message 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, path, arg) def runMessage(self, message, path, arg=None): """def runMessage(self, message, path, arg=None) message: the message type "change_active": change the active record "clear": clear instance 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, path, arg) if message == "change_active": if self.__budget.hasPath(arg): _path_record = arg self.__active_path_record = _path_record def getWidget(self): """def getWidget(self) Return de pane widget """ return self.__widget def getPath(self): """def getPath(self) return the tuple that identifies the pane in the notebook page """ return self.__view.path def setPath(self, path): """def setPath(self) set the tuple that identifies the pane in the notebook page """ self.__path = path self.__view.path = path def getClone(self, new_path): """getClone(self, new_path) new_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_path, self.__active_path_record) def clear(self): """clear(self) Clear the intance atributes """ del self.__wr_page del self.__budget del self.__path del self.__widget del self.__view del self.__connected del self.__connected_button path = property(getPath, setPath, 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 Returns the newly created Paned instance Ancestry: +-- object +-- Paned Atributes: "widget": Pane widget("gtk.VPaned" or "gtk.HPaned" object) "__orientation": The orientation of de gtk.Paned, can be "v" or "h" "__items": list of items showed in the paned, its can be View or Paned instances "__path": the paned path in the page Methods: __init__(self) __getitem__(self, item) getClone(self, new_path) getItem(self, path) runMessage(self, messge, path, arg=None) getWidget(self) {get/set}Path clear(self) """ # TODO: *control the position paned separator. Now is always 200 pixels # 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 # TODO: *control the position pane separator when the size of the window # TODO: change with the same ascpect ratio def __init__(self, orientation, path, item1, item2): """def __init__(self, oritentation, path, item1, item2) orientation: The orientation of de gtk.Paned, can be "v" or "h" path: the paned path in the page item1: the top or left pane object item2: the bottom or right pane object 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.set_position(200) self.__widget.show() self.__items = [item1, item2] self.__path = path def __getitem__(self, item): """__getitem__(self, 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_path): """getClone(self, new_path) Return a clone Paned instance with the path new_path """ return Paned(self.__orientation, new_path, self.__items[0].getClone(new_path + (0,)), self.__items[1].getClone(new_path + (1,))) def getItem(self,path): """def getItem(self, path) Return the item whith the specified path. """ _item = self.__items[path[0]] if len(path) == 1: return _item else: return _item.getItem(path[1:]) def setItem(self, path, item_list): """def setItem(self, 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 path == 0 or path == 1: _old_item = self.__items[path] self.__widget.remove(_old_item.widget) self.__items[path] = item if 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, path, arg=None): """def runMessage(self, message, page_path, arg=None) message: the message type "change_active": change the active record "clear": clear instance page_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.path == path: _item.runMessage(message, path, arg) def getWidget(self): """def getWidget(self) Return de gtk.Paned widget """ return self.__widget def getPath(self): """def getPath(self) Return de Paned path in the notebook page """ return self.__path def setPath(self, path): """def setPath(self) sets the tuple that identifies the pane in the notebook page """ self.__path = path self.__items[0].path = path + (0,) self.__items[1].path = path + (1,) def clear(self): del self.__widget del self.__orientation del self.__items del self.__path widget = property(getWidget, None, None, "gtk.Paned widget") path = property(getPath, setPath, 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 isntances) Methods: __init__(self) __getitem__(self, item) createColumn(self, args) createTextBaseColumn(self,args) createBaseColumn(self,args) """ def __init__(self, args): """__init__(self, 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(self, 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(self,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(self,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, path) budget: budget showed ("base.Budget" object) page: weak reference from Page instance which creates this class path: tuple that represents the view path in the Page Returns the newly created DecompositionList instance Ancestry: +-- object +-- TreeView +-- DecompositionList Atributes: "budget": Budget to show, base.obra instance. "widget or __scrolled_window": Window that contains the table, (gtk.ScrolledWindow) "path": Pane page identifier "page": weak reference from Page instance which creates this class "__active_color": background color of the active cell, a gtk.gdk.Color object "__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] "__methond_message": Method to send messages to the page "__liststore": list model which store the list data (gtk.ListStore object) "__treeview": widget for displaying decomposition lists (gtk.TreeView) "__index_column": Index column (gtk.TreeViewColumn object) "__code_column": Record code column (gtk.TreeViewColumn) "__unit_column": Unit of measure column (gtk.TreeViewColumn) "__description_column": record's short description column (gtk.TreeViewColumn) "__measure_column": Measure column (gtk.TreeViewColumn) "__price_column": Price column (gtk.TreeViewColumn) "__amount_column": Amount column(gtk.TreeViewColumn) "__end_column": End empty column (gtk.TreeViewColumn) "__treeselection": active selection "__selection_control": state of the selection control (True/False) "__cursor": cursor position in the table Methods: __init__(self, budget) treeviewCursorChanged(self, treeview) treeviewClickedEvent(self, widget, event) treeviewKeyPressEvent(self, widget, event) moveCursor(self, treeview, step, count) controlSelection(self, selection) selectAll(self, column) setColumnsHeaders(self) setListstoreValues(self, puntero, treeiter=None) colorCell(self, column, cell_renderer, tree_model, iter, lcolor) _claculateAmount(self, row_path, tree_model) showParentRecord(self, column) showMessageRecord(self, camino,_code): showRowRecord(self, treeview, path, column) runMessage(self, messagem path, arg=None) _clear(self) getWidget(self) {get/set}Path {get/seg}Page getBudget(self) getActivePathRecord(self) """ def __init__(self, budget, page, path, path_record=(0,)): """def __init__(self, budget, page, path) budget: budget showed ("base.Budget" object) page: weak reference from Page instance which creates this class path: tuple that represents the path of the List in the Page 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.__path = path # ListStore self.__liststore = gtk.ListStore(object #, int, int, str, str, str, str, str,str ) if path_record is None: print _("DecompositionList.__init__: 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): """def treeviewCursorChanged(self, 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): """def treeviewClickedEvent(self, 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): """def treeviewKeyPressEvent(self, 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): """def treeviewKeyPressEvent(self, widget, event) 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): """def controlSelection(self, 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): """def selectAll(self, 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): """def setColumnsHeaders(self) 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): """def setListstoreValues(self, 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): """def colorCell(self, 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): """def showParentRecord(self, 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.__path, arg) self.__treeview.set_cursor(_parent, self.__cursor[1]) self.__cursor = self.__treeview.get_cursor() def showMessageRecord(self, record_path): """def showMessageRecord(self, 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): """def showRowRecord(self, 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.__path, _arg ) def runMessage(self, message, path, arg=None): """def runMessage(self, message, path, arg=None) message: the message type "change_active": change the active record "clear": clear instance 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): """def _clear(self) it deletes the __budget value this would not be necessary if there were not circular references, which are pending to fix """ del self.__budget def getWidget(self): """def getWidget(self) return the main widget (gtk.ScrolledWindow) """ return self.__scrolled_window def getPath(self): """def getPath(self) return the tuple that identifies the pane in the notebook page """ return self.__path def setPath(self, path): """def setPath(self) sets the tuple that identifies the pane in the notebook page """ self.__path = path def getPage(self): """def getPage(self) return the Page """ return self.__page def setPage(self,page): """def setPage(self) set the Page """ self.__page = page def getBudget(self): """def getBudget(self) return the Budget objet """ return self.__budget def getActivePathRecord(self): """def getActivePathRecord(self) return the Active Path Record """ return self.__active_path_record widget = property(getWidget, None, None, "Pane configuration list") path = property(getPath, setPath, 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, path) budget: budget showed ("base.Budget" object) page: weak reference from Page instance which creates this class path: tuple that represents the path of the List in the Page Returns the newly created DecompositionList instance Ancestry: +-- object +-- TreeView +-- DecompositionList Atributes: "budget": Budget to show, base.obra instance. "__active_path_record": path of the active record in the budget "widget or __scrolled_window": Window that contains the table, (gtk.ScrolledWindow) "path": Pane page identifier "page": weak reference from Page instance which creates this class "__active_color": The background color of the active cell as a gtk.gdk.Color object "__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] "__methond_message": Method to send messages to the page "__liststore": list model which store the list data (gtk.ListStore object) "__treeview": widget for displaying decomposition lists (gtk.TreeView) "__index_column": Index column (gtk.TreeViewColumn object) "__code_column": Record code column (gtk.TreeViewColumn) "__unit_column": Unit of measure column (gtk.TreeViewColumn) "__description_column": record's short description column (gtk.TreeViewColumn) "__measure_column": Measure column (gtk.TreeViewColumn) "__price_column": Price column (gtk.TreeViewColumn) "__amount_column": Amount column(gtk.TreeViewColumn) "__end_column": End empty column (gtk.TreeViewColumn) "__treeselection": active selection "__selection_control": state of the selection control (True/False) "__cursor": Situation of the cursor in the table Methods: __init__(self, budget, page, path, path_record=(0,)) setListstoreValues(self, path_record) setColumnsHeaders(self) controlSelection(self, selection) showMessageRecord(self, record_path) treeviewCursorChanged(self, treeview) moveCursor(self, treeview, step, count) treeviewClickedEvent(self, widget, event) treeviewKeyPressEvent(self, widget, event) runMessage(self, message, path, arg=None) selectAll(self, column) colorCell(self, column, cell_renderer, tree_model, iter, lcolor) _clear(self) getWidget(self) {get/set}Path {get/set}Page getBudget(self) getActivePathRecord(self) """ def __init__(self, budget, page, path, path_record=(0,)): """def __init__(self, budget, page, path, path_record=(0,)) budget: budget: budget showed ("base.Budget" object) page: weak reference from Page instance which creates this class path: tuple that represents the path of the List in the Page path_record: path of the active record in the budget 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.__path = 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), ]) 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, args): pass def setListstoreValues(self, path_record): """def setListstoreValues(self, 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, ## _line.type, ## _line.comment, ## _line.units, ## _line.length, ## _line.width, ## _line.height ] _treeiter = self.__liststore.append(_values) else: raise ValueError, utils.mapping(_("measure must be a Measure "\ "object. Type: $1"), (type(_measure),)) def setColumnsHeaders(self): """def setColumnsHeaders(self) 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): """def controlSelection(self, 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): """def showMessageRecord(self, 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): """def treeviewCursorChanged(self, 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): """def treeviewKeyPressEvent(self, widget, event) 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): """def treeviewClickedEvent(self, 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): """def treeviewKeyPressEvent(self, 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, path, arg=None): """def runMessage(self, message, path, arg=None) message: the message type "change_active": change the active record "clear": clear instance 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): """def selectAll(self, 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): """def colorCell(self, 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): """def _clear(self) it deletes the __budget value this would not be necessary if there were not circular references, which are pending to fix """ del self.__budget def getWidget(self): """def getWidget(self) return the main widget (gtk.ScrolledWindow) """ return self.__scrolled_window def getPath(self): """def getPath(self) return the tuple that identifies the pane in the notebook page """ return self.__path def setPath(self, path): """def setPath(self) sets the tuple that identifies the pane in the notebook page """ self.__path = path def getPage(self): """def getPage(self) return the Page """ return self.__page def setPage(self,page): """def setPage(self) set the Page """ self.__page = page def getBudget(self): """def getBudget(self) return the Budget objet """ return self.__budget def getActivePathRecord(self): """def getActivePathRecord(self) return the Active Path Record """ return self.__active_path_record widget = property(getWidget, None, None, "Pane configuration list") path = property(getPath, setPath, 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: budget code: code record Ancestry: +-- object +-- Description Atributes: "widget": the main widget (gtk.ScrolledWindow object) "path": the tuple that identifies the pane in the notebook page TODO "budget": The budget (base.obra objetc) "active_code": The active code of the record "__textbuffer": The textbuffer of the textview that contain the record text. "__label": The gtk.label with the title of the pane Methods: __init__(self, budget, code) setActiveCode(self, code) runMessage(self, message, nt, arg=None) _clear(self) getWidget(self) {get/set}Path {get/seg}Page getBudget(self) getActviCode(self) """ # TODO: make standar: "DecompositonList and Description" def __init__(self, budget, page, path, path_record=(0,)): """def __init__(self, budget, page, path, path_record=(0,)) budget: the budget (base.obra object) page: weak reference from Page instance which creates this class path: the path position of the description in the page path_record: the path of the active record 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.__path = 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): """def setActivePathRecord(self, 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, path, arg=None): """def runMessage(self, message, path, arg=None) message: the message type "change_active": change the active record "clear": clear instance 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): """def _clear(self) Delete all instance atributes """ del self.__widget del self.__path del self.__budget del self.__active_code del self.__textbuffer del self.__label def getWidget(self): """def getWidget(self) return the main widget (gtk.ScrolledWindow) """ return self.__widget def getPath(self): """def getPath(self) return the tuple that identifies the pane in the notebook page """ return self.__path def setPath(self, path): """def setPath(self) sets the tuple that identifies the pane in the notebook page """ self.__path = path def getPage(self): """def getPage(self) return the weak reference from Page instance """ return self.__page def setPage(self, page): """def setPage(self) set the weak reference from Page instance """ self.__page = page def getBudget(self): """def getBudget(self) return the budget object """ return self.__budget def getActivePathRecord(self): """def getActivePathRecord(self) return the Active Path Record """ return self.__active_path_record path = property(getPath, setPath, 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.ScrolledWindow object) "path": the tuple that identifies the pane in the notebook page "budget": The budget (base.obra objetc) "active_path_record": The active path record "page": weak reference from Page instance which creates this class "__textbuffer": The textbuffer of the textview that contain the record text. "__label": The gtk.label with the title of the pane "__field_liststore": the field liststore "__field_treeview": the field treeview "__field_selection": the field selected in field treview "__section_liststore": the section liststore "__section_treeview": the section treeview "__section_selection": the section selected in the section treeview Methods: __init__(self, budget, code) setFields(self) setSection(self) setText(self) field_controlSelection(self, selection) section_controlSelection(self, selection) runMessage(self, message, nt, arg=None) _clear(self) getWidget(self) {get/set}Path {get/set}Page getBudget(self) getActviPathRecord(self) """ def __init__(self, budget, page, path, path_record=(0,)): """def __init__(self, budget, page, path, path_record=(0,)) budget: the budget (base.obra object) page: weak reference from Page instance which creates this class path: the path position of the description in the page path_record: the path of the active record 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.__path = 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(self) 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(self) 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(self) 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): """def controlSelection(self, 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): """def controlSelection(self, 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): """def setActivePathRecord(self, 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, path, arg=None): """def runMessage(self, message, path, arg=None) message: the message type "change_active": change the active record "clear": clear instance 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): """def _clear(self) Deletes all the instance atributes """ del self.__page del self.__widget del self.__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): """def getWidget(self) return the main widget (gtk.ScrolledWindow) """ return self.__widget def getPath(self): """def getPath(self) return the tuple that identifies the pane in the notebook page """ return self.__page def setPath(self, path): """def setPath(self) sets the tuple that identifies the pane in the notebook page """ self.__path = path def getPage(self): """def getPage(self) return the weak reference from Page instance """ return self.__page def setPage(self, page): """def setPage(self) set the weak reference from Page instance """ self.__page = page def getBudget(self): """def getBudget(self) return the budget object """ return self.__budget def getActivePathRecord(self): """def getActivePathRecord(self) return the Active Path Record """ return self.__active_path_record path = property(getPath, setPath, 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, code) budget: budget code: code record Ancestry: +-- object +-- Description Atributes: "widget": the main widget (gtk.ScrolledWindow object) "__icon_box": the box that contains the icon "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: __init__(self, budget, code) setActiveCode(self, code) runMessage(self, message, nt, arg=None) _clear(self) getWidget(self) {get/set}Path {get/seg}Page getBudget(self) getActviCode(self) """ def __init__(self, budget, page, path, path_record=(0,)): """def __init__(self, budget, page, path, path_record=(0,)) budget: the budget (base.obra object) page: weak reference from Page instance which creates this class path: the path position of the description in the page path_record: the path of the active record 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.__path = 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(self, 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(self, 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): """def setActivePathRecord(self, 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, path, arg=None): """def runMessage(self, message, path, arg=None) message: the message type "change_active": change the active record "clear": clear instance 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): """def _clear(self) Delete all instance atributes """ del self.__hbox del self.__widget del self.__path del self.__budget del self.__active_code def getWidget(self): """def getWidget(self) return the main widget (gtk.ScrolledWindow) """ return self.__widget def getPath(self): """def getPath(self) return the tuple that identifies the pane in the notebook page """ return self.__path def setPath(self, path): """def setPath(self) sets the tuple that identifies the pane in the notebook page """ self.__path = path def getPage(self): """def getPage(self) return the weak reference from Page instance """ return self.__page def setPage(self, page): """def setPage(self) set the weak reference from Page instance """ self.__page = page def getBudget(self): """def getBudget(self) return the budget object """ return self.__budget def getActivePathRecord(self): """def getActivePathRecord(self) return the Active Path Record """ return self.__active_path_record path = property(getPath, setPath, 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 TextWindow(object): """gui.TextWindow Description: Class to show a description text of a record in a new gtk window Constructor: TextWindow(code, text) code: code of the record text: description text of the record Ancestry: +-- object +-- TextWindow Atributes: Methods: __init__(self, code, text) main(self) destroy(self, widget) """ def __init__(self, code, text): """def __init__(self, code, text) code: code of the record text: description text of the record Creates an shows the window. """ _window = gtk.Window(gtk.WINDOW_TOPLEVEL) _window.set_resizable(True) _window.set_default_size(700, 300) _window.set_title(utils.mapping(_("$1 text"), (code,))) _window.set_border_width(0) _box1 = gtk.VBox(False, 0) _window.add(_box1) _box1.show() _sw = gtk.ScrolledWindow() _sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) _textview = gtk.TextView() _textview.set_wrap_mode(gtk.WRAP_WORD) _textbuffer = _textview.get_buffer() _sw.add(_textview) _sw.show() _textview.show() _box1.pack_start(_sw) _textbuffer.set_text(text) _window.connect("destroy", self.destroy) _window.show() def main(self): """def main(self) Starts the GTK+ event processing loop. """ gtk.main() def destroy(self, widget): """destroy(self, widget) widget: the widget where the event is emitted from Method connected to "destroy" signal of 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 CompanyView(object): """gui.CompanyView: Description: Class to show the company records of a budget Constructor: CompanyView(budget, page, path) budget: budget showed ("base.Budget" object) page: weak reference from Page instance which creates this class path: tuple that represents the path of the List in the Page Returns the newly created CompanyView instance Ancestry: +-- object +-- CompanyView Atributes: "budget": Budget to show, base.obra instance. "active_path_record" "widget": Window that contains the main widget, (gtk.ScrolledWindow) "path": Pane page identifier "page": weak reference from Page instance which creates this class "__methond_message": Method to send messages to the page Methods: __init__(self, budget, page, path, path_record=(0,)) runMessage(self, message, path, arg=None) _clear(self) getWidget(self) {get/set}Path {get/set}Page getBudget(self) getActivePathRecord(self) """ def __init__(self, budget, page, path, path_record=(0,)): """def __init__(self, budget, page, path, path_record=(0,)) budget: budget: budget showed ("base.Budget" object) page: weak reference from Page instance which creates this class path: tuple that represents the path of the List in the Page path_record: path of the active record in the budget Sets the init atributes Creates the """ 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.__path = path self.__active_path_record = path_record # HVox self.__hbox = gtk.HPaned() self.__hbox.set_position(230) # TreeStore self.__treestore = gtk.TreeStore(str, str) self.setTreeStoreValues() # Select Treeview self.__select_treeview = gtk.TreeView(self.__treestore) self.__select_treeview.set_enable_search(False) self.__select_treeview.set_reorderable(False) self.__select_treeview.set_headers_visible(False) self.__select_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.__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"])] self.__code_column = gtk.TreeViewColumn() self.__code_column.set_clickable(True) self.__code_column.set_fixed_width(200) _code_cell = gtk.CellRendererText() _code_cell.set_property('foreground-gdk', _text_color) self.__code_column.pack_start(_code_cell, True) self.__code_column.add_attribute(_code_cell, 'text', 0) _summary_cell = gtk.CellRendererText() _summary_cell.set_property('foreground-gdk', _text_color) self.__code_column.pack_start(_summary_cell, True) self.__code_column.add_attribute(_summary_cell, 'text', 1) # Index column self.__select_treeview.append_column(self.__code_column) # control selection self.__treeselection = self.__select_treeview.get_selection() self.__treeselection.set_mode(gtk.SELECTION_SINGLE) self.__treeselection.set_select_function(self.controlSelection) # Show self.setColumnsHeaders() self.__scrolled_window.show() # Option View self.__option_View = OptionView("") # Selection self.__select_treeview.set_cursor((0,), None, False) self.__select_treeview.grab_focus() # self.__hbox.add1(self.__scrolled_window) self.__hbox.add2(self.__option_View.widget) self.__hbox.show() self.__widget = self.__hbox def setOptions(self, type): 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.setOptions(_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.setOptions(_options) else: print _("Unknow Option Type") def setOptionValues(self, company_key): self.__option_View.setValues(_values) def setTreeStoreValues(self): """def setListstoreValues(self) 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 setColumnsHeaders(self): """def setColumnsHeaders(self) Sets the headers column values """ #self.columns[1].set_title(_("Type")) # Σ parcial Σ total #self.columns[2].set_title(_("Comment")) #self.columns[3].set_title(_("N")) #self.columns[4].set_title(_("Length")) #self.columns[5].set_title(_("Width")) #self.columns[6].set_title(_("Height")) pass def controlSelection(self, selection): """def controlSelection(self, 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.setOptions(_selection) self.__option_View.setValues(_values) return True def showMessageRecord(self, record_path): """def showMessageRecord(self, 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, path, arg=None): """def runMessage(self, message, path, arg=None) message: the message type "change_active": change the active record "clear": clear instance 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): """def colorCell(self, 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): """def _clear(self) it deletes the __budget value this would not be necessary if there were not circular references, which are pending to fix """ del self.__budget def getWidget(self): """def getWidget(self) return the main widget (gtk.ScrolledWindow) """ return self.__widget def getPath(self): """def getPath(self) return the tuple that identifies the pane in the notebook page """ return self.__path def setPath(self, path): """def setPath(self) sets the tuple that identifies the pane in the notebook page """ self.__path = path def getPage(self): """def getPage(self) return the Page """ return self.__page def setPage(self,page): """def setPage(self) set the Page """ self.__page = page def getBudget(self): """def getBudget(self) return the Budget objet """ return self.__budget def getActivePathRecord(self): """def getActivePathRecord(self) 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") path = property(getPath, setPath, 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: "__liststore" "__treeview" "__option_column" "__value_column" "__type_column" "__treeselection" "__widget": Main windget "__option_list" "__option_dict" "__description_label" "option_types" "widget": __widget Methods: __init__(self, option_list) createColumn(self, args) createTextBaseColumn(self,args) createBaseColumn(self,args) """ def __init__(self, option_list): """__init__(self, option_list) """ 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 self.__treeselection = self.__treeview.get_selection() self.__treeselection.set_mode(gtk.SELECTION_MULTIPLE) self.__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): """def treeviewKeyPressEvent(self, 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): """def treeviewClickedEvent(self, 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): """def controlSelection(self, 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): """def colorCell(self, 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(self, 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") return def setValues(self, values): """setValues(self, 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): """def getWidget(self) return the main widget (gtk.ScrolledWindow) """ return self.__widget widget = property(getWidget, None, None, "main widget")