Example #1
0
class AdditionListSlave(SearchSlave):
    """A slave that offers a simple list and its management.

    This slave also has the option to display a small message right next to the
    buttons
    """

    domain = 'stoq'
    toplevel_name = gladefile = 'AdditionListSlave'
    widgets = ('add_button', 'delete_button', 'klist', 'list_vbox',
               'edit_button')
    gsignal('on-edit-item', object)
    gsignal('on-add-item', object)
    gsignal('before-delete-items', object)
    gsignal('after-delete-items')

    def __init__(self,
                 store,
                 columns=None,
                 editor_class=None,
                 klist_objects=None,
                 visual_mode=False,
                 restore_name=None,
                 tree=False):
        """ Creates a new AdditionListSlave object

        :param store:         a store
        :param columns:       column definitions
        :type columns:        sequence of :class:`kiwi.ui.objectlist.Columns`
        :param editor_class:  the window that is going to be open when user
                              clicks on add_button or edit_button.
        :type: editor_class:  a :class:`stoqlib.gui.editors.BaseEditor` subclass
        :param klist_objects: initial objects to insert into the list
        :param visual_mode:   if we are working on visual mode, that means,
                              not possible to edit the model on this object
        type visual_mode:     bool
        :param restore_name:  the name used to save and restore the columns
                              on a cache system (e.g. pickle)
        :type restore_name:   basestring
        :param tree:          Indication of which kind of list we are adding.
                              If `True` ObjectTree otherwise ObjectList will be
                              added
        """
        columns = columns or self.get_columns()
        SearchSlave.__init__(self,
                             columns=columns,
                             restore_name=restore_name,
                             store=store)
        self.tree = tree
        self.klist = ObjectTree() if tree else ObjectList()
        self.list_vbox.add(self.klist)
        self.list_vbox.show_all()

        if not self.columns:
            raise StoqlibError("columns must be specified")
        self.visual_mode = visual_mode
        self.store = store
        self.set_editor(editor_class)
        self._can_edit = True
        self._callback_id = None
        if self.visual_mode:
            self.hide_add_button()
            self.hide_edit_button()
            self.hide_del_button()
        items = klist_objects or self.get_items()
        self._setup_klist(items)
        self._update_sensitivity()

    def _setup_klist(self, klist_objects):
        self.klist.set_columns(self.columns)
        self.klist.set_selection_mode(gtk.SELECTION_MULTIPLE)
        if self.tree:
            (self.klist.append(obj.parent_item, obj) for obj in klist_objects)
        else:
            self.klist.add_list(klist_objects)
        if self.visual_mode:
            self.klist.set_sensitive(False)

    def _update_sensitivity(self, *args):
        if self.visual_mode:
            return
        can_delete = _can_edit = True
        objs = self.get_selection()
        if not objs:
            _can_edit = can_delete = False
        elif len(objs) > 1:
            _can_edit = False

        self.add_button.set_sensitive(True)
        self.edit_button.set_sensitive(_can_edit)
        self.delete_button.set_sensitive(can_delete)

    def _edit_model(self, model=None, parent=None):
        edit_mode = model
        result = self.run_editor(model)

        if not result:
            return

        if edit_mode:
            self.emit('on-edit-item', result)
            self.klist.update(result)
        else:
            if self.tree:
                self.klist.append(parent, result)
            else:
                self.klist.append(result)
            # Emit the signal after we added the item to the list to be able to
            # check the length of the list in our validation callbacks.
            self.emit('on-add-item', result)

        # As we have a selection extended mode for kiwi list, we
        # need to unselect everything before select the new instance.
        self.klist.unselect_all()
        self.klist.select(result)
        self._update_sensitivity()

    def _edit(self):
        if not self._can_edit:
            return
        objs = self.get_selection()
        qty = len(objs)
        if qty != 1:
            raise SelectionError(
                ("Please select only one item before choosing Edit."
                 "\nThere are currently %d items selected") % qty)
        self._edit_model(objs[0])

    def _clear(self):
        objs = self.get_selection()
        qty = len(objs)
        if qty < 1:
            raise SelectionError('There are no objects selected')

        msg = stoqlib_ngettext(_('Delete this item?'),
                               _('Delete these %d items?') % qty, qty)
        delete_label = stoqlib_ngettext(_("Delete item"), _("Delete items"),
                                        qty)

        keep_label = stoqlib_ngettext(_("Keep it"), _("Keep them"), qty)
        if not yesno(msg, gtk.RESPONSE_NO, delete_label, keep_label):
            return
        self.emit('before-delete-items', objs)
        if qty == len(self.klist):
            self.klist.clear()
        else:
            for obj in objs:
                self.klist.remove(obj)
        self.klist.unselect_all()
        self._update_sensitivity()
        self.emit('after-delete-items')

    #
    # Hooks
    #

    def get_items(self):
        return []

    def get_columns(self):
        raise NotImplementedError("get_columns must be implemented in "
                                  "subclasses")

    def run_editor(self, model):
        """This can be overriden to provide a custom run_dialog line,
        or a conversion function for the model
        """
        if self._editor_class is None:
            raise TypeError(
                "%s cannot create or edit items without the editor_class "
                "argument set" % (self.__class__.__name__))

        self.store.savepoint('before_run_editor_addition')
        retval = run_dialog(self._editor_class,
                            None,
                            store=self.store,
                            model=model)
        if not retval:
            self.store.rollback_to_savepoint('before_run_editor_addition')
        return retval

    def delete_model(self, model):
        """Deletes a model, can be overridden in subclass
        :param model: model to delete
        """
        model.__class__.delete(model.id, store=self.store)

    #
    # Public API
    #

    def add_extra_button(self, label=None, stock=None):
        """Add an extra button on the this slave

        The extra button will be appended at the end of the button box,
        the one containing the add/edit/delete buttons

        :param label: label of the button, can be ``None`` if stock is passed
        :param stock: stock label of the button, can be ``None`` if label
            is passed
        :param returns: the button added
        :rtype: gtk.Button
        """
        if label is None and stock is None:
            raise TypeError("You need to provide a label or a stock argument")

        button = gtk.Button(label=label, stock=stock)
        button.set_property('can_focus', True)
        self.button_box.pack_end(button, False, False)
        button.show()

        return button

    def set_message(self, message, details_callback=None):
        """Display a simple message on a label, next to the add, edit, delete buttons
        :param message: a message with properly escaped markup
        """
        self.message_hbox.set_visible(True)
        self.message_details_button.set_visible(bool(details_callback))
        if details_callback:
            if self._callback_id:
                self.message_details_button.disconnect(self._callback_id)
            self._callback_id = self.message_details_button.connect(
                'clicked', details_callback)

        self.message_label.set_markup(message)

    def clear_message(self):
        self.message_hbox.set_visible(False)

    def get_selection(self):
        # XXX: add get_selected_rows and raise exceptions if not in the
        #      right mode
        if self.klist.get_selection_mode() == gtk.SELECTION_MULTIPLE:
            return self.klist.get_selected_rows()
        selection = self.klist.get_selected()
        if not selection:
            return []
        return [selection]

    def hide_add_button(self):
        self.add_button.hide()

    def hide_edit_button(self):
        self._can_edit = False
        self.edit_button.hide()

    def hide_del_button(self):
        self.delete_button.hide()

    def set_editor(self, editor_class):
        if editor_class and not issubclass(editor_class,
                                           (BaseEditor, BaseWizard)):
            raise TypeError("editor_class must be a BaseEditor subclass")
        self._editor_class = editor_class

    #
    # Signal handlers
    #

    def on_klist__row_activated(self, *args):
        self._edit()

    def on_klist__selection_changed(self, *args):
        self._update_sensitivity()

    def on_add_button__clicked(self, button):
        self._edit_model()

    def on_edit_button__clicked(self, button):
        self._edit()

    def on_delete_button__clicked(self, button):
        self._clear()
Example #2
0
class AdditionListSlave(SearchSlave):
    """A slave that offers a simple list and its management.

    This slave also has the option to display a small message right next to the
    buttons
    """

    domain = 'stoq'
    toplevel_name = gladefile = 'AdditionListSlave'
    widgets = ('add_button',
               'delete_button',
               'klist',
               'list_vbox',
               'edit_button')
    gsignal('before-edit-item', object, retval=object)
    gsignal('on-edit-item', object)
    gsignal('on-add-item', object)
    gsignal('before-delete-items', object)
    gsignal('after-delete-items')

    def __init__(self, store, columns=None, editor_class=None,
                 klist_objects=None, visual_mode=False, restore_name=None,
                 tree=False):
        """ Creates a new AdditionListSlave object

        :param store:         a store
        :param columns:       column definitions
        :type columns:        sequence of :class:`kiwi.ui.objectlist.Columns`
        :param editor_class:  the window that is going to be open when user
                              clicks on add_button or edit_button.
        :type: editor_class:  a :class:`stoqlib.gui.editors.BaseEditor` subclass
        :param klist_objects: initial objects to insert into the list
        :param visual_mode:   if we are working on visual mode, that means,
                              not possible to edit the model on this object
        type visual_mode:     bool
        :param restore_name:  the name used to save and restore the columns
                              on a cache system (e.g. pickle)
        :type restore_name:   basestring
        :param tree:          Indication of which kind of list we are adding.
                              If `True` ObjectTree otherwise ObjectList will be
                              added
        """
        columns = columns or self.get_columns()
        SearchSlave.__init__(self, columns=columns,
                             restore_name=restore_name,
                             store=store)
        self.tree = tree
        self.klist = ObjectTree() if tree else ObjectList()
        self.list_vbox.add(self.klist)
        self.list_vbox.show_all()

        if not self.columns:
            raise StoqlibError("columns must be specified")
        self.visual_mode = visual_mode
        self.store = store
        self.set_editor(editor_class)
        self._can_edit = True
        self._callback_id = None
        if self.visual_mode:
            self.hide_add_button()
            self.hide_edit_button()
            self.hide_del_button()
        items = klist_objects or self.get_items()
        self._setup_klist(items)
        self._update_sensitivity()

    def _setup_klist(self, klist_objects):
        self.klist.set_columns(self.columns)
        self.klist.set_selection_mode(gtk.SELECTION_MULTIPLE)
        if self.tree:
            (self.klist.append(obj.parent_item, obj) for obj in klist_objects)
        else:
            self.klist.add_list(klist_objects)
        if self.visual_mode:
            self.klist.set_sensitive(False)

    def _update_sensitivity(self, *args):
        if self.visual_mode:
            return
        can_delete = _can_edit = True
        objs = self.get_selection()
        if not objs:
            _can_edit = can_delete = False
        elif len(objs) > 1:
            _can_edit = False

        self.add_button.set_sensitive(True)
        self.edit_button.set_sensitive(_can_edit)
        self.delete_button.set_sensitive(can_delete)

    def _edit_model(self, model=None, parent=None):
        edit_mode = model
        result = self.emit('before-edit-item', model)
        if result is None:
            result = self.run_editor(model)

        if not result:
            return

        if edit_mode:
            self.emit('on-edit-item', result)
            self.klist.update(result)
        else:
            if self.tree:
                self.klist.append(parent, result)
            else:
                self.klist.append(result)
            # Emit the signal after we added the item to the list to be able to
            # check the length of the list in our validation callbacks.
            self.emit('on-add-item', result)

        # As we have a selection extended mode for kiwi list, we
        # need to unselect everything before select the new instance.
        self.klist.unselect_all()
        self.klist.select(result)
        self._update_sensitivity()

    def _edit(self):
        if not self._can_edit:
            return
        objs = self.get_selection()
        qty = len(objs)
        if qty != 1:
            raise SelectionError(
                ("Please select only one item before choosing Edit."
                 "\nThere are currently %d items selected") % qty)
        self._edit_model(objs[0])

    def _clear(self):
        objs = self.get_selection()
        qty = len(objs)
        if qty < 1:
            raise SelectionError('There are no objects selected')

        msg = stoqlib_ngettext(
            _('Delete this item?'),
            _('Delete these %d items?') % qty,
            qty)
        delete_label = stoqlib_ngettext(
            _("Delete item"),
            _("Delete items"),
            qty)

        keep_label = stoqlib_ngettext(
            _("Keep it"),
            _("Keep them"),
            qty)
        if not yesno(msg, gtk.RESPONSE_NO, delete_label, keep_label):
            return
        self.emit('before-delete-items', objs)
        if qty == len(self.klist):
            self.klist.clear()
        else:
            for obj in objs:
                self.klist.remove(obj)
        self.klist.unselect_all()
        self._update_sensitivity()
        self.emit('after-delete-items')

    #
    # Hooks
    #

    def get_items(self):
        return []

    def get_columns(self):
        raise NotImplementedError("get_columns must be implemented in "
                                  "subclasses")

    def run_editor(self, model):
        """This can be overriden to provide a custom run_dialog line,
        or a conversion function for the model
        """
        if self._editor_class is None:
            raise TypeError(
                "%s cannot create or edit items without the editor_class "
                "argument set" % (self.__class__.__name__))

        self.store.savepoint('before_run_editor_addition')
        retval = run_dialog(self._editor_class, None, store=self.store,
                            model=model)
        if not retval:
            self.store.rollback_to_savepoint('before_run_editor_addition')
        return retval

    def delete_model(self, model):
        """Deletes a model, can be overridden in subclass
        :param model: model to delete
        """
        model.__class__.delete(model.id, store=self.store)

    #
    # Public API
    #

    def add_extra_button(self, label=None, stock=None):
        """Add an extra button on the this slave

        The extra button will be appended at the end of the button box,
        the one containing the add/edit/delete buttons

        :param label: label of the button, can be ``None`` if stock is passed
        :param stock: stock label of the button, can be ``None`` if label
            is passed
        :param returns: the button added
        :rtype: gtk.Button
        """
        if label is None and stock is None:
            raise TypeError("You need to provide a label or a stock argument")

        button = gtk.Button(label=label, stock=stock)
        button.set_property('can_focus', True)
        self.button_box.pack_end(button, False, False)
        button.show()

        return button

    def set_message(self, message, details_callback=None):
        """Display a simple message on a label, next to the add, edit, delete buttons
        :param message: a message with properly escaped markup
        """
        self.message_hbox.set_visible(True)
        self.message_details_button.set_visible(bool(details_callback))
        if details_callback:
            if self._callback_id:
                self.message_details_button.disconnect(self._callback_id)
            self._callback_id = self.message_details_button.connect(
                'clicked', details_callback)

        self.message_label.set_markup(message)

    def clear_message(self):
        self.message_hbox.set_visible(False)

    def get_selection(self):
        # XXX: add get_selected_rows and raise exceptions if not in the
        #      right mode
        if self.klist.get_selection_mode() == gtk.SELECTION_MULTIPLE:
            return self.klist.get_selected_rows()
        selection = self.klist.get_selected()
        if not selection:
            return []
        return [selection]

    def hide_add_button(self):
        self.add_button.hide()

    def hide_edit_button(self):
        self._can_edit = False
        self.edit_button.hide()

    def hide_del_button(self):
        self.delete_button.hide()

    def set_editor(self, editor_class):
        if editor_class and not issubclass(editor_class,
                                           (BaseEditor, BaseWizard)):
            raise TypeError("editor_class must be a BaseEditor subclass")
        self._editor_class = editor_class

    #
    # Signal handlers
    #

    def on_klist__row_activated(self, *args):
        self._edit()

    def on_klist__selection_changed(self, *args):
        self._update_sensitivity()

    def on_add_button__clicked(self, button):
        self._edit_model()

    def on_edit_button__clicked(self, button):
        self._edit()

    def on_delete_button__clicked(self, button):
        self._clear()
Example #3
0
class GTKProject(SlaveDelegate):
    """A facade of kmcos.types.Project so that
    pygtk can display in a TreeView.
    """
    def __init__(self, parent, menubar):
        self.project_data = ObjectTree([
            Column('name', use_markup=True, data_type=str, sorted=True),
            Column('info')
        ])

        self.project_data.connect('row-activated', self.on_row_activated)
        self.model_tree = Project()
        self._set_treeview_hooks()

        self.menubar = menubar

        self.set_parent(parent)

        self.filename = ''

        self.undo_stack = UndoStack(self.model_tree.__repr__, self.import_file,
                                    self.project_data.select, menubar,
                                    self.meta, 'Initialization')

        SlaveDelegate.__init__(self, toplevel=self.project_data)

    def _set_treeview_hooks(self):
        """Fudge function to import to access function to kmcos.types.Project
        to kmcos.gui.GTKProject.
        """
        self.project_data.clear()
        # Meta
        self.meta = self.project_data.append(None, self.model_tree.meta)
        self.model_tree.meta = self.meta

        # Layer List
        self.model_tree.add_layer = self.add_layer
        self.layer_list = self.project_data.append(None,
                                                   self.model_tree.layer_list)
        self.get_layers = lambda: \
            sorted(self.project_data.get_descendants(self.layer_list),
                   key=lambda x: x.name)
        self.model_tree.get_layers = self.get_layers
        self.lattice = self.layer_list

        # Parameter List
        self.parameter_list = self.project_data.append(
            None, self.model_tree.parameter_list)
        self.add_parameter = lambda parameter: \
            self.project_data.append(self.parameter_list, parameter)
        self.model_tree.add_parameter = self.add_parameter
        self.get_parameters = lambda: \
            sorted(self.project_data.get_descendants(self.parameter_list),
                   key=lambda x: x.name)
        self.model_tree.get_parameters = self.get_parameters

        # Species List
        self.species_list = self.project_data.append(
            None, self.model_tree.species_list)
        self.add_species = lambda species: \
            self.project_data.append(self.species_list, species)
        self.model_tree.add_species = self.add_species
        self.get_speciess = lambda: \
            sorted(self.project_data.get_descendants(self.species_list),
                   key=lambda x: x.name)
        self.model_tree.get_speciess = self.get_speciess

        # Process List
        self.process_list = self.project_data.append(
            None, self.model_tree.process_list)
        self.add_process = lambda process:\
            self.project_data.append(self.process_list, process)
        self.model_tree.add_process = self.add_process
        self.get_processes = lambda: \
            sorted(self.project_data.get_descendants(self.process_list),
                   key=lambda x: x.name)
        self.model_tree.get_processes = self.get_processes

        # Output List
        self.output_list = self.project_data.append(
            None, self.model_tree.output_list)
        self.add_output = lambda output:\
            self.project_data.append(self.output_list, output)
        self.model_tree.add_output = self.add_output
        self.get_outputs = lambda:  \
            sorted(self.project_data.get_descendants(self.output_list),
                   key=lambda x: x.name)
        self.model_tree.get_outputs = self.get_outputs

    def add_layer(self, layer):
        self.project_data.append(self.layer_list, layer)
        if len(self.get_layers()) == 1:
            self.set_default_layer(layer.name)
            self.set_substrate_layer(layer.name)
        return layer

    def set_default_species(self, species):
        self.model_tree.species_list.default_species = species

    def set_substrate_layer(self, layer):
        self.model_tree.layer_list.substrate_layer = layer

    def set_default_layer(self, layer):
        self.model_tree.layer_list.default_layer = layer

    def update(self, model):
        """Update the object tree."""
        self.project_data.update(model)

    def on_row_activated(self, _tree, data):
        if isinstance(data, Layer):
            data.active = not data.active

    def get_name(self):
        """Return project name."""
        if self.filename:
            return os.path.basename(self.filename)
        else:
            return 'Untitled'

    def __repr__(self):
        return str(self.model_tree)

    def import_file(self, filename):
        """Import XML project file into editor GUI,
        unfolding the object tree.

        """
        self.filename = filename
        self.model_tree.import_file(filename)
        self.expand_all()

    def expand_all(self):
        """Expand all list of the project tree
        """
        self.project_data.expand(self.species_list)
        self.project_data.expand(self.layer_list)
        self.project_data.expand(self.parameter_list)
        self.project_data.expand(self.process_list)
        self.project_data.expand(self.output_list)

    def on_key_press(self, _, event):
        """When the user hits the keyboard focusing the treeview
        this event is triggered. Right now the only supported function
        is to deleted the selected item
        """
        selection = self.project_data.get_selected()
        if gtk.gdk.keyval_name(event.keyval) == 'Delete':
            if (isinstance(selection, Species)
                    or isinstance(selection, Process)
                    or isinstance(selection, Parameter)
                    or isinstance(selection, Layer)):
                if kiwi.ui.dialogs.yesno(
                    "Do you really want to delete '%s'?" \
                        % selection.name) == gtk.RESPONSE_YES:
                    self.project_data.remove(selection)

    def on_project_data__selection_changed(self, _, elem):
        """When a new item is selected in the treeview this function
        loads the main area of the window with the corresponding form
        and data.
        """
        slave = self.get_parent().get_slave('workarea')
        if slave:
            self.get_parent().detach_slave('workarea')
        if isinstance(elem, Layer):
            if self.meta.model_dimension in [1, 3]:
                self.get_parent().toast('Only 2d supported')
                return
            self.undo_stack.start_new_action('Edit Layer %s' % elem.name, elem)
            form = LayerEditor(elem, self)
            self.get_parent().attach_slave('workarea', form)
            form.focus_topmost()
        elif isinstance(elem, Meta):
            self.undo_stack.start_new_action('Edit Meta', elem)
            meta_form = MetaForm(self.meta, self)
            self.get_parent().attach_slave('workarea', meta_form)
            meta_form.focus_toplevel()
            meta_form.focus_topmost()
        elif isinstance(elem, OutputList):
            self.undo_stack.start_new_action('Edit Output', elem)
            form = OutputForm(self.output_list, self)
            self.get_parent().attach_slave('workarea', form)
            form.focus_topmost()
        elif isinstance(elem, Parameter):
            self.undo_stack.start_new_action('Edit Parameter %s' % elem.name,
                                             elem)
            form = ParameterForm(elem, self)
            self.get_parent().attach_slave('workarea', form)
            form.focus_topmost()
        elif isinstance(elem, Process):
            if self.meta.model_dimension in [1, 3]:
                self.get_parent().toast('Only 2d supported')
                return
            self.undo_stack.start_new_action('Edit Process %s' % elem.name,
                                             elem)
            form = ProcessForm(elem, self)
            self.get_parent().attach_slave('workarea', form)
            form.focus_topmost()
        elif isinstance(elem, ProcessList):
            if self.meta.model_dimension in [1, 3]:
                self.get_parent().toast('Only 2d supported')
                return
            self.undo_stack.start_new_action('Batch process editing', elem)
            form = BatchProcessForm(self)
            self.get_parent().attach_slave('workarea', form)
            form.focus_topmost()
        elif isinstance(elem, Species):
            self.undo_stack.start_new_action('Edit species', elem)
            form = SpeciesForm(elem, self.project_data)
            self.get_parent().attach_slave('workarea', form)
            form.focus_topmost()
        elif isinstance(elem, SpeciesList):
            self.undo_stack.start_new_action('Edit default species', elem)
            form = SpeciesListForm(elem, self)
            self.get_parent().attach_slave('workarea', form)
            form.focus_topmost()
        elif isinstance(elem, LayerList):
            self.undo_stack.start_new_action('Edit lattice', elem)
            dimension = self.meta.model_dimension
            form = LatticeForm(elem, dimension, self)
            self.get_parent().attach_slave('workarea', form)
            form.focus_topmost()
        else:
            self.get_parent().toast('Not implemented, yet(%s).' % type(elem))
Example #4
0
class GTKProject(SlaveDelegate):
    """A facade of kmos.types.Project so that
    pygtk can display in a TreeView.
    """
    def __init__(self, parent, menubar):
        self.project_data = ObjectTree([Column('name',
                                               use_markup=True,
                                               data_type=str,
                                               sorted=True),
                                        Column('info')])

        self.project_data.connect('row-activated', self.on_row_activated)
        self.model_tree = Project()
        self._set_treeview_hooks()

        self.menubar = menubar

        self.set_parent(parent)


        self.filename = ''

        self.undo_stack = UndoStack(
            self.model_tree.__repr__,
            self.import_xml_file,
            self.project_data.select,
            menubar,
            self.meta,
            'Initialization')

        SlaveDelegate.__init__(self, toplevel=self.project_data)

    def _set_treeview_hooks(self):
        """Fudge function to import to access function to kmos.types.Project
        to kmos.gui.GTKProject.
        """
        self.project_data.clear()
        # Meta
        self.meta = self.project_data.append(None, self.model_tree.meta)
        self.model_tree.meta = self.meta

        # Layer List
        self.model_tree.add_layer = self.add_layer
        self.layer_list = self.project_data.append(None,
                                   self.model_tree.layer_list)
        self.get_layers = lambda :\
            sorted(self.project_data.get_descendants(self.layer_list),
                   key=lambda x: x.name)
        self.model_tree.get_layers = self.get_layers
        self.lattice = self.layer_list

        # Parameter List
        self.parameter_list = self.project_data.append(None,
                                       self.model_tree.parameter_list)
        self.add_parameter = lambda parameter :\
            self.project_data.append(self.parameter_list, parameter)
        self.model_tree.add_parameter = self.add_parameter
        self.get_parameters = lambda :\
            sorted(self.project_data.get_descendants(self.parameter_list),
                   key=lambda x: x.name)
        self.model_tree.get_parameters = self.get_parameters

        # Species List
        self.species_list = self.project_data.append(None,
                                   self.model_tree.species_list)
        self.add_species = lambda species :\
            self.project_data.append(self.species_list, species)
        self.model_tree.add_species = self.add_species
        self.get_speciess = lambda :\
            sorted(self.project_data.get_descendants(self.species_list),
                   key=lambda x: x.name)
        self.model_tree.get_speciess = self.get_speciess


        # Process List
        self.process_list = self.project_data.append(None,
                                     self.model_tree.process_list)
        self.add_process = lambda process:\
            self.project_data.append(self.process_list, process)
        self.model_tree.add_process = self.add_process
        self.get_processes = lambda :\
            sorted(self.project_data.get_descendants(self.process_list),
                   key=lambda x: x.name)
        self.model_tree.get_processes = self.get_processes

        # Output List
        self.output_list = self.project_data.append(None,
                                self.model_tree.output_list)
        self.add_output = lambda output:\
            self.project_data.append(self.output_list, output)
        self.model_tree.add_output = self.add_output
        self.get_outputs = lambda : \
            sorted(self.project_data.get_descendants(self.output_list),
                   key=lambda x: x.name)
        self.model_tree.get_outputs = self.get_outputs

    def add_layer(self, layer):
        self.project_data.append(self.layer_list, layer)
        if len(self.get_layers()) == 1 :
            self.set_default_layer(layer.name)
            self.set_substrate_layer(layer.name)

    def set_default_species(self, species):
        self.model_tree.species_list.default_species = species

    def set_substrate_layer(self, layer):
        self.model_tree.layer_list.substrate_layer = layer

    def set_default_layer(self, layer):
        self.model_tree.layer_list.default_layer = layer

    def update(self, model):
        self.project_data.update(model)

    def on_row_activated(self, tree, data):
        if isinstance(data, Layer):
            data.active = not data.active

    def get_name(self):
        if self.filename:
            return os.path.basename(self.filename)
        else:
            return 'Untitled'

    def __repr__(self):
        return str(self.model_tree)

    def import_xml_file(self, filename):
        self.model_tree.import_xml_file(filename)
        self.expand_all()

    def expand_all(self):
        """Expand all list of the project tree
        """
        self.project_data.expand(self.species_list)
        self.project_data.expand(self.layer_list)
        self.project_data.expand(self.parameter_list)
        self.project_data.expand(self.process_list)
        self.project_data.expand(self.output_list)

    def on_key_press(self, _, event):
        """When the user hits the keyboard focusing the treeview
        this event is triggered. Right now the only supported function
        is to deleted the selected item
        """
        selection = self.project_data.get_selected()
        if gtk.gdk.keyval_name(event.keyval) == 'Delete':
            if(isinstance(selection, Species)
            or isinstance(selection, Process)
            or isinstance(selection, Parameter)
            or isinstance(selection, Layer)):
                if kiwi.ui.dialogs.yesno(
                    "Do you really want to delete '%s'?" \
                        % selection.name) == gtk.RESPONSE_YES:
                    self.project_data.remove(selection)

    def on_project_data__selection_changed(self, _, elem):
        """When a new item is selected in the treeview this function
        loads the main area of the window with the corresponding form
        and data.
        """
        slave = self.get_parent().get_slave('workarea')
        if slave:
            self.get_parent().detach_slave('workarea')
        if isinstance(elem, Layer):
            if self.meta.model_dimension in [1, 3]:
                self.get_parent().toast('Only 2d supported')
                return
            self.undo_stack.start_new_action('Edit Layer %s' % elem.name,
                                                               elem)
            form = LayerEditor(elem, self)
            self.get_parent().attach_slave('workarea', form)
            form.focus_topmost()
        elif isinstance(elem, Meta):
            self.undo_stack.start_new_action('Edit Meta', elem)
            meta_form = MetaForm(self.meta, self)
            self.get_parent().attach_slave('workarea', meta_form)
            meta_form.focus_toplevel()
            meta_form.focus_topmost()
        elif isinstance(elem, OutputList):
            self.undo_stack.start_new_action('Edit Output', elem)
            form = OutputForm(self.output_list, self)
            self.get_parent().attach_slave('workarea', form)
            form.focus_topmost()
        elif isinstance(elem, Parameter):
            self.undo_stack.start_new_action('Edit Parameter %s' % elem.name,
                                                                   elem)
            form = ParameterForm(elem, self)
            self.get_parent().attach_slave('workarea', form)
            form.focus_topmost()
        elif isinstance(elem, Process):
            if self.meta.model_dimension in [1, 3]:
                self.get_parent().toast('Only 2d supported')
                return
            self.undo_stack.start_new_action('Edit Process %s' % elem.name,
                                                                 elem)
            form = ProcessForm(elem, self)
            self.get_parent().attach_slave('workarea', form)
            form.focus_topmost()
        elif isinstance(elem, ProcessList):
            if self.meta.model_dimension in [1, 3]:
                self.get_parent().toast('Only 2d supported')
                return
            self.undo_stack.start_new_action('Batch process editing', elem)
            form = BatchProcessForm(self)
            self.get_parent().attach_slave('workarea', form)
            form.focus_topmost()
        elif isinstance(elem, Species):
            self.undo_stack.start_new_action('Edit species', elem)
            form = SpeciesForm(elem, self.project_data)
            self.get_parent().attach_slave('workarea', form)
            form.focus_topmost()
        elif isinstance(elem, SpeciesList):
            self.undo_stack.start_new_action('Edit default species', elem)
            form = SpeciesListForm(elem, self)
            self.get_parent().attach_slave('workarea', form)
            form.focus_topmost()
        elif isinstance(elem, LayerList):
            self.undo_stack.start_new_action('Edit lattice', elem)
            dimension = self.meta.model_dimension
            form = LatticeForm(elem, dimension, self)
            self.get_parent().attach_slave('workarea', form)
            form.focus_topmost()
        else:
            self.get_parent().toast('Not implemented, yet(%s).' % type(elem))