class GenericInputEditDialog(AbstractInputDialog):
    def __init__(self, window_manager, presenter):
        super().__init__(window_manager, presenter)

    def create_dialog(self):
        super().create_dialog()
        self.set_default_buttons()

        self.label = AlexLabel(self.interior)
        self.label.pack()

        self.entry = AlexEntry(self.interior)
        self.entry.pack()

    def config_dialog(self, label=_('Please edit string:'), initvalue=''):

        self.label.set(label)
        self.entry.set(initvalue)

    def _get_entry(self):
        return self.entry.get()

    def _set_entry(self, value):
        self.entry.set(value)

    input = property(_get_entry, _set_entry)
class ReferenceView(Frame):  # @UndefinedVariable
    def __init__(self, parent, presenter, label):
        super().__init__(parent, borderwidth=1, relief=RIDGE)
        self.parent = parent
        self.presenter = presenter
        self.presenter.view = self

        self.labelframe = Frame(self)
        self.labelframe.pack(pady=5)

        self.listbox = AlexComboBox(self)
        self.listbox.pack(fill=X, padx=5)

        self._add_label(label)
        self.pack(side=LEFT, padx=5, pady=5)

        self.buttonframe = Frame(self)
        self.buttonframe.pack()
        self.buttons = []

    def _add_label(self, label):

        self.label = AlexLabel(self.labelframe)
        self.label.pack()
        self.label.set(label)

    def _set_items(self, items):
        self.deactivate()
        self.listbox.set_items(items)
        self.activate()

    def _get_selected_item(self):
        return self.listbox.get()

    def _get_items(self):
        return self.listbox.get_items()

    def add_button(self, action):
        self.buttons.append(
            AlexButton(self.buttonframe,
                       text=action.label,
                       command=action.callback))
        self.buttons[-1].pack(side=LEFT, padx=5, pady=5)

    def deactivate(self):
        for button in self.buttons:
            button.configure(state=DISABLED)

    def activate(self):
        for button in self.buttons:
            button.configure(state=NORMAL)

    def show_message(self, message_text):
        messagebox.showinfo(_("Hint"), message_text)

    items = property(_get_items, _set_items)
    selected_item = property(_get_selected_item)
class GenericTreeSelectionDialog(AbstractInputDialog):
    def __init__(self, window_manager, presenter):

        super().__init__(window_manager, presenter)

        self.tree_widget = None
        self.filter_is_set = False

    def create_dialog(self):

        super().create_dialog()

        self.label = AlexLabel(self.interior)
        self.label.pack(side=TOP, padx=5, pady=5)

        filter_frame = Frame(self.interior)
        AlexLabel(filter_frame, text=_('Search tree:')).pack(side=LEFT, pady=5)
        self.filter_entry = AlexEntry(filter_frame)
        self.filter_entry.bind("<KeyRelease>",
                               lambda event: self._apply_filter(event))
        self.filter_entry.pack(side=LEFT, fill=X, expand=YES)
        filter_frame.pack(side=TOP, expand=YES, fill=X)

        self.set_default_buttons()

    def config_dialog(self, label=_('Select a tree node')):
        self.label.set(label)

    def _apply_filter(self, event):
        filter_string = self.filter_entry.get()
        if len(filter_string) > 2:
            visible_nodes = self.tree_widget.apply_filter(filter_string)
            if visible_nodes < 20:
                self.tree_widget.expand_all()
            self.filter_is_set = True
        else:
            if self.filter_is_set:
                self.tree_widget.clear_filter()
                self.filter_is_set = False

    def set_tree(self, tree):
        if self.tree_widget is not None:
            self.tree_widget.destroy()
        self.tree_widget = AlexTree(self.interior, tree)
        self.tree_widget.pack()

    def activate(self, callback, label):
        if self.window is not None:
            self.label.set(label)
        super().activate(callback, label=label)

    input = property(lambda self: self.tree_widget.get())
    tree = property(None, set_tree)
    def create_dialog(self):

        super().create_dialog()

        label = AlexLabel(self.interior)
        label.set("%s:" % _('Please select year'))
        label.pack()

        self.year_combo_box = AlexComboBox(self.interior)
        self.year_combo_box.pack(padx=5, pady=5)

        self.set_default_buttons()
class GenericBooleanSelectionDialog(AbstractInputDialog):
    @inject
    def __init__(self, window_manager: guiinjectorkeys.WINDOW_MANAGER_KEY,
                 presenter: guiinjectorkeys.GENERIC_INPUT_DIALOG_PRESENTER):
        super().__init__(window_manager, presenter)

    def create_dialog(self):
        super().create_dialog()
        self.add_button(_('Yes'), self.presenter.yes_action)
        self.add_button(_('No'), self.presenter.no_action)
        self.label = AlexLabel(self.interior)
        self.label.pack(padx=20, pady=20)

    def config_dialog(self, question=('Select yes or no')):

        self.label.set(question)
Ejemplo n.º 6
0
    def __init__(self, test_classes):

        self.message_broker = MessageBroker()
        self.window_manager = WindowManager(self.message_broker)

        self.create_test_instances(test_classes)

        self.root = self.window_manager.create_new_window()
        geometry = '800x450'
        self.root.geometry(geometry)

        self.test_frame = None

        top_frame = Frame(self.root)
        top_frame.pack(side=TOP, fill=BOTH, expand=TRUE)

        message_frame = Frame(self.root)
        message_frame.pack(side=TOP)

        button_frame = Frame(self.root)
        button_frame.pack(side=TOP)

        self.message_label = AlexLabel(message_frame)
        self.message_label.pack(side=LEFT)

        self.menu_frame = Frame(top_frame)
        self.menu_frame.pack(side=LEFT, anchor=NW, padx=5)

        label = AlexLabel(self.menu_frame)
        label.set("Select a test")
        label.pack()

        self.tests = AlexListBox(
            self.menu_frame,  # @UndefinedVariable
            height=len(self.test_instances),
            selectioncommand=self.run_selected_test,
        )

        self.tests.set_items(self.test_instances)
        self.tests.pack(anchor=NW)

        self.widget_frame = Frame(top_frame, borderwidth=1, relief=SOLID)
        self.widget_frame.pack(side=LEFT, fill=BOTH, expand=TRUE)

        quit_button = Button(button_frame, command=self.root.quit, text="Quit")
        quit_button.pack(side=LEFT)
 def create_dialog(self):
     super().create_dialog()
     for input_field in range(0, self.number_of_entries):
         date_entry = DateEntryFrame(self.interior)
         date_entry.day_entry.bind('<KeyRelease>',
                                   lambda event, i=input_field, f='day':
                                   self._on_change(event, i, f))
         date_entry.month_entry.bind('<KeyRelease>',
                                     lambda event, i=input_field, f='month':
                                     self._on_change(event, i, f))
         date_entry.year_entry.bind('<KeyRelease>',
                                    lambda event, i=input_field, f='year':
                                    self._on_change(event, i, f))
         date_entry.pack(padx=10)
         self.date_entry.append(date_entry)
     empty_label = AlexLabel(self.interior)
     empty_label.pack()
     self.set_default_buttons()
class EventConfirmationDialog(AbstractInputDialog):
    @inject
    def __init__(self, window_manager: guiinjectorkeys.WINDOW_MANAGER_KEY,
                 presenter: guiinjectorkeys.EVENT_CONFIRMATION_PRESENTER_KEY):
        super().__init__(window_manager, presenter)

    def create_dialog(self):

        super().create_dialog()

        self.add_button(_('Create new event'), self.presenter.cancel_action)
        self.label = AlexLabel(self.interior,
                               wraplength=550,
                               font=("Helvetica", 14, "bold"))
        self.label.pack()
        self.event_frame = None

    def config_dialog(self, event_list=[], date=None):

        self.label.set(
            _("Events exist on %s. Please select the event you want or create a new one"
              ) % date)

        if self.event_frame is not None:
            self.event_frame.destroy()

        self.event_frame = Frame(self.interior)
        self.event_frame.pack()
        row_counter = 0
        for event in event_list:
            description = AlexLabel(self.event_frame,
                                    wraplength=500,
                                    justify=LEFT,
                                    text=event.description)
            description.grid(row=row_counter, column=0, sticky=W)

            def closure(event):
                return lambda: self._set_return_value(event)

            button = AlexButton(self.event_frame,
                                text=_("Goto event"),
                                command=closure(event))
            button.grid(row=row_counter, column=1)
            row_counter += 1
    def create_dialog(self):

        self.window = self.window_manager.create_new_window()
        self.window.withdraw()

        super().__init__(self.window)
        self.pack()

        label = AlexLabel(self)
        label.set(_("Please select user:"))
        label.pack(padx=5, pady=5)

        self.combobox = AlexComboBox(self)
        self.combobox.pack(padx=5, pady=5)

        buttonframe = Frame(self)
        buttonframe.pack(padx=5, pady=5)

        AlexButton(buttonframe, text=_('OK'),
                   command=self.presenter.ok_action).pack(side=LEFT)
        AlexButton(buttonframe,
                   text=_('Cancel'),
                   command=self.presenter.cancel_action).pack(side=LEFT)
class BaseWindow(Frame):
    """
        This class handles a lot of the functionality of the
        main windows of the application that are not dependent
        on the record type: menus, navigation buttons, the references
        grid etc.
    
    """
    GOTO_DIALOG = 'goto_dialog'
    FILTER_DIALOG = 'filter_dialog'

    def __init__(self, window_manager, message_broker, presenter, dialogs,
                 plugins):

        self.window_manager = window_manager
        self.window = self.window_manager.create_new_window()
        self.window.withdraw()

        message_broker.subscribe(self)

        super().__init__(self.window)

        self.presenter = presenter
        self.presenter.view = self

        self.dialogs = dialogs
        self.plugins = plugins

        self._entity = None
        self._entity_has_changed = False

        self.references = []
        self.new_record_id = None
        self.filter_object = None

        self._add_frames()

        self.references_frame = Frame(self.window, border=2, relief=RIDGE)
        self.references_frame.pack(side=TOP, anchor=NW, expand=YES, fill=BOTH)

        self._add_message_bar()

    def receive_message(self, message):
        if message == CONF_SETUP_FINISHED:
            self.show_window()

    def show_window(self):

        self.window.deiconify()

    def _get_icon_dir(self):
        this_module = BaseWindow.__module__
        this_file = os.path.abspath(sys.modules[this_module].__file__)
        this_directory = os.path.dirname(this_file)
        return os.path.join(this_directory, 'Icons')

    def _add_frames(self):

        top = Frame(self.window)
        top.pack(fill=X, expand=1)

        self._add_menu(top)

        self._add_filter_warning(self.window)

        self.entity_frame = Frame(self.window)
        self.entity_frame.pack(side=TOP, anchor=NW)
        self._populate_entity_frame()

    def _add_menu(self, parent):

        # pylint: disable=no-member
        self.menubar = AlexMenuBar(parent)
        self.window.config(menu=self.menubar)

        self.menubar.addmenu(_('Records'), '')
        self.menubar.addmenuitem(_('Records'),
                                 'command',
                                 label=_('First record'),
                                 command=self.presenter.goto_first)
        self.menubar.addmenuitem(_('Records'),
                                 'command',
                                 label=_('Last record'),
                                 command=self.presenter.goto_last)
        self.menubar.addmenuitem(_('Records'),
                                 'command',
                                 label=_('Next record'),
                                 command=self.presenter.goto_next)
        self.menubar.addmenuitem(_('Records'),
                                 'command',
                                 label=_('Previous record'),
                                 command=self.presenter.goto_previous)
        self.menubar.addmenuitem(_('Records'),
                                 'command',
                                 label=_('New record'),
                                 command=self._create_new)
        self.menubar.addmenuitem(_('Records'),
                                 'command',
                                 label=_('Delete record'),
                                 command=self.presenter.delete)
        self.menubar.addmenuitem(_('Records'),
                                 'command',
                                 label=_('Quit'),
                                 command=self.presenter.quit)

        self.menubar.addmenu(_('Navigation'))
        self.menubar.addmenuitem(_('Navigation'),
                                 'command',
                                 label=_('Goto record'),
                                 command=self._activate_record_dialog)
        self.menubar.addmenuitem(_('Navigation'),
                                 'command',
                                 label=_('Filtering'),
                                 command=self._toggle_filter)

        self.shortcutbar = AlexShortcutBar(parent)
        self.shortcutbar.pack(side=LEFT)

        icondir = self._get_icon_dir()

        self.shortcutbar.addshortcut(imagefile=os.path.join(
            icondir, 'first.gif'),
                                     command=self.presenter.goto_first,
                                     tooltip=_('Goto first record'))
        self.shortcutbar.addshortcut(imagefile=os.path.join(
            icondir, 'previous.gif'),
                                     command=self.presenter.goto_previous,
                                     tooltip=_('Go one record back'))
        self.shortcutbar.addshortcut(imagefile=os.path.join(
            icondir, 'new.gif'),
                                     command=self._create_new,
                                     tooltip=_('Create a new record'))
        self.shortcutbar.addshortcut(imagefile=os.path.join(
            icondir, 'next.gif'),
                                     command=self.presenter.goto_next,
                                     tooltip=_('Go one record forward'))
        self.shortcutbar.addshortcut(imagefile=os.path.join(
            icondir, 'last.gif'),
                                     command=self.presenter.goto_last,
                                     tooltip=_('Goto last record'))

        for plugin in self.plugins:
            plugin.attach_to_window(self)

    def _add_filter_warning(self, parent):

        self.filter_warning = AlexLabel(parent, text="", foreground='red')
        self.filter_warning.pack(side=TOP)

    def add_references(self, reference_factories):

        side = RIGHT

        for factory in reference_factories:
            if side == RIGHT:
                row = Frame(self.references_frame)
                row.pack(side=TOP, expand=YES, fill=BOTH)
                side = LEFT
            else:
                side = RIGHT
            view = factory.get_view(row)
            self.references.append(view)
            view.pack(side=side, expand=YES, fill=BOTH, padx=5, pady=5)

    def _add_message_bar(self):

        message_frame = Frame(self.window)
        message_frame.pack(side=TOP, anchor=NW, fill=X, expand=1)
        message_bar = AlexMessageBar(message_frame)
        message_bar.pack(fill=X, expand=1)
        # TODO: inject message broker into windows
        self.presenter.message_broker.subscribe(message_bar)

    def entity_has_changed(self):
        if self._entity_has_changed:
            return True
        self._view_to_entity()
        return self._entity_has_changed

    def _populate_entity_frame(self):
        raise Exception("Implement in child class!")

    def _entity_to_view(self, entity):
        raise Exception("Implement in child class!")

    def _view_to_entity(self):
        raise Exception("Implement in child class!")

    def _execute_dialog(self, dialog, *params, **kw):
        return self.dialogs[dialog].activate(*params, **kw)

    def _toggle_filter(self):
        if self.filter_object is None:
            self.dialogs[self.FILTER_DIALOG].activate(self._activate_filter)
        else:
            self.filter_object = None
            self.presenter.update_filter_expression()
            self.filter_warning.configure(text="")

    def _activate_filter(self, filter_object):
        self.filter_object = filter_object
        self.presenter.update_filter_expression()
        self.filter_warning.configure(text=_("Filter is set!"))
        self.presenter.goto_first()

    def _activate_record_dialog(self):
        self.dialogs[self.GOTO_DIALOG].activate(self._goto_record)

    def _goto_record(self, record_id):
        self.new_record_id = record_id
        self.presenter.goto_record()

    # This is kind of hackish because we want to be able to overwrite the setters
    # and getters in child classes. Without lambda, it would use the methods
    # in the parent class
    entity = property(lambda self: self._view_to_entity(),
                      lambda self, entity: self._entity_to_view(entity))
class DocumentWindow(BaseWindow):
    '''
    The window for manipulating documents.
    '''
    @inject
    @singleton
    def __init__(self, window_manager: guiinjectorkeys.WINDOW_MANAGER_KEY,
                 message_broker: guiinjectorkeys.MESSAGE_BROKER_KEY,
                 presenter: guiinjectorkeys.DOCUMENT_WINDOW_PRESENTER_KEY,
                 dialogs: guiinjectorkeys.DOCUMENT_WINDOW_DIALOGS_KEY,
                 document_menu_additions: guiinjectorkeys.
                 DOCUMENT_MENU_ADDITIONS_KEY):
        self.notebook = None
        self._description_widget = None
        self._condition_widget = None
        self._keywords_widget = None
        super().__init__(window_manager, message_broker, presenter, dialogs,
                         document_menu_additions)
        self.window.title(_("Alexandria documents"))

    def _create_new(self):
        self.presenter.create_new()

    def _change_widget_state(self, state):
        self._description_widget.configure(state=state)
        self._condition_widget.configure(state=state)
        self._keywords_widget.configure(state=state)

    def _clear_widgets(self):
        self._document_label.set(_("No document available"))
        self._description_widget.set('')
        self._condition_widget.set('')
        self._keywords_widget.set('')

    def _disable_widgets(self):
        self._change_widget_state(DISABLED)

    def _enable_widgets(self):
        self._change_widget_state(NORMAL)

    def _populate_entity_frame(self):
        # pylint: disable=no-member
        self._document_label = AlexLabel(self.entity_frame,
                                         text=_("No document available"))
        self._document_label.pack(padx=7, pady=7)
        self.notebook = Notebook(self.entity_frame, width=600)
        self.notebook.pack(fill=X)
        description = Frame(self.notebook)
        self.notebook.add(description, text=_('Description'))
        self._description_widget = AlexText(description,
                                            font="Helvetica 12 bold",
                                            wrap=WORD,
                                            height=6)
        self._description_widget.pack(fill=X)
        condition = Frame(self.notebook)
        self.notebook.add(condition, text=_('Condition'))
        self._condition_widget = AlexText(condition,
                                          font="Helvetica 12 bold",
                                          wrap=WORD,
                                          height=6)
        self._condition_widget.pack(fill=X)
        keywords = Frame(self.notebook)
        self.notebook.add(keywords, text=_('Keywords'))
        self._keywords_widget = AlexText(keywords,
                                         font="Helvetica 12 bold",
                                         wrap=WORD,
                                         height=6)
        self._keywords_widget.pack(fill=X)

    def _view_to_entity(self):
        if self._entity == None:
            return None

        if self._description_widget.get() != self._entity.description:
            self._entity_has_changed = True
            self._entity.description = self._description_widget.get()
        if self._condition_widget.get() != self._entity.condition:
            self._entity_has_changed = True
            self._entity.condition = self._condition_widget.get()
        if self._keywords_widget.get() != self._entity.keywords:
            self._entity_has_changed = True
            self._entity.keywords = self._keywords_widget.get()

        return self._entity

    def _entity_to_view(self, entity):

        if self._entity != entity:
            self._entity_has_changed = False

        if self._entity == None:
            self._enable_widgets()

        self._entity = entity
        if entity == None:
            self._clear_widgets()
            self._disable_widgets()
            return

        if self._entity.id == None:
            self._document_label.set(_("New document"))
        else:
            self._document_label.set(
                _("Document no.{0:d} ({1!s})").format(
                    self._entity.id, self._entity.document_type.description))
        self._description_widget.set(self._entity.description)
        self._condition_widget.set(self._entity.condition)
        self._keywords_widget.set(self._entity.keywords)
class AbstractInputDialog:
    '''
    A basic dialog skeleton for input dialogs. For simple
    message dialogs use the native dialogs of tkinter.

    This provides a rather simple framework for fast creating
    dialogs that return user input to the calling component.
    
    The framework works like this:
    
    - Make a subclass of this class
    - Overwrite the create_dialog method. You need to
      call the method in this superclass to provide you
      with the basic frames in the dialog window.
      Add your input stuff to the interior frame and
      your buttons to the button_frame (there are methods
      to help you for this)
    - Make a subclass of the AbstractInputDialogPresenter
    - Create action methods in the presenter that
      are bound to the buttons in the dialog window
    - The actions that are considered to close the
      dialog must set the return_value property of
      the view. This will close the dialog window and
      return the return_value to the caller of activate
    - Inject the dialog presenter into the dialog
    - Inject the dialog into your component that wants to
      use it
    - Call the activate method in the dialog in your
      component. You need to set a callback for your
      value. This callback will be executed with a value
      when the presenter closes the dialog window
    '''
    def __init__(self, window_manager, presenter):
        self.window_manager = window_manager
        self.presenter = presenter
        self.window = None
        self.callback = None

    def create_dialog(self):
        '''
        Extend this method in your child class. It already
        provides three frames: interior, buttons_frame and
        errormessage. The errormessage frame already has
        a label that may be read and set by the errormessage
        property.
        To set default buttons in the button_frame, use the
        set default buttons.
        Other buttons may be set through the add_button method.
        '''

        self.window = self.window_manager.create_new_window()
        self.window.protocol("WM_DELETE_WINDOW",
                             lambda: self._set_return_value(None))
        self.window.transient()
        self.window.attributes('-topmost', True)
        self.window.withdraw()

        self.interior = Frame(self.window)
        self.interior.pack()

        self.buttons_frame = Frame(self.window)
        self.buttons_frame.pack()

        self.message_frame = Frame(self.window)
        self.message_frame.pack()

        self._errormessage = AlexLabel(self.message_frame)
        self._errormessage.pack(side=TOP)

    def add_button(self, label, callback):
        '''
        Fast setup method for buttons. Just provide
        a label and a callback and a button will be
        appended to the button_frame
        '''

        button = AlexButton(self.buttons_frame, command=callback)
        button.set(label)
        button.pack(side=LEFT, padx=5, pady=5)
        return button

    def set_default_buttons(self):
        '''
        This method may be used in child classes
        to set the default buttons OK and Cancel
        '''
        self.add_button(_('OK'), self.presenter.ok_action)
        self.add_button(_('Cancel'), self.presenter.cancel_action)

    def _get_errormessage(self):
        message = self._errormessage.get()
        if message == '':
            return None
        else:
            return message

    def _set_errormessage(self, message):
        if message == None:
            self._errormessage.set('')
        else:
            self._errormessage.set(message)

    def activate(self, callback, **kw):
        '''
        '''
        if self.window is None:
            self.create_dialog()

        self.config_dialog(**kw)

        if self.window is None:
            callback(None)
            return
        self.callback = callback

        self.presenter.view = self
        self.window.deiconify()
        self.window.grab_set()

    def config_dialog(self, **kw):

        pass

    def _set_return_value(self, value):
        self.window.grab_release()
        self.window.withdraw()
        self.callback(value)

    return_value = property(None, _set_return_value)
    errormessage = property(_get_errormessage, _set_errormessage)