view Gtk/gui.py @ 5:6502bfdaa84d

update import durus database
author Miguel Ángel Bárcena Rodríguez <miguelangel@obraencurso.es>
date Sat, 06 Nov 2010 21:30:33 +0100
parents 4e976a99efb9
children 2fc6b47dbe70
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 de 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 globals
from Generic import openwith

# Load default icon
if os.path.exists(globals.getAppPath("ICON")):
    icon = gtk.gdk.pixbuf_new_from_file(globals.getAppPath("ICON"))
    gtk.window_set_default_icon_list(icon)
else:
    print utils.mapping(_("The icon file does not exist. '$1'"),
          (globals.getAppPath("ICON"),))

# Autodetect desktop
if globals.desktop["autodetect"]:
    openwith.autodetect_desktop()
    print utils.mapping(_("pyArq-Presupuestos running on $1"),
                        (globals.desktop["desktop"],))

class MainWindow(object):
    """gui.MainWindow:
    
    Description:
        Creates and shows the main window.
        This is the interface base class.
    Constructor:
        gui.MainWindow(): Returns the newly created main window instance
    Ancestry:
    +-- object
      +-- MainWindow
    Atributes:
        "window": Main window widget ("gtk.Window" object)
        "__budget_temp_list": Temporal list of budgets
        "__budget_list": List of budgets ("base.Budget" objects)
        "__page_list": List of pages ("Page" object)
        "__notebook": Notebook widget ("gtk.Notebook" object)
        "__general_action_group": the "General" action group
    Methods:
        __init__(self)
        _main(self)
        _addBudget(self, budget)
        _appendPage(self)
        _testBudgetList(self)
        _menuitemImportFiebdc(self, widget)
        _menuitemImportPriceDatabase(self, widget)
        _menuitemOpenPriceDatabase(self, widget)
        _menuitemOpen
        _menuitemClose(self, widget)
        _delete_event(self, widget, event)
        _destroy(self, widget)
    """
    # 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="Test">
        <menuitem action="ImportFiebdcPriceDatabase"/>
        <menuitem action="OpenPriceDatabase"/>
      </menu>
    </menubar>
    <toolbar name="ToolBar">
      <toolitem action="ImportFiebdc"/>
      <separator/>
      <toolitem action="Close"/>
      <separator name="sep1"/>
    </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 = []
        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")),
             ("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(_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 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 budget file.
        
        Creates and shows a 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 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:
            return
        #_page = self.__page_list.pop(_page_num)
        _page = self.__page_list[_page_num]
        if isinstance(_page, Page):
            #not loading budget
            self.__budget_list.pop(_page_num)
        if isinstance(_page, EmptyPage) and _page.filetype == "durus":
            print _("Cancel reading Durus database has not been implemented.")
        else:
            self.__page_list.pop(_page_num)
            _page.clear()
            self.__notebook.remove_page(_page_num)

    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):
        return self.__notebook
    def getPageList(self):
        return self.__page_list
    def getBudgetList(self):
        return self.__budget_list

class EmptyPage(object):
    """
    """
    def __init__(self, mainWindow, readFileMethod, budget, filename,
                 cancelMethod, filetype):
        """def __init__(self, mainWindow, readFileMethod, budget, filename,
                        cancelMethod, filetype)
        
        """
        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(globals.getAppPath("THROBBER-ICON"))
        self.__throbber.show()
        self.__animationThobber = gtk.gdk.PixbufAnimation(
                                  globals.getAppPath("THROBBER-GIF"))
        self.__quietThobber = self.__throbber.get_pixbuf()
        self.__budget_icon = gtk.gdk.pixbuf_new_from_file_at_size(
                             globals.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(globals.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.__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()

    def clear(self):
        """def clear(self)
        
        Cancel thread
        """
        self.__children.cancel()
        
    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(budget, active_code=None):
        budget: budget to be showed in this page (base.Budget object)
        active_code: the code of the active record 
        Returns the newly created Page instance
    Ancestry:
    +-- object
      +-- Page
    Atributes:
        "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
        "widget": Read. Notebook page Widget. (a gtk.VBox instance)
        "title": Read. Notebook page title (gtk.Label object)
        "__active_path_record": The active path record
        "__main_item": main item in the page, can be a View object or a Paned 
            object
    Methods:
        __init__(self, budget=None, active_code=None)
        propagateMessageFrom(self, message, path, arg=None)
        sendMessageTo(self, pane, message, path, arg=None)
        clear(self)
        getItem(self,path)
        setMainItem(self, item)
        itemsFactory(self, list_paned, path=(0,))
        setActivePathRecord(self, path_record)
        getTitle(self)
        getWidget(self)
        setBudget(self, budget)
        getBudget(self)
        getPanesList(self)
    """
    # 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, budget, path_record=(0,)):
        """def __init__(self, budget=None, active_code=None)
        
        budget: "base.Budget" object
        active_code: the code of the active record
        Sets the atributes
            * __panes_list: info to create the panes
            * budget (base.Budget object)
            * active_code
        """
        #TODO: __panes_list should come from config file...
        self.__widget = gtk.VBox()
        self.__panes_list = [ "v", "DecompositionList", [ "v", "Measure",
            "RecordDescription" ]]
        self.__main_item = None
        self.setBudget(budget)
        self.setActivePathRecord(path_record)
        self.__widget.show()

    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
             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, path, arg)
        elif message == "autoclose":
            self._closeItem(path)
        elif message == "split h":
            self._splitItem(path, "h")
        elif message == "split v":
            self._splitItem(path, "v")
            
    def sendMessageTo(self, pane, message, path, arg=None):
        """def sendMessageTo(self, pane,message, path, arg=None)
        pane: the receiver pane
        message: string message
        path: tuple that represents the pane path which emits the message
        arg: arguments for the message
        
        Sends a message to a pane
        """
        if not pane.path == path:
            pane.runMessage(message, path, arg)

    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,path):
        """def getItem(self, path
        
        Return the item whith the path "path", it can return a Paned instance
        or a View instance
        """
        _item = self.__main_item
        if len(path) == 1:
            return _item
        else:
            return _item.getItem(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, path, orientation):
        """_splitItem(self, path, orientation)
        
        Splits the item that is identifies by the path and the orientation
        """
        _item = self.getItem(path)
        _parent = self.getItem(path[:-1])
        _item.setPath(path+ (0,))
        _item_clone0 = _item.getClone(path + (0,))
        _item_clone1 = _item.getClone(path + (1,))
        _paned = Paned(orientation, path, _item_clone0, _item_clone1)
        if len(path) > 1:
            _parent.setItem(path[-1], [_paned])
        else:
            self.setMainItem(_paned)
        
    def _closeItem(self, path):
        """_closeItem(self, path)
        
        Closes the item that is identifies by the path
        """
        _item = self.getItem(path)
        if len(path) > 1:
            # There are more than one item
            _parent = self.getItem(path[:-1])
            _brothers = [ _brother for _brother in _parent]
            _brothers.remove(_item)
            _brother = _brothers[0]
            
            _parent.widget.remove(_brother.widget)
            _brother.path = path[:-1]
            if len(path) > 2:
                _grandparent = self.getItem(path[:-2])
                _grandparent.setItem(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, path=(0,)):
        """def itemsFactory(self, list_paned, 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"
        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],path + (0,))
            _item2 = self.itemsFactory(list_paned[2],path + (1,)) 
            _item = Paned(list_paned[0], path, _item1, _item2)
        elif list_paned[0] == "DecompositionList":
            _item = View( "DecompositionList", self.__budget,
                weakref.ref(self), path, self.__active_path_record)
        elif list_paned[0] == "RecordDescription":
            _item = View( "RecordDescription", self.__budget,weakref.ref(self),
                path, self.__active_path_record)
        elif list_paned[0] == "Measure":
            _item = View( "Measure", self.__budget, weakref.ref(self), path,
                self.__active_path_record)
        elif list_paned[0] == "Sheet of Conditions":
            _item  = Sheet(sef.__budget, weakref.ref(self), path,
                self.__active_path_record)
        elif list_paned[0] == "FileView":
            _item  = FileView(sef.__budget, weakref.ref(self), path,
                self.__active_path_record)
        elif list_paned[0] == "CompanyView":
            _item  = CompanyView(sef.__budget, weakref.ref(self), 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 self.__budget.hasPath(path_record):
            self.__active_path_record = path_record
        else:
            raise ValueError, utils.mapping(_("The budget does not have the "\
                  "path record: $1"), (str(path_record),))

    def getTitle(self):
        """def getTtle(self)
        
        Return the title of the page, 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")

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(globals.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(globals.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(globals.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(globals.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(globals.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(globals.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(globals.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(globals.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(globals.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(globals.getAppPath("DECOMPOSITION-ICON"))
            self.__view_type = "DecompositionList"
        elif _index == 1:
            self.__view = Description(_budget, _wr_page, _path,
                         _path_record)
            _view_icon.set_from_file(globals.getAppPath("DESCRIPTION-ICON"))
            self.__view_type = "RecordDescription"
        elif _index == 2:
            self.__view = Measure(_budget, _wr_page, _path,
                         _path_record)
            _view_icon.set_from_file(globals.getAppPath("MEASURE-ICON"))
            self.__view_type = "Measure"
        elif _index == 3:
            self.__view = Sheet(_budget, _wr_page, _path,
                         _path_record)
            _view_icon.set_from_file(globals.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(globals.getAppPath("SHEET-ICON"))
            self.__view_type = "FileView"
        elif _index == 5:
            self.__view = CompanyView(_budget, _wr_page, _path,
                          _path_record)
            _view_icon.set_from_file(globals.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(globals.getAppPath("DISCONNECTED-ICON"))
            _icon.show()
            self.__connected_button.set_icon_widget(_icon)
            self.__connected = False
        else:
            _icon = gtk.Image()
            _icon.set_from_file(globals.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(globals.color["TEXT"]))
            _pixbuf_index_cell = gtk.CellRendererPixbuf()
            _arrow_icon = gtk.gdk.pixbuf_new_from_file(
                globals.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(globals.color["INDEX-UNEVEN"]),
                gtk.gdk.color_parse(globals.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(globals.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(globals.color["TEXT"])
        _background_color = [
            gtk.gdk.color_parse(globals.color["UNEVEN"]),
            gtk.gdk.color_parse(globals.color["EVEN"])]
        self.__chapter_background_colors = [
            gtk.gdk.color_parse(globals.color["CHAPTER-UNEVEN"]),
            gtk.gdk.color_parse(globals.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(globals.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(
            globals.getAppPath("CHAPTER-ICON"))
        self.unit_icon  = gtk.gdk.pixbuf_new_from_file(
            globals.getAppPath("UNIT-ICON") )
        self.material_icon  = gtk.gdk.pixbuf_new_from_file(
            globals.getAppPath("MATERIAL-ICON") )
        self.machinery_icon = gtk.gdk.pixbuf_new_from_file(
            globals.getAppPath("MACHINERY-ICON"))
        self.labourforce_icon = gtk.gdk.pixbuf_new_from_file(
            globals.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(globals.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(globals.color["TEXT"])
        _calculated_text =gtk.gdk.color_parse(globals.color["CALCULATED-TEXT"])
        _background_color = [
            gtk.gdk.color_parse(globals.color["UNEVEN"]),
            gtk.gdk.color_parse(globals.color["EVEN"])]
        self.__chapter_background_colors = [
            gtk.gdk.color_parse(globals.color["CHAPTER-UNEVEN"]),
            gtk.gdk.color_parse(globals.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(
            globals.getAppPath("CALCULATEDLINE-ICON"))
        self.normalline_icon  = gtk.gdk.pixbuf_new_from_file(
            globals.getAppPath("NORMALLINE-ICON") )
        self.parcialline_icon  = gtk.gdk.pixbuf_new_from_file(
            globals.getAppPath("PARCIALLINE-ICON") )
        self.acumulatedline_icon = gtk.gdk.pixbuf_new_from_file(
            globals.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(
                               globals.color["SUBTOTAL-PARCIAL"])
                    _subtotal = _measure_line.parcial_subtotal
                else: #elif _type == 2:
                    _color = gtk.gdk.color_parse(globals.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(globals.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(
                                    globals.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(
                                    globals.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(globals.color["TEXT"])
        _background_color = [
            gtk.gdk.color_parse(globals.color["UNEVEN"]),
            gtk.gdk.color_parse(globals.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(globals.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(globals.color["TEXT"])
        _background_color = [
            gtk.gdk.color_parse(globals.color["UNEVEN"]),
            gtk.gdk.color_parse(globals.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(globals.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(globals.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