All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.marid.ide.frames.schema.SchemaFrame Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2014 Dmitry Ovchinnikov
 * Marid, the free data acquisition and visualization software
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see .
 */

package org.marid.ide.frames.schema;

import images.Images;
import org.marid.bd.BlockComponent;
import org.marid.bd.schema.SchemaEditor;
import org.marid.bd.schema.SchemaModel;
import org.marid.bd.shapes.LinkShape;
import org.marid.bd.shapes.LinkShapeEvent;
import org.marid.dyn.MetaInfo;
import org.marid.ide.components.BlockMenuProvider;
import org.marid.ide.components.BlockPersister;
import org.marid.ide.components.ProfileManager;
import org.marid.ide.frames.MaridFrame;
import org.marid.ide.profile.Profile;
import org.marid.spring.annotation.PrototypeComponent;
import org.marid.swing.SwingUtil;
import org.springframework.beans.factory.annotation.Autowired;

import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.plaf.LayerUI;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.awt.event.WindowEvent;
import java.io.File;

import static java.awt.Color.RED;
import static java.awt.SystemColor.infoText;
import static java.lang.String.format;
import static javax.swing.BorderFactory.*;

/**
 * @author Dmitry Ovchinnikov
 */
@PrototypeComponent
@MetaInfo(name = "Schema Editor")
public class SchemaFrame extends MaridFrame {

    protected final ProfileManager profileManager;
    protected final BlockPersister persister;
    protected final SchemaEditor schemaEditor;
    protected final JLayer layer;
    protected final JMenu blocksMenu = new JMenu(s("Blocks"));

    protected File file;

    @Autowired
    public SchemaFrame(BlockMenuProvider blockMenuProvider, ProfileManager profileManager, BlockPersister persister, SchemaEditor schemaEditor) {
        super("Schema");
        this.profileManager = profileManager;
        this.persister = persister;
        enableEvents(AWTEvent.COMPONENT_EVENT_MASK | AWTEvent.WINDOW_EVENT_MASK);
        centerPanel.add(layer = new JLayer<>(this.schemaEditor = schemaEditor, new SchemaLayerUI()));
        getContentPane().setBackground(getBackground());
        getJMenuBar().add(blocksMenu);
        blockMenuProvider.fillMenu(blocksMenu);
    }

    public void fireEvent(AWTEvent event) {
        layer.getUI().eventDispatched(event, layer);
    }

    @Override
    protected void processWindowEvent(WindowEvent e) {
        super.processWindowEvent(e);
        switch (e.getID()) {
            case WindowEvent.WINDOW_OPENED:
                schemaEditor.start();
                break;
            case WindowEvent.WINDOW_CLOSED:
                schemaEditor.stop();
                break;
        }
    }

    public void selectionMode(Action action, ActionEvent event) {
        schemaEditor.setSelectionMode((boolean) action.getValue(Action.SELECTED_KEY));
    }

    @Override
    protected void fillActions() {
        addAction("/File/o/Open", "Open...", "open", this::open).setKey("control O").enableToolbar();
        addAction("/File/s/Save", "Save", "save", this::save).setKey("control S").enableToolbar();
        addAction("/File/s/SaveAs", "Save As...", "save", this::saveAs).setKey("control shift S");
        addAction("/Schema/z/ZoomIn", "Zoom In...", "zoomin", e -> schemaEditor.zoomIn()).setKey("control I").enableToolbar();
        addAction("/Schema/z/ZoomOut", "Zoom Out...", "zoomout", e -> schemaEditor.zoomOut()).setKey("control B").enableToolbar();
        addAction("/Schema/z/ZoomReset", "Reset zoom", "zoom", e -> schemaEditor.resetZoom()).setKey("control Z").enableToolbar();
        addAction("/Schema/s/SelectionMode", "Selection mode", "selection", this::selectionMode).setKey("control J").setSelected(false).enableToolbar();
        addAction("/Schema/r/Refresh", "Refresh", "refresh", e -> schemaEditor.repaint()).setKey("F5").enableToolbar();
        addAction("/Schema/r/ResetInOut", "Reset input/output selection", "reset", schemaEditor::resetInputOutputSelection).setKey("control shift T").enableToolbar();
        addAction("/Schema/a/AlignToLeft", "Align to left", "alignleft", schemaEditor::alignToLeft).setKey("control shift L").enableToolbar();
        addAction("/Schema/a/AlignToRight", "Align to right", "alignright", schemaEditor::alignToRight).setKey("control shift R").enableToolbar();
        addAction("b/Build/r/Build", "Build", "hammer", e -> new SchemaModel(schemaEditor).getSchema().build()).setKey("F7").enableToolbar();
    }

    protected void open(ActionEvent actionEvent) {
        final Profile profile = profileManager.getCurrentProfile();
        final File dir = profile == null ? new File(".") : profile.getContextPath().toFile();
        final JFileChooser chooser = new JFileChooser(dir);
        chooser.setAcceptAllFileFilterUsed(false);
        chooser.addChoosableFileFilter(new FileNameExtensionFilter("XML files", "xml"));
        chooser.setMultiSelectionEnabled(false);
        switch (chooser.showOpenDialog(this)) {
            case JFileChooser.APPROVE_OPTION:
                try {
                    final SchemaModel model = persister.load(chooser.getSelectedFile().toPath());
                    schemaEditor.load(model);
                    file = chooser.getSelectedFile();
                } catch (Exception x) {
                    showMessage(ERROR_MESSAGE, "Load error", "Load {0} error", x, chooser.getSelectedFile());
                }
                break;
        }
    }

    protected void save(ActionEvent actionEvent) {
        if (file == null) {
            saveAs(actionEvent);
            return;
        }
        try {
            final SchemaModel model = new SchemaModel(schemaEditor);
            persister.save(model, file.toPath());
        } catch (Exception x) {
            showMessage(ERROR_MESSAGE, "Save error", "Save {0} error", x, file);
        }
    }

    protected void saveAs(ActionEvent actionEvent) {
        final Profile profile = profileManager.getCurrentProfile();
        final File dir = profile == null ? new File(".") : profile.getContextPath().toFile();
        final JFileChooser chooser = new JFileChooser(dir);
        chooser.setAcceptAllFileFilterUsed(false);
        chooser.addChoosableFileFilter(new FileNameExtensionFilter("XML files", "xml"));
        chooser.setMultiSelectionEnabled(false);
        switch (chooser.showSaveDialog(this)) {
            case JFileChooser.APPROVE_OPTION:
                file = chooser.getSelectedFile();
                save(actionEvent);
                break;
        }
    }

    protected class SchemaLayerUI extends LayerUI {

        private JLabel tooltip = null;

        @Override
        public void paint(Graphics g, JComponent c) {
            super.paint(g, c);
            if (tooltip != null) {
                final Rectangle bounds = tooltip.getBounds();
                if (bounds.getMaxX() > schemaEditor.getWidth()) {
                    tooltip.setLocation(schemaEditor.getWidth() - bounds.width, tooltip.getY());
                }
                if (bounds.getMaxY() > schemaEditor.getHeight()) {
                    tooltip.setLocation(tooltip.getX(), schemaEditor.getHeight() - bounds.height);
                }
                try {
                    g.translate(tooltip.getX(), tooltip.getY());
                    tooltip.print(g);
                } finally {
                    g.translate(-tooltip.getX(), -tooltip.getY());
                }
            }
        }

        @Override
        public void installUI(JComponent c) {
            super.installUI(c);
            ((JLayer) c).setLayerEventMask(AWTEvent.MOUSE_EVENT_MASK);
        }

        @Override
        public void uninstallUI(JComponent c) {
            super.uninstallUI(c);
            ((JLayer) c).setLayerEventMask(0L);
        }

        @Override
        public void eventDispatched(AWTEvent e, JLayer l) {
            super.eventDispatched(e, l);
            switch (e.getID()) {
                case MouseEvent.MOUSE_ENTERED:
                    if (e.getSource() instanceof BlockComponent.Input) {
                        final BlockComponent.Input input = (BlockComponent.Input) e.getSource();
                        final Point point = ((MouseEvent) e).getLocationOnScreen();
                        SwingUtilities.convertPointFromScreen(point, schemaEditor);
                        showTooltip(format("%s: %s", input.getInput().getName(), input.getInput().getInputType().getCanonicalName()), point);
                    } else if (e.getSource() instanceof BlockComponent.Output) {
                        final BlockComponent.Output output = (BlockComponent.Output) e.getSource();
                        final Point point = ((MouseEvent) e).getLocationOnScreen();
                        SwingUtilities.convertPointFromScreen(point, schemaEditor);
                        showTooltip(format("%s: %s", output.getOutput().getName(), output.getOutput().getOutputType().getCanonicalName()), point);
                    }
                    break;
                case MouseEvent.MOUSE_EXITED:
                    if (e.getSource() instanceof BlockComponent.Input || e.getSource() instanceof BlockComponent.Output) {
                        hideTooltip();
                    }
                    break;
                default:
                    if (e instanceof LinkShapeEvent) {
                        switch (e.getID()) {
                            case LinkShapeEvent.MOUSE_ENTERED:
                                final LinkShapeEvent event = (LinkShapeEvent) e;
                                final LinkShape link = event.getSource();
                                if (!link.isValid()) {
                                    showError(m("Types mismatch: {0} -> {1}",
                                            link.getOutputType().getCanonicalName(),
                                            link.getInputType().getCanonicalName()), event.getPoint());
                                }
                                break;
                            case LinkShapeEvent.MOUSE_EXITED:
                                hideTooltip();
                                break;
                        }
                    }
                    break;
            }
        }

        public void hideTooltip() {
            if (tooltip != null) {
                tooltip = null;
                layer.repaint();
            }
        }

        public void showTooltip(String text, Point point) {
            showMessage(Images.getIcon("info.png"), SystemColor.info, text, point);
        }

        public void showError(String text, Point point) {
            showMessage(Images.getIcon("warning.png"), RED.brighter().brighter(), text, point);
        }

        public void showMessage(ImageIcon icon, Color color, String text, Point point) {
            final JLabel label = new JLabel(text, icon, SwingConstants.LEFT);
            label.setOpaque(true);
            label.setForeground(infoText);
            label.setBackground(SwingUtil.color(color, 200));
            label.setBorder(createCompoundBorder(createEtchedBorder(), createEmptyBorder(3, 3, 3, 3)));
            label.setLocation(point.x + 10, point.y + 10);
            label.setSize(label.getPreferredSize());
            tooltip = label;
            layer.repaint();
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy