You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by nt...@apache.org on 2018/03/05 07:47:32 UTC

[1/4] cayenne git commit: CAY-2407

Repository: cayenne
Updated Branches:
  refs/heads/master fd0d06ec9 -> 7758dbf42


CAY-2407


Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/8b48c7c6
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/8b48c7c6
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/8b48c7c6

Branch: refs/heads/master
Commit: 8b48c7c6f327e22877a8ddf9b547dea6179fba8f
Parents: 1525bc7
Author: Arseni Bulatski <an...@gmail.com>
Authored: Mon Feb 19 10:48:28 2018 +0300
Committer: Arseni Bulatski <an...@gmail.com>
Committed: Mon Feb 19 10:48:28 2018 +0300

----------------------------------------------------------------------
 .../cayenne/map/SQLTemplateDescriptor.java      |  41 +++-
 .../modeler/editor/SQLTemplateMainTab.java      | 116 ++++++++-
 .../modeler/editor/SQLTemplateOrderingTab.java  | 237 +++++++++++++++++++
 .../modeler/editor/SQLTemplatePrefetchTab.java  | 236 ++++++++++++++++++
 .../modeler/editor/SQLTemplateTabbedView.java   |   7 +
 .../AddPrefetchUndoableEditForSqlTemplate.java  |  35 +++
 6 files changed, 666 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/8b48c7c6/cayenne-server/src/main/java/org/apache/cayenne/map/SQLTemplateDescriptor.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/map/SQLTemplateDescriptor.java b/cayenne-server/src/main/java/org/apache/cayenne/map/SQLTemplateDescriptor.java
index e1c3afe..7e449ca 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/map/SQLTemplateDescriptor.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/map/SQLTemplateDescriptor.java
@@ -22,9 +22,7 @@ import org.apache.cayenne.configuration.ConfigurationNodeVisitor;
 import org.apache.cayenne.query.SQLTemplate;
 import org.apache.cayenne.util.XMLEncoder;
 
-import java.util.HashMap;
-import java.util.Map;
-import java.util.TreeSet;
+import java.util.*;
 
 /**
  * @since 4.0
@@ -32,6 +30,7 @@ import java.util.TreeSet;
 public class SQLTemplateDescriptor extends QueryDescriptor {
 
     protected String sql;
+    protected List<String> prefetches = new ArrayList<>();
 
     protected Map<String, String> adapterSql = new HashMap<>();
 
@@ -67,6 +66,34 @@ public class SQLTemplateDescriptor extends QueryDescriptor {
         this.adapterSql = adapterSql;
     }
 
+    /**
+     * Returns list of prefetch paths for this query.
+     */
+    public List<String> getPrefetches() {
+        return prefetches;
+    }
+
+    /**
+     * Sets list of prefetch paths for this query.
+     */
+    public void setPrefetches(List<String> prefetches) {
+        this.prefetches = prefetches;
+    }
+
+    /**
+     * Adds single prefetch path to this query.
+     */
+    public void addPrefetch(String prefetchPath) {
+        this.prefetches.add(prefetchPath);
+    }
+
+    /**
+     * Removes single prefetch path from this query.
+     */
+    public void removePrefetch(String prefetchPath) {
+        this.prefetches.remove(prefetchPath);
+    }
+
     @Override
     public SQLTemplate buildQuery() {
         SQLTemplate template = new SQLTemplate();
@@ -77,6 +104,14 @@ public class SQLTemplateDescriptor extends QueryDescriptor {
 
         template.initWithProperties(this.getProperties());
 
+        List<String> prefetches = this.getPrefetches();
+
+        if (prefetches != null && !prefetches.isEmpty()) {
+            for (String prefetch : prefetches) {
+                template.addPrefetch(prefetch);
+            }
+        }
+
         // init SQL
         template.setDefaultTemplate(this.getSql());
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8b48c7c6/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplateMainTab.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplateMainTab.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplateMainTab.java
index 387391c..78ef8d0 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplateMainTab.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplateMainTab.java
@@ -25,22 +25,35 @@ import com.jgoodies.forms.layout.FormLayout;
 import com.jgoodies.forms.layout.RowSpec;
 import org.apache.cayenne.configuration.event.QueryEvent;
 import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.map.Entity;
 import org.apache.cayenne.map.ObjEntity;
 import org.apache.cayenne.map.QueryDescriptor;
 import org.apache.cayenne.modeler.Application;
 import org.apache.cayenne.modeler.ProjectController;
+import org.apache.cayenne.modeler.util.CellRenderers;
+import org.apache.cayenne.modeler.util.Comparators;
 import org.apache.cayenne.modeler.util.ProjectUtil;
 import org.apache.cayenne.modeler.util.TextAdapter;
+import org.apache.cayenne.modeler.util.combo.AutoCompletion;
 import org.apache.cayenne.project.extension.info.ObjectInfo;
 import org.apache.cayenne.query.CapsStrategy;
 import org.apache.cayenne.query.SQLTemplate;
 import org.apache.cayenne.util.Util;
 import org.apache.cayenne.validation.ValidationException;
 
-import javax.swing.*;
-import java.awt.*;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.JComboBox;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import java.awt.BorderLayout;
+import java.awt.Component;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -69,12 +82,14 @@ public class SQLTemplateMainTab extends JPanel {
     protected ProjectController mediator;
     protected TextAdapter name;
     protected TextAdapter comment;
+    protected JComboBox<ObjEntity> queryRoot;
     protected SelectPropertiesPanel properties;
 
     public SQLTemplateMainTab(ProjectController mediator) {
         this.mediator = mediator;
 
         initView();
+        initController();
     }
 
     private void initView() {
@@ -93,13 +108,17 @@ public class SQLTemplateMainTab extends JPanel {
             }
         };
 
+        queryRoot = Application.getWidgetFactory().createComboBox();
+        AutoCompletion.enable(queryRoot);
+        queryRoot.setRenderer(CellRenderers.listRendererWithIcons());
+
         properties = new SQLTemplateQueryPropertiesPanel(mediator);
 
         // assemble
         CellConstraints cc = new CellConstraints();
         FormLayout layout = new FormLayout(
                 "right:max(80dlu;pref), 3dlu, fill:max(200dlu;pref)",
-                "p, 3dlu, p, 3dlu, p");
+                "p, 3dlu, p, 3dlu, p, 3dlu, p");
         PanelBuilder builder = new PanelBuilder(layout);
         builder.setDefaultDialogBorder();
 
@@ -108,12 +127,22 @@ public class SQLTemplateMainTab extends JPanel {
         builder.add(name.getComponent(), cc.xy(3, 3));
         builder.addLabel("Comment:", cc.xy(1, 5));
         builder.add(comment.getComponent(), cc.xy(3, 5));
+        builder.addLabel("Query Root:", cc.xy(1, 7));
+        builder.add(queryRoot, cc.xy(3, 7));
 
         this.setLayout(new BorderLayout());
         this.add(builder.getPanel(), BorderLayout.NORTH);
         this.add(properties, BorderLayout.CENTER);
     }
 
+    private void initController() {
+        RootSelectionHandler rootHandler = new RootSelectionHandler();
+
+        queryRoot.addActionListener(rootHandler);
+        queryRoot.addFocusListener(rootHandler);
+        queryRoot.getEditor().getEditorComponent().addFocusListener(rootHandler);
+    }
+
     /**
      * Updates the view from the current model state. Invoked when a currently displayed
      * query is changed.
@@ -130,6 +159,17 @@ public class SQLTemplateMainTab extends JPanel {
         properties.initFromModel(query);
         comment.setText(getQueryComment(query));
 
+        DataMap map = mediator.getCurrentDataMap();
+        ObjEntity[] roots = map.getObjEntities().toArray(new ObjEntity[0]);
+
+        if (roots.length > 1) {
+            Arrays.sort(roots, Comparators.getDataMapChildrenComparator());
+        }
+
+        DefaultComboBoxModel<ObjEntity> model = new DefaultComboBoxModel<>(roots);
+        model.setSelectedItem(query.getRoot());
+        queryRoot.setModel(model);
+
         setVisible(true);
     }
 
@@ -177,6 +217,76 @@ public class SQLTemplateMainTab extends JPanel {
     }
 
     /**
+     * Handler to user's actions with root selection combobox
+     */
+    class RootSelectionHandler implements FocusListener, ActionListener {
+        String newName = null;
+        boolean needChangeName;
+
+        public void actionPerformed(ActionEvent ae) {
+            QueryDescriptor query = getQuery();
+            if (query != null) {
+                Entity root = (Entity) queryRoot.getModel().getSelectedItem();
+
+                if (root != null) {
+                    query.setRoot(root);
+
+                    if (needChangeName) { //not changed by user
+                        /*
+                         * Doing auto name change, following CAY-888 #2
+                         */
+                        String newPrefix = root.getName() + "Query";
+                        newName = newPrefix;
+
+                        DataMap map = mediator.getCurrentDataMap();
+                        long postfix = 1;
+
+                        while (map.getQueryDescriptor(newName) != null) {
+                            newName = newPrefix + (postfix++);
+                        }
+
+                        name.setText(newName);
+                    }
+                }
+            }
+        }
+
+        public void focusGained(FocusEvent e) {
+            //reset new name tracking
+            newName = null;
+
+            QueryDescriptor query = getQuery();
+            if (query != null) {
+                needChangeName = hasDefaultName(query);
+            } else {
+                needChangeName = false;
+            }
+        }
+
+        public void focusLost(FocusEvent e) {
+            if (newName != null) {
+                setQueryName(newName);
+            }
+
+            newName = null;
+            needChangeName = false;
+        }
+
+        /**
+         * @return whether specified's query name is 'default' i.e. Cayenne generated
+         * A query's name is 'default' if it starts with 'UntitledQuery' or with root name.
+         *
+         * We cannot follow user input because tab might be opened many times
+         */
+        boolean hasDefaultName(QueryDescriptor query) {
+            String prefix = query.getRoot() == null ? "UntitledQuery" :
+                    CellRenderers.asString(query.getRoot()) + "Query";
+
+            return name.getComponent().getText().startsWith(prefix);
+        }
+    }
+
+    /**
      * Returns an entity that maps to a procedure query result class.
      */
     ObjEntity getEntity(QueryDescriptor query) {

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8b48c7c6/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplateOrderingTab.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplateOrderingTab.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplateOrderingTab.java
new file mode 100644
index 0000000..c21841d
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplateOrderingTab.java
@@ -0,0 +1,237 @@
+/*****************************************************************
+ *   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
+ *
+ *    http://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.editor;
+
+import org.apache.cayenne.configuration.event.QueryEvent;
+import org.apache.cayenne.map.Entity;
+import org.apache.cayenne.map.QueryDescriptor;
+import org.apache.cayenne.map.SQLTemplateDescriptor;
+import org.apache.cayenne.map.SelectQueryDescriptor;
+import org.apache.cayenne.modeler.Application;
+import org.apache.cayenne.modeler.ProjectController;
+import org.apache.cayenne.modeler.util.EntityTreeModel;
+import org.apache.cayenne.modeler.util.MultiColumnBrowser;
+import org.apache.cayenne.modeler.util.UIUtil;
+import org.apache.cayenne.query.Ordering;
+import org.apache.cayenne.query.SQLTemplate;
+import org.apache.cayenne.query.SortOrder;
+import org.apache.cayenne.swing.components.image.FilteredIconFactory;
+import org.apache.cayenne.util.CayenneMapEntry;
+
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.JTable;
+import javax.swing.ListSelectionModel;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.table.AbstractTableModel;
+import javax.swing.table.TableModel;
+import javax.swing.tree.TreeModel;
+import java.awt.BorderLayout;
+import java.awt.CardLayout;
+import java.awt.Dimension;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.prefs.Preferences;
+
+/**
+ * A panel for picking SQLTemplate orderings.
+ *
+ */
+public class SQLTemplateOrderingTab extends JPanel implements PropertyChangeListener {
+    // property for split pane divider size
+    private static final String SPLIT_DIVIDER_LOCATION_PROPERTY = "query.orderings.divider.location";
+
+    static final Dimension BROWSER_CELL_DIM = new Dimension(150, 100);
+    static final Dimension TABLE_DIM = new Dimension(460, 60);
+
+    static final String PATH_HEADER = "Path";
+    static final String ASCENDING_HEADER = "Ascending";
+    static final String IGNORE_CASE_HEADER = "Ignore Case";
+
+    static final String REAL_PANEL = "real";
+    static final String PLACEHOLDER_PANEL = "placeholder";
+
+    protected ProjectController mediator;
+    protected SQLTemplateDescriptor sqlTemplate;
+
+    protected MultiColumnBrowser browser;
+    protected JTable table;
+
+    protected CardLayout cardLayout;
+    protected JPanel messagePanel;
+
+    public SQLTemplateOrderingTab(ProjectController mediator) {
+        this.mediator = mediator;
+
+        initView();
+        initController();
+    }
+
+    protected void initView() {
+
+        messagePanel = new JPanel(new BorderLayout());
+        cardLayout = new CardLayout();
+
+        Preferences detail = Application.getInstance().getPreferencesNode(this.getClass(), "");
+
+        int defLocation = Application.getFrame().getHeight() / 2;
+        int location = detail != null ? detail.getInt(
+                getDividerLocationProperty(),
+                defLocation) : defLocation;
+
+        //As of CAY-888 #3 main pane is now a JSplitPane. Top component is a bit larger.
+        JSplitPane mainPanel = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
+        mainPanel.addPropertyChangeListener(JSplitPane.DIVIDER_LOCATION_PROPERTY, this);
+        mainPanel.setDividerLocation(location);
+
+        mainPanel.setTopComponent(createEditorPanel());
+        mainPanel.setBottomComponent(createSelectorPanel());
+
+        setLayout(cardLayout);
+        add(mainPanel, REAL_PANEL);
+        add(messagePanel, PLACEHOLDER_PANEL);
+    }
+
+    protected void initController() {
+
+        // scroll to selected row whenever a selection even occurs
+        table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
+
+            public void valueChanged(ListSelectionEvent e) {
+                if (!e.getValueIsAdjusting()) {
+                    UIUtil.scrollToSelectedRow(table);
+                }
+            }
+        });
+    }
+
+    protected void initFromModel() {
+        QueryDescriptor query = mediator.getCurrentQuery();
+
+        if (query == null || !QueryDescriptor.SQL_TEMPLATE.equals(query.getType())) {
+            processInvalidModel("Unknown query.");
+            return;
+        }
+
+        if (!(query.getRoot() instanceof Entity)) {
+            processInvalidModel("SQLTemplate has no root set.");
+            return;
+        }
+
+        this.sqlTemplate = (SQLTemplateDescriptor) query;
+        browser.setModel(createBrowserModel((Entity) sqlTemplate.getRoot()));
+
+        // init column sizes
+       // table.getColumnModel().getColumn(0).setPreferredWidth(250);
+
+        cardLayout.show(this, REAL_PANEL);
+    }
+
+    protected void processInvalidModel(String message) {
+        JLabel messageLabel = new JLabel(message, JLabel.CENTER);
+
+        messagePanel.removeAll();
+        messagePanel.add(messageLabel, BorderLayout.CENTER);
+        cardLayout.show(this, PLACEHOLDER_PANEL);
+    }
+
+    protected JPanel createEditorPanel() {
+
+        table = new JTable();
+        table.setRowHeight(25);
+        table.setRowMargin(3);
+        table.setPreferredScrollableViewportSize(TABLE_DIM);
+        table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+
+        JPanel panel = new JPanel(new BorderLayout());
+        panel.add(new JScrollPane(table), BorderLayout.CENTER);
+
+        return panel;
+    }
+
+    protected JPanel createSelectorPanel() {
+        browser = new MultiColumnBrowser();
+        browser.setPreferredColumnSize(BROWSER_CELL_DIM);
+        browser.setDefaultRenderer();
+
+        JPanel panel = new JPanel(new BorderLayout());
+        panel.add(new JScrollPane(
+                browser,
+                JScrollPane.VERTICAL_SCROLLBAR_NEVER,
+                JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED), BorderLayout.CENTER);
+
+        // setting minimal size, otherwise scrolling looks awful, because of
+        // VERTICAL_SCROLLBAR_NEVER strategy
+        panel.setMinimumSize(panel.getPreferredSize());
+
+        return panel;
+    }
+
+    protected TreeModel createBrowserModel(Entity entity) {
+        return new EntityTreeModel(entity);
+    }
+
+    protected String getSelectedPath() {
+        Object[] path = browser.getSelectionPath().getPath();
+
+        // first item in the path is Entity, so we must have
+        // at least two elements to constitute a valid ordering path
+        if (path.length < 2) {
+            return null;
+        }
+
+        StringBuilder buffer = new StringBuilder();
+
+        // attribute or relationships
+        CayenneMapEntry first = (CayenneMapEntry) path[1];
+        buffer.append(first.getName());
+
+        for (int i = 2; i < path.length; i++) {
+            CayenneMapEntry pathEntry = (CayenneMapEntry) path[i];
+            buffer.append(".").append(pathEntry.getName());
+        }
+
+        return buffer.toString();
+    }
+
+    /**
+     * Updates split pane divider location in properties
+     */
+    public void propertyChange(PropertyChangeEvent evt) {
+        if (JSplitPane.DIVIDER_LOCATION_PROPERTY.equals(evt.getPropertyName())) {
+            int value = (Integer) evt.getNewValue();
+
+            Preferences detail = Application.getInstance().getPreferencesNode(this.getClass(), "");
+            detail.putInt(getDividerLocationProperty(), value);
+        }
+    }
+
+    /**
+     * Returns name of a property for divider location.
+     */
+    protected String getDividerLocationProperty() {
+        return SPLIT_DIVIDER_LOCATION_PROPERTY;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8b48c7c6/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplatePrefetchTab.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplatePrefetchTab.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplatePrefetchTab.java
new file mode 100644
index 0000000..b9e7147
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplatePrefetchTab.java
@@ -0,0 +1,236 @@
+/*****************************************************************
+ *   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
+ *
+ *    http://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.editor;
+
+import org.apache.cayenne.configuration.event.QueryEvent;
+import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.ExpressionException;
+import org.apache.cayenne.exp.ExpressionFactory;
+import org.apache.cayenne.map.Attribute;
+import org.apache.cayenne.map.Entity;
+import org.apache.cayenne.map.Relationship;
+import org.apache.cayenne.modeler.Application;
+import org.apache.cayenne.modeler.ProjectController;
+import org.apache.cayenne.modeler.undo.AddPrefetchUndoableEdit;
+import org.apache.cayenne.modeler.undo.AddPrefetchUndoableEditForSqlTemplate;
+import org.apache.cayenne.modeler.util.CayenneAction;
+import org.apache.cayenne.modeler.util.EntityTreeFilter;
+import org.apache.cayenne.modeler.util.EntityTreeModel;
+import org.apache.cayenne.modeler.util.ModelerUtil;
+import org.apache.cayenne.swing.components.image.FilteredIconFactory;
+
+import javax.swing.BorderFactory;
+import javax.swing.Icon;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JToolBar;
+import javax.swing.table.AbstractTableModel;
+import javax.swing.table.TableModel;
+import javax.swing.tree.TreeModel;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+public class SQLTemplatePrefetchTab extends SQLTemplateOrderingTab{
+
+    public SQLTemplatePrefetchTab(ProjectController mediator) {
+        super(mediator);
+    }
+
+    protected JComponent createToolbar() {
+
+        JButton add = new CayenneAction.CayenneToolbarButton(null, 1);
+        add.setText("Add Prefetch");
+        Icon addIcon = ModelerUtil.buildIcon("icon-plus.png");
+        add.setIcon(addIcon);
+        add.setDisabledIcon(FilteredIconFactory.createDisabledIcon(addIcon));
+
+        add.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                String prefetch = getSelectedPath();
+
+                if (prefetch == null) {
+                    return;
+                }
+
+                addPrefetch(prefetch);
+
+                Application.getInstance().getUndoManager().addEdit(new AddPrefetchUndoableEditForSqlTemplate(prefetch, SQLTemplatePrefetchTab.this));
+            }
+
+        });
+
+        JButton remove = new CayenneAction.CayenneToolbarButton(null, 3);
+        remove.setText("Remove Prefetch");
+        Icon removeIcon = ModelerUtil.buildIcon("icon-trash.png");
+        remove.setIcon(removeIcon);
+        remove.setDisabledIcon(FilteredIconFactory.createDisabledIcon(removeIcon));
+
+        remove.addActionListener(new ActionListener() {
+
+            public void actionPerformed(ActionEvent e) {
+                int selection = table.getSelectedRow();
+
+                if (selection < 0) {
+                    return;
+                }
+
+                String prefetch = (String) table.getModel().getValueAt(selection, 0);
+
+                removePrefetch(prefetch);
+            }
+
+        });
+
+        JToolBar toolBar = new JToolBar();
+        toolBar.setBorder(BorderFactory.createEmptyBorder());
+        toolBar.setFloatable(false);
+        toolBar.add(add);
+        toolBar.add(remove);
+        return toolBar;
+    }
+
+    protected TreeModel createBrowserModel(Entity entity) {
+        EntityTreeModel treeModel = new EntityTreeModel(entity);
+        treeModel.setFilter(
+                new EntityTreeFilter() {
+                    public boolean attributeMatch(Object node, Attribute attr) {
+                        return false;
+                    }
+
+                    public boolean relationshipMatch(Object node, Relationship rel) {
+                        return true;
+                    }
+                });
+        return treeModel;
+    }
+
+    protected TableModel createTableModel() {
+        return new PrefetchModel();
+    }
+
+    public void addPrefetch(String prefetch) {
+
+        // check if such prefetch already exists
+        if (!sqlTemplate.getPrefetches().isEmpty() && sqlTemplate.getPrefetches().contains(prefetch)) {
+            return;
+        }
+
+        sqlTemplate.addPrefetch(prefetch);
+
+        // reset the model, since it is immutable
+        table.setModel(createTableModel());
+
+        mediator.fireQueryEvent(new QueryEvent(this, sqlTemplate));
+    }
+
+    public void removePrefetch(String prefetch) {
+        sqlTemplate.removePrefetch(prefetch);
+
+        // reset the model, since it is immutable
+        table.setModel(createTableModel());
+        mediator.fireQueryEvent(new QueryEvent(this, sqlTemplate));
+    }
+
+    boolean isToMany(String prefetch) {
+        if (sqlTemplate == null) {
+            return false;
+        }
+
+        Object root = sqlTemplate.getRoot();
+
+        // totally invalid path would result in ExpressionException
+        try {
+            Expression exp = ExpressionFactory.exp(prefetch);
+            Object object = exp.evaluate(root);
+            if (object instanceof Relationship) {
+                return ((Relationship) object).isToMany();
+            }
+            else {
+                return false;
+            }
+        }
+        catch (ExpressionException e) {
+            return false;
+        }
+    }
+
+    /**
+     * A table model for the Ordering editing table.
+     */
+    final class PrefetchModel extends AbstractTableModel {
+
+        String[] prefetches;
+
+        PrefetchModel() {
+            if (sqlTemplate != null) {
+                prefetches = new String[sqlTemplate.getPrefetches().size()];
+
+                for (int i = 0; i < prefetches.length; i++) {
+                    prefetches[i] = sqlTemplate.getPrefetches().get(i);
+                }
+            }
+        }
+
+        public int getColumnCount() {
+            return 2;
+        }
+
+        public int getRowCount() {
+            return (prefetches != null) ? prefetches.length : 0;
+        }
+
+        public Object getValueAt(int row, int column) {
+            switch (column) {
+                case 0:
+                    return prefetches[row];
+                case 1:
+                    return isToMany(prefetches[row]) ? Boolean.TRUE : Boolean.FALSE;
+                default:
+                    throw new IndexOutOfBoundsException("Invalid column: " + column);
+            }
+        }
+
+        public Class getColumnClass(int column) {
+            switch (column) {
+                case 0:
+                    return String.class;
+                case 1:
+                    return Boolean.class;
+                default:
+                    throw new IndexOutOfBoundsException("Invalid column: " + column);
+            }
+        }
+
+        public String getColumnName(int column) {
+            switch (column) {
+                case 0:
+                    return "Prefetch Path";
+                case 1:
+                    return "To Many";
+                default:
+                    throw new IndexOutOfBoundsException("Invalid column: " + column);
+            }
+        }
+
+        public boolean isCellEditable(int row, int column) {
+            return false;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8b48c7c6/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplateTabbedView.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplateTabbedView.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplateTabbedView.java
index 48c7bc7..2862c05 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplateTabbedView.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplateTabbedView.java
@@ -37,6 +37,7 @@ public class SQLTemplateTabbedView extends JTabbedPane {
     protected ProjectController mediator;
     protected SQLTemplateMainTab mainTab;
     protected SQLTemplateScriptsTab scriptsTab;
+    protected SQLTemplatePrefetchTab prefetchTab;
     protected int lastSelectionIndex;
 
     public SQLTemplateTabbedView(ProjectController mediator) {
@@ -54,6 +55,9 @@ public class SQLTemplateTabbedView extends JTabbedPane {
 
         this.scriptsTab = new SQLTemplateScriptsTab(mediator);
         addTab("SQL Scripts", scriptsTab);
+
+        this.prefetchTab = new SQLTemplatePrefetchTab(mediator);
+        addTab("Prefetches", prefetchTab);
     }
 
     private void initController() {
@@ -104,6 +108,9 @@ public class SQLTemplateTabbedView extends JTabbedPane {
             case 1:
                 scriptsTab.initFromModel();
                 break;
+            case 2:
+                prefetchTab.initFromModel();
+                break;
         }
     }
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/8b48c7c6/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/undo/AddPrefetchUndoableEditForSqlTemplate.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/undo/AddPrefetchUndoableEditForSqlTemplate.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/undo/AddPrefetchUndoableEditForSqlTemplate.java
new file mode 100644
index 0000000..4ab68ac
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/undo/AddPrefetchUndoableEditForSqlTemplate.java
@@ -0,0 +1,35 @@
+package org.apache.cayenne.modeler.undo;
+
+import org.apache.cayenne.modeler.editor.SQLTemplatePrefetchTab;
+import org.apache.cayenne.modeler.editor.SelectQueryPrefetchTab;
+
+import javax.swing.undo.AbstractUndoableEdit;
+import javax.swing.undo.CannotRedoException;
+import javax.swing.undo.CannotUndoException;
+
+public class AddPrefetchUndoableEditForSqlTemplate extends AbstractUndoableEdit {
+
+    private String prefetch;
+    private SQLTemplatePrefetchTab tab;
+
+    public AddPrefetchUndoableEditForSqlTemplate(String prefetch, SQLTemplatePrefetchTab tab) {
+        super();
+        this.prefetch = prefetch;
+        this.tab = tab;
+    }
+
+    @Override
+    public String getPresentationName() {
+        return "Add Prefetch";
+    }
+
+    @Override
+    public void redo() throws CannotRedoException {
+        tab.addPrefetch(prefetch);
+    }
+
+    @Override
+    public void undo() throws CannotUndoException {
+        tab.removePrefetch(prefetch);
+    }
+}


[4/4] cayenne git commit: Remove code duplication in SelectQuery and SQLTemplate tabs

Posted by nt...@apache.org.
Remove code duplication in SelectQuery and SQLTemplate tabs


Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/7758dbf4
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/7758dbf4
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/7758dbf4

Branch: refs/heads/master
Commit: 7758dbf420b1cb611d0710a26304d7d2c34227c7
Parents: f86af37
Author: stariy <st...@gmail.com>
Authored: Mon Mar 5 10:47:08 2018 +0300
Committer: stariy <st...@gmail.com>
Committed: Mon Mar 5 10:47:08 2018 +0300

----------------------------------------------------------------------
 .../modeler/editor/BaseQueryMainTab.java        |  90 ++++++++++
 .../modeler/editor/RootSelectionHandler.java    |  86 ++++++++++
 .../modeler/editor/SQLTemplateMainTab.java      | 169 ++-----------------
 .../modeler/editor/SelectQueryMainTab.java      | 140 +--------------
 4 files changed, 199 insertions(+), 286 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/7758dbf4/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/BaseQueryMainTab.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/BaseQueryMainTab.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/BaseQueryMainTab.java
new file mode 100644
index 0000000..a1d9033
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/BaseQueryMainTab.java
@@ -0,0 +1,90 @@
+package org.apache.cayenne.modeler.editor;
+
+import org.apache.cayenne.configuration.event.QueryEvent;
+import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.map.ObjEntity;
+import org.apache.cayenne.map.QueryDescriptor;
+import org.apache.cayenne.modeler.Application;
+import org.apache.cayenne.modeler.ProjectController;
+import org.apache.cayenne.modeler.util.CellRenderers;
+import org.apache.cayenne.modeler.util.ProjectUtil;
+import org.apache.cayenne.modeler.util.TextAdapter;
+import org.apache.cayenne.modeler.util.combo.AutoCompletion;
+import org.apache.cayenne.util.Util;
+import org.apache.cayenne.validation.ValidationException;
+
+import javax.swing.*;
+
+abstract class BaseQueryMainTab extends JPanel {
+    protected ProjectController mediator;
+    protected TextAdapter name;
+    protected JComboBox<ObjEntity> queryRoot;
+
+    BaseQueryMainTab(ProjectController mediator) {
+        this.mediator = mediator;
+    }
+
+    protected void initQueryRoot() {
+        queryRoot = Application.getWidgetFactory().createComboBox();
+        AutoCompletion.enable(queryRoot);
+        queryRoot.setRenderer(CellRenderers.listRendererWithIcons());
+
+        RootSelectionHandler rootHandler = new RootSelectionHandler(this);
+
+        queryRoot.addActionListener(rootHandler);
+        queryRoot.addFocusListener(rootHandler);
+        queryRoot.getEditor().getEditorComponent().addFocusListener(rootHandler);
+    }
+
+    public TextAdapter getNameField() {
+        return name;
+    }
+
+    public JComboBox<ObjEntity> getQueryRoot() {
+        return queryRoot;
+    }
+
+    public ProjectController getMediator() {
+        return mediator;
+    }
+
+    /**
+     * Initializes Query name from string.
+     */
+    void setQueryName(String newName) {
+        if (newName != null && newName.trim().length() == 0) {
+            newName = null;
+        }
+
+        QueryDescriptor query = getQuery();
+
+        if (query == null) {
+            return;
+        }
+
+        if (Util.nullSafeEquals(newName, query.getName())) {
+            return;
+        }
+
+        if (newName == null) {
+            throw new ValidationException("SelectQuery name is required.");
+        }
+
+        DataMap map = mediator.getCurrentDataMap();
+        QueryDescriptor matchingQuery = map.getQueryDescriptor(newName);
+
+        if (matchingQuery == null) {
+            // completely new name, set new name for entity
+            QueryEvent e = new QueryEvent(this, query, query.getName());
+            ProjectUtil.setQueryName(map, query, newName);
+            mediator.fireQueryEvent(e);
+        } else if (matchingQuery != query) {
+            // there is a query with the same name
+            throw new ValidationException("There is another query named '"
+                    + newName
+                    + "'. Use a different name.");
+        }
+    }
+
+    abstract QueryDescriptor getQuery();
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/7758dbf4/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/RootSelectionHandler.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/RootSelectionHandler.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/RootSelectionHandler.java
new file mode 100644
index 0000000..8bafed2
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/RootSelectionHandler.java
@@ -0,0 +1,86 @@
+package org.apache.cayenne.modeler.editor;
+
+import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.map.Entity;
+import org.apache.cayenne.map.QueryDescriptor;
+import org.apache.cayenne.modeler.util.CellRenderers;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+
+/**
+ * Handler to user's actions with root selection combobox
+ */
+class RootSelectionHandler implements FocusListener, ActionListener {
+    private String newName = null;
+    private boolean needChangeName;
+    private final BaseQueryMainTab queryTab;
+
+    RootSelectionHandler(BaseQueryMainTab queryTab) {
+        this.queryTab = queryTab;
+    }
+
+    public void actionPerformed(ActionEvent ae) {
+        QueryDescriptor query = queryTab.getQuery();
+        if (query != null) {
+            Entity root = (Entity) queryTab.getQueryRoot().getModel().getSelectedItem();
+
+            if (root != null) {
+                query.setRoot(root);
+
+                if (needChangeName) { //not changed by user
+                    /*
+                     * Doing auto name change, following CAY-888 #2
+                     */
+                    String newPrefix = root.getName() + "Query";
+                    newName = newPrefix;
+
+                    DataMap map = queryTab.getMediator().getCurrentDataMap();
+                    long postfix = 1;
+
+                    while (map.getQueryDescriptor(newName) != null) {
+                        newName = newPrefix + (postfix++);
+                    }
+
+                    queryTab.getNameField().setText(newName);
+                }
+            }
+        }
+    }
+
+    public void focusGained(FocusEvent e) {
+        //reset new name tracking
+        newName = null;
+
+        QueryDescriptor query = queryTab.getQuery();
+        if (query != null) {
+            needChangeName = hasDefaultName(query);
+        } else {
+            needChangeName = false;
+        }
+    }
+
+    public void focusLost(FocusEvent e) {
+        if (newName != null) {
+            queryTab.setQueryName(newName);
+        }
+
+        newName = null;
+        needChangeName = false;
+    }
+
+    /**
+     * @return whether specified's query name is 'default' i.e. Cayenne generated
+     * A query's name is 'default' if it starts with 'UntitledQuery' or with root name.
+     *
+     * We cannot follow user input because tab might be opened many times
+     */
+    boolean hasDefaultName(QueryDescriptor query) {
+        String prefix = query.getRoot() == null ? "UntitledQuery" :
+            CellRenderers.asString(query.getRoot()) + "Query";
+
+        return queryTab.getNameField().getComponent().getText().startsWith(prefix);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/7758dbf4/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplateMainTab.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplateMainTab.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplateMainTab.java
index 78ef8d0..cbfb99e 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplateMainTab.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplateMainTab.java
@@ -25,34 +25,23 @@ import com.jgoodies.forms.layout.FormLayout;
 import com.jgoodies.forms.layout.RowSpec;
 import org.apache.cayenne.configuration.event.QueryEvent;
 import org.apache.cayenne.map.DataMap;
-import org.apache.cayenne.map.Entity;
 import org.apache.cayenne.map.ObjEntity;
 import org.apache.cayenne.map.QueryDescriptor;
 import org.apache.cayenne.modeler.Application;
 import org.apache.cayenne.modeler.ProjectController;
-import org.apache.cayenne.modeler.util.CellRenderers;
 import org.apache.cayenne.modeler.util.Comparators;
-import org.apache.cayenne.modeler.util.ProjectUtil;
 import org.apache.cayenne.modeler.util.TextAdapter;
-import org.apache.cayenne.modeler.util.combo.AutoCompletion;
 import org.apache.cayenne.project.extension.info.ObjectInfo;
 import org.apache.cayenne.query.CapsStrategy;
 import org.apache.cayenne.query.SQLTemplate;
-import org.apache.cayenne.util.Util;
-import org.apache.cayenne.validation.ValidationException;
 
 import javax.swing.DefaultComboBoxModel;
 import javax.swing.DefaultListCellRenderer;
 import javax.swing.JComboBox;
 import javax.swing.JList;
-import javax.swing.JPanel;
 import javax.swing.JTextField;
 import java.awt.BorderLayout;
 import java.awt.Component;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.FocusEvent;
-import java.awt.event.FocusListener;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
@@ -61,7 +50,7 @@ import java.util.Map;
  * A main panel for editing a SQLTemplate.
  * 
  */
-public class SQLTemplateMainTab extends JPanel {
+public class SQLTemplateMainTab extends BaseQueryMainTab {
 
     private static final String DEFAULT_CAPS_LABEL = "Database Default";
     private static final String LOWER_CAPS_LABEL = "Force Lower Case";
@@ -79,17 +68,14 @@ public class SQLTemplateMainTab extends JPanel {
         labelCapsLabels.put(CapsStrategy.UPPER, UPPER_CAPS_LABEL);
     }
 
-    protected ProjectController mediator;
-    protected TextAdapter name;
     protected TextAdapter comment;
-    protected JComboBox<ObjEntity> queryRoot;
     protected SelectPropertiesPanel properties;
 
     public SQLTemplateMainTab(ProjectController mediator) {
-        this.mediator = mediator;
+        super(mediator);
 
+        initQueryRoot();
         initView();
-        initController();
     }
 
     private void initView() {
@@ -108,10 +94,6 @@ public class SQLTemplateMainTab extends JPanel {
             }
         };
 
-        queryRoot = Application.getWidgetFactory().createComboBox();
-        AutoCompletion.enable(queryRoot);
-        queryRoot.setRenderer(CellRenderers.listRendererWithIcons());
-
         properties = new SQLTemplateQueryPropertiesPanel(mediator);
 
         // assemble
@@ -135,14 +117,6 @@ public class SQLTemplateMainTab extends JPanel {
         this.add(properties, BorderLayout.CENTER);
     }
 
-    private void initController() {
-        RootSelectionHandler rootHandler = new RootSelectionHandler();
-
-        queryRoot.addActionListener(rootHandler);
-        queryRoot.addFocusListener(rootHandler);
-        queryRoot.getEditor().getEditorComponent().addFocusListener(rootHandler);
-    }
-
     /**
      * Updates the view from the current model state. Invoked when a currently displayed
      * query is changed.
@@ -173,120 +147,13 @@ public class SQLTemplateMainTab extends JPanel {
         setVisible(true);
     }
 
+    @Override
     protected QueryDescriptor getQuery() {
         QueryDescriptor query = mediator.getCurrentQuery();
         return (query != null && QueryDescriptor.SQL_TEMPLATE.equals(query.getType())) ? query : null;
     }
 
     /**
-     * Initializes Query name from string.
-     */
-    void setQueryName(String newName) {
-        if (newName != null && newName.trim().length() == 0) {
-            newName = null;
-        }
-
-        QueryDescriptor query = getQuery();
-
-        if (query == null) {
-            return;
-        }
-
-        if (Util.nullSafeEquals(newName, query.getName())) {
-            return;
-        }
-
-        if (newName == null) {
-            throw new ValidationException("Query name is required.");
-        }
-
-        DataMap map = mediator.getCurrentDataMap();
-
-        if (map.getQueryDescriptor(newName) == null) {
-            // completely new name, set new name for entity
-            QueryEvent e = new QueryEvent(this, query, query.getName());
-            ProjectUtil.setQueryName(map, query, newName);
-            mediator.fireQueryEvent(e);
-        }
-        else {
-            // there is a query with the same name
-            throw new ValidationException("There is another query named '"
-                    + newName
-                    + "'. Use a different name.");
-        }
-    }
-
-    /**
-     * Handler to user's actions with root selection combobox
-     */
-    class RootSelectionHandler implements FocusListener, ActionListener {
-        String newName = null;
-        boolean needChangeName;
-
-        public void actionPerformed(ActionEvent ae) {
-            QueryDescriptor query = getQuery();
-            if (query != null) {
-                Entity root = (Entity) queryRoot.getModel().getSelectedItem();
-
-                if (root != null) {
-                    query.setRoot(root);
-
-                    if (needChangeName) { //not changed by user
-                        /*
-                         * Doing auto name change, following CAY-888 #2
-                         */
-                        String newPrefix = root.getName() + "Query";
-                        newName = newPrefix;
-
-                        DataMap map = mediator.getCurrentDataMap();
-                        long postfix = 1;
-
-                        while (map.getQueryDescriptor(newName) != null) {
-                            newName = newPrefix + (postfix++);
-                        }
-
-                        name.setText(newName);
-                    }
-                }
-            }
-        }
-
-        public void focusGained(FocusEvent e) {
-            //reset new name tracking
-            newName = null;
-
-            QueryDescriptor query = getQuery();
-            if (query != null) {
-                needChangeName = hasDefaultName(query);
-            } else {
-                needChangeName = false;
-            }
-        }
-
-        public void focusLost(FocusEvent e) {
-            if (newName != null) {
-                setQueryName(newName);
-            }
-
-            newName = null;
-            needChangeName = false;
-        }
-
-        /**
-         * @return whether specified's query name is 'default' i.e. Cayenne generated
-         * A query's name is 'default' if it starts with 'UntitledQuery' or with root name.
-         *
-         * We cannot follow user input because tab might be opened many times
-         */
-        boolean hasDefaultName(QueryDescriptor query) {
-            String prefix = query.getRoot() == null ? "UntitledQuery" :
-                    CellRenderers.asString(query.getRoot()) + "Query";
-
-            return name.getComponent().getText().startsWith(prefix);
-        }
-    }
-
-    /**
      * Returns an entity that maps to a procedure query result class.
      */
     ObjEntity getEntity(QueryDescriptor query) {
@@ -319,7 +186,7 @@ public class SQLTemplateMainTab extends JPanel {
     }
 
     final class LabelCapsRenderer extends DefaultListCellRenderer {
-
+        @Override
         public Component getListCellRendererComponent(
                 JList list,
                 Object object,
@@ -333,22 +200,20 @@ public class SQLTemplateMainTab extends JPanel {
 
     final class SQLTemplateQueryPropertiesPanel extends RawQueryPropertiesPanel {
 
-        private JComboBox labelCase;
+        private JComboBox<CapsStrategy> labelCase;
 
         SQLTemplateQueryPropertiesPanel(ProjectController mediator) {
             super(mediator);
         }
 
+        @Override
         protected PanelBuilder createPanelBuilder() {
             labelCase = Application.getWidgetFactory().createUndoableComboBox();
             labelCase.setRenderer(new LabelCapsRenderer());
 
-            labelCase.addActionListener(new ActionListener() {
-
-                public void actionPerformed(ActionEvent event) {
-                    CapsStrategy value = (CapsStrategy) labelCase.getModel().getSelectedItem();
-                    setQueryProperty(SQLTemplate.COLUMN_NAME_CAPITALIZATION_PROPERTY, value.name());
-                }
+            labelCase.addActionListener(event -> {
+                CapsStrategy value = (CapsStrategy) labelCase.getModel().getSelectedItem();
+                setQueryProperty(SQLTemplate.COLUMN_NAME_CAPITALIZATION_PROPERTY, value.name());
             });
 
             PanelBuilder builder = super.createPanelBuilder();
@@ -365,25 +230,27 @@ public class SQLTemplateMainTab extends JPanel {
             return builder;
         }
 
+        @Override
         public void initFromModel(QueryDescriptor query) {
             super.initFromModel(query);
 
             if (query != null && QueryDescriptor.SQL_TEMPLATE.equals(query.getType())) {
-                DefaultComboBoxModel labelCaseModel = new DefaultComboBoxModel(
-                        LABEL_CAPITALIZATION);
-
+                DefaultComboBoxModel<CapsStrategy> labelCaseModel = new DefaultComboBoxModel<>(LABEL_CAPITALIZATION);
                 String columnNameCapitalization = query.getProperty(SQLTemplate.COLUMN_NAME_CAPITALIZATION_PROPERTY);
 
-                labelCaseModel.setSelectedItem(columnNameCapitalization != null ?
-                        CapsStrategy.valueOf(columnNameCapitalization) : CapsStrategy.DEFAULT);
+                labelCaseModel.setSelectedItem(columnNameCapitalization != null
+                        ? CapsStrategy.valueOf(columnNameCapitalization)
+                        : CapsStrategy.DEFAULT);
                 labelCase.setModel(labelCaseModel);
             }
         }
 
+        @Override
         protected void setEntity(ObjEntity entity) {
             SQLTemplateMainTab.this.setEntity(entity);
         }
 
+        @Override
         public ObjEntity getEntity(QueryDescriptor query) {
             if (query != null && QueryDescriptor.SQL_TEMPLATE.equals(query.getType())) {
                 return SQLTemplateMainTab.this.getEntity(query);
@@ -399,5 +266,5 @@ public class SQLTemplateMainTab extends JPanel {
                 setEntity(null);
             }
         }
-    };
+    }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/7758dbf4/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SelectQueryMainTab.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SelectQueryMainTab.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SelectQueryMainTab.java
index e68d17a..c0bc6d1 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SelectQueryMainTab.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SelectQueryMainTab.java
@@ -20,10 +20,6 @@
 package org.apache.cayenne.modeler.editor;
 
 import java.awt.BorderLayout;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.FocusEvent;
-import java.awt.event.FocusListener;
 import java.awt.event.ItemEvent;
 import java.awt.event.ItemListener;
 import java.util.Arrays;
@@ -31,8 +27,6 @@ import java.util.Iterator;
 
 import javax.swing.DefaultComboBoxModel;
 import javax.swing.JCheckBox;
-import javax.swing.JComboBox;
-import javax.swing.JPanel;
 import javax.swing.JTextField;
 
 import org.apache.cayenne.configuration.event.QueryEvent;
@@ -44,18 +38,14 @@ import org.apache.cayenne.map.Entity;
 import org.apache.cayenne.map.ObjEntity;
 import org.apache.cayenne.map.QueryDescriptor;
 import org.apache.cayenne.map.SelectQueryDescriptor;
-import org.apache.cayenne.modeler.Application;
+import org.apache.cayenne.query.SelectQuery;
 import org.apache.cayenne.swing.components.JCayenneCheckBox;
 import org.apache.cayenne.modeler.ProjectController;
-import org.apache.cayenne.modeler.util.CellRenderers;
 import org.apache.cayenne.modeler.util.Comparators;
 import org.apache.cayenne.modeler.util.ExpressionConvertor;
-import org.apache.cayenne.modeler.util.ProjectUtil;
 import org.apache.cayenne.modeler.util.TextAdapter;
 import org.apache.cayenne.modeler.util.ValidatorTextAdapter;
-import org.apache.cayenne.modeler.util.combo.AutoCompletion;
 import org.apache.cayenne.project.extension.info.ObjectInfo;
-import org.apache.cayenne.query.*;
 import org.apache.cayenne.util.CayenneMapEntry;
 import org.apache.cayenne.util.Util;
 import org.apache.cayenne.validation.ValidationException;
@@ -68,20 +58,17 @@ import com.jgoodies.forms.layout.FormLayout;
  * A tabbed pane that contains editors for various SelectQuery parts.
  * 
  */
-public class SelectQueryMainTab extends JPanel {
+public class SelectQueryMainTab extends BaseQueryMainTab {
 
-    protected ProjectController mediator;
-
-    protected TextAdapter name;
     protected TextAdapter comment;
-    protected JComboBox<ObjEntity> queryRoot;
     protected TextAdapter qualifier;
     protected JCheckBox distinct;
     protected ObjectQueryPropertiesPanel properties;
 
     public SelectQueryMainTab(ProjectController mediator) {
-        this.mediator = mediator;
+        super(mediator);
 
+        initQueryRoot();
         initView();
         initController();
     }
@@ -96,10 +83,6 @@ public class SelectQueryMainTab extends JPanel {
             }
         };
 
-        queryRoot = Application.getWidgetFactory().createComboBox();
-        AutoCompletion.enable(queryRoot);
-        queryRoot.setRenderer(CellRenderers.listRendererWithIcons());
-
         qualifier = new ValidatorTextAdapter(new JTextField()) {
 
             @Override
@@ -150,11 +133,6 @@ public class SelectQueryMainTab extends JPanel {
     }
 
     private void initController() {
-        RootSelectionHandler rootHandler = new RootSelectionHandler();
-
-        queryRoot.addActionListener(rootHandler);
-        queryRoot.addFocusListener(rootHandler);
-        queryRoot.getEditor().getEditorComponent().addFocusListener(rootHandler);
 
         distinct.addItemListener(new ItemListener() {
 
@@ -215,6 +193,7 @@ public class SelectQueryMainTab extends JPanel {
         setVisible(true);
     }
 
+    @Override
     protected SelectQueryDescriptor getQuery() {
         if(mediator.getCurrentQuery() == null) {
             return null;
@@ -277,45 +256,6 @@ public class SelectQueryMainTab extends JPanel {
     }
 
     /**
-     * Initializes Query name from string.
-     */
-    void setQueryName(String newName) {
-        if (newName != null && newName.trim().length() == 0) {
-            newName = null;
-        }
-
-        QueryDescriptor query = getQuery();
-
-        if (query == null) {
-            return;
-        }
-
-        if (Util.nullSafeEquals(newName, query.getName())) {
-            return;
-        }
-
-        if (newName == null) {
-            throw new ValidationException("SelectQuery name is required.");
-        }
-
-        DataMap map = mediator.getCurrentDataMap();
-        QueryDescriptor matchingQuery = map.getQueryDescriptor(newName);
-
-        if (matchingQuery == null) {
-            // completely new name, set new name for entity
-            QueryEvent e = new QueryEvent(this, query, query.getName());
-            ProjectUtil.setQueryName(map, query, newName);
-            mediator.fireQueryEvent(e);
-        }
-        else if (matchingQuery != query) {
-            // there is a query with the same name
-            throw new ValidationException("There is another query named '"
-                    + newName
-                    + "'. Use a different name.");
-        }
-    }
-
-    /**
      * Advanced checking of an expression, needed because Expression.fromString()
      * might terminate normally, but returned Expression will not be appliable
      * for real Entities.
@@ -351,76 +291,6 @@ public class SelectQueryMainTab extends JPanel {
             throw new ValidationException(eex.getUnlabeledMessage());
         }
     }
-    
-    /**
-     * Handler to user's actions with root selection combobox
-     */
-    class RootSelectionHandler implements FocusListener, ActionListener {
-        String newName = null;
-        boolean needChangeName;
-
-        public void actionPerformed(ActionEvent ae) {
-            QueryDescriptor query = getQuery();
-            if (query != null) {
-                Entity root = (Entity) queryRoot.getModel().getSelectedItem();
-
-                if (root != null) {
-                    query.setRoot(root);
-                    
-                    if (needChangeName) { //not changed by user
-                        /*
-                         * Doing auto name change, following CAY-888 #2
-                         */
-                        String newPrefix = root.getName() + "Query";
-                        newName = newPrefix;
-                        
-                        DataMap map = mediator.getCurrentDataMap();
-                        long postfix = 1;
-                        
-                        while (map.getQueryDescriptor(newName) != null) {
-                            newName = newPrefix + (postfix++);
-                        }
-                        
-                        name.setText(newName);
-                    }
-                }
-            }
-        }
-
-        public void focusGained(FocusEvent e) {
-            //reset new name tracking
-            newName = null;
-            
-            QueryDescriptor query = getQuery();
-            if (query != null) {
-                needChangeName = hasDefaultName(query);
-            } else {
-                needChangeName = false;
-            }
-        }
-
-        public void focusLost(FocusEvent e) {
-            if (newName != null) {
-                setQueryName(newName);
-            }
-            
-            newName = null;
-            needChangeName = false;
-        }
-
-        /**
-         * @return whether specified's query name is 'default' i.e. Cayenne generated
-         * A query's name is 'default' if it starts with 'UntitledQuery' or with root name.
-         * 
-         * We cannot follow user input because tab might be opened many times
-         */
-        boolean hasDefaultName(QueryDescriptor query) {
-            String prefix = query.getRoot() == null ? "UntitledQuery" :
-                CellRenderers.asString(query.getRoot()) + "Query";
-            
-            return name.getComponent().getText().startsWith(prefix);
-        }
-    }
 
     private void setQueryComment(String text) {
         QueryDescriptor query = getQuery();


[2/4] cayenne git commit: CAY-2407 add prefetch to sqlTemplate in Modeler

Posted by nt...@apache.org.
CAY-2407 add prefetch to sqlTemplate in Modeler


Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/193c6aa4
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/193c6aa4
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/193c6aa4

Branch: refs/heads/master
Commit: 193c6aa4f6221efc7ac9d436fca50e865d63c229
Parents: 8b48c7c
Author: Arseni Bulatski <an...@gmail.com>
Authored: Tue Feb 20 12:39:14 2018 +0300
Committer: Arseni Bulatski <an...@gmail.com>
Committed: Tue Feb 20 13:08:03 2018 +0300

----------------------------------------------------------------------
 RELEASE-NOTES.txt                               |   1 +
 .../cayenne/map/QueryDescriptorLoader.java      |   1 +
 .../cayenne/map/SQLTemplateDescriptor.java      |  24 +-
 .../org/apache/cayenne/query/SQLTemplate.java   |   1 +
 .../modeler/editor/SQLTemplateOrderingTab.java  | 237 -------------------
 .../modeler/editor/SQLTemplatePrefetchTab.java  | 193 ++++++++++++++-
 6 files changed, 213 insertions(+), 244 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/193c6aa4/RELEASE-NOTES.txt
----------------------------------------------------------------------
diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index bcbd440..cfd075a 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -23,6 +23,7 @@ CAY-2395 cdbimport: add option to create project file
 CAY-2396 Upgrade maven-assembly-plugin to 3.1.0
 CAY-2403 Extract eventbridges to top level
 CAY-2404 Move itests to maven-plugins
+CAY-2407 Modeler: add prefetch support for the SQLTemplate query
 
 Bug Fixes:
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/193c6aa4/cayenne-server/src/main/java/org/apache/cayenne/map/QueryDescriptorLoader.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/map/QueryDescriptorLoader.java b/cayenne-server/src/main/java/org/apache/cayenne/map/QueryDescriptorLoader.java
index d8370de..8b05207 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/map/QueryDescriptorLoader.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/map/QueryDescriptorLoader.java
@@ -75,6 +75,7 @@ public class QueryDescriptorLoader {
                 break;
             case QueryDescriptor.SQL_TEMPLATE:
                 ((SQLTemplateDescriptor) descriptor).setSql(sql);
+                ((SQLTemplateDescriptor) descriptor).setPrefetches(prefetches);
                 ((SQLTemplateDescriptor) descriptor).setAdapterSql(adapterSql);
                 break;
             case QueryDescriptor.EJBQL_QUERY:

http://git-wip-us.apache.org/repos/asf/cayenne/blob/193c6aa4/cayenne-server/src/main/java/org/apache/cayenne/map/SQLTemplateDescriptor.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/map/SQLTemplateDescriptor.java b/cayenne-server/src/main/java/org/apache/cayenne/map/SQLTemplateDescriptor.java
index 7e449ca..e3a0709 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/map/SQLTemplateDescriptor.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/map/SQLTemplateDescriptor.java
@@ -19,10 +19,15 @@
 package org.apache.cayenne.map;
 
 import org.apache.cayenne.configuration.ConfigurationNodeVisitor;
+import org.apache.cayenne.query.PrefetchTreeNode;
 import org.apache.cayenne.query.SQLTemplate;
 import org.apache.cayenne.util.XMLEncoder;
 
-import java.util.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeSet;
 
 /**
  * @since 4.0
@@ -102,16 +107,17 @@ public class SQLTemplateDescriptor extends QueryDescriptor {
             template.setRoot(root);
         }
 
-        template.initWithProperties(this.getProperties());
 
-        List<String> prefetches = this.getPrefetches();
 
+        List<String> prefetches = this.getPrefetches();
         if (prefetches != null && !prefetches.isEmpty()) {
             for (String prefetch : prefetches) {
-                template.addPrefetch(prefetch);
+                template.addPrefetch(PrefetchTreeNode.withPath(prefetch, PrefetchTreeNode.DISJOINT_BY_ID_PREFETCH_SEMANTICS));
             }
         }
 
+        template.initWithProperties(this.getProperties());
+
         // init SQL
         template.setDefaultTemplate(this.getSql());
 
@@ -188,6 +194,16 @@ public class SQLTemplateDescriptor extends QueryDescriptor {
             }
         }
 
+        PrefetchTreeNode prefetchTree = new PrefetchTreeNode();
+
+        for (String prefetchPath : prefetches) {
+            PrefetchTreeNode node = prefetchTree.addPath(prefetchPath);
+            node.setSemantics(PrefetchTreeNode.DISJOINT_BY_ID_PREFETCH_SEMANTICS);
+            node.setPhantom(false);
+        }
+
+        encoder.nested(prefetchTree, delegate);
+
         delegate.visitQuery(this);
         encoder.end();
     }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/193c6aa4/cayenne-server/src/main/java/org/apache/cayenne/query/SQLTemplate.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/query/SQLTemplate.java b/cayenne-server/src/main/java/org/apache/cayenne/query/SQLTemplate.java
index eed51c1..3a5230f 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/query/SQLTemplate.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/query/SQLTemplate.java
@@ -491,6 +491,7 @@ public class SQLTemplate extends AbstractQuery implements ParameterizedQuery {
 		return metaData.getPrefetchTree();
 	}
 
+
 	/**
 	 * Adds a prefetch.
 	 * 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/193c6aa4/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplateOrderingTab.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplateOrderingTab.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplateOrderingTab.java
deleted file mode 100644
index c21841d..0000000
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplateOrderingTab.java
+++ /dev/null
@@ -1,237 +0,0 @@
-/*****************************************************************
- *   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
- *
- *    http://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.editor;
-
-import org.apache.cayenne.configuration.event.QueryEvent;
-import org.apache.cayenne.map.Entity;
-import org.apache.cayenne.map.QueryDescriptor;
-import org.apache.cayenne.map.SQLTemplateDescriptor;
-import org.apache.cayenne.map.SelectQueryDescriptor;
-import org.apache.cayenne.modeler.Application;
-import org.apache.cayenne.modeler.ProjectController;
-import org.apache.cayenne.modeler.util.EntityTreeModel;
-import org.apache.cayenne.modeler.util.MultiColumnBrowser;
-import org.apache.cayenne.modeler.util.UIUtil;
-import org.apache.cayenne.query.Ordering;
-import org.apache.cayenne.query.SQLTemplate;
-import org.apache.cayenne.query.SortOrder;
-import org.apache.cayenne.swing.components.image.FilteredIconFactory;
-import org.apache.cayenne.util.CayenneMapEntry;
-
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JSplitPane;
-import javax.swing.JTable;
-import javax.swing.ListSelectionModel;
-import javax.swing.event.ListSelectionEvent;
-import javax.swing.event.ListSelectionListener;
-import javax.swing.table.AbstractTableModel;
-import javax.swing.table.TableModel;
-import javax.swing.tree.TreeModel;
-import java.awt.BorderLayout;
-import java.awt.CardLayout;
-import java.awt.Dimension;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-import java.util.prefs.Preferences;
-
-/**
- * A panel for picking SQLTemplate orderings.
- *
- */
-public class SQLTemplateOrderingTab extends JPanel implements PropertyChangeListener {
-    // property for split pane divider size
-    private static final String SPLIT_DIVIDER_LOCATION_PROPERTY = "query.orderings.divider.location";
-
-    static final Dimension BROWSER_CELL_DIM = new Dimension(150, 100);
-    static final Dimension TABLE_DIM = new Dimension(460, 60);
-
-    static final String PATH_HEADER = "Path";
-    static final String ASCENDING_HEADER = "Ascending";
-    static final String IGNORE_CASE_HEADER = "Ignore Case";
-
-    static final String REAL_PANEL = "real";
-    static final String PLACEHOLDER_PANEL = "placeholder";
-
-    protected ProjectController mediator;
-    protected SQLTemplateDescriptor sqlTemplate;
-
-    protected MultiColumnBrowser browser;
-    protected JTable table;
-
-    protected CardLayout cardLayout;
-    protected JPanel messagePanel;
-
-    public SQLTemplateOrderingTab(ProjectController mediator) {
-        this.mediator = mediator;
-
-        initView();
-        initController();
-    }
-
-    protected void initView() {
-
-        messagePanel = new JPanel(new BorderLayout());
-        cardLayout = new CardLayout();
-
-        Preferences detail = Application.getInstance().getPreferencesNode(this.getClass(), "");
-
-        int defLocation = Application.getFrame().getHeight() / 2;
-        int location = detail != null ? detail.getInt(
-                getDividerLocationProperty(),
-                defLocation) : defLocation;
-
-        //As of CAY-888 #3 main pane is now a JSplitPane. Top component is a bit larger.
-        JSplitPane mainPanel = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
-        mainPanel.addPropertyChangeListener(JSplitPane.DIVIDER_LOCATION_PROPERTY, this);
-        mainPanel.setDividerLocation(location);
-
-        mainPanel.setTopComponent(createEditorPanel());
-        mainPanel.setBottomComponent(createSelectorPanel());
-
-        setLayout(cardLayout);
-        add(mainPanel, REAL_PANEL);
-        add(messagePanel, PLACEHOLDER_PANEL);
-    }
-
-    protected void initController() {
-
-        // scroll to selected row whenever a selection even occurs
-        table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
-
-            public void valueChanged(ListSelectionEvent e) {
-                if (!e.getValueIsAdjusting()) {
-                    UIUtil.scrollToSelectedRow(table);
-                }
-            }
-        });
-    }
-
-    protected void initFromModel() {
-        QueryDescriptor query = mediator.getCurrentQuery();
-
-        if (query == null || !QueryDescriptor.SQL_TEMPLATE.equals(query.getType())) {
-            processInvalidModel("Unknown query.");
-            return;
-        }
-
-        if (!(query.getRoot() instanceof Entity)) {
-            processInvalidModel("SQLTemplate has no root set.");
-            return;
-        }
-
-        this.sqlTemplate = (SQLTemplateDescriptor) query;
-        browser.setModel(createBrowserModel((Entity) sqlTemplate.getRoot()));
-
-        // init column sizes
-       // table.getColumnModel().getColumn(0).setPreferredWidth(250);
-
-        cardLayout.show(this, REAL_PANEL);
-    }
-
-    protected void processInvalidModel(String message) {
-        JLabel messageLabel = new JLabel(message, JLabel.CENTER);
-
-        messagePanel.removeAll();
-        messagePanel.add(messageLabel, BorderLayout.CENTER);
-        cardLayout.show(this, PLACEHOLDER_PANEL);
-    }
-
-    protected JPanel createEditorPanel() {
-
-        table = new JTable();
-        table.setRowHeight(25);
-        table.setRowMargin(3);
-        table.setPreferredScrollableViewportSize(TABLE_DIM);
-        table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-
-        JPanel panel = new JPanel(new BorderLayout());
-        panel.add(new JScrollPane(table), BorderLayout.CENTER);
-
-        return panel;
-    }
-
-    protected JPanel createSelectorPanel() {
-        browser = new MultiColumnBrowser();
-        browser.setPreferredColumnSize(BROWSER_CELL_DIM);
-        browser.setDefaultRenderer();
-
-        JPanel panel = new JPanel(new BorderLayout());
-        panel.add(new JScrollPane(
-                browser,
-                JScrollPane.VERTICAL_SCROLLBAR_NEVER,
-                JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED), BorderLayout.CENTER);
-
-        // setting minimal size, otherwise scrolling looks awful, because of
-        // VERTICAL_SCROLLBAR_NEVER strategy
-        panel.setMinimumSize(panel.getPreferredSize());
-
-        return panel;
-    }
-
-    protected TreeModel createBrowserModel(Entity entity) {
-        return new EntityTreeModel(entity);
-    }
-
-    protected String getSelectedPath() {
-        Object[] path = browser.getSelectionPath().getPath();
-
-        // first item in the path is Entity, so we must have
-        // at least two elements to constitute a valid ordering path
-        if (path.length < 2) {
-            return null;
-        }
-
-        StringBuilder buffer = new StringBuilder();
-
-        // attribute or relationships
-        CayenneMapEntry first = (CayenneMapEntry) path[1];
-        buffer.append(first.getName());
-
-        for (int i = 2; i < path.length; i++) {
-            CayenneMapEntry pathEntry = (CayenneMapEntry) path[i];
-            buffer.append(".").append(pathEntry.getName());
-        }
-
-        return buffer.toString();
-    }
-
-    /**
-     * Updates split pane divider location in properties
-     */
-    public void propertyChange(PropertyChangeEvent evt) {
-        if (JSplitPane.DIVIDER_LOCATION_PROPERTY.equals(evt.getPropertyName())) {
-            int value = (Integer) evt.getNewValue();
-
-            Preferences detail = Application.getInstance().getPreferencesNode(this.getClass(), "");
-            detail.putInt(getDividerLocationProperty(), value);
-        }
-    }
-
-    /**
-     * Returns name of a property for divider location.
-     */
-    protected String getDividerLocationProperty() {
-        return SPLIT_DIVIDER_LOCATION_PROPERTY;
-    }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/193c6aa4/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplatePrefetchTab.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplatePrefetchTab.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplatePrefetchTab.java
index b9e7147..0398eee 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplatePrefetchTab.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SQLTemplatePrefetchTab.java
@@ -25,32 +25,177 @@ import org.apache.cayenne.exp.ExpressionException;
 import org.apache.cayenne.exp.ExpressionFactory;
 import org.apache.cayenne.map.Attribute;
 import org.apache.cayenne.map.Entity;
+import org.apache.cayenne.map.QueryDescriptor;
 import org.apache.cayenne.map.Relationship;
+import org.apache.cayenne.map.SQLTemplateDescriptor;
 import org.apache.cayenne.modeler.Application;
 import org.apache.cayenne.modeler.ProjectController;
-import org.apache.cayenne.modeler.undo.AddPrefetchUndoableEdit;
 import org.apache.cayenne.modeler.undo.AddPrefetchUndoableEditForSqlTemplate;
 import org.apache.cayenne.modeler.util.CayenneAction;
 import org.apache.cayenne.modeler.util.EntityTreeFilter;
 import org.apache.cayenne.modeler.util.EntityTreeModel;
 import org.apache.cayenne.modeler.util.ModelerUtil;
+import org.apache.cayenne.modeler.util.MultiColumnBrowser;
+import org.apache.cayenne.modeler.util.UIUtil;
 import org.apache.cayenne.swing.components.image.FilteredIconFactory;
+import org.apache.cayenne.util.CayenneMapEntry;
 
 import javax.swing.BorderFactory;
 import javax.swing.Icon;
 import javax.swing.JButton;
 import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.JTable;
 import javax.swing.JToolBar;
+import javax.swing.ListSelectionModel;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
 import javax.swing.table.AbstractTableModel;
 import javax.swing.table.TableModel;
 import javax.swing.tree.TreeModel;
+import java.awt.BorderLayout;
+import java.awt.CardLayout;
+import java.awt.Dimension;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.prefs.Preferences;
 
-public class SQLTemplatePrefetchTab extends SQLTemplateOrderingTab{
+public class SQLTemplatePrefetchTab extends JPanel implements PropertyChangeListener {
+
+    // property for split pane divider size
+    private static final String SPLIT_DIVIDER_LOCATION_PROPERTY = "query.orderings.divider.location";
+
+    static final Dimension BROWSER_CELL_DIM = new Dimension(150, 100);
+    static final Dimension TABLE_DIM = new Dimension(460, 60);
+
+    static final String PATH_HEADER = "Path";
+    static final String ASCENDING_HEADER = "Ascending";
+    static final String IGNORE_CASE_HEADER = "Ignore Case";
+
+    static final String REAL_PANEL = "real";
+    static final String PLACEHOLDER_PANEL = "placeholder";
+
+    protected ProjectController mediator;
+    protected SQLTemplateDescriptor sqlTemplate;
+
+    protected MultiColumnBrowser browser;
+    protected JTable table;
+
+    protected CardLayout cardLayout;
+    protected JPanel messagePanel;
 
     public SQLTemplatePrefetchTab(ProjectController mediator) {
-        super(mediator);
+        this.mediator = mediator;
+
+        initView();
+        initController();
+    }
+
+    protected void initView() {
+
+        messagePanel = new JPanel(new BorderLayout());
+        cardLayout = new CardLayout();
+
+        Preferences detail = Application.getInstance().getPreferencesNode(this.getClass(), "");
+
+        int defLocation = Application.getFrame().getHeight() / 2;
+        int location = detail != null ? detail.getInt(
+                getDividerLocationProperty(),
+                defLocation) : defLocation;
+
+        //As of CAY-888 #3 main pane is now a JSplitPane. Top component is a bit larger.
+        JSplitPane mainPanel = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
+        mainPanel.addPropertyChangeListener(JSplitPane.DIVIDER_LOCATION_PROPERTY, this);
+        mainPanel.setDividerLocation(location);
+
+        mainPanel.setTopComponent(createEditorPanel());
+        mainPanel.setBottomComponent(createSelectorPanel());
+
+        setLayout(cardLayout);
+        add(mainPanel, REAL_PANEL);
+        add(messagePanel, PLACEHOLDER_PANEL);
+    }
+
+    protected void initController() {
+
+        // scroll to selected row whenever a selection even occurs
+        table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
+
+            public void valueChanged(ListSelectionEvent e) {
+                if (!e.getValueIsAdjusting()) {
+                    UIUtil.scrollToSelectedRow(table);
+                }
+            }
+        });
+    }
+
+    protected void initFromModel() {
+        QueryDescriptor query = mediator.getCurrentQuery();
+
+        if (query == null || !QueryDescriptor.SQL_TEMPLATE.equals(query.getType())) {
+            processInvalidModel("Unknown query.");
+            return;
+        }
+
+        if (!(query.getRoot() instanceof Entity)) {
+            processInvalidModel("SQLTemplate has no root set.");
+            return;
+        }
+
+        this.sqlTemplate = (SQLTemplateDescriptor) query;
+        browser.setModel(createBrowserModel((Entity) sqlTemplate.getRoot()));
+        table.setModel(createTableModel());
+
+        // init column sizes
+        table.getColumnModel().getColumn(0).setPreferredWidth(250);
+
+        cardLayout.show(this, REAL_PANEL);
+    }
+
+    protected void processInvalidModel(String message) {
+        JLabel messageLabel = new JLabel(message, JLabel.CENTER);
+
+        messagePanel.removeAll();
+        messagePanel.add(messageLabel, BorderLayout.CENTER);
+        cardLayout.show(this, PLACEHOLDER_PANEL);
+    }
+
+    protected JPanel createEditorPanel() {
+
+        table = new JTable();
+        table.setRowHeight(25);
+        table.setRowMargin(3);
+        table.setPreferredScrollableViewportSize(TABLE_DIM);
+        table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+
+        JPanel panel = new JPanel(new BorderLayout());
+        panel.add(new JScrollPane(table), BorderLayout.CENTER);
+
+        return panel;
+    }
+
+    protected JPanel createSelectorPanel() {
+        browser = new MultiColumnBrowser();
+        browser.setPreferredColumnSize(BROWSER_CELL_DIM);
+        browser.setDefaultRenderer();
+
+        JPanel panel = new JPanel(new BorderLayout());
+        panel.add(createToolbar(), BorderLayout.NORTH);
+        panel.add(new JScrollPane(
+                browser,
+                JScrollPane.VERTICAL_SCROLLBAR_NEVER,
+                JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED), BorderLayout.CENTER);
+
+        // setting minimal size, otherwise scrolling looks awful, because of
+        // VERTICAL_SCROLLBAR_NEVER strategy
+        panel.setMinimumSize(panel.getPreferredSize());
+
+        return panel;
     }
 
     protected JComponent createToolbar() {
@@ -106,6 +251,29 @@ public class SQLTemplatePrefetchTab extends SQLTemplateOrderingTab{
         return toolBar;
     }
 
+    protected String getSelectedPath() {
+        Object[] path = browser.getSelectionPath().getPath();
+
+        // first item in the path is Entity, so we must have
+        // at least two elements to constitute a valid ordering path
+        if (path.length < 2) {
+            return null;
+        }
+
+        StringBuilder buffer = new StringBuilder();
+
+        // attribute or relationships
+        CayenneMapEntry first = (CayenneMapEntry) path[1];
+        buffer.append(first.getName());
+
+        for (int i = 2; i < path.length; i++) {
+            CayenneMapEntry pathEntry = (CayenneMapEntry) path[i];
+            buffer.append(".").append(pathEntry.getName());
+        }
+
+        return buffer.toString();
+    }
+
     protected TreeModel createBrowserModel(Entity entity) {
         EntityTreeModel treeModel = new EntityTreeModel(entity);
         treeModel.setFilter(
@@ -172,6 +340,25 @@ public class SQLTemplatePrefetchTab extends SQLTemplateOrderingTab{
     }
 
     /**
+     * Updates split pane divider location in properties
+     */
+    public void propertyChange(PropertyChangeEvent evt) {
+        if (JSplitPane.DIVIDER_LOCATION_PROPERTY.equals(evt.getPropertyName())) {
+            int value = (Integer) evt.getNewValue();
+
+            Preferences detail = Application.getInstance().getPreferencesNode(this.getClass(), "");
+            detail.putInt(getDividerLocationProperty(), value);
+        }
+    }
+
+    /**
+     * Returns name of a property for divider location.
+     */
+    protected String getDividerLocationProperty() {
+        return SPLIT_DIVIDER_LOCATION_PROPERTY;
+    }
+
+    /**
      * A table model for the Ordering editing table.
      */
     final class PrefetchModel extends AbstractTableModel {


[3/4] cayenne git commit: Merge remote-tracking branch 'remotes/parent/pr/274' into asf-master

Posted by nt...@apache.org.
Merge remote-tracking branch 'remotes/parent/pr/274' into asf-master

# Conflicts:
#	RELEASE-NOTES.txt


Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/f86af37f
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/f86af37f
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/f86af37f

Branch: refs/heads/master
Commit: f86af37f6293494baa2616f67b8447429639724d
Parents: fd0d06e 193c6aa
Author: stariy <st...@gmail.com>
Authored: Mon Mar 5 10:13:29 2018 +0300
Committer: stariy <st...@gmail.com>
Committed: Mon Mar 5 10:13:29 2018 +0300

----------------------------------------------------------------------
 RELEASE-NOTES.txt                               |   1 +
 .../cayenne/map/QueryDescriptorLoader.java      |   1 +
 .../cayenne/map/SQLTemplateDescriptor.java      |  51 +++
 .../org/apache/cayenne/query/SQLTemplate.java   |   1 +
 .../modeler/editor/SQLTemplateMainTab.java      | 116 ++++-
 .../modeler/editor/SQLTemplatePrefetchTab.java  | 423 +++++++++++++++++++
 .../modeler/editor/SQLTemplateTabbedView.java   |   7 +
 .../AddPrefetchUndoableEditForSqlTemplate.java  |  35 ++
 8 files changed, 632 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/f86af37f/RELEASE-NOTES.txt
----------------------------------------------------------------------
diff --cc RELEASE-NOTES.txt
index af9c490,cfd075a..fd87dd5
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@@ -23,7 -23,7 +23,8 @@@ CAY-2395 cdbimport: add option to creat
  CAY-2396 Upgrade maven-assembly-plugin to 3.1.0
  CAY-2403 Extract eventbridges to top level
  CAY-2404 Move itests to maven-plugins
 +CAY-2406 Add prefetch-related API to SQLSelect
+ CAY-2407 Modeler: add prefetch support for the SQLTemplate query
  
  Bug Fixes:
  

http://git-wip-us.apache.org/repos/asf/cayenne/blob/f86af37f/cayenne-server/src/main/java/org/apache/cayenne/query/SQLTemplate.java
----------------------------------------------------------------------