Esempio n. 1
0
class BaseEditor(BaseEditorSlave, RunnableView):
    """ Base class for editor dialogs. It offers methods of
    BaseEditorSlave, a windows title and OK/Cancel buttons.
    """

    #: the model type name of the model we are editing.
    #: This value will be showed in the title of the editor and can not
    #: be merely the attribute __name__ of the object for usability reasons.
    #: Call sites will decide what could be the best name applicable in each
    #: situation.
    model_name = None
    header = ''
    size = ()
    title = None
    hide_footer = False
    #: a list of widget names that when activated will confirm the dialog
    confirm_widgets = ()
    help_section = None
    form_holder_name = 'toplevel'

    def __init__(self, store, model=None, visual_mode=False):
        if store is not None and isinstance(store, StoqlibStore):
            store.needs_retval = True
        self._confirm_disabled = False

        # FIXME:
        # BasicEditor should inheirt from BasicDialog and instantiate
        # the slave inside here, but it requires some major surgery
        BaseEditorSlave.__init__(self, store, model,
                                 visual_mode=visual_mode)

        self.main_dialog = BasicDialog(title=self.get_title(self.model),
                                       header_text=self.header,
                                       help_section=self.help_section,
                                       size=self.size)
        # Do not close the dialog if re return False on self.confirm
        self.main_dialog.enable_confirm_validation = True
        self.main_dialog.attach_slave("main", self)
        self.main_dialog.connect('confirm', self._on_main_dialog__confirm)
        self.main_dialog.connect('cancel', self._on_main_dialog__cancel)

        # This helps kiwis ui test, set the name of ourselves to
        # the classname of the slave, which is much more helpful than
        # just "BasicDialog"
        self.main_dialog.get_toplevel().set_name(self.__class__.__name__)

        if self.hide_footer or self.visual_mode:
            self.main_dialog.hide_footer()

        for name in self.confirm_widgets:
            self.set_confirm_widget(getattr(self, name))

        self.register_validate_function(self._validation_function)
        self.force_validation()

    def _get_title_format(self):
        if self.visual_mode:
            return _(u"Details of %s")
        if self.edit_mode:
            return _(u'Edit Details of "%s"')
        return _(u"Add %s")

    def get_title(self, model):
        if self.title:
            return self.title
        if not model:
            raise ValueError("A model should be defined at this point")

        title_format = self._get_title_format()
        if self.model_name:
            model_name = self.model_name
        else:
            # Fallback to the name of the class
            model_name = type(self.model).__name__

        return title_format % model_name

    def enable_window_controls(self):
        """Enables the window controls
        See :class:`kiwi.ui.views.BaseView.enable_window_controls`.
        """
        self.main_dialog.enable_window_controls()

    def set_description(self, description):
        """Sets the description of the model object which is used by the editor
        :param description:
        """
        format = self._get_title_format()
        self.main_dialog.set_title(format % description)

    def refresh_ok(self, validation_value):
        """ Refreshes ok button sensitivity according to widget validators
        status """
        if self._confirm_disabled:
            return
        self.main_dialog.ok_button.set_sensitive(validation_value)

    def add_button(self, label=None, stock=None):
        """
        Adds a button to editor. The added button is returned which you
        can use to connect signals on.
        :param label: label of the button
        :param stock: stock label of the button
        :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.props.can_focus = True
        self.main_dialog.action_area.pack_start(button, False, False)
        self.main_dialog.action_area.reorder_child(button, 0)
        button.show()
        return button

    def cancel(self):
        """
        Cancel the dialog.
        """
        # set this before runing BaseEditorSlave.cancel so
        # on_cancel can modify self.retval, if needed
        self.retval = False
        BaseEditorSlave.cancel(self)

        self.main_dialog.close()
        if isinstance(self.store, StoqlibStore):
            self.store.retval = self.retval

        log.info("%s: Closed (cancelled), retval=%r" % (
            self.__class__.__name__, self.retval))

    def confirm(self):
        """
        Confirm the dialog.
        """
        # set this before runing BaseEditorSlave.confirm so
        # on_confirm can modify self.retval, if needed
        self.retval = self.model

        if self._confirm_disabled:
            return False
        if not BaseEditorSlave.confirm(self):
            return False

        self.main_dialog.close()
        if isinstance(self.store, StoqlibStore):
            self.store.retval = self.retval

        log.info("%s: Closed (confirmed), retval=%r" % (
            self.__class__.__name__, self.retval))

        return True

    def enable_ok(self):
        """
        Enable the ok button of the dialog, eg makes it possible
        to close/confirm the dialog.
        """
        self.main_dialog.enable_ok()
        self._confirm_disabled = False

    def disable_ok(self):
        """
        Enable the ok button of the dialog, eg makes it possible
        to close/confirm the dialog.
        """
        self.main_dialog.disable_ok()
        self._confirm_disabled = True

    def enable_normal_window(self):
        """
        Enable the dialog as a normal window.
        This tells the window manager that the window
        should behave as a normal window instead of a dialog.
        """
        toplevel = self.main_dialog.get_toplevel()
        toplevel.set_type_hint(gdk.WINDOW_TYPE_HINT_NORMAL)

    def set_confirm_widget(self, widget_name):
        """
        Make a widget confirmable, eg activating that widget would
        close the dialog.
        :param widget_name: name of the widget to be confirmable
        """
        self.main_dialog.set_confirm_widget(widget_name)

    def set_message(self, message, message_type=gtk.MESSAGE_INFO):
        """Sets a message for this editor
        :param message: message to add
        :param message_type: type of message to add
        """
        self.main_dialog.set_message(message, message_type)

    # RunnableView
    # This delegate everything to self.main_dialog

    def close(self):
        self.main_dialog.close()

    def run(self):
        self.main_dialog.run()

    def get_current_toplevel(self):
        return self.main_dialog.get_current_toplevel()

    def destroy(self):
        self.main_dialog.destroy()

    def set_transient_for(self, window):
        self.main_dialog.set_transient_for(window)

    # Callbacks

    def _on_main_dialog__cancel(self, dialog, retval):
        self.cancel()

    def _on_main_dialog__confirm(self, dialog, retval):
        return self.confirm()

    def _validation_function(self, is_valid):
        self.refresh_ok(is_valid)
Esempio n. 2
0
class BaseEditor(BaseEditorSlave, RunnableView):
    """ Base class for editor dialogs. It offers methods of
    BaseEditorSlave, a windows title and OK/Cancel buttons.
    """

    #: the model type name of the model we are editing.
    #: This value will be showed in the title of the editor and can not
    #: be merely the attribute __name__ of the object for usability reasons.
    #: Call sites will decide what could be the best name applicable in each
    #: situation.
    model_name = None
    header = ''
    size = ()
    title = None
    hide_footer = False

    #: if we need to ask the user if he really wants to cancel the dialog if
    #: there are any changes done that would be lost otherwise
    need_cancel_confirmation = False

    #: a list of widget names that when activated will confirm the dialog
    confirm_widgets = ()
    help_section = None
    form_holder_name = 'toplevel'

    def __init__(self, store, model=None, visual_mode=False):
        self._confirm_disabled = False

        # FIXME:
        # BasicEditor should inheirt from BasicDialog and instantiate
        # the slave inside here, but it requires some major surgery
        BaseEditorSlave.__init__(self, store, model,
                                 visual_mode=visual_mode)

        self.main_dialog = BasicDialog(title=self.get_title(self.model),
                                       header_text=self.header,
                                       help_section=self.help_section,
                                       size=self.size)
        # Do not close the dialog if re return False on self.confirm
        self.main_dialog.enable_confirm_validation = True
        self.main_dialog.attach_slave("main", self)
        self.main_dialog.connect('confirm', self._on_main_dialog__confirm)
        self.main_dialog.connect('cancel', self._on_main_dialog__cancel)

        dialog_toplevel = self.main_dialog.get_toplevel()
        dialog_toplevel.connect('response', self._on_toplevel__response)
        dialog_toplevel.connect('delete-event', self._on_toplevel__delete_event)

        # This helps kiwis ui test, set the name of ourselves to
        # the classname of the slave, which is much more helpful than
        # just "BasicDialog"
        self.main_dialog.get_toplevel().set_name(self.__class__.__name__)

        if self.hide_footer or self.visual_mode:
            self.main_dialog.hide_footer()

        for name in self.confirm_widgets:
            self.set_confirm_widget(getattr(self, name))

        self.register_validate_function(self._validation_function)
        self.force_validation()
        # We need to use self.model instead of model, since BaseEditorSlave
        # will create one if its None
        EditorCreateEvent.emit(self, self.model, store, visual_mode)

        if store is not None:
            # This needs to be the last thing done on __init__ since we don't want
            # to consider things like self.create_model as a change
            self._store_pending_count = store.get_pending_count()

    #
    #  Private
    #

    def _get_title_format(self):
        if self.visual_mode:
            return _(u"Details of %s")
        if self.edit_mode:
            return _(u'Edit Details of "%s"')
        return _(u"Add %s")

    def _need_cancel_confirmation(self):
        return self.need_cancel_confirmation and self.has_changes()

    #
    #  Public
    #

    def has_changes(self):
        """Check if there are changes on this editor

        By default we will check if there're any pending changes on
        :obj:`.store` and that information will be used by
        :attr:`.need_cancel_confirmation`
        """
        if self.store is None:
            return False
        return self.store.get_pending_count() > self._store_pending_count

    def get_title(self, model):
        if self.title:
            return self.title
        if not model:
            raise ValueError("A model should be defined at this point")

        title_format = self._get_title_format()
        if self.model_name:
            model_name = self.model_name
        else:
            # Fallback to the name of the class
            model_name = type(self.model).__name__

        return title_format % model_name

    def enable_window_controls(self):
        """Enables the window controls
        See :class:`kiwi.ui.views.BaseView.enable_window_controls`.
        """
        self.main_dialog.enable_window_controls()

    def set_description(self, description):
        """Sets the description of the model object which is used by the editor
        :param description:
        """
        format = self._get_title_format()
        self.main_dialog.set_title(format % description)

    def refresh_ok(self, validation_value):
        """ Refreshes ok button sensitivity according to widget validators
        status """
        if self._confirm_disabled:
            return
        self.main_dialog.ok_button.set_sensitive(validation_value)

    def add_button(self, label=None, stock=None):
        """
        Adds a button to editor. The added button is returned which you
        can use to connect signals on.
        :param label: label of the button
        :param stock: stock label of the button
        :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.props.can_focus = True
        self.main_dialog.action_area.pack_start(button, False, False)
        self.main_dialog.action_area.reorder_child(button, 0)
        button.show()
        return button

    def cancel(self):
        """
        Cancel the dialog.
        """
        if (self._need_cancel_confirmation() and
            not yesno(_("If you cancel this dialog all changes will be lost. "
                        "Are you sure?"), gtk.RESPONSE_NO,
                      _("Cancel"), _("Don't cancel"))):
            return False

        # set this before runing BaseEditorSlave.cancel so
        # on_cancel can modify self.retval, if needed
        self.retval = False
        BaseEditorSlave.cancel(self)

        self.main_dialog.close()
        if isinstance(self.store, StoqlibStore):
            self.store.retval = self.retval

        log.info("%s: Closed (cancelled), retval=%r" % (
            self.__class__.__name__, self.retval))

        return True

    def confirm(self):
        """
        Confirm the dialog.
        """
        # set this before runing BaseEditorSlave.confirm so
        # on_confirm can modify self.retval, if needed
        self.retval = self.model

        if self._confirm_disabled:
            return False
        if not BaseEditorSlave.confirm(self):
            return False

        self.main_dialog.close()
        if isinstance(self.store, StoqlibStore):
            self.store.retval = self.retval

        log.info("%s: Closed (confirmed), retval=%r" % (
            self.__class__.__name__, self.retval))

        return True

    def enable_ok(self):
        """
        Enable the ok button of the dialog, eg makes it possible
        to close/confirm the dialog.
        """
        self.main_dialog.enable_ok()
        self._confirm_disabled = False

    def disable_ok(self):
        """
        Enable the ok button of the dialog, eg makes it possible
        to close/confirm the dialog.
        """
        self.main_dialog.disable_ok()
        self._confirm_disabled = True

    def enable_normal_window(self):
        """
        Enable the dialog as a normal window.
        This tells the window manager that the window
        should behave as a normal window instead of a dialog.
        """
        toplevel = self.main_dialog.get_toplevel()
        toplevel.set_type_hint(gdk.WINDOW_TYPE_HINT_NORMAL)

    def set_confirm_widget(self, widget_name):
        """
        Make a widget confirmable, eg activating that widget would
        close the dialog.
        :param widget_name: name of the widget to be confirmable
        """
        self.main_dialog.set_confirm_widget(widget_name)

    def set_message(self, message, message_type=None):
        """Sets a message for this editor
        :param message: message to add
        :param message_type: type of message to add
        """
        if message_type is None:
            message_type = gtk.MESSAGE_INFO
        self.main_dialog.set_message(message, message_type)

    # RunnableView
    # This delegate everything to self.main_dialog

    def close(self):
        self.main_dialog.close()

    def run(self):
        self.main_dialog.run()

    def get_current_toplevel(self):
        return self.main_dialog.get_current_toplevel()

    def destroy(self):
        self.main_dialog.destroy()

    def set_transient_for(self, window):
        self.main_dialog.set_transient_for(window)

    # Callbacks

    def _on_main_dialog__cancel(self, dialog, retval):
        return self.cancel()

    def _on_main_dialog__confirm(self, dialog, retval):
        return self.confirm()

    def _validation_function(self, is_valid):
        self.refresh_ok(is_valid)

    def _on_toplevel__delete_event(self, widget, *args, **kwargs):
        # Avoid the dialog being closed when hitting 'Esc' and we would need
        # confirm the cancelation.
        if self._need_cancel_confirmation():
            return True

    def _on_toplevel__response(self, dialog, response, *args, **kwargs):
        # FIXME: For the delete-event to really stops from destroying the
        # dialog, we also need to stop the response event emission. See
        # http://faq.pygtk.org/index.py?req=show&file=faq10.013.htp
        # for more details
        if (self._need_cancel_confirmation() and
                response == gtk.RESPONSE_DELETE_EVENT):
            dialog.emit_stop_by_name('response')
Esempio n. 3
0
class BaseEditor(BaseEditorSlave, RunnableView):
    """ Base class for editor dialogs. It offers methods of
    BaseEditorSlave, a windows title and OK/Cancel buttons.
    """

    #: the model type name of the model we are editing.
    #: This value will be showed in the title of the editor and can not
    #: be merely the attribute __name__ of the object for usability reasons.
    #: Call sites will decide what could be the best name applicable in each
    #: situation.
    model_name = None
    header = ''
    size = ()
    title = None
    hide_footer = False
    #: a list of widget names that when activated will confirm the dialog
    confirm_widgets = ()
    help_section = None
    form_holder_name = 'toplevel'

    def __init__(self, store, model=None, visual_mode=False):
        if store is not None and isinstance(store, StoqlibStore):
            store.needs_retval = True
        self._confirm_disabled = False

        # FIXME:
        # BasicEditor should inheirt from BasicDialog and instantiate
        # the slave inside here, but it requires some major surgery
        BaseEditorSlave.__init__(self, store, model, visual_mode=visual_mode)

        self.main_dialog = BasicDialog(title=self.get_title(self.model),
                                       header_text=self.header,
                                       help_section=self.help_section,
                                       size=self.size)
        # Do not close the dialog if re return False on self.confirm
        self.main_dialog.enable_confirm_validation = True
        self.main_dialog.attach_slave("main", self)
        self.main_dialog.connect('confirm', self._on_main_dialog__confirm)
        self.main_dialog.connect('cancel', self._on_main_dialog__cancel)

        # This helps kiwis ui test, set the name of ourselves to
        # the classname of the slave, which is much more helpful than
        # just "BasicDialog"
        self.main_dialog.get_toplevel().set_name(self.__class__.__name__)

        if self.hide_footer or self.visual_mode:
            self.main_dialog.hide_footer()

        for name in self.confirm_widgets:
            self.set_confirm_widget(getattr(self, name))

        self.register_validate_function(self._validation_function)
        self.force_validation()

    def _get_title_format(self):
        if self.visual_mode:
            return _(u"Details of %s")
        if self.edit_mode:
            return _(u'Edit Details of "%s"')
        return _(u"Add %s")

    def get_title(self, model):
        if self.title:
            return self.title
        if not model:
            raise ValueError("A model should be defined at this point")

        title_format = self._get_title_format()
        if self.model_name:
            model_name = self.model_name
        else:
            # Fallback to the name of the class
            model_name = type(self.model).__name__

        return title_format % model_name

    def enable_window_controls(self):
        """Enables the window controls
        See :class:`kiwi.ui.views.BaseView.enable_window_controls`.
        """
        self.main_dialog.enable_window_controls()

    def set_description(self, description):
        """Sets the description of the model object which is used by the editor
        :param description:
        """
        format = self._get_title_format()
        self.main_dialog.set_title(format % description)

    def refresh_ok(self, validation_value):
        """ Refreshes ok button sensitivity according to widget validators
        status """
        if self._confirm_disabled:
            return
        self.main_dialog.ok_button.set_sensitive(validation_value)

    def add_button(self, label=None, stock=None):
        """
        Adds a button to editor. The added button is returned which you
        can use to connect signals on.
        :param label: label of the button
        :param stock: stock label of the button
        :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.props.can_focus = True
        self.main_dialog.action_area.pack_start(button, False, False)
        self.main_dialog.action_area.reorder_child(button, 0)
        button.show()
        return button

    def cancel(self):
        """
        Cancel the dialog.
        """
        # set this before runing BaseEditorSlave.cancel so
        # on_cancel can modify self.retval, if needed
        self.retval = False
        BaseEditorSlave.cancel(self)

        self.main_dialog.close()
        if isinstance(self.store, StoqlibStore):
            self.store.retval = self.retval

        log.info("%s: Closed (cancelled), retval=%r" %
                 (self.__class__.__name__, self.retval))

    def confirm(self):
        """
        Confirm the dialog.
        """
        # set this before runing BaseEditorSlave.confirm so
        # on_confirm can modify self.retval, if needed
        self.retval = self.model

        if self._confirm_disabled:
            return False
        if not BaseEditorSlave.confirm(self):
            return False

        self.main_dialog.close()
        if isinstance(self.store, StoqlibStore):
            self.store.retval = self.retval

        log.info("%s: Closed (confirmed), retval=%r" %
                 (self.__class__.__name__, self.retval))

        return True

    def enable_ok(self):
        """
        Enable the ok button of the dialog, eg makes it possible
        to close/confirm the dialog.
        """
        self.main_dialog.enable_ok()
        self._confirm_disabled = False

    def disable_ok(self):
        """
        Enable the ok button of the dialog, eg makes it possible
        to close/confirm the dialog.
        """
        self.main_dialog.disable_ok()
        self._confirm_disabled = True

    def enable_normal_window(self):
        """
        Enable the dialog as a normal window.
        This tells the window manager that the window
        should behave as a normal window instead of a dialog.
        """
        toplevel = self.main_dialog.get_toplevel()
        toplevel.set_type_hint(gdk.WINDOW_TYPE_HINT_NORMAL)

    def set_confirm_widget(self, widget_name):
        """
        Make a widget confirmable, eg activating that widget would
        close the dialog.
        :param widget_name: name of the widget to be confirmable
        """
        self.main_dialog.set_confirm_widget(widget_name)

    def set_message(self, message, message_type=gtk.MESSAGE_INFO):
        """Sets a message for this editor
        :param message: message to add
        :param message_type: type of message to add
        """
        self.main_dialog.set_message(message, message_type)

    # RunnableView
    # This delegate everything to self.main_dialog

    def close(self):
        self.main_dialog.close()

    def run(self):
        self.main_dialog.run()

    def get_current_toplevel(self):
        return self.main_dialog.get_current_toplevel()

    def destroy(self):
        self.main_dialog.destroy()

    def set_transient_for(self, window):
        self.main_dialog.set_transient_for(window)

    # Callbacks

    def _on_main_dialog__cancel(self, dialog, retval):
        self.cancel()

    def _on_main_dialog__confirm(self, dialog, retval):
        return self.confirm()

    def _validation_function(self, is_valid):
        self.refresh_ok(is_valid)
Esempio n. 4
0
class BaseEditor(BaseEditorSlave, RunnableView):
    """ Base class for editor dialogs. It offers methods of
    BaseEditorSlave, a windows title and OK/Cancel buttons.
    """

    #: the model type name of the model we are editing.
    #: This value will be showed in the title of the editor and can not
    #: be merely the attribute __name__ of the object for usability reasons.
    #: Call sites will decide what could be the best name applicable in each
    #: situation.
    model_name = None
    header = ''
    size = ()
    title = None
    hide_footer = False

    #: if we need to ask the user if he really wants to cancel the dialog if
    #: there are any changes done that would be lost otherwise
    need_cancel_confirmation = False

    #: a list of widget names that when activated will confirm the dialog
    confirm_widgets = ()
    help_section = None
    form_holder_name = 'toplevel'

    def __init__(self, store, model=None, visual_mode=False):
        self._confirm_disabled = False

        # FIXME:
        # BasicEditor should inheirt from BasicDialog and instantiate
        # the slave inside here, but it requires some major surgery
        BaseEditorSlave.__init__(self, store, model, visual_mode=visual_mode)

        self.main_dialog = BasicDialog(title=self.get_title(self.model),
                                       header_text=self.header,
                                       help_section=self.help_section,
                                       size=self.size)
        # Do not close the dialog if re return False on self.confirm
        self.main_dialog.enable_confirm_validation = True
        self.main_dialog.attach_slave("main", self)
        self.main_dialog.connect('confirm', self._on_main_dialog__confirm)
        self.main_dialog.connect('cancel', self._on_main_dialog__cancel)

        dialog_toplevel = self.main_dialog.get_toplevel()
        dialog_toplevel.connect('response', self._on_toplevel__response)
        dialog_toplevel.connect('delete-event',
                                self._on_toplevel__delete_event)

        # This helps kiwis ui test, set the name of ourselves to
        # the classname of the slave, which is much more helpful than
        # just "BasicDialog"
        self.main_dialog.get_toplevel().set_name(self.__class__.__name__)

        if self.hide_footer or self.visual_mode:
            self.main_dialog.hide_footer()

        for name in self.confirm_widgets:
            self.set_confirm_widget(getattr(self, name))

        self.register_validate_function(self._validation_function)
        self.force_validation()
        # We need to use self.model instead of model, since BaseEditorSlave
        # will create one if its None
        EditorCreateEvent.emit(self, self.model, store, visual_mode)

        if store is not None:
            # This needs to be the last thing done on __init__ since we don't want
            # to consider things like self.create_model as a change
            self._store_pending_count = store.get_pending_count()

    #
    #  Private
    #

    def _get_title_format(self):
        if self.visual_mode:
            return _(u"Details of %s")
        if self.edit_mode:
            return _(u'Edit Details of "%s"')
        return _(u"Add %s")

    def _need_cancel_confirmation(self):
        return self.need_cancel_confirmation and self.has_changes()

    #
    #  Public
    #

    def has_changes(self):
        """Check if there are changes on this editor

        By default we will check if there're any pending changes on
        :obj:`.store` and that information will be used by
        :attr:`.need_cancel_confirmation`
        """
        if self.store is None:
            return False
        return self.store.get_pending_count() > self._store_pending_count

    def get_title(self, model):
        if self.title:
            return self.title
        if not model:
            raise ValueError("A model should be defined at this point")

        title_format = self._get_title_format()
        if self.model_name:
            model_name = self.model_name
        else:
            # Fallback to the name of the class
            model_name = type(self.model).__name__

        return title_format % model_name

    def enable_window_controls(self):
        """Enables the window controls
        See :class:`kiwi.ui.views.BaseView.enable_window_controls`.
        """
        self.main_dialog.enable_window_controls()

    def set_description(self, description):
        """Sets the description of the model object which is used by the editor
        :param description:
        """
        format = self._get_title_format()
        self.main_dialog.set_title(format % description)

    def refresh_ok(self, validation_value):
        """ Refreshes ok button sensitivity according to widget validators
        status """
        if self._confirm_disabled:
            return
        self.main_dialog.ok_button.set_sensitive(validation_value)

    def add_button(self, label=None, stock=None):
        """
        Adds a button to editor. The added button is returned which you
        can use to connect signals on.
        :param label: label of the button
        :param stock: stock label of the button
        :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.props.can_focus = True
        self.main_dialog.action_area.pack_start(button, False, False, 0)
        self.main_dialog.action_area.reorder_child(button, 0)
        button.show()
        return button

    def cancel(self):
        """
        Cancel the dialog.
        """
        if (self._need_cancel_confirmation() and not yesno(
                _("If you cancel this dialog all changes will be lost. "
                  "Are you sure?"), Gtk.ResponseType.NO, _("Cancel"),
                _("Don't cancel"))):
            return False

        # set this before runing BaseEditorSlave.cancel so
        # on_cancel can modify self.retval, if needed
        self.retval = False
        BaseEditorSlave.cancel(self)

        self.main_dialog.close()
        if isinstance(self.store, StoqlibStore):
            self.store.retval = self.retval

        log.info("%s: Closed (cancelled), retval=%r" %
                 (self.__class__.__name__, self.retval))

        return True

    def confirm(self):
        """
        Confirm the dialog.
        """
        # set this before runing BaseEditorSlave.confirm so
        # on_confirm can modify self.retval, if needed
        self.retval = self.model

        if self._confirm_disabled:
            return False
        if not BaseEditorSlave.confirm(self):
            return False

        self.main_dialog.close()
        if isinstance(self.store, StoqlibStore):
            self.store.retval = self.retval

        log.info("%s: Closed (confirmed), retval=%r" %
                 (self.__class__.__name__, self.retval))

        return True

    def enable_ok(self):
        """
        Enable the ok button of the dialog, eg makes it possible
        to close/confirm the dialog.
        """
        self.main_dialog.enable_ok()
        self._confirm_disabled = False

    def disable_ok(self):
        """
        Enable the ok button of the dialog, eg makes it possible
        to close/confirm the dialog.
        """
        self.main_dialog.disable_ok()
        self._confirm_disabled = True

    def enable_normal_window(self):
        """
        Enable the dialog as a normal window.
        This tells the window manager that the window
        should behave as a normal window instead of a dialog.
        """
        toplevel = self.main_dialog.get_toplevel()
        toplevel.set_type_hint(Gdk.WindowTypeHint.NORMAL)

    def set_confirm_widget(self, widget_name):
        """
        Make a widget confirmable, eg activating that widget would
        close the dialog.
        :param widget_name: name of the widget to be confirmable
        """
        self.main_dialog.set_confirm_widget(widget_name)

    def set_message(self, message, message_type=None):
        """Sets a message for this editor
        :param message: message to add
        :param message_type: type of message to add
        """
        if message_type is None:
            message_type = Gtk.MessageType.INFO
        self.main_dialog.set_message(message, message_type)

    # RunnableView
    # This delegate everything to self.main_dialog

    def close(self):
        self.main_dialog.close()

    def run(self):
        self.main_dialog.run()

    def get_current_toplevel(self):
        return self.main_dialog.get_current_toplevel()

    def destroy(self):
        self.main_dialog.destroy()

    def set_transient_for(self, window):
        self.main_dialog.set_transient_for(window)

    # Callbacks

    def _on_main_dialog__cancel(self, dialog, retval):
        return self.cancel()

    def _on_main_dialog__confirm(self, dialog, retval):
        return self.confirm()

    def _validation_function(self, is_valid):
        self.refresh_ok(is_valid)

    def _on_toplevel__delete_event(self, widget, *args, **kwargs):
        # Avoid the dialog being closed when hitting 'Esc' and we would need
        # confirm the cancelation.
        if self._need_cancel_confirmation():
            return True

    def _on_toplevel__response(self, dialog, response, *args, **kwargs):
        # FIXME: For the delete-event to really stops from destroying the
        # dialog, we also need to stop the response event emission. See
        # http://faq.pyGtk.org/index.py?req=show&file=faq10.013.htp
        # for more details
        if (self._need_cancel_confirmation()
                and response == Gtk.ResponseType.DELETE_EVENT):
            dialog.emit_stop_by_name('response')