Esempio n. 1
0
    def action_new(self):
        """The new model menu action.  This action will create a new
        UML model.  This will trigger a FileManagerStateChange event."""

        element_factory = self.element_factory
        main_window = self.main_window

        if element_factory.size():
            dialog = QuestionDialog(
                gettext("Opening a new model will flush the"
                        " currently loaded model.\nAny changes"
                        " made will not be saved. Do you want to"
                        " continue?"),
                parent=main_window.window,
            )

            answer = dialog.answer
            dialog.destroy()

            if not answer:
                return

        element_factory.flush()
        with element_factory.block_events():
            model = element_factory.create(UML.Package)
            model.name = gettext("New model")
            diagram = element_factory.create(UML.Diagram)
            diagram.package = model
            diagram.name = gettext("main")
        self.filename = None
        element_factory.model_ready()
Esempio n. 2
0
    def action_new_from_template(self):
        """This menu action opens the new model from template dialog."""

        filters = [
            {
                "name": gettext("Gaphor Models"),
                "pattern": "*.gaphor"
            },
            {
                "name": gettext("All Files"),
                "pattern": "*"
            },
        ]

        file_dialog = FileDialog(gettext("New Gaphor Model From Template"),
                                 filters=filters)

        filename = file_dialog.selection

        file_dialog.destroy()

        log.debug(filename)

        if filename:
            self.load(filename)
            self.filename = None
Esempio n. 3
0
    def construct(self):
        page = Gtk.VBox()

        hbox = Gtk.HBox()
        label = Gtk.Label(label="")
        label.set_justify(Gtk.Justification.LEFT)
        self.size_group.add_widget(label)
        hbox.pack_start(label, False, True, 0)

        button = Gtk.CheckButton(label=gettext("Orthogonal"))
        button.set_active(self.item.orthogonal)
        button.connect("toggled", self._on_orthogonal_change)
        hbox.pack_start(button, True, True, 0)

        page.pack_start(hbox, False, True, 0)

        hbox = Gtk.HBox()
        label = Gtk.Label(label="")
        label.set_justify(Gtk.Justification.LEFT)
        self.size_group.add_widget(label)
        hbox.pack_start(label, False, True, 0)

        button = Gtk.CheckButton(label=gettext("Horizontal"))
        button.set_active(self.item.horizontal)
        button.connect("toggled", self._on_horizontal_change)
        hbox.pack_start(button, True, True, 0)

        page.pack_start(hbox, False, True, 0)

        return page
Esempio n. 4
0
    def construct(self):
        page = super().construct()

        if not self.subject:
            return page

        hbox = Gtk.HBox()
        label = Gtk.Label(label="")
        label.set_justify(Gtk.Justification.LEFT)
        self.size_group.add_widget(label)
        hbox.pack_start(label, False, True, 0)

        button = Gtk.CheckButton(label=gettext("Show direction"))
        button.set_active(self.item.show_direction)
        button.connect("toggled", self._on_show_direction_change)
        hbox.pack_start(button, True, True, 0)

        button = Gtk.Button.new_from_icon_name(
            "object-flip-horizontal-symbolic", Gtk.IconSize.BUTTON)
        button.connect("clicked", self._on_invert_direction_change)
        hbox.pack_start(button, True, True, 0)

        page.pack_start(hbox, False, True, 0)

        box = self.construct_end(gettext("Head"), self.item.head_end)
        if box:
            page.pack_start(box, False, True, 0)

        box = self.construct_end(gettext("Tail"), self.item.tail_end)
        if box:
            page.pack_start(box, False, True, 0)

        return page
Esempio n. 5
0
class XMIExport(Service, ActionProvider):
    def __init__(self, element_factory, file_manager, export_menu):
        self.element_factory = element_factory
        self.file_manager = file_manager
        export_menu.add_actions(self)

    def shutdown(self):
        pass

    @action(
        name="file-export-xmi",
        label=gettext("Export to XMI"),
        tooltip=gettext("Export model to XMI (XML Model Interchange) format"),
    )
    def execute(self):
        filename = self.file_manager.filename
        filename = filename.replace(".gaphor", ".xmi") if filename else "model.xmi"
        file_dialog = FileDialog(
            gettext("Export model to XMI file"), action="save", filename=filename
        )

        filename = file_dialog.selection

        if filename and len(filename) > 0:
            logger.debug(f"Exporting XMI model to: {filename}")
            export = exportmodel.XMIExport(self.element_factory)
            try:
                export.export(filename)
            except Exception as e:
                logger.error(f"Error while saving model to file {filename}: {e}")
Esempio n. 6
0
    def construct(self):
        page = super().construct()

        subject = self.subject

        if not subject:
            return page

        hbox = create_hbox_label(self, page, gettext("Entry"))
        entry = Gtk.Entry()
        if subject.entry:
            entry.set_text(subject.entry.name or "")
        entry.connect("changed", self.on_text_change, self.set_entry)
        hbox.pack_start(entry, True, True, 0)

        hbox = create_hbox_label(self, page, gettext("Exit"))
        entry = Gtk.Entry()
        if subject.exit:
            entry.set_text(subject.exit.name or "")
        entry.connect("changed", self.on_text_change, self.set_exit)
        hbox.pack_start(entry, True, True, 0)

        hbox = create_hbox_label(self, page, gettext("Do Activity"))
        entry = Gtk.Entry()
        if subject.doActivity:
            entry.set_text(self.subject.doActivity.name or "")
        entry.connect("changed", self.on_text_change, self.set_do_activity)
        hbox.pack_start(entry, True, True, 0)

        page.show_all()

        return page
Esempio n. 7
0
    def load(self, filename):
        """Load the Gaphor model from the supplied file name.  A status window
        displays the loading progress.  The load generator updates the progress
        queue.  The loader is passed to a GIdleThread which executes the load
        generator.  If loading is successful, the filename is set."""

        queue = Queue()
        status_window = StatusWindow(
            gettext("Loading..."),
            gettext("Loading model from {filename}").format(filename=filename),
            parent=self.main_window.window,
            queue=queue,
        )

        try:
            loader = storage.load_generator(filename.encode("utf-8"),
                                            self.element_factory)
            worker = GIdleThread(loader, queue)

            worker.start()
            worker.wait()

            if worker.error:
                worker.reraise()

            self.filename = filename
            self.event_manager.handle(FileLoaded(self, filename))
        except (QueueEmpty, QueueFull):
            error_handler(message=gettext(
                "Error while loading model from file {filename}").format(
                    filename=filename))
            raise
        finally:
            status_window.destroy()
Esempio n. 8
0
def zoom_buttons():
    box = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0)
    box.get_style_context().add_class("linked")
    box.pack_start(
        icon_button(
            "zoom-in-symbolic",
            "diagram.zoom-in",
            gettext("Zoom in") + f" ({primary()}++)",
        ),
        False,
        False,
        0,
    )
    box.pack_start(
        icon_button(
            "zoom-original-symbolic",
            "diagram.zoom-100",
            gettext("Zoom 100%") + f" ({primary()}+0)",
        ),
        False,
        False,
        0,
    )
    box.pack_start(
        icon_button(
            "zoom-out-symbolic",
            "diagram.zoom-out",
            gettext("Zoom out") + f" ({primary()}+-)",
        ),
        False,
        False,
        0,
    )
    box.show()
    return box
Esempio n. 9
0
def undo_buttons():
    box = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0)
    box.get_style_context().add_class("linked")
    box.pack_start(
        icon_button(
            "edit-undo-symbolic",
            "win.edit-undo",
            gettext("Undo") + f" ({primary()}+Z)",
        ),
        False,
        False,
        0,
    )
    box.pack_start(
        icon_button(
            "edit-redo-symbolic",
            "win.edit-redo",
            gettext("Redo") + f" ({primary()}+Shift+Z)",
        ),
        False,
        True,
        0,
    )
    box.show()
    return box
Esempio n. 10
0
    def construct(self):
        page = super().construct()

        subject = self.subject

        if not subject:
            return page

        hbox = create_hbox_label(self, page, gettext("Upper bound"))
        entry = Gtk.Entry()
        entry.set_text(subject.upperBound or "")
        entry.connect("changed", self._on_upper_bound_change)
        hbox.pack_start(entry, True, True, 0)

        hbox = create_hbox_label(self, page, "")
        combo = Gtk.ComboBoxText()
        for v in self.ORDERING_VALUES:
            combo.append_text(v)
        combo.set_active(self.ORDERING_VALUES.index(subject.ordering))
        combo.connect("changed", self._on_ordering_change)
        hbox.pack_start(combo, False, True, 0)

        hbox = create_hbox_label(self, page, "")
        button = Gtk.CheckButton(gettext("Ordering"))
        button.set_active(self.item.show_ordering)
        button.connect("toggled", self._on_ordering_show_change)
        hbox.pack_start(button, False, True, 0)

        return page
Esempio n. 11
0
    def construct(self):
        page = Gtk.VBox()

        if not self.item.subject:
            return page

        # Show operations toggle
        hbox = Gtk.HBox()
        label = Gtk.Label(label="")
        label.set_justify(Gtk.Justification.LEFT)
        hbox.pack_start(label, False, True, 0)
        button = Gtk.CheckButton(label=gettext("Show operations"))
        button.set_active(self.item.show_operations)
        button.connect("toggled", self._on_show_operations_change)
        hbox.pack_start(button, True, True, 0)
        page.pack_start(hbox, False, True, 0)

        def create_model():
            return ClassOperations(self.item, (str, bool, bool, object))

        self.model = create_model()
        tip = """\
Add and edit class operations according to UML syntax. Operation syntax examples
- call()
- + call(a: int, b: str)
- # call(a: int: b: str): bool
"""
        tree_view = create_tree_view(
            self.model, (gettext("Operation"), gettext("A"), gettext("S")), tip
        )
        page.pack_start(tree_view, True, True, 0)

        @AsyncIO(single=True)
        def handler(event):
            if not tree_view.props.has_focus and self.item and self.item.subject:
                self.model = create_model()
                tree_view.set_model(self.model)

        self.watcher.watch("ownedOperation.name", handler).watch(
            "ownedOperation.isAbstract", handler
        ).watch("ownedOperation.visibility", handler).watch(
            "ownedOperation.returnResult.lowerValue", handler
        ).watch(
            "ownedOperation.returnResult.upperValue", handler
        ).watch(
            "ownedOperation.returnResult.typeValue", handler
        ).watch(
            "ownedOperation.formalParameter.lowerValue", handler
        ).watch(
            "ownedOperation.formalParameter.upperValue", handler
        ).watch(
            "ownedOperation.formalParameter.typeValue", handler
        ).watch(
            "ownedOperation.formalParameter.defaultValue", handler
        ).subscribe_all()
        tree_view.connect("destroy", self.watcher.unsubscribe_all)

        return page
Esempio n. 12
0
def create_stereotype_tree_view(model, toggle_stereotype, set_slot_value):
    """
    Create a tree view for an editable tree model.

    :Parameters:
     model
        Model, for which tree view is created.
    """
    tree_view = Gtk.TreeView.new_with_model(model)
    tree_view.set_search_column(-1)

    # Stereotype/Attributes
    col = Gtk.TreeViewColumn.new()
    col.set_title("{} / {}".format(gettext("Stereotype"), gettext("Attribute")))
    col.set_expand(True)
    renderer = Gtk.CellRendererToggle()
    renderer.set_property("active", True)
    renderer.set_property("activatable", True)
    renderer.connect("toggled", toggle_stereotype, model, 2)
    col.pack_start(renderer, False)
    col.add_attribute(renderer, "active", 2)

    def show_checkbox(column, cell, model, iter, data):
        # value = model.get_value(iter, 4)
        # cell.set_property('active', value is not None)
        value = model.get_value(iter, 3)
        cell.set_property("visible", isinstance(value, UML.Stereotype))

    col.set_cell_data_func(renderer, show_checkbox)

    renderer = Gtk.CellRendererText.new()
    renderer.set_property("editable", False)
    renderer.set_property("is-expanded", True)
    col.pack_start(renderer, False)
    col.add_attribute(renderer, "text", 0)
    tree_view.append_column(col)

    # TODO: use col.set_cell_data_func(renderer, func, None) to toggle visibility
    # Value
    renderer = Gtk.CellRendererText()
    renderer.set_property("is-expanded", True)
    renderer.connect("edited", set_slot_value, model, 1)
    col = Gtk.TreeViewColumn(gettext("Value"), renderer, text=1)
    col.set_expand(True)

    def set_editable(column, cell, model, iter, data):
        value = model.get_value(iter, 4)
        cell.set_property("editable", bool(value))

    col.set_cell_data_func(renderer, set_editable)
    tree_view.append_column(col)

    # tree_view.connect('key_press_event', remove_on_keypress)
    # tree_view.connect('key_press_event', swap_on_keypress)

    return tree_view
Esempio n. 13
0
def load_default_model(session):
    element_factory = session.get_service("element_factory")
    element_factory.flush()
    with element_factory.block_events():
        model = element_factory.create(UML.Package)
        model.name = gettext("New model")
        diagram = element_factory.create(UML.Diagram)
        diagram.package = model
        diagram.name = gettext("main")
    element_factory.model_ready()
Esempio n. 14
0
def create_hamburger_model(export_menu, tools_menu):
    model = Gio.Menu.new()

    part = Gio.Menu.new()
    part.append(gettext("New Window"), "app.file-new")
    part.append(gettext("New from Template"), "app.file-new-template")
    model.append_section(None, part)

    part = Gio.Menu.new()
    part.append(gettext("Save"), "win.file-save")
    part.append(gettext("Save As..."), "win.file-save-as")
    part.append_submenu(gettext("Export"), export_menu)
    model.append_section(None, part)

    part = Gio.Menu.new()
    part.append_submenu(gettext("Tools"), tools_menu)
    model.append_section(None, part)

    part = Gio.Menu.new()
    part.append(gettext("Preferences"), "win.preferences")
    part.append(gettext("Keyboard Shortcuts"), "app.shortcuts")
    part.append(gettext("About Gaphor"), "app.about")
    model.append_section(None, part)

    return model
Esempio n. 15
0
    def construct(self):
        page = Gtk.VBox()

        if not self.item.subject:
            return page

        # Show attributes toggle
        hbox = Gtk.HBox()
        label = Gtk.Label(label="")
        label.set_justify(Gtk.Justification.LEFT)
        hbox.pack_start(label, False, True, 0)
        button = Gtk.CheckButton(label=gettext("Show attributes"))
        button.set_active(self.item.show_attributes)
        button.connect("toggled", self._on_show_attributes_change)
        hbox.pack_start(button, True, True, 0)
        page.pack_start(hbox, False, True, 0)

        def create_model():
            return ClassAttributes(self.item, (str, bool, object))

        self.model = create_model()

        tip = """\
Add and edit class attributes according to UML syntax. Attribute syntax examples
- attr
- + attr: int
- # /attr: int
"""
        tree_view = create_tree_view(
            self.model, (gettext("Attributes"), gettext("S")), tip
        )
        page.pack_start(tree_view, True, True, 0)

        @AsyncIO(single=True)
        def handler(event):
            # Single it's asynchronous, make sure all properties are still there
            if not tree_view.props.has_focus and self.item and self.item.subject:
                self.model = create_model()
                tree_view.set_model(self.model)

        self.watcher.watch("ownedAttribute.name", handler).watch(
            "ownedAttribute.isDerived", handler
        ).watch("ownedAttribute.visibility", handler).watch(
            "ownedAttribute.isStatic", handler
        ).watch(
            "ownedAttribute.lowerValue", handler
        ).watch(
            "ownedAttribute.upperValue", handler
        ).watch(
            "ownedAttribute.defaultValue", handler
        ).watch(
            "ownedAttribute.typeValue", handler
        ).subscribe_all()
        tree_view.connect("destroy", self.watcher.unsubscribe_all)
        return page
Esempio n. 16
0
 def new(self):
     element_factory = self.element_factory
     element_factory.flush()
     with element_factory.block_events():
         model = element_factory.create(UML.Package)
         model.name = gettext("New model")
         diagram = element_factory.create(UML.Diagram)
         diagram.package = model
         diagram.name = gettext("main")
     self.filename = None
     element_factory.model_ready()
Esempio n. 17
0
 def update_shapes(self, event=None):
     self.shape = Box(
         Box(
             Text(
                 text=lambda: stereotypes_str(self.subject, ["block"]),
                 style={
                     "min-width": 0,
                     "min-height": 0
                 },
             ),
             EditableText(
                 text=lambda: self.subject.name or "",
                 width=lambda: self.width - 4,
                 style={
                     "font-weight":
                     FontWeight.BOLD,
                     "font-style":
                     FontStyle.ITALIC if self.subject
                     and self.subject.isAbstract else FontStyle.NORMAL,
                 },
             ),
             Text(
                 text=lambda: from_package_str(self),
                 style={
                     "font-size": 10,
                     "min-width": 0,
                     "min-height": 0
                 },
             ),
             style={"padding": (12, 4, 12, 4)},
         ),
         *(self.show_parts and self.subject and [
             self.block_compartment(
                 gettext("parts"),
                 lambda a: a.aggregation == "composite",
             )
         ] or []),
         *(self.show_references and self.subject and [
             self.block_compartment(
                 gettext("references"),
                 lambda a: a.aggregation != "composite",
             )
         ] or []),
         *(self.show_stereotypes and stereotype_compartments(self.subject)
           or []),
         style={
             "min-width": 100,
             "min-height": 50,
             "vertical-align": VerticalAlign.TOP,
         },
         draw=draw_border,
     )
Esempio n. 18
0
    def verify_orphans(self):
        """Verify that no orphaned elements are saved.

        This method checks of there are any orphan references in the
        element factory.  If orphans are found, a dialog is displayed
        asking the user if it is OK to unlink them.
        """

        orphans = verify.orphan_references(self.element_factory)

        if orphans:
            log.info("Found orphan references %s", orphans)
            main_window = self.main_window

            dialog = QuestionDialog(
                gettext(
                    "The model contains some references to items that are not maintained. Do you want to clean the model before saving?"
                ),
                parent=main_window.window,
            )

            answer = dialog.answer
            dialog.destroy()

            if not answer:
                for orphan in orphans:
                    orphan.unlink()
Esempio n. 19
0
    def action_new_from_template(self):
        """This menu action opens the new model from template dialog."""

        filename = self.file_dialog(gettext("New Gaphor Model From Template"))
        if filename:
            self.load(filename)
            self.filename = None
Esempio n. 20
0
    def construct(self):
        page = super().construct()

        subject = self.subject

        if not subject:
            return page

        hbox = create_hbox_label(self, page, gettext("Guard"))
        entry = Gtk.Entry()
        v = subject.guard.specification
        entry.set_text(v if v else "")
        changed_id = entry.connect("changed", self._on_guard_change)
        hbox.pack_start(entry, True, True, 0)

        def handler(event):
            entry.handler_block(changed_id)
            v = event.new_value
            entry.set_text(v if v else "")
            entry.handler_unblock(changed_id)

        self.watcher.watch("guard[Constraint].specification", handler).subscribe_all()
        entry.connect("destroy", self.watcher.unsubscribe_all)

        return page
Esempio n. 21
0
    def action_open(self):
        """This menu action opens the standard model open dialog."""

        filename = self.file_dialog(gettext("Open Gaphor Model"))

        if filename:
            self.load(filename)
Esempio n. 22
0
    def construct(self):
        page = super().construct()
        item = self.item

        # Fold toggle
        hbox = Gtk.HBox()
        label = Gtk.Label(label="")
        label.set_justify(Gtk.Justification.LEFT)
        self.size_group.add_widget(label)
        hbox.pack_start(label, False, True, 0)

        button = Gtk.CheckButton(gettext("Folded"))
        button.set_active(item.folded != Folded.NONE)
        button.connect("toggled", self._on_fold_change)

        connected_items = [
            c.item for c in item.canvas.get_connections(connected=item)
        ]
        disallowed = (ConnectorItem, )
        can_fold = not any(
            map(lambda i: isinstance(i, disallowed), connected_items))

        button.set_sensitive(can_fold)
        hbox.pack_start(button, True, True, 0)
        page.pack_start(hbox, False, True, 0)

        return page
Esempio n. 23
0
 def save_svg_action(self):
     diagram = self.diagrams.get_current_diagram()
     filename = self.save_dialog(
         diagram, gettext("Export diagram to SVG"), "svg", "image/svg+xml"
     )
     if filename:
         self.save_svg(filename, diagram)
Esempio n. 24
0
 def save_png_action(self):
     diagram = self.diagrams.get_current_diagram()
     filename = self.save_dialog(
         diagram, gettext("Export diagram to PNG"), "png", "image/png"
     )
     if filename:
         self.save_png(filename, diagram)
Esempio n. 25
0
def create_recent_files_model(recent_manager=None):
    model = Gio.Menu.new()
    model.append_section(
        gettext("Recently opened files"),
        RecentFilesMenu(recent_manager or Gtk.RecentManager.get_default()),
    )
    return model
Esempio n. 26
0
 def save_pdf_action(self):
     diagram = self.diagrams.get_current_diagram()
     filename = self.save_dialog(
         diagram, gettext("Export diagram to PDF"), "pdf", "application/pdf"
     )
     if filename:
         self.save_pdf(filename, diagram)
Esempio n. 27
0
    def save_dialog(self, diagram, title, ext):

        filename = (diagram.name or "export") + ext
        file_dialog = FileDialog(title, action="save", filename=filename)

        save = False
        while True:
            filename = file_dialog.selection
            if os.path.exists(filename):
                question = gettext(
                    "The file {filename} already exists. Do you want to replace it?"
                ).format(filename=filename)
                question_dialog = QuestionDialog(question)
                answer = question_dialog.answer
                question_dialog.destroy()
                if answer:
                    save = True
                    break
            else:
                save = True
                break

        file_dialog.destroy()

        if save and filename:
            return filename
Esempio n. 28
0
 def save_pdf_action(self):
     title = gettext("Export diagram to PDF")
     ext = ".pdf"
     diagram = self.diagrams.get_current_diagram()
     filename = self.save_dialog(diagram, title, ext)
     if filename:
         self.save_pdf(filename, diagram)
Esempio n. 29
0
 def save_svg_action(self):
     title = gettext("Export diagram to SVG")
     ext = ".svg"
     diagram = self.diagrams.get_current_diagram()
     filename = self.save_dialog(diagram, title, ext)
     if filename:
         self.save_svg(filename, diagram)
Esempio n. 30
0
def error_message(e):
    if not isinstance(e, IOError):
        return gettext(
            "Gaphor was not able to store the model, probably due to an internal error:\n{exc}\nIf you think this is a bug, please contact the developers."
        ).format(exc=str(e))
    if e.errno == 13:
        return gettext(
            "You do not have the permissions necessary to save the model.\nPlease check that you typed the location correctly and try again."
        )
    elif e.errno == 28:
        return gettext(
            "You do not have enough free space on the device to save the model.\nPlease free up some disk space and try again or save it in a different location."
        )
    return gettext(
        "The model cannot be stored at this location:\n{exc}\nPlease check that you typed the location correctly and try again."
    ).format(exc=str(e))