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

org.apache.cayenne.modeler.CayenneModelerFrame Maven / Gradle / Ivy

There is a newer version: 5.0-M1
Show newest version
/*****************************************************************
 *   Licensed to the Apache Software Foundation (ASF) under one
 *  or more contributor license agreements.  See the NOTICE file
 *  distributed with this work for additional information
 *  regarding copyright ownership.  The ASF licenses this file
 *  to you under the Apache License, Version 2.0 (the
 *  "License"); you may not use this file except in compliance
 *  with the License.  You may obtain a copy of the License at
 *
 *    https://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing,
 *  software distributed under the License is distributed on an
 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *  KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations
 *  under the License.
 ****************************************************************/

package org.apache.cayenne.modeler;

import org.apache.cayenne.modeler.action.AboutAction;
import org.apache.cayenne.modeler.action.ActionManager;
import org.apache.cayenne.modeler.action.ConfigurePreferencesAction;
import org.apache.cayenne.modeler.action.CopyAction;
import org.apache.cayenne.modeler.action.CreateDataMapAction;
import org.apache.cayenne.modeler.action.CreateDbEntityAction;
import org.apache.cayenne.modeler.action.CreateEmbeddableAction;
import org.apache.cayenne.modeler.action.CreateNodeAction;
import org.apache.cayenne.modeler.action.CreateObjEntityAction;
import org.apache.cayenne.modeler.action.CreateProcedureAction;
import org.apache.cayenne.modeler.action.CreateQueryAction;
import org.apache.cayenne.modeler.action.CutAction;
import org.apache.cayenne.modeler.action.DbEntitySyncAction;
import org.apache.cayenne.modeler.action.DocumentationAction;
import org.apache.cayenne.modeler.action.ExitAction;
import org.apache.cayenne.modeler.action.FindAction;
import org.apache.cayenne.modeler.action.GenerateCodeAction;
import org.apache.cayenne.modeler.action.GenerateDBAction;
import org.apache.cayenne.modeler.action.ImportDataMapAction;
import org.apache.cayenne.modeler.action.ImportEOModelAction;
import org.apache.cayenne.modeler.action.InferRelationshipsAction;
import org.apache.cayenne.modeler.action.MigrateAction;
import org.apache.cayenne.modeler.action.NavigateBackwardAction;
import org.apache.cayenne.modeler.action.NavigateForwardAction;
import org.apache.cayenne.modeler.action.NewProjectAction;
import org.apache.cayenne.modeler.action.ObjEntitySyncAction;
import org.apache.cayenne.modeler.action.OpenProjectAction;
import org.apache.cayenne.modeler.action.PasteAction;
import org.apache.cayenne.modeler.action.ProjectAction;
import org.apache.cayenne.modeler.action.RedoAction;
import org.apache.cayenne.modeler.action.RemoveAction;
import org.apache.cayenne.modeler.action.RevertAction;
import org.apache.cayenne.modeler.action.SaveAction;
import org.apache.cayenne.modeler.action.SaveAsAction;
import org.apache.cayenne.modeler.action.ShowLogConsoleAction;
import org.apache.cayenne.modeler.action.UndoAction;
import org.apache.cayenne.modeler.action.ValidateAction;
import org.apache.cayenne.modeler.action.dbimport.ReverseEngineeringToolMenuAction;
import org.apache.cayenne.modeler.dialog.LogConsole;
import org.apache.cayenne.modeler.dialog.welcome.WelcomeScreen;
import org.apache.cayenne.modeler.editor.EditorView;
import org.apache.cayenne.modeler.event.DataMapDisplayEvent;
import org.apache.cayenne.modeler.event.DataMapDisplayListener;
import org.apache.cayenne.modeler.event.DataNodeDisplayEvent;
import org.apache.cayenne.modeler.event.DataNodeDisplayListener;
import org.apache.cayenne.modeler.event.DbEntityDisplayListener;
import org.apache.cayenne.modeler.event.EmbeddableDisplayEvent;
import org.apache.cayenne.modeler.event.EmbeddableDisplayListener;
import org.apache.cayenne.modeler.event.EntityDisplayEvent;
import org.apache.cayenne.modeler.event.MultipleObjectsDisplayEvent;
import org.apache.cayenne.modeler.event.MultipleObjectsDisplayListener;
import org.apache.cayenne.modeler.event.ObjEntityDisplayListener;
import org.apache.cayenne.modeler.event.ProcedureDisplayEvent;
import org.apache.cayenne.modeler.event.ProcedureDisplayListener;
import org.apache.cayenne.modeler.event.QueryDisplayEvent;
import org.apache.cayenne.modeler.event.QueryDisplayListener;
import org.apache.cayenne.modeler.event.RecentFileListListener;
import org.apache.cayenne.modeler.pref.ComponentGeometry;
import org.apache.cayenne.modeler.util.ModelerUtil;
import org.apache.cayenne.modeler.util.RecentFileMenu;
import org.apache.cayenne.swing.components.MainToolBar;
import org.apache.cayenne.swing.components.TopBorder;
import org.slf4j.LoggerFactory;

import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.JTextField;
import javax.swing.JToolBar;
import java.awt.AWTEvent;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Toolkit;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.List;
import java.util.Vector;

/**
 * Main frame of CayenneModeler. Responsibilities include coordination of
 * enabling/disabling of menu and toolbar.
 */
public class CayenneModelerFrame extends JFrame implements DataNodeDisplayListener,
        DataMapDisplayListener, ObjEntityDisplayListener, DbEntityDisplayListener,
        QueryDisplayListener, ProcedureDisplayListener, MultipleObjectsDisplayListener,
        EmbeddableDisplayListener {

    protected EditorView view;
    protected RecentFileMenu recentFileMenu;
    protected ActionManager actionManager;
    protected JLabel status;

    /**
     * Menu which shows/hides log console
     */
    protected JCheckBoxMenuItem logMenu;

    /**
     * Split panel, where main project editor and external component, like log console,
     * are located
     */
    protected JSplitPane splitPane;

    /**
     * Component, plugged into this frame
     */
    protected Component dockComponent;

    /**
     * Listeners for changes in recent file menu
     */
    protected List recentFileListeners;

    /**
     * Welcome screen, shown when no project is open
     */
    protected WelcomeScreen welcomeScreen;

    public CayenneModelerFrame(ActionManager actionManager) {
        this.actionManager = actionManager;

        recentFileListeners = new Vector<>();

        setIconImage(ModelerUtil.buildIcon("CayenneModeler.png").getImage());
        initMenus();
        initToolbar();
        initStatusBar();
        initWelcome();

        fireRecentFileListChanged(); // start filling list in welcome screen and in menu

        setView(null);
    }

    /**
     * Returns an action object associated with the key.
     */
    private  T getAction(Class type) {
        return actionManager.getAction(type);
    }

    protected void initMenus() {
        getContentPane().setLayout(new BorderLayout());

        JMenu fileMenu = new JMenu("File");
        JMenu editMenu = new JMenu("Edit");
        JMenu projectMenu = new JMenu("Project");
        JMenu toolMenu = new JMenu("Tools");
        JMenu helpMenu = new JMenu("Help");

        fileMenu.setMnemonic(KeyEvent.VK_F);
        editMenu.setMnemonic(KeyEvent.VK_E);
        projectMenu.setMnemonic(KeyEvent.VK_P);
        toolMenu.setMnemonic(KeyEvent.VK_T);
        helpMenu.setMnemonic(KeyEvent.VK_H);

        fileMenu.add(getAction(NewProjectAction.class).buildMenu());
        fileMenu.add(getAction(OpenProjectAction.class).buildMenu());
        fileMenu.add(getAction(ProjectAction.class).buildMenu());
        fileMenu.add(getAction(ImportDataMapAction.class).buildMenu());
        fileMenu.addSeparator();
        fileMenu.add(getAction(SaveAction.class).buildMenu());
        fileMenu.add(getAction(SaveAsAction.class).buildMenu());
        fileMenu.add(getAction(RevertAction.class).buildMenu());
        fileMenu.addSeparator();

        editMenu.add(getAction(UndoAction.class).buildMenu());
        editMenu.add(getAction(RedoAction.class).buildMenu());
        editMenu.add(getAction(CutAction.class).buildMenu());
        editMenu.add(getAction(CopyAction.class).buildMenu());
        editMenu.add(getAction(PasteAction.class).buildMenu());

        recentFileMenu = new RecentFileMenu("Recent Projects");
        addRecentFileListListener(recentFileMenu);
        fileMenu.add(recentFileMenu);

        fileMenu.addSeparator();
        fileMenu.add(getAction(ExitAction.class).buildMenu());

        projectMenu.add(getAction(ValidateAction.class).buildMenu());
        projectMenu.addSeparator();
        projectMenu.add(getAction(CreateNodeAction.class).buildMenu());
        projectMenu.add(getAction(CreateDataMapAction.class).buildMenu());

        projectMenu.add(getAction(CreateObjEntityAction.class).buildMenu());
        projectMenu.add(getAction(CreateEmbeddableAction.class).buildMenu());
        projectMenu.add(getAction(CreateDbEntityAction.class).buildMenu());

        projectMenu.add(getAction(CreateProcedureAction.class).buildMenu());
        projectMenu.add(getAction(CreateQueryAction.class).buildMenu());

        projectMenu.addSeparator();
        projectMenu.add(getAction(ObjEntitySyncAction.class).buildMenu());
        projectMenu.add(getAction(DbEntitySyncAction.class).buildMenu());
        projectMenu.addSeparator();
        projectMenu.add(getAction(RemoveAction.class).buildMenu());

        toolMenu.add(getAction(ReverseEngineeringToolMenuAction.class).buildMenu());
        toolMenu.add(getAction(InferRelationshipsAction.class).buildMenu());
        toolMenu.add(getAction(ImportEOModelAction.class).buildMenu());
        toolMenu.addSeparator();
        toolMenu.add(getAction(GenerateCodeAction.class).buildMenu());
        toolMenu.add(getAction(GenerateDBAction.class).buildMenu());
        toolMenu.add(getAction(MigrateAction.class).buildMenu());

        // Menu for opening Log console
        toolMenu.addSeparator();

        logMenu = getAction(ShowLogConsoleAction.class).buildCheckBoxMenu();

        if (!LogConsole.getInstance().getConsoleProperty(LogConsole.DOCKED_PROPERTY)
                && LogConsole.getInstance().getConsoleProperty(LogConsole.SHOW_CONSOLE_PROPERTY)) {
            LogConsole.getInstance().setConsoleProperty(LogConsole.SHOW_CONSOLE_PROPERTY, false);
        }

        updateLogConsoleMenu();
        toolMenu.add(logMenu);

        toolMenu.addSeparator();
        toolMenu.add(getAction(ConfigurePreferencesAction.class).buildMenu());

        helpMenu.add(getAction(AboutAction.class).buildMenu());
        helpMenu.add(getAction(DocumentationAction.class).buildMenu());

        JMenuBar menuBar = new JMenuBar();

        menuBar.add(fileMenu);
        menuBar.add(editMenu);
        menuBar.add(projectMenu);
        menuBar.add(toolMenu);
        menuBar.add(helpMenu);

        setJMenuBar(menuBar);
    }

    /**
     * Selects/deselects menu item, depending on status of log console
     */
    public void updateLogConsoleMenu() {
        logMenu.setSelected(LogConsole.getInstance().getConsoleProperty(LogConsole.SHOW_CONSOLE_PROPERTY));
    }

    protected void initStatusBar() {
        status = new JLabel();
        status.setFont(status.getFont().deriveFont(Font.PLAIN, 10));

        splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
        splitPane.setBorder(TopBorder.create());
        splitPane.getInsets().left = 5;
        splitPane.getInsets().right = 5;
        splitPane.setResizeWeight(0.7);

        //  Moving this to try-catch block per CAY-940. Exception will be stack-traced
        try {
            ComponentGeometry geometry = new ComponentGeometry(this.getClass(), "splitPane/divider");
            geometry.bindIntProperty(splitPane, JSplitPane.DIVIDER_LOCATION_PROPERTY, 400);
        } catch (Exception ex) {
            LoggerFactory.getLogger(getClass()).error("Cannot bind divider property", ex);
        }

        JPanel statusBar = new JPanel(new FlowLayout(FlowLayout.LEFT, 3, 1));
        statusBar.setBorder(TopBorder.create());
        // add placeholder
        statusBar.add(Box.createVerticalStrut(16));
        statusBar.add(status);

        if(getContentPane() instanceof JPanel) {
            ((JPanel) getContentPane()).setBorder(BorderFactory.createEmptyBorder());
        }
        getContentPane().add(splitPane, BorderLayout.CENTER);
        getContentPane().add(statusBar, BorderLayout.SOUTH);
    }

    /**
     * Initializes welcome screen
     */
    protected void initWelcome() {
        welcomeScreen = new WelcomeScreen();
        addRecentFileListListener(welcomeScreen);
    }

    /**
     * Plugs a component in the frame, between main area and status bar
     */
    public void setDockComponent(Component c) {
        if (dockComponent == c) {
            return;
        }

        if (dockComponent != null) {
            splitPane.setBottomComponent(null);
        }

        dockComponent = c;

        if (dockComponent != null) {
            splitPane.setBottomComponent(dockComponent);
        }

        splitPane.validate();
    }

    /**
     * @return Dock component
     */
    public Component getDockComponent() {
        return dockComponent;
    }

    /** Initializes main toolbar. */
    protected void initToolbar() {

        final JToolBar toolBar = new MainToolBar();

        Dimension smallBtnDim = new Dimension(30, 30);
        JButton backButton = getAction(NavigateBackwardAction.class).buildButton(1);
        backButton.setMinimumSize(smallBtnDim);
        backButton.setPreferredSize(smallBtnDim);
        toolBar.add(backButton);

        JButton forwardButton = getAction(NavigateForwardAction.class).buildButton(3);
        forwardButton.setMinimumSize(smallBtnDim);
        forwardButton.setPreferredSize(smallBtnDim);
        toolBar.add(forwardButton);

        toolBar.addSeparator(new Dimension(30, 0));

        toolBar.add(getAction(NewProjectAction.class).buildButton(1));
        toolBar.add(getAction(OpenProjectAction.class).buildButton(2));
        toolBar.add(getAction(SaveAction.class).buildButton(3));

        toolBar.addSeparator();

        JButton removeButton = getAction(RemoveAction.class).buildButton();
        toolBar.add(removeButton);

        toolBar.addSeparator();

        toolBar.add(getAction(CutAction.class).buildButton(1));
        toolBar.add(getAction(CopyAction.class).buildButton(2));
        toolBar.add(getAction(PasteAction.class).buildButton(3));

        toolBar.addSeparator();

        toolBar.add(getAction(UndoAction.class).buildButton(1));
        toolBar.add(getAction(RedoAction.class).buildButton(3));

        toolBar.addSeparator();

        toolBar.add(getAction(CreateNodeAction.class).buildButton(1));
        toolBar.add(getAction(CreateDataMapAction.class).buildButton(3));

        toolBar.addSeparator();

        toolBar.add(getAction(CreateDbEntityAction.class).buildButton(1));
        toolBar.add(getAction(CreateProcedureAction.class).buildButton(3));

        toolBar.addSeparator();

        toolBar.add(getAction(CreateObjEntityAction.class).buildButton(1));
        toolBar.add(getAction(CreateEmbeddableAction.class).buildButton(2));
        toolBar.add(getAction(CreateQueryAction.class).buildButton(3));

        // is used to place search feature components the most right on a toolbar
        toolBar.add(new SearchPanel());

        getContentPane().add(toolBar, BorderLayout.NORTH);

        // Hide some buttons when frame is too small
        final int defaultBtnWidth = removeButton.getUI().getPreferredSize(backButton).width;
        addComponentListener(new ComponentAdapter() {
            private final int[] empty = {};
            private final int[] all = {6, 7, 8, 9, 10, 11, 12, 13, 14};
            private final int[] remove = {6, 7};
            private final int[] removeAndCopy = {6, 7, 8, 9, 10, 11};
            private final int[] undo = {12, 13, 14};
            private final int[] undoAndCopy = {8, 9, 10, 11, 12, 13, 14};

            @Override
            public void componentResized(ComponentEvent e) {
                int[] hidden, shown;
                if(getSize().width < (13 * defaultBtnWidth + 300)) {
                    hidden = all;
                    shown = empty;
                } else if(getSize().width < (16 * defaultBtnWidth + 300)) {
                    hidden = removeAndCopy;
                    shown = undo;
                } else if(getSize().width < (18 * defaultBtnWidth + 300)) {
                    hidden = remove;
                    shown = undoAndCopy;
                } else {
                    hidden = empty;
                    shown = all;
                }

                for(int i : hidden) {
                    toolBar.getComponentAtIndex(i).setVisible(false);
                }
                for(int i : shown) {
                    toolBar.getComponentAtIndex(i).setVisible(true);
                }
            }
        });
    }

    public void currentDataNodeChanged(DataNodeDisplayEvent e) {
        actionManager.dataNodeSelected();
    }

    public void currentDataMapChanged(DataMapDisplayEvent e) {
        actionManager.dataMapSelected();
    }

    public void currentObjEntityChanged(EntityDisplayEvent e) {
        actionManager.objEntitySelected();
    }

    public void currentDbEntityChanged(EntityDisplayEvent e) {
        actionManager.dbEntitySelected();
    }

    public void currentQueryChanged(QueryDisplayEvent e) {
        actionManager.querySelected();
    }

    public void currentProcedureChanged(ProcedureDisplayEvent e) {
        actionManager.procedureSelected();
    }

    public void currentObjectsChanged(MultipleObjectsDisplayEvent e, Application application) {
        actionManager.multipleObjectsSelected(e.getNodes(), application);
    }

    public void currentEmbeddableChanged(EmbeddableDisplayEvent e) {
        actionManager.embeddableSelected();
    }

    /**
     * Returns the right side view panel.
     * 
     * @return EditorView
     */
    public EditorView getView() {
        return view;
    }

    public JLabel getStatus() {
        return status;
    }

    /**
     * Returns the recentFileMenu.
     * 
     * @return RecentFileMenu
     */
    public RecentFileMenu getRecentFileMenu() {
        return recentFileMenu;
    }

    /**
     * Adds editor view to the frame.
     */
    public void setView(EditorView view) {
        int oldLocation = splitPane.getDividerLocation();

        this.view = view;

        if (view != null) {
            splitPane.setTopComponent(view);
        } else {
            splitPane.setTopComponent(welcomeScreen);
        }

        validate();
        splitPane.setDividerLocation(oldLocation);
    }

    /**
     * Adds listener for recent menu changes
     */
    public void addRecentFileListListener(RecentFileListListener listener) {
        recentFileListeners.add(listener);
    }

    /**
     * Notifies all listeners that recent file list has changed
     */
    public void fireRecentFileListChanged() {
        for (RecentFileListListener recentFileListener : recentFileListeners) {
            recentFileListener.recentFileListChanged();
        }
    }

    public class SearchPanel extends JPanel {

        private JLabel searchLabel = new JLabel("Search: ");
        private JPanel box = new JPanel();
        private JTextField findField;

        SearchPanel() {
            super(new BorderLayout());
            initView();
        }

        void initView() {
            findField = new JTextField(10);
            findField.putClientProperty("JTextField.variant", "search");
            findField.setMaximumSize(new Dimension(100, 22));
            findField.setPreferredSize(new Dimension(100, 22));
            findField.addKeyListener(new KeyListener() {
                public void keyPressed(KeyEvent e) {
                    if (e.getKeyCode() != KeyEvent.VK_ENTER) {
                        findField.setBackground(Color.white);
                    }
                }

                public void keyReleased(KeyEvent e) {
                }

                public void keyTyped(KeyEvent e) {
                }
            });
            findField.setAction(getAction(FindAction.class));

            Toolkit.getDefaultToolkit().addAWTEventListener(event -> {
                if (event instanceof KeyEvent) {
                    if (((KeyEvent) event).getModifiers() == Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()
                            && ((KeyEvent) event).getKeyCode() == KeyEvent.VK_F) {
                        findField.requestFocus();
                    }
                }
            }, AWTEvent.KEY_EVENT_MASK);

            searchLabel.setLabelFor(findField);
            // is used to place label and text field one after another
            box.setLayout(new BoxLayout(box, BoxLayout.X_AXIS));
            box.add(searchLabel);
            box.add(findField);

            add(box, BorderLayout.EAST);
        }

        public void hideSearchLabel() {
            searchLabel.setVisible(false);
            findField.setMaximumSize(null);
            findField.setPreferredSize(new Dimension(100, 40));
            findField.setToolTipText("Search");
            box.setOpaque(false);
            box.setBackground(null);
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy