view Gtk/gui.py @ 23:65e7ae0d0e63

GTK2 to GTK3
author Miguel Ángel Bárcena Rodríguez <miguelangel@obraencurso.es>
date Thu, 02 May 2019 16:31:17 +0200
parents 7bd4ca56607d
children 189f8274aecd
line wrap: on
line source

# -*- coding: utf-8 -*-
## File gui.py
## This file is part of pyArq-Presupuestos.
##
## Copyright (C) 2010-2019 Miguel Ángel Bárcena Rodríguez
##                         <miguelangel@obraencurso.es>
##
## pyArq-Presupuestos is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## pyArq-Presupuestos is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program.  If not, see <http://www.gnu.org/licenses/>.
##

"""Gui module

The MainWindow class contain the toplevel WINDOW,
this window have a notebook with a page for each budget.
Each budget or notebook page is showed by the Page class, this class contain
the main widget showed in a page notebook.
The main widget can show the budget information in several panes.
This panes are ordened in Gtk.Paned represented for the class Paned which can
have 2 viewes represented for the View class or other Gtk.Paned that have other
viewes or more Gtk.Paned.
The view can have diferente type of widgets to show the budget information.
The DecompositionList class show the decompositon list information of a record
The Measure class show the measure information of a record
The Sheet class class show the sheet of condition information of a record

The views can send signal to the others.
All the viewes ordered in panes can be or not be connected to the others,
if there are connecteded to the others when the user change the active code in
one of the panes the active code change in the others.

"""
# TODO: Config file

# Modules

# python 2/3 compatibility
from __future__ import absolute_import, division, print_function, unicode_literals

# Standar Modules
import sys
import os
import time

# gui
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from gi.repository import GdkPixbuf
from gi.repository import Gio
from gi.repository import GLib
from gi.repository import Gdk
from gi.repository import Pango

import weakref

# pyArq-Presupuestos Modules
from Gtk import importFiebdc
from Generic import base
from Generic import fiebdc
from Generic import utils
from Generic import globalVars
from Generic import openwith

# Load default icon
_icons = [ "ICON16", "ICON32","ICON64","ICON128"]
_pixbufIcons = []
for _icon in _icons:
    if os.path.exists(globalVars.getAppPath(_icon)):
        _pixbufIcon = GdkPixbuf.Pixbuf.new_from_file(globalVars.getAppPath(_icon))
        _pixbufIcons.append(_pixbufIcon)
    else:
        print(utils.mapping(_("The icon file does not exist. '$1'"),
          (str(globalVars.getAppPath(_icon)),)) )
if len(_pixbufIcons) > 0:
    Gtk.Window.set_default_icon_list(_pixbufIcons)

else:
    print(utils.mapping(_("The icon file does not exist. '$1'"),
          (str(globalVars.getAppPath("ICON")),)) )

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


class App(Gtk.Application):
    """gui.App:
    
    Description:
        This is the Gtk application base class.
    Constructor:
        App()
    Ancestry:
    +-- Gtk.Application https://lazka.github.io/pgi-docs/Gtk-3.0/classes/Application.html
      +-- App
    Atributes:
    Methods:
        do_activate
        do_startup
        do_open
    """

    def __init__(self, *args, **kwargs):
        """__init__()
        
        Sets the application id and application_name.
        """
        self.filesToOpen = []
        self._application_id = "es.obraencurso.pyarq.presupuestos"
        super(App, self).__init__(application_id=self._application_id,
                                  flags=Gio.ApplicationFlags.HANDLES_OPEN,
                                  **kwargs)
        GLib.set_prgname(self._application_id)

    def do_open(self, files, n_files, hint):
        """do_open(files, n_files, hint)
        
        Set the filename list to open.
        """
        self.filesToOpen = files
        self.activate()
        self.filesToOpen = []
        return 0

    def do_activate(self):
        """do_activate()
        
        Shows new appplication windows.
        """
        _mainWindow = MainWindow(self, self.filesToOpen )
        _mainWindow.window.present_with_time(GLib.get_monotonic_time() / 1000)

    def do_startup(self):
        """do_startup()
        
        Sets the app actions.
        """
        Gtk.Application.do_startup(self)
        # App Actions
        action = Gio.SimpleAction.new("newWindow", None)
        action.connect("activate", self._on_newWindow)
        self.add_action(action)

        action = Gio.SimpleAction.new("acell_newWindow", None)
        action.connect("activate", self._on_control_n)
        self.add_action(action)

        action = Gio.SimpleAction.new("about", None)
        action.connect("activate", self._on_about)
        self.add_action(action)

        action = Gio.SimpleAction.new("quit", None)
        action.connect("activate", self._on_quit)
        self.add_action(action)
        
        action = Gio.SimpleAction.new("acell_quit", None)
        action.connect("activate", self._on_control_q)
        self.add_action(action)
        
        # App menu
        _app_menu = Gio.Menu()
        _section_window = Gio.Menu()
        _section_window.append(_("_New window"), "app.newWindow")
        _section_window.append(_("_Close window"), "win.CloseWindow")
        _app_menu.append_section(None,_section_window)
        self.set_accels_for_action('win.acell_close', ["<Primary>x"])
        self.set_accels_for_action('app.acell_newWindow', ["<Primary>n"])
        _section_general = Gio.Menu()
        _section_general.append(_("About") + " " + globalVars.name, "app.about")
        _app_menu.append_section(None,_section_general)
        _section_quit = Gio.Menu()
        _section_quit.append(_("_Quit application"), "app.quit")
        self.set_accels_for_action('app.acell_quit', ["<Primary>q"])
        _app_menu.append_section(None,_section_quit)
        self.set_app_menu(_app_menu)
        # TODO : from gui config
        win_menu = False
        # Win Menu
        if win_menu:
            _win_menu = Gio.Menu()
            _win_submenu_file = Gio.Menu.new()
            _import_fiebdc = Gio.MenuItem.new(_("_Import Fiebdc"), "win.ImportFiebdc")
            _import_fiebdc.set_icon(Gio.Icon.new_for_string("document-open"))
            _win_submenu_file.append_item(_import_fiebdc)
        
            _close_tab = Gio.MenuItem.new(_("_Close tab"), "win.CloseTab")
            _close_tab.set_icon(Gio.Icon.new_for_string("window-close"))
            _win_submenu_file.append_item(_close_tab)
        
            _win_menu.append_submenu(_("_File"), _win_submenu_file)
            _win_submenu_go = Gio.Menu.new()
            _back = Gio.MenuItem.new(_("_Back"), "win.GoPrevious")
            _back.set_icon(Gio.Icon.new_for_string("go-previous"))
            _win_submenu_go.append_item(_back)
            _forward = Gio.MenuItem.new(_("_Forward"), "win.GoPosterior")
            _forward.set_icon(Gio.Icon.new_for_string("go-next"))
            _win_submenu_go.append_item(_forward)
            _up = Gio.MenuItem.new(_("_Up Item"), "win.GoUp")
            _up.set_icon(Gio.Icon.new_for_string("go-up"))
            _win_submenu_go.append_item(_up)
            _root = Gio.MenuItem.new(_("_Root"), "win.GoToRoot")
            _root.set_icon(Gio.Icon.new_for_string("go-top"))
            _win_submenu_go.append_item(_root)
            _win_menu.append_submenu(_("_Go"), _win_submenu_go)
            self.set_menubar(_win_menu)

    def _on_newWindow(self, action, param):
        """on_newWindow(action, param)
        
        Shows new appplication windows.
        """
        _mainWindow = MainWindow(self, [])
        _mainWindow.window.present_with_time(GLib.get_monotonic_time() / 1000)

    def _on_about(self, action, param):
        """_on_about(action, param)
        
        Shows About dialog.
        """
        _aboutDialog = Gtk.AboutDialog(modal=False)
        _aboutDialog.set_program_name(globalVars.name)
        _aboutDialog.set_copyright(base.copyright)
        _aboutDialog.set_authors(base.authors)
        _aboutDialog.set_version(globalVars.version + globalVars.changeset)
        _aboutDialog.set_website(base.website)
        _aboutDialog.set_website_label(base.website_label)
        _aboutDialog.set_license_type(Gtk.License(3))
        _aboutDialog.set_comments(base.comments)
        _aboutDialog.connect("response", self._on_close_aboutdialog)
        _aboutDialog.present_with_time(GLib.get_monotonic_time() / 1000)

    def _on_close_aboutdialog(self, action, parameter):
        """on_close_aboutdialog(action, param)
        
        Close About dialog.
        """
        action.destroy()

    def _on_control_q(self, action, param):
        """on_control_q(action, param)
        
        Quit app.
        """
        print("Control q -> Quit app")
        self.quit()

    def _on_quit(self, action, param):
        """_on_quit(action, param)
        
        Quit app.
        """
        self.quit()

    def _on_control_n(self, action, param):
        """on_control_n(action, param)
        
        Shows new appplication windows.
        """
        print("Control n -> New window")
        self._on_newWindow(action, param)


class MainWindow(object):
    """gui.MainWindow:
    
    Description:
        Creates and shows the main window.
        This is the interface base class.
    Constructor:
        MainWindow(app, files)
    Ancestry:
    +-- object
      +-- MainWindow
    Atributes:
        self.window: Gtk.ApplicationWindow object
    Methods:
        changeHistorySignal
        changeActiveSignal
        appendEmptyPage
        updatePage
        closePage
    """
    # TODO:* Can choose open budget in new window
    # TODO:* Can choose show more than one notebook in the same window or
    # TODO:  can show basedata notebook in a side pane

    def __init__(self, app, files):
        """__init__(app, files)
        
        Initialize the atributes self.__page_list without data.
        Creates the widgets "window" and "__notebook".
        
        app: Gtk.Application instance
        files: Gio.file list from command line
        
        self.window: Gtk.ApplicationWindow object
        self.__page_list: List of pages ("Page" object)
        self.__notebook: Notebook widget ("Gtk.Notebook" object)
        self.__general_action_group: "General" action group
        self.__navigation_action_group: "Navigation" action group
        self.__navigation_is_enabled: True/False
        self.__goBack_button
        """
        self.__page_list = []
        # Main window
        self.window = Gtk.ApplicationWindow(application=app)
        self.window.set_default_size(771, 570)
        self.window.set_title("Presupuestos")
        self.window.set_border_width(5)
        self.window.connect("delete_event", self._delete_event)
        # HeaderBar
        _hb = Gtk.HeaderBar()
        _hb.set_show_close_button(True)
        _hb.props.title = "Presupuestos"
        self.window.set_titlebar(_hb)
        _hb.show()
        # Actions
        # General Actions
        self.__general_action_group = Gio.SimpleActionGroup.new()
        # CloseWindow Action
        _action = Gio.SimpleAction.new("CloseWindow", None)
        _action.connect("activate", self._menuitemClose)
        self.window.add_action(_action)
        self.__general_action_group.insert(_action)
        # CloseWindow from acell Action
        _action = Gio.SimpleAction.new("acell_close", None)
        _action.connect("activate", self._on_control_x)
        self.window.add_action(_action)
        self.__general_action_group.insert(_action)
        # ImportFiebdc Action
        _action = Gio.SimpleAction.new("ImportFiebdc", None)
        _action.connect("activate", self._on_menuitemImportFiebdc)
        self.window.add_action(_action)
        self.__general_action_group.insert(_action)
        # CloseTab action
        self.__closeTab_action = Gio.SimpleAction.new("CloseTab", None)
        self.__closeTab_action.connect("activate", self._on_CloseTab)
        self.window.add_action(self.__closeTab_action)
        self.__general_action_group.insert(self.__closeTab_action)
        # Navigation Actions
        self.__navigation_is_enabled = False
        self.__navigation_action_group = Gio.SimpleActionGroup.new()
        # Go Previous action
        self.__GoPrevious_action = Gio.SimpleAction.new("GoPrevious", None)
        self.__GoPrevious_action.connect("activate", self._menuitemGoPrevious)
        self.window.add_action(self.__GoPrevious_action)
        self.__general_action_group.insert(self.__GoPrevious_action)
        self.__GoPrevious_action.set_enabled(False)
        # Go posterior action
        self.__GoPosterior_action = Gio.SimpleAction.new("GoPosterior", None)
        self.__GoPosterior_action.connect("activate", self._menuitemGoPosterior)
        self.window.add_action(self.__GoPosterior_action)
        self.__general_action_group.insert(self.__GoPosterior_action)
        self.__GoPosterior_action.set_enabled(False)
        # Go Up action
        self.__GoUp_action = Gio.SimpleAction.new("GoUp", None)
        self.__GoUp_action.connect("activate", self._menuitemGoUp)
        self.window.add_action(self.__GoUp_action)
        self.__general_action_group.insert(self.__GoUp_action)
        self.__GoUp_action.set_enabled(False)
        # Go to Root action
        self.__GoToRoot_action = Gio.SimpleAction.new("GoToRoot", None)
        self.__GoToRoot_action.connect("activate", self._menuitemGoToRoot)
        self.window.add_action(self.__GoToRoot_action)
        self.__general_action_group.insert(self.__GoToRoot_action)
        self.__GoToRoot_action.set_enabled(False)
        # Vertical Grid
        _vbox1 = Gtk.Grid()
        _vbox1.set_orientation(Gtk.Orientation(1)) # 1 Vertical
        self.window.add(_vbox1)
        _vbox1.show()
        # Toolbar
        _toolbar = Gtk.Toolbar()
        _toolbar.get_style_context().add_class(Gtk.STYLE_CLASS_PRIMARY_TOOLBAR)
        # Import Fiebdc
        _gtk_image = Gtk.Image.new_from_icon_name("document-open",1)
        _gtk_image.show()
        _ImportFiebdc_button = Gtk.ToolButton.new(_gtk_image , _("Import Fiebdc"))
        _ImportFiebdc_button.set_tooltip_text(_("Import Fiebdc"))
        _ImportFiebdc_button.set_is_important(False)        # label not shown
        _toolbar.insert(_ImportFiebdc_button, -1)
        _ImportFiebdc_button.show()
        _ImportFiebdc_button.set_action_name("win.ImportFiebdc")
        # Close tab
        _gtk_image = Gtk.Image.new_from_icon_name("window-close",1)
        _gtk_image.show()
        _closeTabButton = Gtk.ToolButton.new(_gtk_image , _("_Close tab"))
        _closeTabButton.set_tooltip_text(_("Close tab"))
        _closeTabButton.set_is_important(False)        # label not shown
        _toolbar.insert(_closeTabButton, -1)
        _closeTabButton.show()
        _closeTabButton.set_action_name("win.CloseTab")
        # Separator item
        _separator = Gtk.SeparatorToolItem()
        _separator.show()
        _toolbar.insert(_separator, -1)
        # Go Back
        _gtk_image = Gtk.Image.new_from_icon_name("go-previous",1)
        _gtk_image.show()
        self.__goBack_button = Gtk.MenuToolButton.new(_gtk_image ,_("Back"))
        self.__goBack_button.set_tooltip_text(_("Back"))
        self.__goBack_button.set_is_important(False)        # label not shown
        _toolbar.insert(self.__goBack_button, -1)
        self.__goBack_button.show()
        self.__goBack_button.set_action_name("win.GoPrevious")
        # Go Forward
        _gtk_image = Gtk.Image.new_from_icon_name("go-next",1)
        _gtk_image.show()
        self.__goForward_button = Gtk.MenuToolButton.new(_gtk_image ,_("Forward"))
        self.__goForward_button.set_tooltip_text(_("Forward"))
        self.__goForward_button.set_is_important(False)        # label not shown
        _toolbar.insert(self.__goForward_button, -1)
        self.__goForward_button.show()
        self.__goForward_button.set_action_name("win.GoPosterior")
         # Go Up Item
        _gtk_image = Gtk.Image.new_from_icon_name("go-up",1)
        _gtk_image.show()
        _goUP_button = Gtk.ToolButton.new(_gtk_image ,_("Up Item"))
        _goUP_button.set_tooltip_text(_("Up Item"))
        _goUP_button.set_is_important(False)        # label not shown
        _toolbar.insert(_goUP_button, -1)
        _goUP_button.show()
        _goUP_button.set_action_name("win.GoUp")
         # Go Root Item
        _gtk_image = Gtk.Image.new_from_icon_name("go-top",1)
        _gtk_image.show()
        _goRoot_button = Gtk.ToolButton.new(_gtk_image ,_("Root"))
        _goRoot_button.set_tooltip_text(_("Root"))
        _goRoot_button.set_is_important(False)        # label not shown
        _toolbar.insert(_goRoot_button, -1)
        _goRoot_button.show()
        _goRoot_button.set_action_name("win.GoToRoot")
        # Pack and show
        _toolbar.set_hexpand(True) # with extra horizontal space
        _toolbar.show()
        _vbox1.add(_toolbar)
        # Notebook
        self.__notebook = Gtk.Notebook()
        _vbox1.add(self.__notebook)
        self.__notebook.set_tab_pos(Gtk.PositionType(2)) # Up
        self.__notebook.set_property("expand", True) # widget expand all space
        self.__notebook.set_show_tabs(True)
        self.__notebook.set_show_border(True)
        self.__notebook.set_scrollable(True)
        self.__notebook.connect("switch-page", self._switch_page)
        self.__notebook.show()
        self._main()
        if len(files) > 0:
            for file in files:
                _budget = base.Budget()
                _budget_file = fiebdc.Read()
                _read_method = _budget_file.readFile
                _filename = file.get_path()
                _filetype = "budget"
                _exit_method = _budget_file.cancel
                _file_window = FileSelectionWindow(self,
                    _read_method, _budget, _filename, _exit_method, _filetype)

    def changeHistorySignal(self):
        """changeHistorySignal()
        
        A pane emit the updateHistory signal.
        
        Nothing to do now
        """
        pass

    def changeActiveSignal(self):
        """changeActiveSignal()
        
        A pane emit the change-active signal.
        
        Chech buttons sensitive
        """
        self._checkButtonsSensitive(self.__notebook.get_current_page())

    def _checkButtonsSensitive(self, page_num):
        """_checkButtonsSensitive(page_num)
        
        page_num: page number in notebook
        
        Check and if necessary update the enabled state of the navigation
        buttons.
        """
        _page = self.__page_list[page_num]
        if isinstance(_page, Page) and \
           self.__navigation_is_enabled:
            # GoToRoot and GoUp actions
            _goto_root = self.__GoToRoot_action
            _go_up = self.__GoUp_action
            if len(_page.activePathRecord) == 1 and \
               _goto_root.get_enabled():
                _goto_root.set_enabled(False)
                _go_up.set_enabled(False)
            elif len(_page.activePathRecord) != 1 and \
               not _goto_root.get_enabled():
                _goto_root.set_enabled(True)
                _go_up.set_enabled(True)
            # GoPrevMenu action
            _go_Previous = self.__GoPrevious_action
            _go_prev = self.__GoPrevious_action
            if _page.previousPathRecord is None:
                if _go_prev.get_enabled():
                    _go_prev.set_enabled(False)
                    self.__goBack_button.props.menu = None
            else:
                if not _go_prev.get_enabled():
                    _go_prev.set_enabled(True)
                    self.__goBack_button.set_menu(_page.back_menu)
            # GoPostMenu action
            _go_Posterior = self.__GoPosterior_action
            if _page.posteriorPathRecord is None:
                if _go_Posterior.get_enabled():
                    _go_Posterior.set_enabled(False)
                    self.__goForward_button.props.menu = None
            else:
                if not _go_Posterior.get_enabled():
                    _go_Posterior.set_enabled(True)
                    self.__goForward_button.set_menu(_page.forward_menu)

    def _disable_navigation(self):
        self.__GoPrevious_action.set_enabled(False)
        self.__GoPosterior_action.set_enabled(False)
        self.__GoUp_action.set_enabled(False)
        self.__GoToRoot_action.set_enabled(False)
        self.__navigation_is_enabled = False

    def _switch_page(self, notebook, page, page_num,):
        """_switch_page(notebook, page, page_num)
         
        Method connected to the "switch-page" signal of the notebook widget
        
        It shows/hides closeTabButton
        and changes the sensitive state of the navigation action group
        """
        for _page_num, _page in enumerate(self.__page_list):
            if _page_num == page_num:
                _page.closeTabButton.show()
            else:
                _page.closeTabButton.hide()
        _page = self.__page_list[page_num]
        
        if isinstance(_page, EmptyPage) and \
            self.__navigation_is_enabled:
            self._disable_navigation()
        elif isinstance(_page, Page):
            if not self.__navigation_is_enabled:
                self.__navigation_is_enabled = True
                self._checkButtonsSensitive(page_num)

    def _main(self):
        """main()
        
        Shows window.
        """
        self.window.show()

    def appendEmptyPage(self, emptyPage):
        """appendEmptyPage(emptyPage)
        
        Append a empty page to the notebook.
        """
        self.__page_list.append(emptyPage)
        self.__notebook.append_page(emptyPage.widget, emptyPage.title)
        # TODO: reordenable and detachable Pages
        #self.__notebook.set_tab_reorderable(emptyPage.widget, True)
        #self.__notebook.set_tab_detachable(emptyPage.widget, True)

    def updatePage(self, empty_page, page):
        """updatePage(page)
        
        Update emptyPage to Page.
        """
        _page_num = self.__notebook.page_num(empty_page.widget)
        self.__page_list[_page_num] = page
        if self.__notebook.get_current_page() == _page_num:
            if not self.__navigation_is_enabled:
                self.__navigation_is_enabled = True
                self._checkButtonsSensitive(_page_num)

    def _on_control_x(self, action, param):
        print("Control x -> Close window")
        self.window.destroy()

    def _on_menuitemImportFiebdc(self, action, parameter):
        """_on_menuitemImportFiebdc(action, parameter)
        
        action: the action  where the event is emitted from
        parameter: None
        Callback to open a budget file.
        
        Creates and shows a file selection window to open a budget file.
        """
        _budget = base.Budget()
        _budget_file = fiebdc.Read()
        _read_method = _budget_file.readFile
        _filename = ""
        _filetype = "budget"
        _exit_method = _budget_file.cancel
        _file_window = FileSelectionWindow(self,
            _read_method, _budget, _filename, _exit_method, _filetype)

    def _menuitemClose(self, action, parameter):
        """_menuitemClose(action, parameter)
        
        action: the action  where the event is emitted from
        parameter: None
        
        Callback to close the main window.
        """
        self.window.destroy()

    def _on_CloseTab(self, action, parameter):
        """_on_CloseTab(action, parameter)
        
        action: the action  where the event is emitted from
        parameter: None
        
        Callback to close tab.
        """
        _page_num = self.__notebook.get_current_page()
        if _page_num != -1:
            _page = self.__page_list[_page_num]
            _page.close()

    def closePage(self, page):
        """closePage(page)
        
        page: EmptyPage or Page object
        
        Removes a page from notebook and page_list.
        Hide navigation action group if necessary
        """
        if page in self.__page_list:
            _page_num = self.__page_list.index(page)
            self.__page_list.pop(_page_num)
            page.clear()
            self.__notebook.remove_page(_page_num)
            if len(self.__page_list) == 0:
                self._disable_navigation()
        else:
            raise IndexError( _("The page is not in the page list") )

    def _menuitemGoToRoot(self, action, parameter):
        """_menuitemGoToRoot(action, parameter)
        
        action: the action  where the event is emitted from
        parameter: None
        
        Callback to go to root record.
        """
        _page_num = self.__notebook.get_current_page()
        if _page_num == -1:
            return
        _page = self.__page_list[_page_num]
        if isinstance(_page, Page):
            # not loading budget
            _page.propagateMessageFrom("change_active", (-1,), (0,))

    def _menuitemGoUp(self, action, parameter):
        """_menuitemGoUp(action, parameter)
        
        action: the action  where the event is emitted from
        parameter: None
        
        Callback to go to up record.
        """
        _page_num = self.__notebook.get_current_page()
        if _page_num != -1:
            _page = self.__page_list[_page_num]
            if isinstance(_page, Page):
                # not loading budget
                _active_path = _page.activePathRecord
                if len(_active_path) > 1:
                    _budget = _page.budget
                    _up_path = _active_path[:-1]
                    if _budget.hasPath(_up_path):
                        _page.propagateMessageFrom("change_active", (-1,),
                                                   _up_path)

    def _menuitemGoPrevious(self, action, parameter):
        """_menuitemGoPrevious(action, parameter)
        
        action: the action  where the event is emitted from
        parameter: None
        
        Callback to go to previous record.
        """
        _page_num = self.__notebook.get_current_page()
        if _page_num != -1:
            _page = self.__page_list[_page_num]
            if isinstance(_page, Page):
                # not loading budget
                _previous_path = _page.previousPathRecord
                if _previous_path is not None:
                    _budget = _page.budget
                    if _budget.hasPath(_previous_path):
                        _page.propagateMessageFrom("change_active", (-1,),
                                                   _previous_path)

    def _menuitemGoPosterior(self, action, parameter):
        """_menuitemPosterior(action, parameter)
        
        action: the action  where the event is emitted from
        parameter: None
        
        Callback to go to posterior record.
        """
        _page_num = self.__notebook.get_current_page()
        if _page_num != -1:
            _page = self.__page_list[_page_num]
            if isinstance(_page, Page):
                # not loading budget
                _posterior_path = _page.posteriorPathRecord
                if _posterior_path is not None:
                    _budget = _page.budget
                    if _budget.hasPath(_posterior_path):
                        _page.propagateMessageFrom("change_active", (-1,),
                                                   _posterior_path)

    def _delete_event(self, widget, event):
        """_delete_event(widget, event)
        
        widget: the widget where the event is emitted from
        event: the "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


class FileSelectionWindow(object):
    """gui.FileSelectionWindow:
    
    Description:
        Class to show the selection file window
    Constructor:
        FileSelectionWindow(mainWindow, readFileMethod, budget,
            filename, cancelMethod, filetype)
    Ancestry:
    +-- object
      +-- FileSelectionWindow
    Atributes:
        No public Atributes
    Methods:
        No public Methods
    """

    def __init__(self, mainWindow, readFileMethod, budget, filename,
                 cancelMethod, filetype):
        """__init__(mainWindow, readFileMethod, budget,
                    filename, cancelMethod, filetype)
        
        mainWindow: MainWindow object
        readFileMethod: Method to read the selected file
        budget: base.Budget object
        filename: "file"
        cancelMethod: Method to cancel the read method
        fileytpe: "budget" or "database".
        Sets the init atributes, creates the file selection window
        Connects the events:
            * clicked ok button: _openFile
            * clicked cancel button: destroy window
            * destroy event: _destroy
        """
        # TODO: Add file filter
        self.__mainWindow = mainWindow
        self.__readFileMethod = readFileMethod
        self.__budget = budget
        self.__filetype = filetype
        self.__cancelMethod = cancelMethod
        self.__file = None
        self.__filename = filename
        if self.__filename == "":
            self.__dialog = Gtk.FileChooserNative.new(_("Open File"),
                mainWindow.window, Gtk.FileChooserAction.OPEN, _("Open File"),
                _("Cancel") )
            self.__dialog.set_current_folder(globalVars.getHomePath("BUDGET"))
            _response = self.__dialog.run()
            if _response in [ Gtk.ResponseType.OK, Gtk.ResponseType.ACCEPT,
                              Gtk.ResponseType.YES, Gtk.ResponseType.APPLY]:
                self._openFile(self.__dialog.get_filename())
            elif _response == Gtk.ResponseType.CANCEL:
                self.__dialog.destroy()
        else:
            self.__dialog = None
            self._openFile(self.__filename)

    def _launchProgressWindow(self, file):
        """_launchProgressWindow(file)
        
        Launch the progress window
        """
        self.__filename = file
        _emptyPage = EmptyPage(self.__mainWindow, self.__readFileMethod,
                               self.__budget, self.__filename,
                               self.__cancelMethod, self.__filetype)
        self.__mainWindow.appendEmptyPage(_emptyPage)
        _emptyPage.run()

    def _openFile(self, filename):
        """_openFile(filename)
        
        filename: the filename to open
        If the selected file has a bc3 extension 
        _launchProgressWindow is called
        """
        _file = filename
        if sys.getfilesystemencoding():
            _file = _file.decode(sys.getfilesystemencoding())
        self.__file = _file
        _filename = os.path.basename(self.__file)
        _filename_ext = _filename.split(".")[-1]
        if (self.__filetype == "budget" or self.__filetype == "database") and \
            _filename_ext != "bc3" and _filename_ext != "BC3":
            print(_("The file must have 'bc3' extension") )
        else:
            if self.__dialog is not None:
                self.__dialog.destroy()
            # TODO: the file exits? is it not binary?, can it be readed?
            self._launchProgressWindow(self.__file)


class EmptyPage(object):
    """gui.EmptyPage:
    
    Description:
    It creates and shows a page in the notebook while a budget is loaded.
    The page show the pyarq logo, loading time and a progress bar.
    Constructor:
        EmptyPage(mainWindow, readFileMethod, budget, filename,
                 cancelMethod, filetype):
            mainWindow: Mainwindow object
            readFileMethod: Method to read the selected file
            budget: base.Budget object
            filename: "file"
            cancelMethod: Method to cancel the read method
            filetype: "budget", "database"
    Ancestry:
    +-- object
      +-- EmptyPage
    Atributes:
        widget: Read. Main widget showed in the pane
        title: Read. Page Title
        filetype: Read. budget or basedata
        endSuccessfully: Read-Write. False/True
    Methods:
        run
        readFile_progress
        readFile_send_message
        readFile_set_statistics
        readFile_end
        readFile_cancel
        stopLoading
        updateGui
        threadFinishedSignal
        threadCanceled
        on_close_button
        close
        clear
    """

    def __init__(self, mainWindow, readFileMethod, budget, filename,
                 cancelMethod, filetype):
        """__init__(mainWindow, readFileMethod, budget, filename,
                        cancelMethod, filetype)
        
        mainWindow: Mainwindow object
        readFileMethod: Method to read the selected file
        budget: base.Budget object
        filename: "file"
        cancelMethod: Method to cancel the read method
        filetype: "budget" or "database"
        
        self.__mainWindow: Mainwindow object
        self.endSuccessfully False/True
        self.__readFileMethod: Method to read the selected file
        self.__budget: base.Budget object
        self.__filename: "file"
        self.__cancelMethod: Method to cancel the read method
        self.__filetype: "budget" or "database"
        self.__children: the read thread
        self.__progress: 0 to 1 progress
        self.__statistics: record statistics
        self.__widget: main widget, a vertial Gtk.Grid object
        self.__main_item: None
        self.__throbber: Gtk.Spinner()
        self.__budget_icon: Gtk.Image()
        self.__title: a horizontal Gtk.Grid
        self.__statusbar: a Gtk.Statusbar
        self.__statuscontext: the statusbar context
        self.__progress_bar: a Gtk.ProgressBar
        """
        self.__mainWindow = mainWindow
        self.endSuccessfully = False
        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.__statistics = None
        self.__widget = Gtk.Grid()
        self.__widget.set_orientation(Gtk.Orientation(1)) # 1 Vertical
        self.__main_item = None
        self.__widget.show()
        # Throbber
        self.__throbber = Gtk.Spinner()
        self.__throbber.show()
        self.__budget_icon = Gtk.Image()
        _budget_pixbuf = GdkPixbuf.Pixbuf.new_from_file(
                             globalVars.getAppPath("BUDGET-ICON"))
        self.__budget_icon.set_from_pixbuf(_budget_pixbuf)
        _filename = os.path.basename(filename)
        _rootfilename = os.path.splitext(_filename)[0]
        if not _rootfilename == "":
            _filename = _rootfilename
        if len(_filename) > 28:
            _titleLabel = Gtk.Label(_filename[:25] + "...")
            _titleLabel.set_tooltip_text(_filename)
        else:
            _titleLabel = Gtk.Label(_filename)
        _titleLabel.show()
        self.__title = Gtk.Grid()
        self.__title.set_column_spacing(4)
        self.__title.set_orientation(Gtk.Orientation(0)) # 0 Horizontal
        self.__title.add(self.__budget_icon)
        self.__title.add(self.__throbber)
        self.__title.add(_titleLabel)
        # Close tab
        _gtk_image = Gtk.Image()
        _gtk__pixbuf = Gtk.IconTheme.get_default().load_icon(
                                  "window-close-symbolic", 16, 0)
        _gtk_image.set_from_pixbuf(_gtk__pixbuf)
        _gtk_image.show()
        self.closeTabButton = Gtk.ToolButton.new(_gtk_image , _("_Close tab"))
        self.closeTabButton.set_tooltip_text(_("Close tab"))
        self.closeTabButton.set_is_important(False)        # label not shown
        self.__title.add(self.closeTabButton)
        self.closeTabButton.hide()
        self.__closeTabId = self.closeTabButton.connect("clicked", self.on_close_button)
        # Statusbar
        self.__statusbar = Gtk.Statusbar()
        self.__statuscontext = self.__statusbar.get_context_id("Statusbar")
        self.__statusbar.show()
        _iconVbox = Gtk.Grid()
        _iconVbox.set_orientation(Gtk.Orientation(1)) # 1 Vertical
        _iconVbox.props.halign = Gtk.Align(3) # 3 Center
        _iconVbox.props.valign = Gtk.Align(3) # 3 Center
        _iconVbox.set_property("expand", True) # widget expand all space
        _pyArqIcon = Gtk.Image()
        _pyArqIcon.set_from_file(globalVars.getAppPath("PYARQ-ICON"))
        _pyArqIcon.show()
        _iconVbox.add(_pyArqIcon)
        _link = Gtk.LinkButton.new("http://pyarq.obraencurso.es")
        _iconVbox.add(_link)
        _link.show()
        _iconVbox.show()
        self.__widget.add(_iconVbox)
        self.__progress_bar = Gtk.ProgressBar()
        self.__progress_bar.set_show_text(True)
        self.__progress_bar.show()
        self.__statusbar.pack_start(self.__progress_bar, False, False, 0)
        self.__widget.add(self.__statusbar)
        self.__main_item = None

    def run(self):
        """run()
        
        Launch clildren and timeouts
        """
        self.__statusbar.push(self.__statuscontext, _("Time: 0s"))
        self.__throbber.start()
        self._launchChildren()
        self._launchTimeout()

    def readFile_progress(self, percent):
        """readFile_progress(percent)
        
        percent: Percentage executed.
        
        Sets progress
        """
        _progress = str(int(round(100 * percent,0)))
        self.__progress = percent

    def readFile_send_message(self, message):
        """readFile_send_message(message)
        
        message: mesage from readFile method
        
        print( message )
        """
        print( message )

    def readFile_set_statistics(self, statistics):
        """readFile_set_statistics(statistics)
        
        statistics: record statistics from readFile method
        
        sets record statistics
        """
        self.__statistics = statistics

    def readFile_end(self):
        """readFile_end()
        
        The readFile method end successfully
        """
        self.endSuccessfully = True
        print( self.__statistics.str() )

    def readFile_cancel(self):
        """readFile_cancel()
        
        The readFile method is canceled
        """
        self.endSuccessfully = False
        print(_("Process terminated") )

    def stopLoading(self):
        """stopLoading()
        
        Stop progressbar
        """
        self.__throbber.destroy()
        self.__budget_icon.show()
        self.__progress_bar.hide()
        self.__statusbar.pop(self.__statuscontext)

    def _launchChildren(self):
        """_launchChildren()
        
        Launch the thread to read the file
        """
        if self.__children is None:
            self.__children = importFiebdc.Thread(self, self.__mainWindow,
                self.__readFileMethod, self.__budget, self.__filename,
                self.__cancelMethod, self.__filetype)
            self.__children.start()

    def _launchTimeout(self):
        """_launchTimeout()
        
        Launch the timeouts: 
            1- update progress bar
            2- update time label
            3- If the other timetouts are stoped the window is closed
        """
        GLib.timeout_add(1000, self._updateLabel, time.time())
        GLib.timeout_add(500, self._updateProgressBar)
        self.__cancel = [False, False]
        GLib.timeout_add(1000, self._autoClose)

    def updateGui(self):
        while Gtk.events_pending():
            Gtk.main_iteration()
    
    def _updateProgressBar(self):
        """_updateProgressBar()
        
        update progress bar in a timeout
        If the thread end or is canceled the timeout is stoped
        """
        if  self.__children is None or self.__children.isCanceled() == True:
            self.__cancel[0] = True
            return False
        else:
            self.__progress_bar.set_fraction(self.__progress)
            _text = "%s%%" %str(int(round(100 * self.__progress,0)))
            self.__progress_bar.set_text(_text)
            return True

    def _updateLabel(self, _time):
        """_updateLabel(_time)
        
        update time label in a timeout
        If the thread end or is canceled the timeout is stoped
        """
        if  self.__children is None or self.__children.isCanceled() == True:
            self.__cancel[1] = True
            return False
        else:
            _time = time.time() - _time
            _text = utils.mapping(_("Time: $1"), ("%.0f" %_time,))
            self.__statusbar.pop(self.__statuscontext)
            self.__statusbar.push(self.__statuscontext, _text)
            return True

    def _autoClose(self):
        """_autoClose()
        
        If the time label and progress bar timeouts are stoped the window is 
        closed and ist tiemeout is stoped
        """
        #_autoClose timeout do nothig
        if self.__cancel == [ True, True ]:
            return False
        else:
            return True

    def threadFinishedSignal(self, budget):
        """threadFinishedSignal(budget)
        
        Sets the self.__children to None
        This causes that the timeouts is ended.
        This method is called from thread when it finish
        """
        self.__budget = budget
        self.__children = None
        self.stopLoading()
        _page = Page(self.__mainWindow, self.__budget, self.closeTabButton)
        _children = self.__widget.get_children()
        for _child in _children:
            self.__widget.remove(_child)
        self.__widget.add(_page.widget)
        self.closeTabButton.disconnect(self.__closeTabId)
        self.closeTabButton.connect("clicked", _page.on_close_button)
        self.__mainWindow.updatePage(self, _page)

    def threadCanceled(self):
        """threadCanceled()
        
        Sets the __children atribute to None
        This causes that the timeouts is ended.
        This method is called from thread when is canceled
        """
        self.__children = None
        self.stopLoading()
        self.__mainWindow.closePage(self)

    def on_close_button(self, widget):
        """on_close_button()
        
        Call close
        """
        self.close()

    def close(self):
        """close()
        
        Close page canceling children
        """
        self.__children.cancel()

    def clear(self):
        """clear()
        
        Nothig to do now
        """
        pass

    def _getWidget(self):
        """_getWidget()
        
        Return de main widget to show in the page
        """
        return self.__widget

    def _getTitle(self):
        """_getTitle()
        
        Return the title of the page, a Gtk.Label objetc
        """
        return self.__title

    def _getFiletype(self):
        """_getFiletipe()
        
        Return the title of the page, a Gtk.Label objetc
        """
        return self.__filetype

    widget = property(_getWidget, None, None,
                      "Main widget showed in the pane")
    title = property(_getTitle, None, None,
                      "Page Title")
    filetype = property(_getFiletype, None, None,
                      "Filetype: budget or basedata")


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:
        Page(mainWindow, budget, closeTabButton, active_code=None)
            mainwindow: MainWindow object
            budget: base.Budget object
            closeTabButton. button winget to close tab
            active_code: Active record code
    Ancestry:
    +-- object
      +-- Page
    Atributes:
        widget: Read. Notebook page Widget. (a vertical Gtk.Grid instance)
        budget: Read-Write. Budget to show in the page. (base.obra object)
        panes_list: Read. info list for create the panes
            ej: [ "v", pane1, pane2 ] , [ "h", pane1, pane2 ]
                [ "v", [ "h", pane1, pane2 ], [ "h", pane1, pane2 ] ]
            pane types:
                * "DecompositionList": its creates a "DecompositionList" object 
                * "RecordDescription" : its creates a "Description" objetc
                * "Measure": its creates a "Measure" objetc
                * "FileView": its creates a "FileView" objet
                * "CompanyView": its creates a "CompanyView" object
        title: Read. Notebook page title (Gtk.Label object)
        activePathRecord: Read. The active path record
        previousPathRecord: Read. The previous path record
        posteriorPathRecord Read. The posterior path record
        back_menu: back menu to show in menutoolbutton
        forward_menu: forward menu to show in menutoolbutton
    Methods:
        propagateMessageFrom
        sendMessageTo
        on_close_button
        close
        clear
        getItem
    """
    # TODO:  * The panes can be ordered as the user wishes 
    # TODO:  * Panes in windows
    # TODO:  * pane types
    # TODO:      * General budget properties (is better a dialog?)

    def __init__(self, mainWindow, budget, closeTabButton, path_record=None):
        """__init__(mainWindow, budget, closeTabButton,  path_record=None)
        
        mainWindow: MainWindow object
        budget: "base.Budget" object
        closeTabButton: Button widget to close tab
        path_record: the active path record
        
        self.__mainWindow: MainWindow object
        self.__widget: a Gtk.Grid
        self.__panes_list: 
        self.__main_item: Main item in Page. (Paned object or View object)
        self.closeTabButton: : Button widget to close tab
        self.__active_path_record:
        self.__history_back:
        self.__history_forward:
        self.__back_menu: a Gtk.Menu
        self.__forward_menu: a Gtk.Menu
        """
        if path_record is None:
            path_record = (0,)
        self.__mainWindow = mainWindow
        self.closeTabButton = closeTabButton
        self.__widget = Gtk.Grid()
        self.__widget.set_orientation(Gtk.Orientation(1)) # 1 Vertical
        self.__widget.props.margin = 5
        #TODO: __panes_list should come from gui config file...
        # "DecompositionList" "RecordDescription" "Measure" "Sheet of Conditions"
        # "FileView" "CompanyView"
        self.__panes_list = [ "v", "DecompositionList", [ "v", "Measure",
            "RecordDescription" ]]
        self.__main_item = None
        self.__active_path_record = ()
        self.__history_back = []
        self.__history_forward = []
        self.__back_menu = Gtk.Menu()
        self.__back_menu.show()
        self.__forward_menu = Gtk.Menu()
        self.__forward_menu.show()
        self.budget = budget            # Create all items and widgets
        self._setActivePathRecord(path_record)
        self.__widget.show()
        self.__budget_icon = GdkPixbuf.Pixbuf.new_from_file(
            globalVars.getAppPath("BUDGET-ICON"))
        self.__chapter_icon = GdkPixbuf.Pixbuf.new_from_file(
            globalVars.getAppPath("CHAPTER-ICON"))
        self.__unit_icon  = GdkPixbuf.Pixbuf.new_from_file(
            globalVars.getAppPath("UNIT-ICON") )
        self.__material_icon  = GdkPixbuf.Pixbuf.new_from_file(
            globalVars.getAppPath("MATERIAL-ICON") )
        self.__machinery_icon = GdkPixbuf.Pixbuf.new_from_file(
            globalVars.getAppPath("MACHINERY-ICON"))
        self.__labourforce_icon = GdkPixbuf.Pixbuf.new_from_file(
            globalVars.getAppPath("LABOURFORCE-ICON"))

    def propagateMessageFrom(self, message, pane_path, arg=None):
        """propagateMessageFrom(message, pane_path, arg=None)
        
        message: string message
                * "change_active": change active code
                * "autoclose"
                * "split h"
                * "split v"
        pane_path: tuple that represents the pane path which emits the message
        arg: arguments for the message
             if message is "change_active" arg is the path record
        
        The panes are connectted to this method to send messages to other panes
        """
        _budget = self.__budget
        if message == "change_active" and _budget.hasPath(arg):
            self.sendMessageTo(self.__main_item, message, pane_path, arg)
            self._setActivePathRecord(arg)
            self.__mainWindow.changeActiveSignal() # Check sensitive buttons
        elif message == "autoclose":
            self._closeItem(pane_path)
        elif message == "split h":
            self._splitItem(pane_path, "h")
        elif message == "split v":
            self._splitItem(pane_path, "v")

    def sendMessageTo(self, pane, message, pane_path, arg=None):
        """sendMessageTo(pane, message, pane_path, arg=None)
        pane: the receiver pane
        message: string message
        pane_path: tuple that represents the pane pane_path which emits the message
        arg: arguments for the message
        
        Sends a message to a pane
        """
        pane.runMessage(message, pane_path, arg)

    def on_close_button(self, widget):
        self.close()

    def close(self):
        """close()
        
        Close Page
        """
        self.__mainWindow.closePage(self)

    def clear(self):
        """clear()
        
        Clear atributes
        """
        self.propagateMessageFrom("clear", (0,))
        del self.__budget
        del self.__panes_list
        del self.__widget
        del self.__title
        del self.__active_path_record
        del self.__main_item

    def getItem(self, pane_path):
        """getItem(pane_path)
        
        Return the item whith the path "pane_path", it can return a Paned
        instance or a View instance
        """
        _item = self.__main_item
        if len(pane_path) == 1:
            return _item
        else:
            return _item.getItem(pane_path[1:])

    def _setMainItem(self, item):
        """_setMainItem(item)
        
        Sets a new main item in the page
        """
        if not self.__main_item is None:
            _old_main_widget = self.__main_item.widget
            self.__widget.remove(_old_main_widget)
        self.__main_item = item
        _main_widget = self.__main_item.widget
        _main_widget.show()
        self.__widget.add(_main_widget)

    def _splitItem(self, pane_path, orientation):
        """_splitItem(pane_path, orientation)
        
        Splits the item that is identifies by the pane_path and the orientation
        """
        _item = self.getItem(pane_path)
        _item.pane_path = pane_path + (0,)
        _item_clone0 = _item.getClone(pane_path + (0,))
        _item_clone1 = _item.getClone(pane_path + (1,))
        _paned = Paned(orientation, pane_path, _item_clone0, _item_clone1)
        if len(pane_path) > 1:
            _parent = self.getItem(pane_path[:-1])
            _parent.setItem(pane_path[-1], [_paned])
        else:
            self._setMainItem(_paned)

    def _closeItem(self, pane_path):
        """_closeItem(pane_path)
        
        Closes the item that is identifies by the pane_path
        """
        _item = self.getItem(pane_path)
        if len(pane_path) > 1:
            # There are more than one item
            _parent = self.getItem(pane_path[:-1])
            _brothers = [ _brother for _brother in _parent]
            _brothers.remove(_item)
            _brother = _brothers[0]
            
            _parent.widget.remove(_brother.widget)
            _brother.pane_path = pane_path[:-1]
            if len(pane_path) > 2:
                _grandparent = self.getItem(pane_path[:-2])
                _grandparent.setItem(pane_path[-2], [_brother])
                _parent.widget.destroy()
                _parent.clear()
                _item.clear()
            else:
                _grandparent = self
                _grandparent._setMainItem(_brother)
                _parent.widget.destroy()
                _parent.clear()
                _item.clear()
        else:
            # Thre is only one item in the page, it can not be closed
            pass

    def _itemsFactory(self, list_paned, pane_path=None):
        """_itemsFactory(list_paned, pane_path=None)
        
        list_paned: list in "__panes_list" format
            [ "v" or "h", panel1_type, panel2_type]
            which contains the info for create the widgets. 
            panel types:
                * "DecompositionList"
                * "RecordDescription"
                * "Measure"
                * "Sheet of Conditions"
                * "FileView"
                * "CompanyView"
        pane_path: tuple that represents the item path in the page
        
        Creates the items and widgets and returns the main item
        """
        if pane_path is None:
            pane_path = (0,)
        if not isinstance(list_paned , list):
            raise ValueError( _("The value must be a list") )
        if list_paned[0] == "v" or  list_paned[0] == "h":
            if len(list_paned) != 3:
                raise ValueError( _("Incorrect len") )
            if not isinstance(list_paned[1],list):
                list_paned[1] = [list_paned[1]]
            if not isinstance(list_paned[2],list):
                list_paned[2] = [list_paned[2]]
            _item1 = self._itemsFactory(list_paned[1],pane_path + (0,))
            _item2 = self._itemsFactory(list_paned[2],pane_path + (1,)) 
            _item = Paned(list_paned[0], pane_path, _item1, _item2)
        elif list_paned[0] == "DecompositionList":
            _item = View( "DecompositionList", self.__budget,
                weakref.ref(self), pane_path, self.__active_path_record, True)
        elif list_paned[0] == "RecordDescription":
            _item = View( "RecordDescription", self.__budget,weakref.ref(self),
                pane_path, self.__active_path_record, True)
        elif list_paned[0] == "Measure":
            _item = View( "Measure", self.__budget, weakref.ref(self), pane_path,
                self.__active_path_record, True)
        elif list_paned[0] == "Sheet of Conditions":
            _item  = View("Sheet of Conditions", self.__budget, weakref.ref(self), pane_path,
                self.__active_path_record)
        elif list_paned[0] == "FileView":
            _item  = View("FileView", self.__budget, weakref.ref(self), pane_path,
                self.__active_path_record)
        elif list_paned[0] == "CompanyView":
            _item  = View("CompanyView", self.__budget, weakref.ref(self), pane_path,
                self.__active_path_record)
        else:
            _item = None
            raise ValueError( utils.mapping(_("Incorrect item $1"),
                  (str(list_paned[0]),)) )
        return _item

    def _setActivePathRecord(self, path_record):
        """_setActivePathRecord(path_record)
        
        path_record: the active record path
        
        Sets the active record path
        """
        if path_record != self.__active_path_record:
            if self.__budget.hasPath(path_record):
                self.__active_path_record = path_record
                self._appendHistory(path_record)
            else:
                raise ValueError( utils.mapping(_("The budget does not have "\
                    "the path record: $1"), (str(path_record),)) )

    def _appendHistory(self, path):
        """_appendHistory(path))
        
        path: the new active path record
        
        Append the new active path record to history lists and update menus
        """
        if len(self.__history_back) > 1 and path in self.__history_back[:-1]:
            # the new active record is in back history list
            # then append forward history and pop back history
            _items_num = len(self.__history_back) - \
                         self.__history_back.index(path) -1 
            for _item in range(_items_num):
                _record_path = self.__history_back.pop()
                _first_menuitem = self.__back_menu.get_children()[0]
                self.__back_menu.remove(_first_menuitem)
                self.__history_forward.append(_record_path)
                _menuitem = self._menuItemFactory(_record_path)
                _menuitem.connect_object("activate", self._menuHistoryForward,
                    _record_path, _menuitem)
                self.__forward_menu.prepend(_menuitem)
            while len(self.__history_forward) > 100:
                    # list too long
                    self.__history_forward.pop(0)
                    _last_menuitem = self.__forward_menu.get_children()[-1]
                    self.__forward_menu.remove(_last_menuitem)
        else:
            # the new active record not is in back history list
            if len(self.__history_forward) > 1 and \
               path in self.__history_forward:
                # the new active record is in history forward list
                # then append back history and pop forward history
                _items_num = len(self.__history_forward) - \
                             self.__history_forward.index(path)
                for _item in range(_items_num):
                    _record_path = self.__history_forward.pop()
                    _first_menuitem = self.__forward_menu.get_children()[0]
                    self.__forward_menu.remove(_first_menuitem)
                    self.__history_back.append(_record_path)
                    if len(self.__history_back) > 1:
                        _menuitem = self._menuItemFactory(
                            self.__history_back[-2])
                        _menuitem.connect_object("activate",
                            self._menuHistoryBack, self.__history_back[-2],
                            _menuitem)
                        self.__back_menu.prepend(_menuitem)
            else:
                # the new active record not is in history forward list
                # then append back history and clear forward history
                self.__history_forward[:] = []
                for _child in self.__forward_menu.get_children():
                    self.__forward_menu.remove(_child)
                self.__history_back.append(path)
                if len(self.__history_back) > 1:
                    _menuitem = self._menuItemFactory(self.__history_back[-2])
                    _menuitem.connect_object("activate", self._menuHistoryBack,
                        self.__history_back[-2], _menuitem)
                    self.__back_menu.prepend(_menuitem)
            while len(self.__history_back) > 100:
                # list too long
                self.__history_back.pop(0)
                _last_menuitem = self.__back_menu.get_children()[-1]
                self.__back_menu.remove(_last_menuitem)
        self.__mainWindow.changeHistorySignal()

    def _getImage(self, record):
        """_getImage(record)
        
        record: record object
        
        Returns an image depending on the type of record
        """
        _hierarchy = record.recordType.hierarchy
        _type = record.recordType.type
        _subtype = record.recordType.subtype
        if _hierarchy == 0:
            _icon = self.__budget_icon
        elif _hierarchy == 1:
            _icon = self.__chapter_icon
        else:
            if _type == 0:
                _icon = self.__unit_icon
            elif _type == 1:
                _icon = self.__labourforce_icon
            elif _type == 2:
                _icon = self.__machinery_icon
            else:
                _icon = self.__material_icon
        _image = Gtk.Image()
        _image.set_from_pixbuf(_icon)
        return _image

    def _menuFactory(self):
        """_menuFactory()
        
        record: record object
        
        Creates menus for history back an history forward tool buttons
        """
        # Back Menu
        # clear menu
        for _child in self.__back_menu.get_children():
            self.__back_menu.remove(_child)
        # pupulate menu
        if len(self.__history_back) > 1:
            for _record_path in self.__history_back[:-1]:
                _menuitem = self._menuItemFactory(_record_path)
                _menuitem.connect("activate", self._menuHistoryBack,
                    _record_path, _menuitem)
                self.__back_menu.prepend(_menuitem)
        # Forward Menu
        # clear menu
        for _child in self.__forward_menu.get_children():
            self.__forward_menu.remove(_child)
        # pupulate menu
        if len(self.__history_forward) > 0:
            for _record_path in self.__history_forward[:]:
                _menuitem = self._menuItemFactory(_record_path)
                _menuitem.connect("activate", self._menuHistoryForward,
                    _record_path, _menuitem)
                self.__forward_menu.prepend(_menuitem)

    def _menuItemFactory(self, record_path):
        """_menuItemFactory(record_path):
        
        record_path: record path
        
        Creates and return a menuItem to go to the record
        """
        _code = self.budget.getCode(record_path)
        _record = self.budget.getRecord(_code)
        _summary = _record.summary
        _text = _code.decode("utf8") + " " + _summary.decode("utf8")
        if len(_text) > 30:
            _text = _text[:27] + "..."
        _icon = self._getImage(_record)
        _grid = Gtk.Grid()
        _grid.set_orientation(Gtk.Orientation(0)) # 0 Horizontal
        _grid.set_column_spacing(6)
        _label = Gtk.Label(_text)
        _menuitem = Gtk.MenuItem.new()
        _grid.add(_icon)
        _grid.add(_label)
        _menuitem.add(_grid)
        _menuitem.show_all()
        return _menuitem

    def _menuHistoryBack(self, record_path, menu_item):
        """_menuHistoryBack(record_path, menu_item)
        
        Go to the record selected in History Back menu
        """
        if self.budget.hasPath(record_path):
            self.propagateMessageFrom("change_active", (-1,), record_path)

    def _menuHistoryForward(self, record_path, menu_item):
        """_menuHistoryForward(record_path, menu_item)
        
        Go to the record selected in History Forward menu
        """
        if self.budget.hasPath(record_path):
            self.propagateMessageFrom("change_active", (-1,), record_path)

    def _getActivePathRecord(self):
        """_getActivePathRecord()
        
        Return the Active Path Record
        """
        return self.__active_path_record
    
    def _getPreviousPathRecord(self):
        """_getPreviousPathRecord()
        
        Return the Previous Path Record
        """
        if len(self.__history_back) > 1: 
            return self.__history_back[-2]
        else:
            return None

    def _getPosteriorPathRecord(self):
        """_getPosteriorPathRecord()
        
        Return the Posterior Path Record
        """
        if len(self.__history_forward) > 0: 
            return self.__history_forward[-1]
        else:
            return None

    def _getBackMenu(self):
        """_getBackMenu()
        
        Return the Back Menu
        """
        return self.__back_menu

    def _getForwardMenu(self):
        """_getForwardMenu()
        
        Return the Forward Menu
        """
        return self.__forward_menu

    def _getTitle(self):
        """_getTitle()
        
        Return the page title, a Gtk.Label objetc
        """
        return self.__title
    
    def _getWidget(self):
        """_getWidget()
        
        Return de main widget to show in the pane
        """
        return self.__widget
    
    def _setBudget(self, budget):
        """_setBudget(budget)
        
        budget: a base.Budget object
        
        Sets the budget and the active code atributes,
        creates the page title and the widgets in the pane and
        shows the main widget.
        """
        if budget is None:
            self.clear()
            return
        self.__budget = budget
        self._setActivePathRecord((0,))
        # Todo: change page title
        self.__title = Gtk.Label(self.__budget.getCode(
                       self.__active_path_record))
        _panes_list = self.__panes_list
        self.__main_item = self._itemsFactory(_panes_list)
        _main_widget = self.__main_item.widget
        _main_widget.show()
        self.__widget.add(_main_widget)

    def _getBudget(self):
        """_getBudget()
        
        Return de budget, a "base.Budget" object.
        """
        return self.__budget
    
    def _getPanesList(self):
        """_getPanesList()
        
        Return the panes list, info list for create the panes.
        """
        return self.__panes_list

    budget = property(_getBudget, _setBudget, None,
                      "Budget to show, base.Budget object")
    widget = property(_getWidget, None, None,
                      "Main widget showed in the pane")
    title = property(_getTitle, None, None,
                      "Page Title")
    panes_list = property(_getPanesList, None, None,
                      "Info list for create the panes")
    activePathRecord = property(_getActivePathRecord, None, None,
                      "Active Path Record")
    previousPathRecord = property(_getPreviousPathRecord, None, None,
                      "Previous Active Path Record")
    posteriorPathRecord = property(_getPosteriorPathRecord, None, None,
                      "Posterior Active Path Record")
    back_menu = property(_getBackMenu, None, None,
                      "Back Menu")
    forward_menu = property(_getForwardMenu, None, None,
                      "Forward Menu")

class View(object):
    """gui.View:
    
    Description:
        It creates a view to show the budget info
    Constructor:
        View(view_type, budget, wr_page, pane_path, active_path_record,
             connected)
            view_type: the object type to show
                * DecompositionList
                * Description
                * Measure
                * Sheet
                * FileView
                * CompanyView
            budget: the budget to show
            wr_page: weak reference to the page where the view must be showed
            pane_path: the position or path of the view in the page notebook
            active_path_record: the record path that must be showed
            connected: boolean value, True means that the View object sends
            and receives signals from/to others views.
    Ancestry:
    +-- object
      +-- View
    Atributes:
        pane_path: Read-Write. The tuple that identifies the view in the main 
            notebook page
        widget: Read. the main Gtk widget to show in a view object,
            a Gtk.Grid object
    Methods:
        getItem
        propagateMessgeFrom
        runMessage
        getClone
        clear
    """

    def __init__(self, view_type, budget, wr_page, pane_path,
                 active_path_record, connected=True):
        """__init__(view_type, budget, wr_page, pane_path, active_path_record,
                    connected )
        view_type: the object type to show
            * DecompositionList
            * Description
            * Measure
            * Sheet
            * FileView
            * CompanyView
        budget: the budget to show
        wr_page: weak reference to the page where the view must be showed
        pane_path: the position or path of the view in the page notebook
        active_path_record: the record path that must be showed
        
        self.__view_type: the object type to show
            * DecompositionList
            * Description
            * Measure
            * Sheet of conditions
            * FileView
            * CompanyView
        self.__wr_page: weak reference to the page where the view must be
            showed
        self.__budget: the budget to show
        self.__pane_path: the position or path of the view in the page notebook
        self.__connected: boolean value, True means that the View object sends
            and receives signals from/to others views
        self.__widget: main widget. a Gtk.Grid
        self.__view: the object to show:
            * DecompositionList object
            * Description object
            * Measure object
            * Sheet object
            * FileView object
            * Comapany View
        self.__connected_button: a button to switch self.__connected True or
            False
        
        Creates and shows a new view
        """
        self.__view_type = view_type
        self.__wr_page = wr_page
        self.__budget = budget
        self.__pane_path = pane_path
        self.__connected = connected
        # 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.new_with_model(_liststore)
        _cell = Gtk.CellRendererText()
        _combobox.pack_start(_cell, True)
        _combobox.add_attribute(_cell, 'text', 0)
        self.__widget = Gtk.Grid()
        self.__widget.set_orientation(Gtk.Orientation(1)) # 1 Vertical
        _hbox = Gtk.Grid()
        _hbox.set_orientation(Gtk.Orientation(0)) # 0 Horizontal
        if view_type == "DecompositionList":
            self.__view = DecompositionList(budget, weakref.ref(self),
                          pane_path, active_path_record)
            _combobox.set_active(0)
            _view_icon = Gtk.Image()
            _view_icon.set_from_file(globalVars.getAppPath(
                "DECOMPOSITION-ICON"))
        elif view_type == "RecordDescription":
            self.__view = Description(budget, weakref.ref(self),
                          pane_path, active_path_record)
            _combobox.set_active(1)
            _view_icon = Gtk.Image()
            _view_icon.set_from_file(globalVars.getAppPath(
                "DESCRIPTION-ICON"))
        elif view_type == "Measure":
            self.__view = Measure(budget, weakref.ref(self),
                          pane_path, active_path_record)
            _combobox.set_active(2)
            _view_icon = Gtk.Image()
            _view_icon.set_from_file(globalVars.getAppPath("MEASURE-ICON"))
        elif view_type == "Sheet of Conditions":
            self.__view = Sheet(budget, weakref.ref(self),
                          pane_path, active_path_record)
            _combobox.set_active(3)
            _view_icon = Gtk.Image()
            _view_icon.set_from_file(globalVars.getAppPath("SHEET-ICON"))
        elif view_type == "FileView":
            self.__view = FileView(budget, weakref.ref(self),
                          pane_path, active_path_record)
            _combobox.set_active(4)
            _view_icon = Gtk.Image()
            _view_icon.set_from_file(globalVars.getAppPath("FILEVIEW-ICON"))
        elif view_type == "CompanyView":
            self.__view = CompanyView(budget, weakref.ref(self), pane_path,
                          active_path_record)
            _combobox.set_active(5)
            _view_icon = Gtk.Image()
            _view_icon.set_from_file(globalVars.getAppPath("COMPANY-ICON"))
        else:
            raise ValueError( _(utils.mapping("Invalid type of View: $1",
                  view_type)) )
        _view_icon.show()
        _combobox.connect("changed", self._change_combo)
        _combobox.show()
        self.__widget.add(_hbox)
        self.__widget.add(self.__view.widget)
        _hbox.add(_view_icon)
        _hbox.add(_combobox)
        _invisible = Gtk.Grid()
        _invisible.set_orientation(Gtk.Orientation(0)) # 0 Horizontal
        _invisible.set_property("hexpand", True) # widget expand horizontal space
        _invisible.show()
        _hbox.add(_invisible)
        # TODO : Set thist with config
        add_menu = False
        if add_menu:
            _icon_menu = Gtk.Image()
            _icon_menu.set_from_file(globalVars.getAppPath("MENU-ICON"))
            _icon_menu.show()
            _menu_button = Gtk.ToolButton()
            _menu_button.set_icon_widget(_icon_menu)
            _menu_button.connect("clicked", self._menu_view)
            _menu_button.show()
            _hbox.add(_menu_button)

        _icon_horizontal = Gtk.Image()
        _icon_horizontal.set_from_file(globalVars.getAppPath("HORIZONTAL"))
        _icon_horizontal.show()
        _horizontal_button = Gtk.ToolButton()
        _horizontal_button.set_icon_widget(_icon_horizontal)
        _horizontal_button.connect("clicked", self._split_view, "h")
        _horizontal_button.set_tooltip_text(_("Split View Left/Right"))
        _horizontal_button.show()
        _hbox.add(_horizontal_button)
        
        _icon_vertical = Gtk.Image()
        _icon_vertical.set_from_file(globalVars.getAppPath("VERTICAL"))
        _icon_vertical.show()
        _vertical_button = Gtk.ToolButton()
        _vertical_button.set_icon_widget(_icon_vertical)
        _vertical_button.connect("clicked", self._split_view, "v")
        _vertical_button.set_tooltip_text(_("Split View Top/Bottom"))
        _vertical_button.show()
        _hbox.add(_vertical_button)

        self.__connected_button = Gtk.ToolButton()
        _icon_connected = Gtk.Image()
        if self.__connected:
            _icon_connected.set_from_file(globalVars.getAppPath("CONNECTED-ICON"))
            self.__connected_button.set_tooltip_text(_("Disconnect view"))
        else:
            _icon_connected.set_from_file(globalVars.getAppPath("DISCONNECTED-ICON"))
            self.__connected_button.set_tooltip_text(_("Connect view"))
        _icon_connected.show()
        self.__connected_button.set_icon_widget(_icon_connected)
        self.__connected_button.connect("clicked", self._connected)
        self.__connected_button.show()
        _hbox.add(self.__connected_button)

        _icon_close = Gtk.Image()
        _icon_close.set_from_file(globalVars.getAppPath("CLOSE-ICON"))
        _icon_close.show()
        _close_button = Gtk.ToolButton()
        _close_button.set_icon_widget(_icon_close)
        _close_button.connect("clicked", self._closeItem_from_button)
        _close_button.set_tooltip_text(_("Close view"))
        _close_button.show()
        _hbox.add(_close_button)
        _hbox.show()
        self.__widget.show()

    def getItem(self, pane_path):
        """getItem(pane_path)
        
        Return itself.
        """
        return self

    def _closeItem_from_menu(self, close_menuitem):
        """_closeItem_from_menu(close_menuitem)
        
        Method connected to the "clicked" signal of the _close_button widget
        Send the "autoclose" message to the page to close this view
        """
        self.propagateMessageFrom("autoclose", self.__pane_path)

    def _closeItem_from_button(self, close_button):
        """_closeItem_from_button(close_button)
        
        Method connected to the "clicked" signal of the _close_button widget
        Send the "autoclose" message to the page to close this view
        """
        self.propagateMessageFrom("autoclose", self.__pane_path)

    def _change_combo(self, combobox):
        """_change_combo(combobox)
        
        Method connected to the "changed" signal of the _combobox widget
        It changes the view type to the type selected in the combobox
        """
        _index = combobox.get_active()
        _budget = self.__view.budget
        _wr_page = self.__view.wr_page
        _pane_path = self.__view.pane_path
        _path_record = self.__view.active_path_record
        _hbox = self.__widget.get_children()[1]
        _view_icon = _hbox.get_child_at(0, 0)
        _hbox.remove(_view_icon)
        _view_icon.destroy()
        self.__widget.remove(self.__view.widget)
        _view_icon = Gtk.Image()
        if _index == 0:
            self.__view = DecompositionList(_budget, _wr_page, _pane_path,
                          _path_record)
                        
            _view_icon.set_from_file(globalVars.getAppPath(
                "DECOMPOSITION-ICON"))
            self.__view_type = "DecompositionList"
        elif _index == 1:
            self.__view = Description(_budget, _wr_page, _pane_path,
                         _path_record)
            _view_icon.set_from_file(globalVars.getAppPath("DESCRIPTION-ICON"))
            self.__view_type = "RecordDescription"
        elif _index == 2:
            self.__view = Measure(_budget, _wr_page, _pane_path,
                         _path_record)
            _view_icon.set_from_file(globalVars.getAppPath("MEASURE-ICON"))
            self.__view_type = "Measure"
        elif _index == 3:
            self.__view = Sheet(_budget, _wr_page, _pane_path,
                         _path_record)
            _view_icon.set_from_file(globalVars.getAppPath("SHEET-ICON"))
            self.__view_type = "Sheet of Conditions"
        elif _index == 4:
            self.__view = FileView(_budget, _wr_page, _pane_path,
                         _path_record)
            _view_icon.set_from_file(globalVars.getAppPath("FILEVIEW-ICON"))
            self.__view_type = "FileView"
        elif _index == 5:
            self.__view = CompanyView(_budget, _wr_page, _pane_path,
                          _path_record)
            _view_icon.set_from_file(globalVars.getAppPath("COMPANY-ICON"))
            self.__view_type = "CompanyView"
        _view_icon.show()
        _hbox.attach(_view_icon, 0, 0, 1, 1)
        self.__widget.add(self.__view.widget)

    def _menu_view(self, widget):
        """_menu_view(widget)
        
        Method connected to the "clicked" signal of the __connected_button
        It shows a popup menu with some options
        """
        _menu_view = Gtk.Menu()
        _item_leftright = Gtk.MenuItem(_("Split view Left/Right"))
        _menu_view.append(_item_leftright)
        _item_leftright.connect("activate", self._split_view, "h")
        _item_leftright.show()
        _item_topbottom = Gtk.MenuItem(_("Split view Top/Bottom"))
        _menu_view.append(_item_topbottom)
        _item_topbottom.connect("activate", self._split_view, "v")
        _item_topbottom.show()
        _item_close = Gtk.MenuItem(_("Close view"))
        _menu_view.append(_item_close)
        _item_close.connect("activate",self._closeItem_from_menu)
        _item_close.show()
        _menu_view.popup_at_widget(widget, Gdk.Gravity(7), Gdk.Gravity(1), Gtk.get_current_event())

    def _split_view(self, widget, orientation):
        """_menu_view(orientation)
        
        orientation: orientation split, "h" or "v"
        
        Method connected to the "activate" signal of the _item_leftright and
        _item_topbottom menu items.
        It sends the "split" message to the page to splits the view in the
        specified orientation
        """
        self.propagateMessageFrom( "split " + orientation, self.__pane_path)

    def _connected(self, widget):
        """_connected(widget)
        
        Method connected to the "clicked" signal of the _menu_button
        It changes the __connected atribute to True or False, if the 
        _connected atribute is False the view do not send and receive messages
        to/from others views
        """
        if self.__connected:
            _icon = Gtk.Image()
            _icon.set_from_file(globalVars.getAppPath("DISCONNECTED-ICON"))
            _icon.show()
            self.__connected_button.set_icon_widget(_icon)
            self.__connected_button.set_tooltip_text(_("Connect View"))
            self.__connected = False
        else:
            _icon = Gtk.Image()
            _icon.set_from_file(globalVars.getAppPath("CONNECTED-ICON"))
            _icon.show()
            self.__connected_button.set_tooltip_text(_("Disconnect View"))
            self.__connected_button.set_icon_widget(_icon)
            self.__connected = True

    def propagateMessageFrom(self, message, pane_path, arg=None):
        """propagateMessageFrom(message, pane_path, arg=None)
        
        message: string message
        pane_path: tuple that represents the pane path which emits the message
        arg: arguments for the message
        The panes are connectted to this method to send messages to other panes
        """
        if self.__connected or message == "autoclose" or \
           message == "split h" or message == "split v":
            self.__wr_page().propagateMessageFrom(message, pane_path, arg)

    def runMessage(self, message, pane_path, arg=None):
        """runMessage(message, pane_path, arg=None)
        
        message: the message type
            "change_active": change the active record
            "clear": clear instance
        pane_path: tuple that identifies the pane in the notebook page
        arg: tuple whit two items:
            0: record path in the budget
            1: record code
        This method receives a message and executes its corresponding action
        """
        if self.__connected:
            self.__view.runMessage(message, pane_path, arg)

    def _getWidget(self):
        """_getWidget()
        
        Return de pane widget
        """
        return self.__widget

    def _getPanePath(self):
        """_getPanePath()
        
        return the tuple that identifies the pane in the notebook page
        """
        return self.__view.pane_path

    def _setPanePath(self, pane_path):
        """_setPanePath()
        
        set the tuple that identifies the pane in the notebook page
        """
        self.__pane_path = pane_path
        self.__view.pane_path = pane_path

    def getClone(self, new_pane_path):
        """getClone(new_pane_path)
        
        new_pane_path: the path that identifies the clone view in the page
        
        return a clone of itself
        """
        return View(self.__view_type, self.__budget, self.__wr_page,
                       new_pane_path, self.__view.active_path_record,
                       self.__connected)

    def clear(self):
        """clear()
        
        Clear the intance atributes
        """
        del self.__wr_page
        del self.__budget
        del self.__pane_path
        del self.__widget
        del self.__view
        del self.__connected
        del self.__connected_button

    pane_path = property(_getPanePath, _setPanePath, None,
        "path that identifies the item in the notebook page")
    widget = property(_getWidget, None, None, "View widget")


class Paned(object):
    """gui.Paned:
    
    Description:
        It creates and shows Gtk.Paned to show in page budget
    Constructor:
        Paned(orientation, widget1, widget2)
            orientation: The orientation of the pane separator, can be "v" or
                "h"
            widget1: the top or left pane widget
            widget2: the botton or right pane widget
    Ancestry:
    +-- object
      +-- Paned
    Atributes:
        widget: Read. Pane widget("Gtk.Paned" object)
        pane_path: Read-Write. The paned path in the page
    Methods:
        getClone
        getItem
        setItem
        runMessage
        clear(self)
    """
    # TODO:  *control the position paned separator. Now is always in the middle
    # TODO:     can be with a float(0.0-1.0) aspect ratio
    # TODO:          0.0 no space for widget1
    # TODO:          1.0 all the space for widget1

    def __init__(self, orientation, pane_path, item1, item2):
        """__init__(oritentation, pane_path, item1, item2)
        
        orientation: The orientation of de Gtk.Paned, can be "v" or "h"
        pane_path: the paned path in the page
        item1: the top or left pane object
        item2: the bottom or right pane object
        
        self.__orientation: The orientation of de Gtk.Paned, can be "v" or "h"
        self.__widget: Main widget, a Gtk.Paned
        self.__items: list of items showed in the paned, its can be View or
            Paned instances
        self.__pane_path: the paned path in the page
        
        Creates and shows a new Gtk.Paned
        """
        self.__orientation = orientation
        if not isinstance(item1.widget, Gtk.Widget) or \
           not isinstance(item2.widget, Gtk.Widget):
            raise ValueError( _("The item must be a widget object.") )
        if orientation == "v":
            self.__widget = Gtk.Paned.new(Gtk.Orientation(1))
            self.__widget.set_wide_handle(True) 
        elif orientation == "h":
            self.__widget = Gtk.Paned.new(Gtk.Orientation(0))
            self.__widget.set_wide_handle(True) 
        else:
            raise ValueError( _("Invalid orientation.") )
        self.__widget.pack1(item1.widget,True,False)
        self.__widget.pack2(item2.widget,True,False)
        self.__widget.show()
        self.__items = [item1, item2]
        self.__pane_path = pane_path

    def __getitem__(self, item):
        """__getitem__(item)
        
        Called to implement evaluation of self[key].
        The accepted keys should be integers 0 or 1.
        """
        return self.__items[item]

    def getClone(self, new_pane_path):
        """getClone(new_pane_path)
        
        Return a clone Paned instance with the path new_path
        """
        return Paned(self.__orientation, new_pane_path,
                     self.__items[0].getClone(new_pane_path + (0,)),
                     self.__items[1].getClone(new_pane_path + (1,)))

    def getItem(self,pane_path):
        """getItem(pane_path)
        
        Return the item whith the specified path.
        """
        _item = self.__items[pane_path[0]]
        if len(pane_path) == 1:
            return _item
        else:
            return _item.getItem(pane_path[1:])
        
    def setItem(self, pane_path, item_list):
        """setItem(pane_path, item_list)
        
        Sets the first item in the item_list whith the especified path and
        remove the old item in this position.
        """
        item = item_list[0]
        if pane_path == 0 or pane_path == 1:
            _old_item = self.__items[pane_path]
            self.__widget.remove(_old_item.widget)
            self.__items[pane_path] = item
            if pane_path == 0:
                self.__widget.pack1(item.widget,True,False)
            else:
                self.__widget.pack2(item.widget,True,False)
            return True
        return False

    def runMessage(self, message, pane_path, arg=None):
        """runMessage(message, pane_path, arg=None)
        
        message: the message type
            "change_active": change the active record
            "clear": clear instance
        pane_path: tuple that identifies the pane in the notebook page
        arg: arguments
        
        This method receives a message and send this to the items of the paned
        """
        for _item in self.__items:
            if not _item.pane_path == pane_path:
                _item.runMessage(message, pane_path, arg)

    def _getWidget(self):
        """_getWidget()
        
        Return de Gtk.Paned widget
        """
        return self.__widget

    def _getPanePath(self):
        """_getPanePath()
        
        Return de Paned path in the notebook page
        """
        return self.__pane_path

    def _setPanePath(self, pane_path):
        """_setPanePath()
        
        sets the tuple that identifies the pane in the notebook page
        """
        self.__pane_path = pane_path
        self.__items[0].pane_path = pane_path + (0,)
        self.__items[1].pane_path = pane_path + (1,)

    def clear(self):
        """clear()
        
        Delete atributes
        """
        del self.__widget
        del self.__orientation
        del self.__items
        del self.__pane_path

    widget = property(_getWidget, None, None, "Gtk.Paned widget")
    pane_path = property(_getPanePath, _setPanePath, None,
        "Pane path in the notebook page")


class TreeView(object):
    """gui.Treeviev:
    
    Description:
        It creates the columns in a treeview, is the base class for 
        DescompositionList and Measure classes 
    Constructor:
        TreView(args)
        args: list of tuples, the tuple items are:
            0.type:
                * index column
                * float column
                * text column
                * calculated column
                * calculated text
                * type column
            1. clicked method
            2. width
            3. text color
            4. backgruound colors
            5. model column index
    Ancestry:
    +-- object
      +-- TreeView
    Atributes:
        columns: list of columns (Gtk.TreeViewColumn objects)
    Methods:
        createColumn
        createTextBaseColumn
        createBaseColumn
    """

    def __init__(self, args):
        """__init__(args)
        
        args: list of tuples, the tuple items are:
            0.type:
                * index column
                * float column
                * text column
                * calculated column
                * Calculated text
                * type column
            1. clicked method
            2. width
            3. text color
            4. backgruound colors
            5. model column index
        
        Create the columns form the args info calling creatheColumn to create
        each column
        """
        self.columns = [ self.createColumn(arg) for arg in args ]
        self.columns.append(self.createColumn(("END",)))

    def createColumn(self, args):
        """createColumn(args)
        
        args: tuple with the args
            0.type:
                * index column
                * float column
                * text column
                * calculated column
                * calculated text
                * type column
            1. clicked method
            2. width
            3. text color
            4. backgruound colors
            5. model column index
        
        Return a column created whith the arg info
        """
        if args[0] == "INDEX":
            _index_column = self.createBaseColumn(args)
            _text_index_cell = Gtk.CellRendererText()
            _text_index_cell.set_property('foreground',
                globalVars.color["TEXT"])
            _pixbuf_index_cell = Gtk.CellRendererPixbuf()
            _arrow_icon = GdkPixbuf.Pixbuf.new_from_file(
                globalVars.getAppPath("ARROW-ICON"))
            _pixbuf_index_cell.set_property("pixbuf", _arrow_icon)
            _index_column.pack_start(_text_index_cell, True)
            _index_column.pack_start(_pixbuf_index_cell, True)
            _index_column.set_cell_data_func(_text_index_cell,
                self._colorCell,
                [globalVars.color["INDEX-UNEVEN"],
                 globalVars.color["INDEX-EVEN"]])
            return _index_column
        elif args[0] == "TEXT":
            _column, _cell = self.createTextBaseColumn(args)
            _column.add_attribute(_cell, 'text', args[5])
            return _column
        elif args[0] == "FLOAT":
            _column, _cell = self.createTextBaseColumn(args)
            _column.add_attribute(_cell, 'text', args[5])
            _column.get_cells()[0].set_property('xalign', 1.0)
            return _column
        elif args[0] == "CALCULATED":
            _column, cell = self.createTextBaseColumn(args)
            _column.get_cells()[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', 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('background',
                globalVars.color["UNEVEN"])
            _end_column.pack_start(_end_cell, True)
            return _end_column
        return None

    def createTextBaseColumn(self, args):
        """createTextBaseColumn(args)
        
        args: tuple with the args
            0.type:
                * float column
                * text column
                * calculated column
                * calculated text
            1. clicked method
            2. width
            3. text color
            4. backgruound colors
            5. model column index
        
        Return a column and its CellREndererText
        """
        _column = self.createBaseColumn(args)
        _cell = Gtk.CellRendererText()
        _cell.set_property('foreground', args[3])
        _column.pack_start(_cell, True)
        _column.set_cell_data_func(_cell, self._colorCell, args[4])
        return _column, _cell

    def createBaseColumn(self, args):
        """createBaseColumn(args)
        
        args: tuple with the args
            0.type:
                * index column
                * float column
                * text column
                * calculated column
                * calculated text column
                * type column
            1. clicked method
            2. width
            3. text color
            4. backgruound colors
            5. model column index
        
        Return a column
        """
        _column = Gtk.TreeViewColumn()
        _column.set_clickable(True)
        _column.connect("clicked", args[1])
        _column.set_sizing(Gtk.TreeViewColumnSizing(2)) # 2 Fixed
        _column.set_fixed_width(args[2])
        _column.set_resizable(True)
        return _column


class DecompositionList(TreeView):
    """gui.DecompositionList:
    
    Description:
        Class to show a budget Decomposition List
    Constructor:
        DecompositionList(budget, page, pane_path, path_record=None)
        budget: budget showed ("base.Budget" object)
        page: weak reference from Page instance which creates this class
        pane_path: tuple that represents the view path in the Page
        path_record: the record path that must be showed
        Returns the newly created DecompositionList instance
    Ancestry:
    +-- object
      +-- TreeView
        +-- DecompositionList
    Atributes:
        budget: Read. Budget to show, base.obra object.
        widget: Read. Window that contains the table, Gtk.ScrolledWindow
        pane_path: Read-Write. Pane page identifier
        wr_page: Read-Write. weak ref from Page object which creates this class
        active_path_record: Read. Active path record
    Methods:
        runMessage
    """

    def __init__(self, budget, wr_page, pane_path, path_record=None):
        """__init__(budget, page, pane_path, path_record=None)
        
        budget: budget showed ("base.Budget" object)
        page: weak reference from Page instance which creates this class
        pane_path: tuple that represents the path of the List in the Page
        path_record: the record path that must be showed
        
        self.__budget: budget showed ("base.Budget" object)
        self.__wr_page: weak reference from Page instance which creates this class
        self.__pane_path: tuple that represents the path of the List in the Page
        self.__liststore: list model which store the list data
            (Gtk.ListStore object)
        self.__active_path_record: the record path that must be showed
        self.__treeview: widget for displaying decomposition lists
            (Gtk.TreeView)
        self.__scrolled_window: widget to contain the treeview object
        self.__chapter_background_colors: background colors of the Code
            column cells when there is a chapter record,
            list of color [even cell, uneven cell]
        self.__chapter_background_colors
        self.__index_column: Index column (Gtk.TreeViewColumn object)
        self.__code_column: Record code column (Gtk.TreeViewColumn)
        self.__type_column: Record Type column (Gtk.TreeViewColumn)
        self.__unit_column: Unit of measure column (Gtk.TreeViewColumn)
        self.__description_column: record's short description column 
            (Gtk.TreeViewColumn)
        self.__measure_column: Measure column (Gtk.TreeViewColumn)
        self.__price_column: Price column (Gtk.TreeViewColumn)
        self.__amount_column: Amount column(Gtk.TreeViewColumn)
        self.__end_column: End empty column (Gtk.TreeViewColumn)
        self.__chapter_icon: a GdkPixbuf.Pixbuf
        self.__unit_icon: a GdkPixbuf.Pixbuf
        self.__material_icon: a GdkPixbuf.Pixbuf
        self.__machinery_icon: a GdkPixbuf.Pixbuf
        self.__labourforce_icon: a GdkPixbuf.Pixbuf
        self.__treeselection: active selection
        self.__selection_control: state of the selection control (True/False)
        self.__cursor: cursor position in the table
        
        Sets the init atributes
        Creates the init list values in self.__liststore from the budget 
            showing the top record descomposition
        Creates the list in self.__treeview
            * Creates the columns and cell
            * Sets te the column headers values
            * Sets the selection properties
            * Connects the events
        """
        # TODO: to group all columns in a dicctionary
        # Budget
        if not isinstance(budget, base.Budget):
            raise ValueError( _("Argument must be a Budget object") )
        self.__budget = budget
        self.__wr_page = wr_page
        self.__pane_path = pane_path
        # ListStore
        self.__liststore = Gtk.ListStore(object
            #, int, int, str, str, str, str, str,str
            )
        if path_record is None:
            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_property("expand", True) # widget expand all space
        self.__scrolled_window.set_policy(Gtk.PolicyType(1),
                                        Gtk.PolicyType(1)) # 1 Automatic
        self.__scrolled_window.add(self.__treeview)
        # colors
        _text_color = globalVars.color["TEXT"]
        _background_color = [
            globalVars.color["UNEVEN"],
            globalVars.color["EVEN"]]
        self.__chapter_background_colors = [
            globalVars.color["CHAPTER-UNEVEN"],
            globalVars.color["CHAPTER-EVEN"]]
        super(DecompositionList,self).__init__(
            [("INDEX",self._selectAll,42),
            ("CALCULATEDTEXT", self._showParentRecord, 
             100, _text_color, _background_color),
            ("PIXBUF", self._showParentRecord, 26, _text_color,
             _background_color),
            ("CALCULATEDTEXT", self._showParentRecord,
             52, _text_color, _background_color),
            ("CALCULATEDTEXT", self._showParentRecord,
            245, _text_color, _background_color),
            ("CALCULATED", self._showParentRecord,
            90, _text_color, _background_color),
            ("CALCULATED", self._showParentRecord,
            90, _text_color, _background_color),
            ("CALCULATED", self._showParentRecord,
            90, globalVars.color["CALCULATED-TEXT"],
            _background_color),
            ])
        self.__index_column = self.columns[0]
        self.__code_column = self.columns[1]
        self.__type_column = self.columns[2]
        self.__unit_column = self.columns[3]
        self.__description_column = self.columns[4]
        self.__measure_column = self.columns[5]
        self.__price_column = self.columns[6]
        self.__amount_column = self.columns[7]
        self.__end_column = self.columns[8]
        # Index column
        self.__treeview.append_column(self.__index_column)
        # Code column
        self.__treeview.append_column(self.__code_column)
        # Type column
        self.__treeview.append_column(self.__type_column)
        self.__chapter_icon = GdkPixbuf.Pixbuf.new_from_file(
            globalVars.getAppPath("CHAPTER-ICON"))
        self.__unit_icon  = GdkPixbuf.Pixbuf.new_from_file(
            globalVars.getAppPath("UNIT-ICON") )
        self.__material_icon  = GdkPixbuf.Pixbuf.new_from_file(
            globalVars.getAppPath("MATERIAL-ICON") )
        self.__machinery_icon = GdkPixbuf.Pixbuf.new_from_file(
            globalVars.getAppPath("MACHINERY-ICON"))
        self.__labourforce_icon = GdkPixbuf.Pixbuf.new_from_file(
            globalVars.getAppPath("LABOURFORCE-ICON"))
        self.__type_column.get_cells()[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.SelectionMode(3)) #  3 MULTIPLE
        self.__treeselection.set_select_function(self._controlSelection)
        self.__selection_control = True
        if len(self.__liststore) > 0:
            _tree_path = Gtk.TreePath.new_from_indices((0,))
            self.__treeview.set_cursor_on_cell(_tree_path ,self.__unit_column,
                self.__unit_column.get_cells()[0],True)
        self.__treeview.grab_focus()
        self.__cursor = self.__treeview.get_cursor()
        # Show
        self._setColumnsHeaders()
        self.__scrolled_window.show()

    def _treeviewCursorChanged(self, treeview):
        """_treeviewCursorChanged(treeview)
        
        treeview: treewiew widget
        Method connected to "cursor-changed" signal
        The "cursor-changed" signal is emitted when the cursor moves or is set
        Sets the new cursor position in self.__cursor, it is used to avoid 
        unnecessary changes in cursor position.
        """
        event = Gtk.get_current_event()
        (_cursor_path, _column) = treeview.get_cursor()
        if event is None or event.type !=  Gdk.EventType(7): # 7 BUTTON_RELEASE
            if not _column is self.__index_column:
                self.__cursor = treeview.get_cursor()

    def _treeviewClickedEvent(self, widget, event):
        """_treeviewClickedEvent(widget, event)
        
        widget: treewiew widget
        event: clicked event
        Method connected to "button-press-event" signal
        The "button-press-event" signal is emitted when a mouse button is
        pressed.
        Returns TRUE to stop other handlers from being invoked for the event.
        Returns FALSE to propagate the event further.
        
        The events in end column are ignored.
        If the user click in a row of the index column the cursor is moved to
        this row but not to the index column
        """
        if event.button == 1:
            path_at_pos = self.__treeview.get_path_at_pos(int(event.x),
                                                        int(event.y))
            if not path_at_pos is None: 
                _path_cursor, _column, _x, _y = path_at_pos
                if _column == self.columns[-1]:
                    return True
                if _column is self.columns[0]:
                    self.__cursor[0] == _path_cursor
        return False

    def _treeviewKeyPressEvent(self, widget, event):
        """_treeviewKeyPressEvent(widget, event)
        
        widget: treewiew widget
        event: Key Press event
        Method connected to "key-press-event" signal
        The "key-press-event" signal is emitted when the user presses a key
        on the keyboard.
        Returns :TRUE to stop other handlers from being invoked for the event.
        Returns :FALSE to propagate the event further.
        
        If the user press the right cursor button and the cursor is in the
        amount column or pres the left cursor button and the cursor is
        in the code column the event is estoped, else the event is propagated. 
        """
        (_cursor_path, _column) = self.__treeview.get_cursor()
        if (event.keyval in [Gdk.keyval_from_name("Right"),
                             Gdk.keyval_from_name("KP_Right")]  \
            and _column == self.columns[-2]) \
            or (event.keyval in [Gdk.keyval_from_name("Left"),
                             Gdk.keyval_from_name("KP_Left")]  \
            and _column == self.columns[1]):
            return True
        return False

    def _moveCursor(self, treeview, step, count):
        """_moveCursor(treeview, step, count)
        
        treeview: the treeview that received the signal
        step: the movement step size
        count: the number of steps to take
        
        Method connected to "move-cursor" signal
        The "move-cursor" signal is emitted when the user moves the cursor
        using the Right, Left, Up or Down arrow keys or the Page Up,
        Page Down, Home and End keys.
        
        Returns :TRUE if the signal was handled.
        """
        return False

    def _controlSelection(self, selection, model, path, path_currently_selected, *data):
        """_controlSelection(selection)
        
        selection: treeselection
        
        Method connected to set_selection_function() 
        This method is called before any node is selected or unselected,
        giving some control over which nodes are selected.
        The selection function should return TRUE if the state
        of the node may be toggled, and FALSE if the state of the node should
        be left unchanged.
        
        The selection only run if the user click in the index column, else
        the previous selection is erased.
        """
        _column = self.__treeview.get_cursor()[1]
        if _column is self.columns[0] \
            or self.__selection_control == False:
            return True
        else:
            self.__selection_control = False
            self.__treeselection.unselect_all()
            self.__selection_control = True
            return False

    def _selectAll(self, column):
        """_selectAll(column)
        
        column: index column
        Method connected to "clicked" event in the index column
        If the user clickes in the index column header selecs or deselects 
        all rows
        """
        (_model, _pathlist) = self.__treeselection.get_selected_rows()
        # it avoid to set cursor in the index column
        if isinstance(self.__cursor[0],Gtk.TreePath):
            self.__treeview.set_cursor(self.__cursor[0], self.__cursor[1])
            self.__selection_control = False
            if len(_pathlist) == 0:
                # select all
                self.__treeselection.select_all()
            else:
                # unselect all
                self.__treeselection.unselect_all()
            self.__selection_control = True

    def _setColumnsHeaders(self):
        """_setColumnsHeaders()
        
        Sets the headers column values
        """
        _path_record = self.__active_path_record
        _number = _path_record[-1]
        _budget = self.__budget
        _code = _budget.getCode(_path_record)
        _decomposition = _budget.getDecomposition(_path_record)
        _stryield = _budget.getStrYield(_decomposition.budgetMeasures[0],
                                        _budget.getRecord(_code).recordType)
        _record = _budget.getRecord(_code)
        _unit = _record.unit
        _description = _record.summary
        _price = _budget.getStrPriceFromRecord(self.budget.getActiveTitle(),
                                               _record, _path_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.decode("utf8") + "]")
        self.__unit_column.set_title(_("Unit") + chr(10) + "[" + _unit.decode("utf8") + "]")
        self.__description_column.set_title(
           _("Description") + chr(10) + "[" + _description.decode("utf8") + "]")
        self.__measure_column.set_title(
            _("Measure") + chr(10) + "[" + _stryield + "]")
        self.__price_column.set_title(
            _("Price") + chr(10) + "[" + _price + "]")
        self.__amount_column.set_title(
            _("Amount") + chr(10) + "[" + str(_amount) + "]")

    def _setListstoreValues(self, path_record):
        """_setListstoreValues(path_record)
        
        path_record: Record path in the budget
        Sets the liststore record values from a path record
        """
        self.__liststore.clear()
        _budget = self.__budget
        if not _budget.hasPath(path_record):
            raise ValueError( _("Invalid path") )
        else:
            _parent_code = _budget.getCode(path_record)
            for N,_code in enumerate(_budget.getchildren(_parent_code)):
                _decomposition = _budget.getNDecomposition(_parent_code, N)
                _record = _budget.getRecord(_code)
                _values = [_record,
                           #_record.hierarchy,
                           #_record.type,
                           #_record.subtype,
                           #_code,
                           #_record.unit,
                           #_record.summary,
                           #_decomposition.yield_,
                           #_decomposition.budget[0].yield_,
                           #_record.prices[_budget.getActiveTitle()].prices]
                           #_record.getPrice(_budget.getActiveTitle())
                           ]
                _treeiter = self.__liststore.append(_values)

    def _colorCell(self, column, cell_renderer, tree_model, iter, lcolor):
        """_colorCell(column, cell_renderer, tree_model, iter, lcolor)
        
        column: the Gtk.TreeViewColumn in the treeview
        cell_renderer: a Gtk.CellRenderer
        tree_model: the Gtk.TreeModel
        iter: Gtk.TreeIter pointing at the row
        lcolor: list with 2 Gtk colors for even and uneven record
        
        Method connected to "set_cell_data_func" of many column
        The set_cell_data_func() method sets the data function (or method) 
        to use for the column Gtk.CellRenderer specified by cell_renderer.
        This function (or method) is used instead of the standard attribute
        mappings for setting the column values, and should set the attributes
        of the cell renderer as appropriate. func may be None to remove the
        current data function. The signature of func is:
        -def celldatafunction(column, cell_renderer, tree_model, iter, lcolor)
        -def celldatamethod(self,column,cell_renderer,tree_model, iter, lcolor)
        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)
        _global_row_path =  self.__active_path_record + (_row_path[0],)
        _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_cells()[1].set_property(
                'cell-background', 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, _global_row_path)
            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',
                globalVars.color["ACTIVE"])
        else:
            cell_renderer.set_property('cell-background',
                lcolor[_number % 2])

    def _showParentRecord(self, column):
        """_showParentRecord(column)
        
        column: the column that is clicked
        Method connected to "clicked" event of many columns
        Show the parent record
        """
        _budget = self.__budget
        if len(self.__active_path_record) == 1:
            # The active record is the root record
            # This avoid to move the cursor to the clicked column
            if isinstance(self.__cursor[0],Gtk.TreePath):
                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.__wr_page()
            _page.propagateMessageFrom("change_active", self.__pane_path, arg)
            self.__treeview.set_cursor(_parent, self.__cursor[1])
            self.__cursor = self.__treeview.get_cursor()

    def _showMessageRecord(self, record_path):
        """_showMessageRecord(record_path)
        
        record_path: the path of  the record to show
        Method connected to "change_active" message
        Show the record especified in the "change_active" message
        """
        _budget = self.__budget
        self.__active_path_record = record_path
        self._setColumnsHeaders()
        self._setListstoreValues(self.__active_path_record)
        self.__treeview.set_cursor((0,))

    def _showRowRecord(self, treeview, treeview_path, column):
        """_showRowRecord(treeview, treeview_path, column)
        
        treeview: treview to show
        treeview_path: the path of the record to show
        code: the code of the record to show
        
        Method connected to "row-activated" event
        The "row-activated" signal is emitted when the row_activated() method
        is called or the user double clicks a treeview row.
        "row-activated" is also emitted when a non-editable row is selected
        and one of the keys: Space, Shift+Space, Return or Enter is pressed.
        Show the especified record
        """
        if not (column is self.__end_column) and \
           not (column is self.__index_column):
            _budget = self.__budget
            _model = treeview.get_model()
            _iter = _model.get_iter(treeview_path)
            _code = _model.get_value(_iter, 0).code
            _path_record = self.__active_path_record
            for _indice  in treeview_path.get_indices():
                _path_record =  _path_record + (_indice,)
            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.__wr_page()
                _page.propagateMessageFrom("change_active", self.__pane_path,
                                       _arg )

    def runMessage(self, message, pane_path, arg=None):
        """runMessage(message, pane_path, arg=None)
        
        message: the message type
            "change_active": change the active record
            "clear": clear instance
        pane_path: tuple that identifies the pane in the notebook page
        arg: tuple whit two items:
            0: record path in the budget
            1: record code
        This method receives a message and executes its corresponding action
        """
        _budget = self.__budget
        if message == "change_active":
            if _budget.hasPath(arg):
                _path_record = arg
                self._showMessageRecord( _path_record)
        elif message == "clear":
            self._clear()

    def _clear(self):
        """_clear()
        
        it deletes the __budget reference
        """
        del self.__budget 

    def _getWidget(self):
        """_getWidget()
        
        return the main widget (Gtk.ScrolledWindow)
        """
        return self.__scrolled_window

    def _getPanePath(self):
        """_getPanePath()
        
        return the tuple that identifies the pane in the notebook page
        """
        return self.__pane_path

    def _setPanePath(self, pane_path):
        """_setPanePath()
        
        sets the tuple that identifies the pane in the notebook page
        """
        self.__pane_path = pane_path

    def _getWrPage(self):
        """_getPage()
        
        return the Page
        """
        return self.__wr_page

    def _setWrPage(self,wr_page):
        """_setWrPage()
        
        set the wr_Page
        """
        self.__wr_page = wr_page

    def _getBudget(self):
        """_getBudget()
        
        return the Budget objet
        """
        return self.__budget

    def _getActivePathRecord(self):
        """_getActivePathRecord()
        
        return the Active Path Record
        """
        return self.__active_path_record

    widget = property(_getWidget, None, None,
        "Pane configuration list")
    pane_path = property(_getPanePath, _setPanePath, None,
        "path that identifie the item in the page notebook")
    wr_page = property(_getWrPage, _setWrPage, None,
        "weak reference from Page instance which creates this class")
    budget =  property(_getBudget, None, None,
        "Budget object")
    active_path_record =  property(_getActivePathRecord, None, None,
        "Active path record")


class Measure(TreeView):
    """gui.Measure:
    
    Description:
        Class to show a Measure List
    Constructor:
        Measure(budget, page, pane_path, path_record=None)
        budget: budget showed ("base.Budget" object)
        page: weak reference from Page instance which creates this class
        pane_path: tuple that represents the path of the List in the Page
        path_record: path of the active record in the budget
    Ancestry:
    +-- object
      +-- TreeView
        +-- DecompositionList
    Atributes:
        budget: Read. Budget to show, base.obra instance.
        widget: Read. Window that contains the table, Gtk.ScrolledWindow
        pane_path: Read-Write. Pane page identifier
        wr_page: Read-Write. weak reference from Page instance which creates
              this class
        active_path_record: Read. Path of the active record in the budget
    Methods:
        runMessage
    """

    def __init__(self, budget, page, pane_path, path_record=None):
        """__init__(budget, page, pane_path, path_record=None)
        
        budget: budget: budget showed ("base.Budget" object)
        wr_page: weak reference from Page instance which creates this class
        pane_path: tuple that represents the path of the List in the Page
        path_record: path of the active record in the budget
        
        self.__budget: budget showed ("base.Budget" object)
        self.__page: weak reference from Page instance which creates this class
        self.__pane_path: tuple that represents the path of the List in the Page
        self.__active_path_record: path of the active record in the budget
        self.__liststore: list model which store the list data
            (Gtk.ListStore object)
        self.__treeview:  widget to display decomposition lists
            (Gtk.TreeView)
        self.__scrolled_window: widget to scroll the treeview
            Gtk.ScrolledWindow()
        self.__chapter_background_colors: The background colors of the Code
            column cells when there is a chapter record
            as a list of color [even cell, uneven cell]
        self.__index_column: Index column (Gtk.TreeViewColumn object)
        self.__linetype_column: Linetype column (Gtk.TreeViewColumn object)
        self.__comment_column: Comment column (Gtk.TreeViewColumn)
        self.__unit_column: Unit column (Gtk.TreeViewColumn)
        self.__length_column: Legth column (Gtk.TreeViewColumn)
        self.__width_column: With column (Gtk.TreeViewColumn)
        self.__height_column: Height column (Gtk.TreeViewColumn)
        self.__formula_column: Formula column (Gtk.TreeViewColumn)
        self.__parcial_column: Parcial column (Gtk.TreeViewColumn)
        self.__subtotal_column: Subtotal column (Gtk.TreeViewColumn)
        self.__end_column: End empty column (Gtk.TreeViewColumn
        self.__calculatedline_icon: GdkPixbuf.Pixbuf
        self.__normalline_icon: GdkPixbuf.Pixbuf
        self.__parcialline_icon: GdkPixbuf.Pixbuf
        self.__acumulatedline_icon: GdkPixbuf.Pixbuf
        self.__treeselection: active selection
        self.__selection_control: state of the selection control (True/False)
        self.__cursor: Situation of the cursor in the table
        
        Sets the init atributes
        Creates the init list values in self.__liststore from the budget 
            showing the top record from the record with path path_record
        Creates the list in self.__treeview
            * Creates the columns and cell
            * Sets te the column headers values
            * Sets the selection properties
            * Connects the events
        """
        # Seting init args
        if path_record is None:
            path_record = (0,)
        if not isinstance(budget, base.Budget):
            raise ValueError( _("Argument must be a Budget object") )
        self.__budget = budget
        self.__wr_page = page
        self.__pane_path = pane_path
        if not isinstance(path_record, tuple):
            print(_("Record path must be a tuple") )
            path_record = (0,)
        self.__active_path_record = path_record
        # ListStore
        self.__liststore = Gtk.ListStore(object)
        self._setListstoreValues(self.__active_path_record)
        # Treeview
        self.__treeview = Gtk.TreeView(self.__liststore)
        self.__treeview.set_enable_search(False)
        self.__treeview.set_reorderable(False)
        self.__treeview.set_headers_clickable(True)
        self.__treeview.show()
        # Scrolled_window
        self.__scrolled_window = Gtk.ScrolledWindow()
        self.__scrolled_window.set_property("expand", True) # widget expand all space
        self.__scrolled_window.set_policy(Gtk.PolicyType(1),
                                          Gtk.PolicyType(1)) # 1 Automatic
        self.__scrolled_window.add(self.__treeview)
        # colors
        _text_color = globalVars.color["TEXT"]
        _calculated_text = globalVars.color["CALCULATED-TEXT"]
        _background_color = [
            globalVars.color["UNEVEN"],
            globalVars.color["EVEN"]]
        self.__chapter_background_colors = [
            globalVars.color["CHAPTER-UNEVEN"],
            globalVars.color["CHAPTER-EVEN"]]
        super(Measure,self).__init__(
            [("INDEX",self._selectAll,42),
            ("PIXBUF", self._passMethod, 40,
             _text_color, _background_color),
            ("CALCULATEDTEXT", self._passMethod, 128,
             _text_color, _background_color),
            ("CALCULATED", self._passMethod, 55,
             _text_color, _background_color),
            ("CALCULATED", self._passMethod, 70,
             _text_color, _background_color),
            ("CALCULATED", self._passMethod, 70,
             _text_color, _background_color),
            ("CALCULATED", self._passMethod, 70,
             _text_color, _background_color),
            ("CALCULATEDTEXT", self._passMethod, 120,
             _text_color, _background_color),
            ("CALCULATED", self._passMethod, 70,
             _calculated_text, _background_color),
            ("CALCULATED", self._passMethod, 70,
             _calculated_text, _background_color),
            ])
        # Colums
        self.__index_column = self.columns[0]
        self.__linetype_column = self.columns[1]
        self.__comment_column = self.columns[2]
        self.__units_column = self.columns[3]
        self.__length_column = self.columns[4]
        self.__width_column = self.columns[5]
        self.__height_column = self.columns[6]
        self.__formula_column = self.columns[7]
        self.__parcial_column = self.columns[8]
        self.__subtotal_column = self.columns[9]
        self.__end_column = self.columns[10]
        # Index column
        self.__treeview.append_column(self.__index_column)
        # Linetype column
        self.__treeview.append_column(self.__linetype_column)
        self.__calculatedline_icon = GdkPixbuf.Pixbuf.new_from_file(
            globalVars.getAppPath("CALCULATEDLINE-ICON"))
        self.__normalline_icon = GdkPixbuf.Pixbuf.new_from_file(
            globalVars.getAppPath("NORMALLINE-ICON") )
        self.__parcialline_icon  = GdkPixbuf.Pixbuf.new_from_file(
            globalVars.getAppPath("PARCIALLINE-ICON") )
        self.__acumulatedline_icon = GdkPixbuf.Pixbuf.new_from_file(
            globalVars.getAppPath("ACUMULATEDLINE-ICON"))
        # Comment column
        self.__treeview.append_column(self.__comment_column)
        # Units column
        self.__treeview.append_column(self.__units_column)
        # Length column
        self.__treeview.append_column(self.__length_column)
        # Width_column
        self.__treeview.append_column(self.__width_column)
        # Height column
        self.__treeview.append_column(self.__height_column)
        # Formula column
        self.__treeview.append_column(self.__formula_column)
        # Parcial column
        self.__treeview.append_column(self.__parcial_column)
        # Subtotal column
        self.__treeview.append_column(self.__subtotal_column)
        # End Column
        self.__treeview.append_column(self.__end_column)
        # Connect
        self.__treeview.connect("move-cursor", self._moveCursor)
        self.__treeview.connect("key-press-event", self._treeviewKeyPressEvent)
        self.__treeview.connect("button-press-event",
            self._treeviewClickedEvent)
        self.__treeview.connect("cursor-changed", self._treeviewCursorChanged)
        # control selection
        self.__treeselection = self.__treeview.get_selection()
        self.__treeselection.set_mode(Gtk.SelectionMode(3)) #  3 MULTIPLE
        self.__treeselection.set_select_function(self._controlSelection)
        self.__selection_control = True
        if len(self.__liststore) > 0:
            _tree_path = Gtk.TreePath.new_from_indices((1,))
            self.__treeview.set_cursor_on_cell(_tree_path, self.columns[1],
            self.columns[1].get_cells()[0],True)
        self.__treeview.grab_focus()
        self.__cursor = self.__treeview.get_cursor()
        # Show
        self._setColumnsHeaders()
        self.__scrolled_window.show()

    def _treeviewCursorChanged(self, treeview):
        """_treeviewCursorChanged(treeview)
        
        treeview: treewiew widget
        Method connected to "cursor-changed" signal
        The "cursor-changed" signal is emitted when the cursor moves or is set
        Sets the new cursor position in self.__cursor, it is used to avoid 
        unnecessary changes in cursor position.
        """
        event = Gtk.get_current_event()
        (_cursor_path, _column) = treeview.get_cursor()
        if event is None or event.type !=  Gdk.EventType(7): # 7 BUTTON_RELEASE
            if not _column is self.__index_column:
                self.__cursor = treeview.get_cursor()

    def _treeviewClickedEvent(self, widget, event):
        """_treeviewClickedEvent(widget, event)
        
        widget: treewiew widget
        event: clicked event
        Method connected to "button-press-event" signal
        The "button-press-event" signal is emitted when a mouse button is
        pressed.
        Returns TRUE to stop other handlers from being invoked for the event.
        Returns FALSE to propagate the event further.
        
        The events in end column are ignored.
        If the user click in a row of the index column the cursor is moved to
        this row but not to the index column
        """
        if event.button == 1:
            path_at_pos = self.__treeview.get_path_at_pos(int(event.x),
                                                        int(event.y))
            if not path_at_pos is None: 
                _path_cursor, _column, _x, _y = path_at_pos
                if _column == self.columns[-1]:
                    return True
                if _column is self.columns[0]:
                    self.__cursor[0] == _path_cursor
        return False

    def _treeviewKeyPressEvent(self, widget, event):
        """_treeviewKeyPressEvent(widget, event)
        
        widget: treewiew widget
        event: Key Press event
        Method connected to "key-press-event" signal
        The "key-press-event" signal is emitted when the user presses a key
        on the keyboard.
        Returns :TRUE to stop other handlers from being invoked for the event.
        Returns :FALSE to propagate the event further.
        
        If the user press the right cursor button and the cursor is in the
        amount column or pres the left cursor button and the cursor is
        in the code column the event is estoped, else the event is propagated. 
        """
        (_cursor_path, _column) = self.__treeview.get_cursor()
        if (event.keyval in [Gdk.keyval_from_name("Right"),
                             Gdk.keyval_from_name("KP_Right")] \
            and _column == self.columns[-2]) \
            or (event.keyval in [Gdk.keyval_from_name("Left"),
                             Gdk.keyval_from_name("KP_Left")] \
            and _column == self.columns[1]):
            return True
        return False

    def _moveCursor(self, treeview, step, count):
        """moveCursor(treeview, step, count)
        
        treeview: the treeview that received the signal
        step: the movement step size
        count: the number of steps to take
        
        Method connected to "move-cursor" signal
        The "move-cursor" signal is emitted when the user moves the cursor
        using the Right, Left, Up or Down arrow keys or the Page Up,
        Page Down, Home and End keys.
        
        Returns :TRUE if the signal was handled.
        """
        return False

    def _controlSelection(self, selection, model, path, path_currently_selected, *data):
        """_controlSelection(selection)
        
        selection: treeselection
        
        Method connected to set_selection_function() 
        This method is called before any node is selected or unselected,
        giving some control over which nodes are selected.
        The selection function should return TRUE if the state
        of the node may be toggled, and FALSE if the state of the node should
        be left unchanged.
        
        The selection only run if the user click in the index column, else
        the previous selection is erased.
        """
        _column = self.__treeview.get_cursor()[1]
        if _column is self.columns[0] \
            or self.__selection_control == False:
            return True
        else:
            self.__selection_control = False
            self.__treeselection.unselect_all()
            self.__selection_control = True
            return False 

    def _selectAll(self, column):
        """_selectAll(column)
        
        column: index column
        Method connected to "clicked" event in the index column
        If the user clickes in the index column header selecs or deselects 
        all rows
        """
        (_model, _pathlist) = self.__treeselection.get_selected_rows()
        # it avoid to set cursor in the index column
        if isinstance(self.__cursor[0],Gtk.TreePath):
            self.__treeview.set_cursor(self.__cursor[0], self.__cursor[1])
            self.__selection_control = False
            if len(_pathlist) == 0:
                # select all
                self.__treeselection.select_all()
            else:
                # unselect all
                self.__treeselection.unselect_all()
            self.__selection_control = True

    def _setColumnsHeaders(self):
        """_setColumnsHeaders()
        
        Sets the headers column values
        """
        _measure = self.__budget.getMeasure(self.__active_path_record)
        _DS = self.__budget.getDecimals("DS")
        _total = _measure.measure
        _total_str = ("%." + str(abs(_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 _setListstoreValues(self, path_record):
        """_setListstoreValues(path_record)
        
        path_record: Record path in the budget
        Sets the liststore record values from a path record
        """
        self.__liststore.clear()
        _budget = self.__budget
        if not _budget.hasPath(path_record):
            raise ValueError( _("Invalid path") )
        else:
            _measure = _budget.getMeasure(path_record)
            if isinstance(_measure, base.Measure):
                _lines = _measure.lines
                for _line in _lines:
                    _values = [ _line ]
                    _treeiter = self.__liststore.append(_values)
            else:
                raise ValueError( utils.mapping(_("measure must be a Measure "\
                      "object. Type: $1"), (str(type(_measure)),)) )

    def _colorCell(self, column, cell_renderer, tree_model, iter, lcolor):
        """_colorCell(column, cell_renderer, tree_model, iter, lcolor)
        
        column: the Gtk.TreeViewColumn in the treeview
        cell_renderer: a Gtk.CellRenderer
        tree_model: the Gtk.TreeModel
        iter: Gtk.TreeIter pointing at the row
        lcolor: list with 2 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_cells()[1].set_property(
                'cell-background', 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(abs(_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(abs(_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(abs(_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(abs(_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(abs(_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 = globalVars.color["SUBTOTAL-PARCIAL"]
                    _subtotal = _measure_line.parcial_subtotal
                else: #elif _type == 2:
                    _color = globalVars.color["SUBTOTAL"]
                    _subtotal = _measure_line.acumulated_subtotal
                lcolor = [_color, _color]
                if isinstance(_subtotal, float):
                    _DS = self.__budget.getDecimals("DS")
                    _subtotal= ("%." + str(abs(_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',
                globalVars.color["ACTIVE"])
        else:
            cell_renderer.set_property('cell-background',
                lcolor[_number % 2])

    def _passMethod(self, column):
        """_passMethod(column)
        
        column: the column that is clicked
        Method connected to "clicked" event of many columns
        Do nothing
        """
        pass

    def _showMessageRecord(self, record_path):
        """_showMessageRecord(record_path)
        
        record_path: the path of the record to show
        Method connected to "change_active" message
        Show the record especified in the "change_active" message
        """
        _budget = self.__budget
        self.__active_path_record = record_path
        self._setColumnsHeaders()
        self._setListstoreValues(self.__active_path_record)
        self.__treeview.set_cursor((0,))

    def runMessage(self, message, pane_path, arg=None):
        """runMessage(message, pane_path, arg=None)
        
        message: the message type
            "change_active": change the active record
            "clear": clear instance
        pane_path: tuple that identifies the pane in the notebook page
        arg: tuple whit two items:
            0: record path in the budget
            1: record code
        This method receives a message and executes its corresponding action
        """
        _budget = self.__budget
        if message == "change_active":
            if _budget.hasPath(arg):
                _path_record = arg
                self._showMessageRecord( _path_record)
        elif message == "clear":
            self._clear()

    def _clear(self):
        """_clear()
        
        it deletes the __budget value
        """
        del self.__budget

    def _getWidget(self):
        """_getWidget()
        
        return the main widget (Gtk.ScrolledWindow)
        """
        return self.__scrolled_window

    def _getPanePath(self):
        """_getPanePath()
        
        return the tuple that identifies the pane in the notebook page
        """
        return self.__pane_path

    def _setPanePath(self, pane_path):
        """_setPanePath()
        
        sets the tuple that identifies the pane in the notebook page
        """
        self.__pane_path = pane_path

    def _getWrPage(self):
        """_getPage()
        
        return the Page
        """
        return self.__wr_page

    def _setWrPage(self,wr_page):
        """_setPage()
        
        set the Page
        """
        self.__wr_page = wr_page

    def _getBudget(self):
        """_getBudget()
        
        return the Budget objet
        """
        return self.__budget

    def _getActivePathRecord(self):
        """getActivePathRecord()
        
        return the Active Path Record
        """
        return self.__active_path_record

    widget = property(_getWidget, None, None,
        "Pane configuration list")
    pane_path = property(_getPanePath, _setPanePath, None,
        "Path that identifies the item in the page notebook")
    wr_page = property(_getWrPage, _setWrPage, 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:
        budget: budget showed ("base.Budget" object)
        page: weak reference from Page instance which creates this class
        pane_path: tuple that represents the view path in the Page
        path_record: the record path that must be showed
        Returns the newly created DecompositionList instance
    Ancestry:
    +-- object
      +-- Description
    Atributes:
        budget: Read. Budget to show, base.obra object.
        widget: the main widget (Gtk.ScrolledWindow object)
        pane_path: Read-Write. Pane page identifier
        wr_page: Read-Write. weak ref from Page object which creates this class
        active_path_record: Read. Active path record
    Methods:
        runMessage
    """
    # TODO: make standard: "DecompositonList and Description"

    def __init__(self, budget, wr_page, pane_path, path_record=None):
        """__init__(budget, page, pane_path, path_record=None)
        
        budget: the budget (base.obra object)
        wr_page: weak reference from Page instance which creates this class
        pane_path: the path position of the description in the page
        path_record: the path of the active record
        
        self.__budget: the budget (base.obra object)
        self.__wr_page: weak reference from Page instance which creates this class
        self.__pane_path: the path position of the description in the page
        self.__active_path_recordthe path of the active record

        self.__textbuffer: The textbuffer of the textview that contain
            the record text.
        self.__label: The Gtk.label with the title of the pane
        self.__widget: the main pane widget, a Gtk.ScrolledWindow()
        
        Creates an shows the scroledwindow that contain the description text
        of the record to be showed in a pane.
        """
        if path_record is None:
            path_record = (0,)
        self.__budget = budget
        self.__wr_page = wr_page
        self.__pane_path = pane_path
        self.__active_path_record = path_record
        _budget = budget
        _text = _budget.getRecord(self.__budget.getCode(
                self.__active_path_record)).text
        _scrollwindow = Gtk.ScrolledWindow()
        _scrollwindow.set_property("expand", True) # widget expand all space
        _scrollwindow.set_policy(Gtk.PolicyType(1),
                                        Gtk.PolicyType(1)) # 1 Automatic
        _scrollwindow.set_shadow_type(1) # NONE 0, IN 1, OUT 2, ETCHED_IN 3,ETCHED_OUT 4
        _textview = Gtk.TextView()
        _textview.set_wrap_mode(2) # 2 Word
        _textview.set_hexpand(True)
        _textview.set_vexpand(True)
        self.__textbuffer = _textview.get_buffer()
        self.__textbuffer.set_text(_text)
        _textview.show()
        _vbox = Gtk.Grid()
        _vbox.set_orientation(Gtk.Orientation(1)) # 1 Vertical
        self.__label = Gtk.Label(utils.mapping(_("Description text of the "\
                     "record $1"), (str(self.__budget.getCode(
                    self.__active_path_record)),)))
        self.__label.set_alignment(0, 0)
        self.__label.show()
        _vbox.add(self.__label)
        _vbox.add(_textview)
        _vbox.show()
        _scrollwindow.add(_vbox)
        _scrollwindow.show()
        self.__widget = _scrollwindow

    def _setActivePathRecord(self, path_record):
        """_setActivePathRecord(path_record))
        
        path_record: active path record
        Set the new path code to show its description text.
        """
        _budget = self.__budget
        self.__active_path_record = path_record
        _code = _budget.getCode(self.__active_path_record)
        self.__label.set_text(utils.mapping(_("Description text of the record "\
            "$1"), (_code.decode("utf8"),)))
        _text = _budget.getRecord(_code).text
        self.__textbuffer.set_text(_text)

    def runMessage(self, message, pane_path, arg=None):
        """runMessage(message, pane_path, arg=None)
        
        message: the message type
            "change_active": change the active record
            "clear": clear instance
        pane_path: tuple that identifies the pane in the notebook page
        arg: tuple whit two items:
            0: record path in the budget
            1: record code
        This method receives a message and executes its corresponding action
        """
        _budget = self.__budget
        if message == "change_active":
            if _budget.hasPath(arg):
                self._setActivePathRecord(arg)
        elif message == "clear":
            self._clear()

    def _clear(self):
        """_clear()
        
        Delete all instance atributes
        """
        del self.__widget
        del self.__pane_path
        del self.__budget
        del self.__active_code
        del self.__textbuffer
        del self.__label

    def _getWidget(self):
        """_getWidget()
        
        return the main widget (Gtk.ScrolledWindow)
        """
        return self.__widget

    def _getPanePath(self):
        """_getPanePath()
        
        return the tuple that identifies the pane in the notebook page
        """
        return self.__pane_path

    def _setPanePath(self, pane_path):
        """_setPanePath()
        
        sets the tuple that identifies the pane in the notebook page
        """
        self.__pane_path = pane_path

    def _getWrPage(self):
        """_getWrPage()
        
        return the weak reference from Page instance
        """
        return self.__wr_page

    def _setWrPage(self, wr_page):
        """_setWrPage()
        
        set the weak reference from Page instance
        """
        self.__wr_page = wr_page

    def _getBudget(self):
        """_getBudget()
        
        return the budget object
        """
        return self.__budget

    def _getActivePathRecord(self):
        """_getActivePathRecord()
        
        return the Active Path Record
        """
        return self.__active_path_record

    pane_path = property(_getPanePath, _setPanePath, None,
        "Path that identifie the item in the page notebook")
    widget = property(_getWidget, None, None,
        "The main widget (Gtk.ScrolledWindow)")
    wr_page = property(_getWrPage, _setWrPage, 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:
        budget: The budget (base.obra objetc)
        widget: the main widget (Gtk.Grid object)
        pane_path: the tuple that identifies the pane in the notebook page
        wr_page: weak reference from Page instance which creates this class
        active_path_record: The active path record
    Methods:
        runMessage
    """

    def __init__(self, budget, wr_page, pane_path, path_record=None):
        """__init__(budget, wr_page, pane_path, path_record=None)
        
        budget: the budget (base.obra object)
        wr_page: weak reference from Page instance which creates this class
        pane_path: the path position of the description in the page
        path_record: the path of the active record
        
        self.__budget: the budget (base.obra object)
        self.__wr_page: weak reference from Page instance which creates this class
        self.__pane_path: the path position of the description in the page
        self.__active_path_record: the path of the active record
        self.__label: The Gtk.label with the title of the pane
        self.__field_liststore: the field liststore
        self.__field_treeview: the field treeview
        self.__field_selection: the field selected in field treview
        self.__section_liststore: the section liststore
        self.__section_treeview: the section treeview
        self.__section_selection: the section selected in the section treeview
        self.__textbuffer: The textbuffer of the textview that contain
            the record text.
        self.__widget: main widget, a Gtk.Grid()
        
        Creates an shows the scroledwindow that contain the description text
        of the record to be showed in a pane.
        """
        if path_record is None:
            path_record = (0,)
        self.__budget = budget
        self.__wr_page = wr_page
        self.__pane_path = pane_path
        self.__active_path_record = path_record
        _budget = budget
        _main_box = Gtk.Grid()
        _main_box.set_orientation(Gtk.Orientation(1)) # 1 Vertical
        self.__label = Gtk.Label(utils.mapping(_("Sheet of Conditions of the "\
                       "record $1"), (self.__budget.getCode(
                       self.__active_path_record),)))
        self.__label.set_xalign(0)
        self.__label.set_yalign(0)
        self.__label.show()
        _frame = Gtk.Frame()
        _frame.set_shadow_type(Gtk.ShadowType(1)) # 1 In
        _frame_box = Gtk.Grid()
        _frame_box.set_orientation(Gtk.Orientation(1)) # 1 Vertical
        _list_box = Gtk.Grid()
        _list_box.set_orientation(Gtk.Orientation(0)) # 0 Horizontal
        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.SelectionMode(1)) #  1 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.PolicyType(1),
                                        Gtk.PolicyType(1)) # 1 Automatic
        _field_scrollwindow.set_property("hexpand", True) # widget expand all space
        _field_scrollwindow.add(self.__field_treeview)
        _field_scrollwindow.set_size_request(-1, 80)
        _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.SelectionMode(1)) #  1 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.PolicyType(1),
                                        Gtk.PolicyType(1)) # 1 Automatic
        _section_scrollwindow.set_property("hexpand", True) # widget expand all space
        _section_scrollwindow.set_size_request(-1, 90)
        _section_scrollwindow.add(self.__section_treeview)
        _section_scrollwindow.show()
        
        _list_box.add(_field_scrollwindow)
        _list_box.add(_section_scrollwindow)
        _list_box.show()
        
        _scrollwindow = Gtk.ScrolledWindow()
        _scrollwindow.set_policy(Gtk.PolicyType(1),
                                        Gtk.PolicyType(1)) # 1 Automatic
        _scrollwindow.set_property("expand", True) # widget expand all space
        _textview = Gtk.TextView()
        _textview.set_wrap_mode(2) # 2 Word
        _textview.set_property("expand", True) # widget expand all space
        self.__textbuffer = _textview.get_buffer()
        _textview.show()
        _hbox = Gtk.Grid()
        _hbox.set_orientation(Gtk.Orientation(0)) # 0 Horizontal
        _hbox.add(_textview)
        _hbox.show()
        _frame_box.add(self.__label)
        _frame_box.add(_list_box)
        _frame_box.show()
        _frame.add(_frame_box)
        _frame.show()
        _main_box.add(_frame)
        _vbox = Gtk.Grid()
        _vbox.set_orientation(Gtk.Orientation(1)) # 1 Vertical
        _vbox.add(_hbox)
        _vbox.show()
        _main_box.add(_scrollwindow)
        _main_box.show()
        _scrollwindow.add(_vbox)
        _scrollwindow.show()
        self.__widget = _main_box
        self._setFields()

    def _setFields(self):
        """_setFields()
        
        Set the fields items in the field treeview
        """
        _record = self.__budget.getRecord(self.__budget.getCode(
                  self.__active_path_record))
        _sheet = _record.getSheet()
        _field_list = _sheet.getFields()
        self.__field_liststore.clear()
        for _field in _field_list:
            _field_text = self.__budget.getSheetField(_field)
            _iter = self.__field_liststore.append([_field, _field_text])
        _treeselection = self.__field_treeview.get_selection()
        _treeselection.select_path(0)

    def _setSection(self):
        """_setSection()
        
        Set the section items in the section treeview
        """
        self.__section_liststore.clear()
        if not self.__field_selection is None:
            _record = self.__budget.getRecord(self.__budget.getCode(
                  self.__active_path_record))
            _sheet = _record.getSheet()
            _section_list = _sheet.getSections(self.__field_selection)
            for _section in _section_list:
                _section_text = self.__budget.getSheetSection(_section)
                _iter = self.__section_liststore.append([_section, _section_text])
            _treeselection = self.__section_treeview.get_selection()
            _treeselection.select_path(0)

    def _setText(self):
        """_setText()
        
        Set the text in the textview
        """
        if not self.__section_selection is None and\
           not self.__field_selection is None:
            _record = self.__budget.getRecord(self.__budget.getCode(
                  self.__active_path_record))
            _sheet = _record.getSheet()
            _paragraph_code = _sheet.getParagraph(self.__field_selection,
                                                  self.__section_selection)
            _paragraph = self.__budget.getSheetParagraph(_paragraph_code)
            self.__textbuffer.set_text(_paragraph)
        else:
            self.__textbuffer.set_text("")

    def _field_controlSelection(self, selection, model, path,
                                path_currently_selected, *data):
        """_controlSelection(selection, model, path,
                             path_currently_selected, *data)
        
        selection: treeselection
        path: selected path
        
        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(path)
        self.__field_selection = self.__field_liststore.get_value(_treeiter, 0)
        self._setSection()
        return True

    def _section_controlSelection(self, selection, model, path,
                                  path_currently_selected, *data):
        """_section_controlSelection(selection, model, 
                                     path, path_currently_selected, *data)
        
        selection: treeselection
        path: selected path
        
        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(path)
        self.__section_selection = self.__section_liststore.get_value(_treeiter, 0)
        self._setText()
        return True

    def _setActivePathRecord(self, path_record):
        """_setActivePathRecord(path_record))
        
        path_record: active path record
        
        Set the new path code to show its sheet of condition text.
        """
        self.__field_selection = None
        self.__field_liststore.clear()
        self.__section_selection = None
        self.__section_liststore.clear()
        self.__textbuffer.set_text("")
        _budget = self.__budget
        self.__active_path_record = path_record
        _code = _budget.getCode(self.__active_path_record)
        self.__label.set_text(utils.mapping(_("Sheet2 of Conditions of the "\
                     "record $1"), (_code,)))
        self._setFields()

    def runMessage(self, message, pane_path, arg=None):
        """runMessage(message, pane_path, arg=None)
        
        message: the message type
            "change_active": change the active record
            "clear": clear instance
        pane_path: tuple that identifies the pane in the notebook page
        arg: tuple whit two items:
            0: record path in the budget
            1: record code
        This method receives a message and executes its corresponding action
        """
        _budget = self.__budget
        if message == "change_active":
            if _budget.hasPath(arg):
                self._setActivePathRecord(arg)
        elif message == "clear":
            self._clear()

    def _clear(self):
        """_clear()
        
        Deletes all the instance atributes
        """
        del self.__wr_page
        del self.__widget
        del self.__pane_path
        del self.__budget
        del self.__active_code
        del self.__textbuffer
        del self.__label
        del self.__textbuffer
        del self.__label
        del self.__field_liststore
        del self.__field_treeview
        del self.__field_selection
        del self.__section_liststore
        del self.__section_treeview
        del self.__section_selection

    def _getWidget(self):
        """_getWidget()
        
        return the main widget (Gtk.ScrolledWindow)
        """
        return self.__widget

    def _getPanePath(self):
        """_getPanePath()
        
        return the tuple that identifies the pane in the notebook page
        """
        return self.__pane_path

    def _setPanePath(self, pane_path):
        """_setPanePath()
        
        sets the tuple that identifies the pane in the notebook page
        """
        self.__pane_path = pane_path

    def _getWrPage(self):
        """_getWrPage()
        
        return the weak reference from Page instance
        """
        return self.__wr_page

    def _setWrPage(self, wr_page):
        """_setWrPage()
        
        set the weak reference from Page instance
        """
        self.__wr_page = wr_page

    def _getBudget(self):
        """_getBudget()
        
        return the budget object
        """
        return self.__budget

    def _getActivePathRecord(self):
        """_getActivePathRecord()
        
        return the Active Path Record
        """
        return self.__active_path_record

    pane_path = property(_getPanePath, _setPanePath, None,
        "Path that identifie the item in the page notebook")
    widget = property(_getWidget, None, None,
                      "Lista de configuracion de vistas")
    wr_page = property(_getWrPage, _setWrPage, None,
        "Weak reference from Page instance which creates this class")
    budget = property(_getBudget, None, None,
        "Budget object")
    active_path_record = property(_getActivePathRecord, None, None,
        "Active Path Record")


class FileView(object):
    """gui.FileView
    
    Description:
        Class to show the file icons of a record in a pane
    Constructor:
        Description(budget, page, pane_path, path_record=None)
        budget: the budget (base.obra object)
        wr_page: weak reference from Page instance which creates this class
        pane_path: the path position of the description in the page
        path_record: the path of the active record
    Ancestry:
    +-- object
      +-- FileView
    Atributes:
        widget: the main widget (Gtk.ScrolledWindow object)
        pane_path: the tuple that identifies the pane in the notebook page
        budget: The budget (base.obra object)
        active_path_record: Read.
        wr_page: Read-Write. weak reference from Page instance which creates this class
    Methods:
        runMessage
    """

    def __init__(self, budget, wr_page, pane_path, path_record=None):
        """__init__(budget, page, pane_path, path_record=None)
        
        budget: the budget (base.obra object)
        wr_page: weak reference from Page instance which creates this class
        pane_path: the path position of the description in the page
        path_record: the path of the active record
        
        self.__budget: the budget (base.obra object)
        self.__wr_page: weak reference from Page instance which creates this class
        self.__pane_path: the path position of the description in the page
        self.__active_path_record: the path of the active record
        self.__active_code: the code of the active record
        self.__icon_box: the box that contains the icon
        self.__widget: main widget, a Gtk.ScrolledWindow
        
        Creates an shows the scroledwindow that contain icon files
        of the record to be showed in a pane.
        """
        if path_record is None:
            path_record = (0,)
        self.__budget = budget
        self.__wr_page = wr_page
        self.__pane_path = pane_path
        self.__active_path_record = path_record
        self.__active_code = budget.getCode(self.__active_path_record)
        _budget = budget
        _record = self.__budget.getRecord(self.__budget.getCode(
                    self.__active_path_record))
                    
        self.__icon_box = self._getIconBox(_record)
        _scrollwindow = Gtk.ScrolledWindow()
        _scrollwindow.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
        self.__icon_box.show()
        _scrollwindow.add(self.__icon_box)
        _scrollwindow.show()
        self.__widget = _scrollwindow

    def _getIconBox(self, record):
        """_getIconBox(record)
        
        record: the active record object
        
        Creates and returns the box whith te icon files of the active record.
        """
        _files = record.getFiles()
        _flowbox = Gtk.FlowBox()
        _flowbox.set_valign(Gtk.Align.START)
        _flowbox.set_max_children_per_line(30)
        _flowbox.set_selection_mode(Gtk.SelectionMode.NONE)
        _flowbox.set_property("expand", True) # widget expand all space
        for _file in _files:
            _path = os.path.dirname(self.__budget.filename)
            _file_path = os.path.join(_path, _file.name)
            _box = Gtk.Grid()
            _box.set_orientation(Gtk.Orientation(1)) # 1 Vertical
            if os.path.exists(_file_path):
                _filetype = utils.getFiletype(_file_path)
                _event_box = Gtk.LinkButton()
                _file_icon = Gtk.Image()
                # "image", "wmf", "dxf", "pdf" , "video",
                # "office-document", "office-presentation", "office-spreadsheet",
                # "html", "rtf", "txt", ""
                # icon
                if _filetype in ["image", "wmf"]:
                    try:
                        _image_pixbuf = GdkPixbuf.Pixbuf.new_from_file(_file_path)
                        _image_pixbuf = _image_pixbuf.scale_simple(64, 64,
                                        GdkPixbuf.InterpType(2)) # 2 BILINEAR
                    except:
                        _image_pixbuf = GdkPixbuf.Pixbuf.new_from_file(
                                        globalVars.getAppPath("IMAGE-ICON"))
                        _image_pixbuf = _image_pixbuf.scale_simple(64, 64,
                                        GdkPixbuf.InterpType(2)) # 2 BILINEAR
                    _file_icon.set_from_pixbuf(_image_pixbuf)
                    _event_box.connect("activate-link", self._launchFile,
                                       _filetype, _file_path)
                elif _filetype == "dxf":
                    _dxf_pixbuf = GdkPixbuf.Pixbuf.new_from_file(
                                        globalVars.getAppPath("DXF-ICON"))
                    _dxf_pixbuf = _dxf_pixbuf.scale_simple(64, 64,
                                  GdkPixbuf.InterpType(2)) # 2 BILINEAR
                    _file_icon.set_from_pixbuf(_dxf_pixbuf)
                    _event_box.connect("activate-link", self._launchFile,
                                       "dxf", _file_path)
                elif _filetype == "pdf":
                    _pdf_pixbuf = GdkPixbuf.Pixbuf.new_from_file(
                                        globalVars.getAppPath("PDF-ICON"))
                    _pdf_pixbuf = _pdf_pixbuf.scale_simple(64, 64,
                                  GdkPixbuf.InterpType(2)) # 2 BILINEAR
                    _file_icon.set_from_pixbuf(_pdf_pixbuf)
                    _event_box.connect("activate-link", self._launchFile,
                                       "pdf", _file_path)
                elif _filetype == "video":
                    _video_pixbuf = Gtk.IconTheme.get_default().load_icon(
                                    "video-x-generic", 64, 0)
                    _file_icon.set_from_pixbuf(_video_pixbuf)
                    _event_box.connect("activate-link", self._launchFile,
                                       "video", _file_path)
                elif _filetype == "office-document":
                    _document_pixbuf = Gtk.IconTheme.get_default().load_icon(
                                       "x-office-document", 64, 0)
                    _file_icon.set_from_pixbuf(_document_pixbuf)
                    _event_box.connect("activate-link", self._launchFile,
                                       "office-document", _file_path)
                elif _filetype == "office-presentation":
                    _presentation_pixbuf = Gtk.IconTheme.get_default().load_icon(
                                           "x-office-presentation", 64, 0)
                    _file_icon.set_from_pixbuf(_presentation_pixbuf)
                    _event_box.connect("activate-link", self._launchFile,
                                       "office-presentation", _file_path)
                elif _filetype == "office-spreadsheet":
                    _spreadsheet_pixbuf = Gtk.IconTheme.get_default().load_icon(
                                          "x-office-spreadsheet", 64, 0)
                    _file_icon.set_from_pixbuf(_spreadsheet_pixbuf)
                    _event_box.connect("activate-link", self._launchFile,
                                       "office-spreadsheet", _file_path)
                elif _filetype == "html":
                    _html_pixbuf = Gtk.IconTheme.get_default().load_icon(
                                   "text-html", 64, 0)
                    _file_icon.set_from_pixbuf(_html_pixbuf)
                    _event_box.connect("activate-link", self._launchFile,
                                       "html", _file_path)
                elif _filetype == "rtf":
                    _rtf_pixbuf = Gtk.IconTheme.get_default().load_icon(
                                  "text-x-generic", 64, 0)
                    _file_icon.set_from_pixbuf(_rtf_pixbuf)
                    _event_box.connect("activate-link", self._launchFile,
                                       "rtf", _file_path)
                elif _filetype == "txt":
                    _txt_pixbuf = Gtk.IconTheme.get_default().load_icon(
                                  "text-x-generic", 64, 0)
                    _file_icon.set_from_pixbuf(_txt_pixbuf)
                    _event_box.connect("activate-link", self._launchFile,
                                       "txt", _file_path)
                else:
                    _missing_pixbuf = Gtk.IconTheme.get_default().load_icon(
                                      "image-missing", 64, 0)
                    _file_icon.set_from_pixbuf(_missing_pixbuf)
                    # Is secure open no detected filetype?
                    #_event_box.connect("activate-link", self._launchFile,
                    #                   "", _file_path)
                    _event_box = Gtk.EventBox()
                _event_box.add(_file_icon)
                _event_box.props.margin = 5 
                _box.add(_event_box)
                _file_icon.show()
                _event_box.show()
            # label
            _label_event_box = Gtk.EventBox()
            _label = Gtk.Label(_file.name)
            _label_event_box.add(_label)
            _label_event_box.show()
            _label.show()
            _label_event_box.props.margin = 5
            _box.add(_label_event_box)
            _box.show()
            _box.props.margin = 5
            _flowbox.add(_box)
        _flowbox.show()
        #_scrolled.show()
        return _flowbox

    def _launchFile(self, widget, kind, file_path):
        """_launchFile(widget, event, kind, file_path)
        
        widget: the widget that emit the signal
        king: kind of file
        file_path: the path file to be launch
        
        Launch the file if a click emit the signal.
        Method connected to "activate-link" signal in images botton link
        Return True: stops propagate event and avoids to raise an error
        when opening an empty uri.
        """
        openwith.launch_file(kind, file_path)
        return True

    def _setActivePathRecord(self, path_record):
        """_setActivePathRecord(path_record))
        
        path_record: active path record
        Set the new path code to show its description text.
        """
        _budget = self.__budget
        self.__active_path_record = path_record
        _code = _budget.getCode(self.__active_path_record)
        _record = self.__budget.getRecord(_code)
        self.__icon_box.destroy()
        self.__icon_box = self._getIconBox(_record)
        self.__icon_box.show()
        self.__widget.add_with_viewport(self.__icon_box)

    def runMessage(self, message, pane_path, arg=None):
        """runMessage(message, pane_path, arg=None)
        
        message: the message type
            "change_active": change the active record
            "clear": clear instance
        pane_path: tuple that identifies the pane in the notebook page
        arg: tuple whit two items:
            0: record path in the budget
            1: record code
        This method receives a message and executes its corresponding action
        """
        _budget = self.__budget
        if message == "change_active":
            if _budget.hasPath(arg):
                self._setActivePathRecord(arg)
        elif message == "clear":
            self._clear()

    def _clear(self):
        """_clear()
        
        Delete all instance atributes
        """
        del self.__widget
        del self.__pane_path
        del self.__budget
        del self.__active_code

    def _getWidget(self):
        """_getWidget()
        
        return the main widget (Gtk.ScrolledWindow)
        """
        return self.__widget

    def _getPanePath(self):
        """_getPanePath()
        
        return the tuple that identifies the pane in the notebook page
        """
        return self.__pane_path

    def _setPanePath(self, pane_path):
        """_setPanePath()
        
        sets the tuple that identifies the pane in the notebook page
        """
        self.__pane_path = pane_path

    def _getWrPage(self):
        """_getWrPage()
        
        return the weak reference from Page instance
        """
        return self.__wr_page

    def _setWrPage(self, wr_page):
        """setPage()
        
        set the weak reference from Page instance
        """
        self.__wr_page = wr_page

    def _getBudget(self):
        """getBudget()
        
        return the budget object
        """
        return self.__budget

    def _getActivePathRecord(self):
        """_getActivePathRecord()
        
        return the Active Path Record
        """
        return self.__active_path_record

    pane_path = property(_getPanePath, _setPanePath, None,
        "Path that identifie the item in the page notebook")
    widget = property(_getWidget, None, None,
        "The main widget (Gtk.ScrolledWindow)")
    wr_page = property(_getWrPage, _setWrPage, None,
        "Weak reference from Page instance which creates this class")
    budget = property(_getBudget, None, None,
        "Budget object")
    active_path_record = property(_getActivePathRecord, None, None,
        "Active Path Record")


class CompanyView(object):
    """gui:CompanyView:
    
    Description:
        Class to show the company records of a budget
    Constructor:
        CompanyView(budget, wr_page, pane_path, path_record=(None)
        budget: budget showed ("base.Budget" object)
        wr_page: weak reference from Page instance which creates this class
        pane_path: tuple that represents the path of the List in the Page
        path_record: path of the active record in the budget
    Ancestry:
    +-- object
      +-- CompanyView
    Atributes:
        active_path_record: Read. Path of the active record in the budget
        widget: Read. Window that contains the main widget, a Gtk.Paned
        pane_path: Read-Write. Pane page identifier
        wr_page: Read-Write. weak reference from Page instance which creates this class
        budget: Read. Budget to show, base.budget instance.
    Methods:
        runMessage
    """

    def __init__(self, budget, wr_page, pane_path, path_record=None):
        """__init__(budget, wr_page, pane_path, path_record=None)
        
        budget: budget showed ("base.Budget" object)
        wr_page: weak reference from Page instance which creates this class
        pane_path: tuple that represents the path of the pane in the Page
        path_record: path of the active record in the budget
        
        self.__selection: "company" or "office" selected treeview
        self.__budget: budget: budget showed ("base.Budget" object)
        self.__wr_page: weak reference from Page instance which creates this class
        self.__pane_path: tuple that represents the path of the List in the Page
        self.__active_path_record: path of the active record in the budget
        self.__widget: main widget, a Gtk.Paned
        self.__treestore: to store companys data
        self.__option_View: OptionView object
        
        Creates an shows the widgets with the company data.
        """
        if path_record is None:
            path_record = (0,)
        self.__selection = None
        # Seting init args
        if not isinstance(budget, base.Budget):
            raise ValueError( _("Argument must be a Budget object") )
        self.__budget = budget
        self.__wr_page = wr_page
        self.__pane_path = pane_path
        self.__active_path_record = path_record
        # main widget
        self.__widget = Gtk.Paned.new(Gtk.Orientation(0)) # 0 Horizontal
        self.__widget.set_position(230)
        # TreeStore
        self.__treestore = Gtk.TreeStore(str, str)
        self._setTreeStoreValues()
        # Select Treeview
        _select_treeview = Gtk.TreeView(self.__treestore)
        _select_treeview.set_enable_search(False)
        _select_treeview.set_reorderable(False)
        _select_treeview.set_headers_visible(False)
        _select_treeview.show()
        # Scrolled_window
        _scrolled_window = Gtk.ScrolledWindow()
        _scrolled_window.set_property("expand", True) # widget expand all space
        _scrolled_window.set_policy(Gtk.PolicyType(1),
                                    Gtk.PolicyType(1)) # 1 Automatic
        _scrolled_window.add(_select_treeview)
        # colors
        _text_color = globalVars.color["TEXT"]
        _background_color = [
            globalVars.color["UNEVEN"],
            globalVars.color["EVEN"]]
        _code_column = Gtk.TreeViewColumn()
        _code_column.set_clickable(True)
        _code_column.set_fixed_width(200)
        _code_cell = Gtk.CellRendererText()
        _code_cell.set_property('foreground', _text_color)
        _code_column.pack_start(_code_cell, True)
        _code_column.add_attribute(_code_cell, 'text', 0)
        _summary_cell = Gtk.CellRendererText()
        _summary_cell.set_property('foreground', _text_color)
        _code_column.pack_start(_summary_cell, True)
        _code_column.add_attribute(_summary_cell, 'text', 1)
        # Index column
        _select_treeview.append_column(_code_column)
        # control selection
        _treeselection = _select_treeview.get_selection()
        _treeselection.set_mode(Gtk.SelectionMode(1)) #  1 SINGLE
        _treeselection.set_select_function(self._controlSelection)
        # Show
        _scrolled_window.show()
        # Option View
        self.__option_View = OptionView()
        # Add to main widget
        self.__widget.add1(_scrolled_window)
        self.__widget.add2(self.__option_View.widget)
        # Selection
        _select_treeview.set_cursor((0,), None, False)
        _select_treeview.grab_focus()
        # Show
        self.__widget.show()

    def _setOptions(self, type):
        """_setOptions(type)
        
        type: "company" or "office"
        Sets the Options in the OptionView
        """
        if type == "company":
            _options = [("code", _("Code"), "string",
                         _("""Code that define the company""")),
                        ("summary", _("Summary"), "string",
                         _("""Summary of the company name""")),
                        ("name", _("Name"), "string",
                         _("""Complete name""")),
                        ("cif", _("CIF"), "string",
                         _("""Fiscal identifier number""")),
                        ("web", _("Web"), "string",
                         _("""Company web page""")),
                        ("email", _("Email"), "string",
                         _("""Company email""")),
                        ]
            self.__option_View.options = _options
        elif type == "office":
            _options = [("officeType", _("Type"), "string",
                         _("""Type of Office:
                           C: Central office
                           D: Local office
                           R: Performer""")),
                        ("subname", _("Name"), "string",
                         _("Office name")),
                        ("address", _("Address"), "string",""),
                        ("postal code", _("Postal code"), "string",""),
                        ("town", _("Town"), "string",""),
                        ("province", _("Province"), "string",""),
                        ("country", _("Country"), "string",""),
                        ("phone", _("Phone"), "list",
                         _("Phone numbers of the office")),
                        ("fax", _("Fax"), "list",
                         _("Fax numbers of the office")),
                        ("contact person", _("Contact person"), "string",
                         _("Contact persons in the office")),
                       ]
            self.__option_View.options = _options
        else:
            print(_("Unknow Option Type") )

    def _setTreeStoreValues(self):
        """_setTreeStoreValues()
        
        Sets the treestore values from the budget
        """
        _budget = self.__budget
        _company_keys = _budget.getCompanyKeys()
        for _company_key in _company_keys:
            _company = _budget.getCompany(_company_key)
            _values = [_company_key, _company.summary]
            _treeiter = self.__treestore.append(None, _values)
            _offices = _company.offices
            for _office in _offices:
                # TODO: Test offices
                _values = [_office.officeType, _office.subname]
                self.__treestore.append(_treeiter, _values)

    def _controlSelection(self, selection, model, path, path_currently_selected, *data):
        """_controlSelection(selection, model, path, path_currently_selected, *data)
        
        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(path) == 1:
            # The selection is a company
            _company_key = self.__treestore[path][0]
            _company = self.__budget.getCompany(_company_key)
            _selection = "company"
            _values = _company.values
        else:
            # The selection is a office
            _company_key = self.__treestore[path[:1]][0]
            _company = self.__budget.getCompany(_company_key)
            _selection = "office"
            _office = _company.offices[path[1]]
            _values = _office.values
        if not self.__selection == _selection:
            self.__selection = _selection
            self._setOptions(_selection)
        self.__option_View.values = _values
        return True

    def _showMessageRecord(self, record_path):
        """_showMessageRecord(record_path)
        
        record_path: the path of the record to show
        Method connected to "change_active" message
        Show the record especified in the "change_active" message
        """
        self.__active_path_record = record_path

    def runMessage(self, message, pane_path, arg=None):
        """runMessage(message, pane_path, arg=None)
        
        message: the message type
            "change_active": change the active record
            "clear": clear instance
        pane_path: tuple that identifies the pane in the notebook page
        arg: tuple whit two items:
            0: record path in the budget
            1: record code
        This method receives a message and executes its corresponding action
        """
        _budget = self.__budget
        if message == "change_active":
            if _budget.hasPath(arg):
                _path_record = arg
                self._showMessageRecord( _path_record)
            pass
        elif message == "clear":
            self._clear()

    def _colorCell(self, column, cell_renderer, tree_model, iter, lcolor):
        """_colorCell(column, cell_renderer, tree_model, iter, lcolor)
        
        column: the Gtk.TreeViewColumn in the treeview
        cell_renderer: a Gtk.CellRenderer
        tree_model: the Gtk.TreeModel
        iter: Gtk.TreeIter pointing at the row
        lcolor: list with 2 gtk colors for even and uneven record
        
        Method connected to "set_cell_data_func" of many column
        The set_cell_data_func() method sets the data function (or method) 
        to use for the column Gtk.CellRenderer specified by cell_renderer.
        This function (or method) is used instead of the standard attribute
        mappings for setting the column values, and should set the attributes
        of the cell renderer as appropriate. func may be None to remove the
        current data function. The signature of func is:
        -def celldatafunction(column, cell, model, iter, user_data)
        -def celldatamethod(self, column, cell, model, iter, user_data)
        where column is the Gtk.TreeViewColumn in the treeview, cell is the
        Gtk.CellRenderer for column, model is the Gtk.TreeModel for the
        treeview and iter is the Gtk.TreeIter pointing at the row.
        
        The method sets cell background color for all columns
        and text for index and amount columns.
        """
        _row_path = tree_model.get_path(iter)
        _number = _row_path[-1]
        if column is self.__index_column:
            cell_renderer.set_property('text', str(_number + 1))
            self.__index_column.get_cells()[1].set_property(
                'cell-background', lcolor[_number % 2])
        if self.__treeview.get_cursor() == (_row_path,column):
            cell_renderer.set_property('cell-background',
                globalVars.color["ACTIVE"])
        else:
            cell_renderer.set_property('cell-background',
                lcolor[_number % 2])

    def _clear(self):
        """_clear()
        
        it deletes the self.__budget value
        """
        del self.__budget

    def _getWidget(self):
        """_getWidget()
        
        return the main widget (Gtk.ScrolledWindow)
        """
        return self.__widget

    def _getPanePath(self):
        """_getPanePath()
        
        return the tuple that identifies the pane in the notebook page
        """
        return self.__pane_path

    def _setPanePath(self, pane_path):
        """_setPanePath()
        
        sets the tuple that identifies the pane in the notebook page
        """
        self.__pane_path = pane_path

    def _getWrPage(self):
        """_getWrPage()
        
        return the Page
        """
        return self.__wr_page

    def _setWrPage(self,wr_page):
        """_setWrPage()
        
        set the Page
        """
        self.__wr_page = wr_page

    def _getBudget(self):
        """_getBudget()
        
        return the Budget objet
        """
        return self.__budget
    
    def _getActivePathRecord(self):
        """_getActivePathRecord()
        
        return the Active Path Record
        """
        return self.__active_path_record
    
    active_path_record = property(_getActivePathRecord, None, None,
        "Active path record")
    widget = property(_getWidget, None, None,
        "main widget")
    pane_path = property(_getPanePath, _setPanePath, None,
        "Path that identifies the item in the page notebook")
    wr_page = property(_getWrPage, _setWrPage, 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()
    Ancestry:
    +-- object
      +-- OptionView
    Atributes:
        widget: Read. Main widget
        options: Write
        values: Write
    Methods:
        No public Methods
    """

    def __init__(self):
        """__init__()
        
        self.__option_dict:
            {"option key" : ["option name", "value", "option type",
                              "option_description"]}
        self.__option_list: option keys list
        self.__option_types: valid option types list
        self.__liststore: Gtk.ListStore
        self.__treeview: Gtk.TreeView
        self.__option_column: option column
        self.__value_column: value column
        self.__type_column: type column
        self.__description_label: Gtk.Label
        self.__widget: Main widget
        
        Creates an shows the widget that contain the option data.
        """
        self.__option_dict = {}
        self.__option_list = []
        self.__option_types = {"boolean" : _("Boolean"),
                             "integer": _("Integer"),
                             "string":  _("Text"),
                             "color" : _("Color"),
                             "list" : _("List")}
        # ListStore
        self.__liststore = Gtk.ListStore(str, str, str, str, str)
        # Treeview
        self.__treeview = Gtk.TreeView(self.__liststore)
        self.__treeview.set_enable_search(False)
        self.__treeview.set_reorderable(False)
        self.__treeview.set_headers_clickable(False)
        # vbox
        _vbox = Gtk.Grid()
        _vbox.set_orientation(Gtk.Orientation(1)) # 1 Vertical
        # Scrolled_window
        _scrolled_window = Gtk.ScrolledWindow()
        _scrolled_window.set_property("expand", True) # widget expand all space
        _scrolled_window.set_policy(Gtk.PolicyType(1),
                                 Gtk.PolicyType(1)) # 1 Automatic
        _scrolled_window.add(self.__treeview)
        _scrolled_window.show()
        _vbox.add(_scrolled_window)
        # colors
        _text_color = globalVars.color["TEXT"]
        _background_color = [
            globalVars.color["UNEVEN"],
            globalVars.color["EVEN"]]
        # Option Column
        self.__option_column = Gtk.TreeViewColumn()
        self.__option_column.set_sizing(Gtk.TreeViewColumnSizing(2)) # 2 Fixed
        self.__option_column.set_fixed_width(150)
        self.__option_column.set_resizable(True)
        _option_cell = Gtk.CellRendererText()
        _option_cell.set_property('foreground', _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.TreeViewColumnSizing(2)) # 2 Fixed
        self.__value_column.set_fixed_width(275)
        self.__value_column.set_resizable(True)
        _value_cell = Gtk.CellRendererText()
        _value_cell.set_property('foreground', _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.TreeViewColumnSizing(2)) # 2 Fixed
        self.__type_column.set_fixed_width(70)
        self.__type_column.set_resizable(True)
        _type_cell = Gtk.CellRendererText()
        _type_cell.set_property('foreground', _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',
                               globalVars.color["UNEVEN"])
        _end_column.pack_start(_end_cell, True)
        self.__treeview.append_column(_end_column)
        # Connect
        self.__treeview.connect("key-press-event", self._treeviewKeyPressEvent)
        self.__treeview.connect("button-press-event", 
            self._treeviewClickedEvent)
        # control selection
        _treeselection = self.__treeview.get_selection()
        _treeselection.set_mode(Gtk.SelectionMode(3)) #  3 MULTIPLE
        _treeselection.set_select_function(self._controlSelection)
        # labels
        _frame = Gtk.Frame()
        _frame.set_shadow_type(2) # NONE 0, IN 1, OUT 2, ETCHED_IN 3,ETCHED_OUT 4
        _vbox2 = Gtk.Grid()
        _vbox2.set_orientation(Gtk.Orientation(1)) # 1 Vertical
        _frame.add(_vbox2)
        _label = Gtk.Label()
        _label.set_xalign(0)
        _label.set_yalign(0)
        _label.set_margin_start(12)
        _label.set_markup("<b>" + _("Description:") + "</b>")
        _label.show()
        self.__description_label  = Gtk.Label()
        self.__description_label.set_xalign(0)
        self.__description_label.set_yalign(0)
        self.__description_label.set_margin_start(24)
        self.__description_label.show()
        _vbox2.add(_label)
        _vbox2.add(self.__description_label)
        _vbox2.show()
        _frame.show()
        _vbox.add(_frame)
        # Show
        self.__treeview.show()
        _vbox.show()
        self.__widget = _vbox

    def _treeviewKeyPressEvent(self, widget, event):
        """_treeviewKeyPressEvent(widget, event)
        
        widget: treewiew widget
        event: Key Press event
        Method connected to "key-press-event" signal
        The "key-press-event" signal is emitted when the user presses a key
        on the keyboard.
        Returns :TRUE to stop other handlers from being invoked for the event.
        Returns :FALSE to propagate the event further.
        
        If the user press the right cursor button and the cursor is in the
        value column or press 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 in [Gdk.keyval_from_name("Right"),
                             Gdk.keyval_from_name("KP_Right")]  \
           and _column == self.__value_column) \
           or (event.keyval in [Gdk.keyval_from_name("Left"),
                             Gdk.keyval_from_name("KP_Left")]  \
           and _column == self.__value_column):
            return True
        else:
            _description = self.__liststore[_cursor_path][4]
            self.__description_label.set_text(_description)
            return False

    def _treeviewClickedEvent(self, widget, event):
        """_treeviewClickedEvent(widget, event)
        
        widget: treewiew widget
        event: clicked event
        Method connected to "button-press-event" signal
        The "button-press-event" signal is emitted when a mouse button is
        pressed.
        Returns TRUE to stop other handlers from being invoked for the event.
        Returns FALSE to propagate the event further.
        
        The cursos is moved to value column.
        """
        path_at_pos = self.__treeview.get_path_at_pos(int(event.x),
                                                      int(event.y))
        if not path_at_pos is None:
            _path_cursor, _column, _x, _y = path_at_pos
            _description = self.__liststore[_path_cursor][4]
            self.__description_label.set_text(_description)
            if _column == self.__value_column:
                return False
            else:
                self.__treeview.set_cursor(_path_cursor,self.__value_column,
                                           True)
                self.__treeview.grab_focus()
                return True
        return True

    def _controlSelection(self, selection, model, path, path_currently_selected,
                          *data):
        """_controlSelection(selection, model, path, path_currently_selected,
                             *data)
        
        selection: treeselection
        
        Method connected to set_selection_function() 
        This method is called before any node is selected or unselected,
        giving some control over which nodes are selected.
        The selection function should return TRUE if the state
        of the node may be toggled, and FALSE if the state of the node should
        be left unchanged.
        
        Return False so none row is selected
        """
        return False

    def _colorCell(self, column, cell_renderer, tree_model, iter, lcolor):
        """_colorCell(column, cell_renderer, tree_model, iter, lcolor)
        
        column: the Gtk.TreeViewColumn in the treeview
        cell_renderer: a Gtk.CellRenderer
        tree_model: the Gtk.TreeModel
        iter: Gtk.TreeIter pointing at the row
        lcolor: list with 2 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',
                globalVars.color["ACTIVE"])
        else:
            cell_renderer.set_property('cell-background',
                lcolor[_number % 2])
        if column is self.__type_column:
            _type = self.__option_types[tree_model[_row_path][3]]
            cell_renderer.set_property('text', _type)

    def _setOptions(self, option_list):
        """_setOptions(option_list)
        
        option_list: list of tuples
            (option, option name, type)
            option: option identifier
            option name: a string with the option name
            Description: a string with the option description
            type: can be "boolean"
                         "integer"
                         "string"
                         "color"
        Sets the Options in the treeview rows
        """
        self.__option_dict = {}
        self.__option_list = []
        self.__liststore.clear()
        if isinstance(option_list, list):
            for _option in option_list:
                if isinstance(_option, tuple) and len(_option) == 4:
                    _option_key = _option[0]
                    _option_name = _option[1]
                    _option_type = _option[2]
                    _option_description = _option[3]
                    #-# str and unicode
                    if (isinstance(_option_key, str) or \
                        isinstance(_option_key, unicode)) and \
                       (isinstance(_option_name, str) or\
                       isinstance(_option_name, unicode))and \
                       _option_type in self.__option_types.keys():
                        self.__liststore.append([_option_key, _option_name, "",
                            _option_type, _option_description])
                        self.__option_dict[_option_key] = [_option_name, "",
                            _option_type, _option_description]
                        self.__option_list.append(_option_key)
                    else:
                        print(_("Option values must be strings") )
                else:
                    print(_("Option must be a tuple with 4 items") )
        else:
            print(_("Option list must be a list") )

    def _setValues(self, values):
        """_setValues(values)
        
        values: dictionary {option : value}

        Sets the Options values
        """
        if isinstance(values, dict):
            for _option, _value in values.iteritems():
                if _option in self.__option_dict:
                    _type = self.__option_dict[_option][2]
                    if _type == "boolean":
                        if isinstance(_value, bool):
                            _num = self.__option_list.index(_option)
                            _iter = self.__liststore.get_iter((_num,))
                            self.__liststore.set_value(_iter, 2, _value)
                            self.__option_dict[_option][1] = _value
                        else:
                            print(_("Icorrect type, must be boolean") )
                    elif _type == "integer":
                        try:
                            _value = int(_value)
                        except ValueError:
                            print(_("Icorrect type, must be integer") )
                        else:
                            _num = self.__option_list.index(_option)
                            _iter = self.__liststore.get_iter((_num,))
                            self.__liststore.set_value(_iter, 2, _value)
                            self.__option_dict[_option][1] = _value
                    elif _type == "string":
                        if isinstance(_value, str):
                            _num = self.__option_list.index(_option)
                            _iter = self.__liststore.get_iter((_num,))
                            self.__liststore.set_value(_iter, 2, _value)
                            self.__option_dict[_option][1] = _value
                        else:
                            print(_("Icorrect type, must be string") )
                    elif _type == "list":
                        if isinstance(_value, list):
                            _num = self.__option_list.index(_option)
                            _iter = self.__liststore.get_iter((_num,))
                            _str_value = ""
                            for _item_value in _value:
                                _str_value = _str_value + _item_value + ","
                            if _str_value[-1] == ",":
                                _str_value = _str_value[:-1]
                            self.__liststore.set_value(_iter, 2, _str_value)
                            self.__option_dict[_option][1] = _value
                        else:
                            print(_("Icorrect type, must be list") )
                    elif _type == "color":
                        if isinstance(_value, str):
                            if Gdk.RGBA().parse(_value):
                                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") )
                    print(_option, _value)
        else:
            print( _("Values must be a dict") )
        self.__treeview.set_cursor(Gtk.TreePath.new_from_indices((0,)),
                                   self.__value_column, False)
        self.__treeview.grab_focus()
        (_cursor_path, _column) = self.__treeview.get_cursor()
        _description = self.__liststore[_cursor_path][4]
        self.__description_label.set_text(_description)

    def _getWidget(self):
        """_getWidget()
        
        return the main widget (Gtk.ScrolledWindow)
        """
        return self.__widget

    widget = property(_getWidget, None, None,
        "main widget")
    values = property(None, _setValues, None,
        "values")
    options = property(None, _setOptions, None,
        "options")