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/11/14 14:27:33 UTC
[02/32] cayenne git commit: cgen. create ui
cgen. create ui
Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/8119ffaa
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/8119ffaa
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/8119ffaa
Branch: refs/heads/master
Commit: 8119ffaa88f70787590df6b23bc86c031337b921
Parents: 831442c
Author: Arseni Bulatski <an...@gmail.com>
Authored: Thu Jun 14 16:57:22 2018 +0300
Committer: Arseni Bulatski <an...@gmail.com>
Committed: Wed Oct 24 13:39:05 2018 +0300
----------------------------------------------------------------------
.../cayenne/gen/xml/CgenConfigHandler.java | 23 +
.../apache/cayenne/gen/xml/CgenExtension.java | 32 ++
.../cayenne/gen/xml/CgenLoaderDelegate.java | 28 +
.../cayenne/gen/xml/CgenSaverDelegate.java | 20 +
.../modeler/editor/DataMapTabbedView.java | 10 +-
.../cayenne/modeler/editor/EditorView.java | 3 +-
.../editor/cgen/ClassesTabController.java | 123 ++++
.../modeler/editor/cgen/ClassesTabPanel.java | 84 +++
.../editor/cgen/CodeGeneratorController.java | 146 +++++
.../cgen/CodeGeneratorControllerBase.java | 289 ++++++++++
.../modeler/editor/cgen/CodeGeneratorPane.java | 76 +++
.../editor/cgen/CustomModeController.java | 238 ++++++++
.../modeler/editor/cgen/CustomModePanel.java | 189 ++++++
.../editor/cgen/CustomPreferencesUpdater.java | 193 +++++++
.../editor/cgen/GeneratorController.java | 568 +++++++++++++++++++
.../editor/cgen/GeneratorControllerPanel.java | 53 ++
.../editor/cgen/GeneratorTabController.java | 71 +++
.../modeler/editor/cgen/GeneratorTabPanel.java | 33 ++
.../editor/cgen/StandardPanelComponent.java | 79 +++
.../modeler/init/CayenneModelerModule.java | 4 +-
20 files changed, 2256 insertions(+), 6 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cayenne/blob/8119ffaa/cayenne-cgen/src/main/java/org/apache/cayenne/gen/xml/CgenConfigHandler.java
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/java/org/apache/cayenne/gen/xml/CgenConfigHandler.java b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/xml/CgenConfigHandler.java
new file mode 100644
index 0000000..23f0ff3
--- /dev/null
+++ b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/xml/CgenConfigHandler.java
@@ -0,0 +1,23 @@
+package org.apache.cayenne.gen.xml;
+
+import org.apache.cayenne.configuration.xml.DataChannelMetaData;
+import org.apache.cayenne.configuration.xml.NamespaceAwareNestedTagHandler;
+import org.apache.cayenne.dbsync.xml.DbImportExtension;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+public class CgenConfigHandler extends NamespaceAwareNestedTagHandler{
+
+ private DataChannelMetaData metaData;
+
+ CgenConfigHandler(NamespaceAwareNestedTagHandler parentHandler, DataChannelMetaData metaData) {
+ super(parentHandler);
+ this.metaData = metaData;
+ this.targetNamespace = DbImportExtension.NAMESPACE;
+ }
+
+ @Override
+ protected boolean processElement(String namespaceURI, String localName, Attributes attributes) throws SAXException {
+ return false;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/8119ffaa/cayenne-cgen/src/main/java/org/apache/cayenne/gen/xml/CgenExtension.java
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/java/org/apache/cayenne/gen/xml/CgenExtension.java b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/xml/CgenExtension.java
new file mode 100644
index 0000000..619bffc
--- /dev/null
+++ b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/xml/CgenExtension.java
@@ -0,0 +1,32 @@
+package org.apache.cayenne.gen.xml;
+
+import org.apache.cayenne.configuration.ConfigurationNodeVisitor;
+import org.apache.cayenne.configuration.xml.DataChannelMetaData;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.project.Project;
+import org.apache.cayenne.project.extension.LoaderDelegate;
+import org.apache.cayenne.project.extension.ProjectExtension;
+import org.apache.cayenne.project.extension.SaverDelegate;
+
+public class CgenExtension implements ProjectExtension {
+
+ public static final String NAMESPACE = "http://cayenne.apache.org/schema/" + Project.VERSION + "/cgen";
+
+ @Inject
+ private DataChannelMetaData metaData;
+
+ @Override
+ public LoaderDelegate createLoaderDelegate() {
+ return null;
+ }
+
+ @Override
+ public SaverDelegate createSaverDelegate() {
+ return new CgenSaverDelegate(metaData);
+ }
+
+ @Override
+ public ConfigurationNodeVisitor<String> createNamingDelegate() {
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/8119ffaa/cayenne-cgen/src/main/java/org/apache/cayenne/gen/xml/CgenLoaderDelegate.java
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/java/org/apache/cayenne/gen/xml/CgenLoaderDelegate.java b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/xml/CgenLoaderDelegate.java
new file mode 100644
index 0000000..44438e3
--- /dev/null
+++ b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/xml/CgenLoaderDelegate.java
@@ -0,0 +1,28 @@
+package org.apache.cayenne.gen.xml;
+
+import org.apache.cayenne.configuration.xml.DataChannelMetaData;
+import org.apache.cayenne.configuration.xml.NamespaceAwareNestedTagHandler;
+
+import org.apache.cayenne.project.extension.LoaderDelegate;
+
+public class CgenLoaderDelegate implements LoaderDelegate {
+
+ private DataChannelMetaData metaData;
+
+ CgenLoaderDelegate(DataChannelMetaData metaData){
+ this.metaData = metaData;
+ }
+
+ @Override
+ public String getTargetNamespace() {
+ return CgenExtension.NAMESPACE;
+ }
+
+ @Override
+ public NamespaceAwareNestedTagHandler createHandler(NamespaceAwareNestedTagHandler parent, String tag) {
+// if(CgenConfigHandler.CONFIG_TAG.equals(tag)) {
+// return new CgenConfigHandler(parent, metaData);
+// }
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/8119ffaa/cayenne-cgen/src/main/java/org/apache/cayenne/gen/xml/CgenSaverDelegate.java
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/java/org/apache/cayenne/gen/xml/CgenSaverDelegate.java b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/xml/CgenSaverDelegate.java
new file mode 100644
index 0000000..f9c7173
--- /dev/null
+++ b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/xml/CgenSaverDelegate.java
@@ -0,0 +1,20 @@
+package org.apache.cayenne.gen.xml;
+
+import org.apache.cayenne.configuration.xml.DataChannelMetaData;
+import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.project.extension.BaseSaverDelegate;
+
+public class CgenSaverDelegate extends BaseSaverDelegate{
+
+ private DataChannelMetaData metaData;
+
+ CgenSaverDelegate(DataChannelMetaData metaData){
+ this.metaData = metaData;
+ }
+
+ @Override
+ public Void visitDataMap(DataMap dataMap) {
+
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/8119ffaa/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/DataMapTabbedView.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/DataMapTabbedView.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/DataMapTabbedView.java
index ed1b6f1..bd9afc5 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/DataMapTabbedView.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/DataMapTabbedView.java
@@ -18,12 +18,13 @@
****************************************************************/
package org.apache.cayenne.modeler.editor;
-import javax.swing.JScrollPane;
-import javax.swing.JTabbedPane;
-
+import org.apache.cayenne.modeler.Application;
import org.apache.cayenne.modeler.ProjectController;
+import org.apache.cayenne.modeler.editor.cgen.CodeGeneratorController;
import org.apache.cayenne.modeler.editor.dbimport.DbImportView;
+import javax.swing.*;
+
/**
* Data map editing tabs container
@@ -55,8 +56,11 @@ public class DataMapTabbedView extends JTabbedPane {
// must be wrapped in a scroll pane
JScrollPane dataMapView = new JScrollPane(new DataMapView(mediator));
JScrollPane dbImportView = new JScrollPane(new DbImportView(mediator));
+ CodeGeneratorController codeGeneratorController = new CodeGeneratorController(Application.getInstance().getFrameController(), mediator);
+ JScrollPane cgenView = new JScrollPane(codeGeneratorController.getView());
addTab("DataMap", dataMapView);
addTab("DbImport", dbImportView);
+ addTab("Cgen", cgenView);
}
}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/8119ffaa/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/EditorView.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/EditorView.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/EditorView.java
index e9b3290..5b4675a 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/EditorView.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/EditorView.java
@@ -103,7 +103,6 @@ public class EditorView extends JPanel implements ObjEntityDisplayListener,
private SQLTemplateTabbedView sqlTemplateView;
private EjbqlTabbedView ejbqlQueryView;
private JTabbedPane dataNodeView;
-
protected ActionManager actionManager;
private FilterController filterController;
@@ -162,7 +161,7 @@ public class EditorView extends JPanel implements ObjEntityDisplayListener,
public EditorView(ProjectController eventController) {
this.eventController = eventController;
- this.actionManager= eventController.getApplication().getActionManager();
+ this.actionManager = eventController.getApplication().getActionManager();
initView();
initController();
http://git-wip-us.apache.org/repos/asf/cayenne/blob/8119ffaa/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/ClassesTabController.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/ClassesTabController.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/ClassesTabController.java
new file mode 100644
index 0000000..2b478ac
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/ClassesTabController.java
@@ -0,0 +1,123 @@
+/*****************************************************************
+ * 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.cgen;
+
+import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.modeler.util.CayenneController;
+import org.apache.cayenne.swing.BindingBuilder;
+import org.apache.cayenne.swing.ImageRendererColumn;
+import org.apache.cayenne.swing.ObjectBinding;
+import org.apache.cayenne.swing.TableBindingBuilder;
+
+import javax.swing.*;
+import java.awt.*;
+
+public class ClassesTabController extends CayenneController {
+
+ public static final String GENERATE_PROPERTY = "generate";
+
+ protected ClassesTabPanel view;
+ protected ObjectBinding tableBinding;
+
+ public ClassesTabController(CodeGeneratorControllerBase parent) {
+ super(parent);
+
+ this.view = new ClassesTabPanel();
+ }
+
+ public void startup(DataMap dataMap){
+ initBindings();
+ }
+
+ protected CodeGeneratorControllerBase getParentController() {
+ return (CodeGeneratorControllerBase) getParent();
+ }
+
+ public Component getView() {
+ return view;
+ }
+
+ protected void initBindings() {
+
+ BindingBuilder builder = new BindingBuilder(
+ getApplication().getBindingFactory(),
+ this);
+
+ builder.bindToAction(view.getCheckAll(), "checkAllAction()");
+
+ TableBindingBuilder tableBuilder = new TableBindingBuilder(builder);
+
+ tableBuilder.addColumn(
+ "",
+ "parent.setCurrentClass(#item), selected",
+ Boolean.class,
+ true,
+ Boolean.TRUE);
+ tableBuilder.addColumn(
+ "Class",
+ "parent.getItemName(#item)",
+ JLabel.class,
+ false,
+ "XXXXXXXXXXXXXX");
+
+ tableBuilder.addColumn(
+ "Comments, Warnings",
+ "parent.getProblem(#item)",
+ String.class,
+ false,
+ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
+
+ this.tableBinding = tableBuilder.bindToTable(view.getTable(), "parent.classes");
+ view.getTable().getColumnModel().getColumn(1).setCellRenderer(new ImageRendererColumn());
+ }
+
+ public boolean isSelected() {
+ return getParentController().isSelected();
+ }
+
+ public void setSelected(boolean selected) {
+ getParentController().setSelected(selected);
+ classSelectedAction();
+ }
+
+ /**
+ * A callback action that updates the state of Select All checkbox.
+ */
+ public void classSelectedAction() {
+ int selectedCount = getParentController().getSelectedEntitiesSize() + getParentController().getSelectedEmbeddablesSize() ;
+
+ if (selectedCount == 0) {
+ view.getCheckAll().setSelected(false);
+ }
+ else if (selectedCount == getParentController().getClasses().size()) {
+ view.getCheckAll().setSelected(true);
+ }
+ }
+
+ /**
+ * An action that updates entity check boxes in response to the Select All state
+ * change.
+ */
+ public void checkAllAction() {
+ if (getParentController().updateSelection(view.getCheckAll().isSelected() ? o -> true : o -> false)) {
+ tableBinding.updateView();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/8119ffaa/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/ClassesTabPanel.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/ClassesTabPanel.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/ClassesTabPanel.java
new file mode 100644
index 0000000..e4fc20c
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/ClassesTabPanel.java
@@ -0,0 +1,84 @@
+/*****************************************************************
+ * 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.cgen;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+
+/**
+ */
+public class ClassesTabPanel extends JPanel {
+
+ protected JTable table;
+ protected JCheckBox checkAll;
+ protected JLabel checkAllLabel;
+
+ public ClassesTabPanel() {
+
+ this.table = new JTable();
+ this.table.setRowHeight(22);
+
+ // TODO: andrus 04/07/2006 - is there an easy way to stick that checkbox in the
+ // table header????
+ this.checkAll = new JCheckBox();
+ this.checkAllLabel = new JLabel("Check All Classes");
+
+ checkAll.addItemListener(new ItemListener() {
+
+ public void itemStateChanged(ItemEvent event) {
+ if (checkAll.isSelected()) {
+ checkAllLabel.setText("Uncheck All Classess");
+ }
+ else {
+ checkAllLabel.setText("Check All Classes");
+ }
+ }
+ });
+
+ // assemble
+ JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.LEADING));
+ topPanel.setBorder(UIManager.getBorder("ToolBar.border"));
+ topPanel.add(checkAll);
+ topPanel.add(checkAllLabel);
+
+ JScrollPane tablePanel = new JScrollPane(
+ table,
+ ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
+ ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
+
+ // set some minimal preferred size, so that it is smaller than other forms used in
+ // the dialog... this way we get the right automated overall size
+ tablePanel.setPreferredSize(new Dimension(300, 200));
+
+ setLayout(new BorderLayout());
+ add(topPanel, BorderLayout.NORTH);
+ add(tablePanel, BorderLayout.CENTER);
+ }
+
+ public JTable getTable() {
+ return table;
+ }
+
+ public JCheckBox getCheckAll() {
+ return checkAll;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/8119ffaa/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/CodeGeneratorController.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/CodeGeneratorController.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/CodeGeneratorController.java
new file mode 100644
index 0000000..8163acb
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/CodeGeneratorController.java
@@ -0,0 +1,146 @@
+/*****************************************************************
+ * 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.cgen;
+
+import org.apache.cayenne.gen.ClassGenerationAction;
+import org.apache.cayenne.modeler.ProjectController;
+import org.apache.cayenne.modeler.dialog.ErrorDebugDialog;
+import org.apache.cayenne.modeler.util.CayenneController;
+import org.apache.cayenne.swing.BindingBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.swing.*;
+import java.awt.*;
+import java.util.Collection;
+import java.util.function.Predicate;
+
+/**
+ * A controller for the class generator dialog.
+ */
+public class CodeGeneratorController extends CodeGeneratorControllerBase {
+ /**
+ * Logger to print stack traces
+ */
+ private static Logger logObj = LoggerFactory.getLogger(ErrorDebugDialog.class);
+
+ protected CodeGeneratorPane view;
+
+ protected ClassesTabController classesSelector;
+ protected GeneratorTabController generatorSelector;
+
+ public CodeGeneratorController(CayenneController parent, ProjectController projectController) {
+ super(parent, projectController);
+ initListeners();
+ this.classesSelector = new ClassesTabController(this);
+ this.generatorSelector = new GeneratorTabController(this);
+ view = new CodeGeneratorPane(generatorSelector.getView(), classesSelector.getView());
+ initBindings();
+ }
+
+ private void initListeners(){
+ projectController.addDataMapDisplayListener(e -> {
+ super.startup(e.getDataMap());
+ classesSelector.startup(e.getDataMap());
+ generatorSelector.startup(e.getDataMap());
+ });
+ }
+
+ @Override
+ public Component getView() {
+ return view;
+ }
+
+ protected void initBindings() {
+ BindingBuilder builder = new BindingBuilder(
+ getApplication().getBindingFactory(),
+ this);
+
+ builder.bindToAction(view.getGenerateButton(), "generateAction()");
+ builder.bindToAction(this, "classesSelectedAction()", SELECTED_PROPERTY);
+ builder.bindToAction(generatorSelector, "generatorSelectedAction()",
+ GeneratorTabController.GENERATOR_PROPERTY);
+
+ generatorSelectedAction();
+ }
+
+ public void generatorSelectedAction() {
+ GeneratorController controller = generatorSelector.getGeneratorController();
+ validate(controller);
+
+ Predicate<Object> predicate = controller != null
+ ? controller.getDefaultClassFilter()
+ : o -> false;
+
+ updateSelection(predicate);
+ classesSelector.classSelectedAction();
+ }
+
+ public void classesSelectedAction() {
+ int size = getSelectedEntitiesSize();
+ String label;
+
+ if (size == 0) {
+ label = "No entities selected";
+ }
+ else if (size == 1) {
+ label = "One entity selected";
+ }
+ else {
+ label = size + " entities selected";
+ }
+
+ label = label.concat("; ");
+
+ int sizeEmb = getSelectedEmbeddablesSize();
+
+ if (sizeEmb == 0) {
+ label = label + "No embeddables selected";
+ }
+ else if (sizeEmb == 1) {
+ label = label + "One embeddable selected";
+ }
+ else {
+ label =label + sizeEmb + " embeddables selected";
+ }
+
+ view.getClassesCount().setText(label);
+ }
+
+ public void generateAction() {
+ Collection<ClassGenerationAction> generators = generatorSelector.getGenerator();
+
+ if (generators != null) {
+ try {
+ for (ClassGenerationAction generator : generators) {
+ generator.execute();
+ }
+ JOptionPane.showMessageDialog(
+ getView(),
+ "Class generation finished");
+ } catch (Exception e) {
+ logObj.error("Error generating classes", e);
+ JOptionPane.showMessageDialog(
+ getView(),
+ "Error generating classes - " + e.getMessage());
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/8119ffaa/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/CodeGeneratorControllerBase.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/CodeGeneratorControllerBase.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/CodeGeneratorControllerBase.java
new file mode 100644
index 0000000..17196fa
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/CodeGeneratorControllerBase.java
@@ -0,0 +1,289 @@
+/*****************************************************************
+ * 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.cgen;
+
+import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.map.Embeddable;
+import org.apache.cayenne.map.ObjEntity;
+import org.apache.cayenne.modeler.ProjectController;
+import org.apache.cayenne.modeler.util.CayenneController;
+import org.apache.cayenne.modeler.util.CellRenderers;
+import org.apache.cayenne.validation.ValidationFailure;
+import org.apache.cayenne.validation.ValidationResult;
+
+import javax.swing.*;
+import java.awt.*;
+import java.util.*;
+import java.util.List;
+import java.util.function.Predicate;
+
+/**
+ * A base superclass of a top controller for the code generator. Defines all common model
+ * parts used in class generation.
+ *
+ */
+public abstract class CodeGeneratorControllerBase extends CayenneController {
+
+ public static final String SELECTED_PROPERTY = "selected";
+
+ protected Collection<DataMap> dataMaps;
+
+ protected DataMap dataMap;
+
+ protected ValidationResult validation;
+
+ protected List<Object> classes;
+
+ protected Set<String> selectedEntities;
+ protected Set<String> selectedEmbeddables;
+
+ protected transient Object currentClass;
+
+ protected ProjectController projectController;
+
+ public CodeGeneratorControllerBase(CayenneController parent, ProjectController projectController) {
+ super(parent);
+ this.projectController = projectController;
+ this.classes = new ArrayList<>();
+
+ this.selectedEntities = new HashSet<>();
+ this.selectedEmbeddables = new HashSet<>();
+ }
+
+ public void startup(DataMap dataMap){
+ this.dataMap = dataMap;
+ classes.clear();
+ this.classes.addAll(dataMap.getObjEntities());
+ this.classes.addAll(dataMap.getEmbeddables());
+ }
+
+ public List<Object> getClasses() {
+ return classes;
+ }
+
+ public abstract Component getView();
+
+ public void validate(GeneratorController validator) {
+
+ ValidationResult validationBuffer = new ValidationResult();
+
+ if (validator != null) {
+ for (Object classObj : classes) {
+ if (classObj instanceof ObjEntity) {
+ validator.validateEntity(
+ validationBuffer,
+ (ObjEntity) classObj,
+ false);
+ }
+ else if (classObj instanceof Embeddable) {
+ validator.validateEmbeddable(validationBuffer, (Embeddable) classObj);
+ }
+ }
+
+ }
+
+ this.validation = validationBuffer;
+ }
+
+ public boolean updateSelection(Predicate<Object> predicate) {
+
+ boolean modified = false;
+
+ for (Object classObj : classes) {
+ boolean select = predicate.test(classObj);
+ if (classObj instanceof ObjEntity) {
+
+ if (select) {
+ if (selectedEntities.add(((ObjEntity) classObj).getName())) {
+ modified = true;
+ }
+ }
+ else {
+ if (selectedEntities.remove(((ObjEntity) classObj).getName())) {
+ modified = true;
+ }
+ }
+ }
+ else if (classObj instanceof Embeddable) {
+ if (select) {
+ if (selectedEmbeddables.add(((Embeddable) classObj).getClassName())) {
+ modified = true;
+ }
+ }
+ else {
+ if (selectedEmbeddables
+ .remove(((Embeddable) classObj).getClassName())) {
+ modified = true;
+ }
+ }
+ }
+
+ }
+
+ if (modified) {
+ firePropertyChange(SELECTED_PROPERTY, null, null);
+ }
+
+ return modified;
+ }
+
+ public List<Embeddable> getSelectedEmbeddables() {
+
+ List<Embeddable> selected = new ArrayList<>(selectedEmbeddables.size());
+
+ for (Object classObj : classes) {
+ if (classObj instanceof Embeddable
+ && selectedEmbeddables.contains(((Embeddable) classObj)
+ .getClassName())) {
+ selected.add((Embeddable) classObj);
+ }
+ }
+
+ return selected;
+ }
+
+ public List<ObjEntity> getSelectedEntities() {
+ List<ObjEntity> selected = new ArrayList<>(selectedEntities.size());
+ for (Object classObj : classes) {
+ if (classObj instanceof ObjEntity
+ && selectedEntities.contains(((ObjEntity) classObj).getName())) {
+ selected.add(((ObjEntity) classObj));
+ }
+ }
+
+ return selected;
+ }
+
+ public int getSelectedEntitiesSize() {
+ return selectedEntities.size();
+ }
+
+ public int getSelectedEmbeddablesSize() {
+ return selectedEmbeddables.size();
+ }
+
+ /**
+ * Returns the first encountered validation problem for an antity matching the name or
+ * null if the entity is valid or the entity is not present.
+ */
+ public String getProblem(Object obj) {
+
+ String name = null;
+
+ if (obj instanceof ObjEntity) {
+ name = ((ObjEntity) obj).getName();
+ }
+ else if (obj instanceof Embeddable) {
+ name = ((Embeddable) obj).getClassName();
+ }
+
+ if (validation == null) {
+ return null;
+ }
+
+ List failures = validation.getFailures(name);
+ if (failures.isEmpty()) {
+ return null;
+ }
+
+ return ((ValidationFailure) failures.get(0)).getDescription();
+ }
+
+ public boolean isSelected() {
+ if (currentClass instanceof ObjEntity) {
+ return selectedEntities
+ .contains(((ObjEntity) currentClass).getName());
+ }
+ if (currentClass instanceof Embeddable) {
+ return selectedEmbeddables
+ .contains(((Embeddable) currentClass).getClassName());
+ }
+ return false;
+
+ }
+
+ public void setSelected(boolean selectedFlag) {
+ if (currentClass == null) {
+ return;
+ }
+ if (currentClass instanceof ObjEntity) {
+ if (selectedFlag) {
+ if (selectedEntities.add(((ObjEntity) currentClass).getName())) {
+ firePropertyChange(SELECTED_PROPERTY, null, null);
+ }
+ }
+ else {
+ if (selectedEntities.remove(((ObjEntity) currentClass).getName())) {
+ firePropertyChange(SELECTED_PROPERTY, null, null);
+ }
+ }
+ }
+ if (currentClass instanceof Embeddable) {
+ if (selectedFlag) {
+ if (selectedEmbeddables.add(((Embeddable) currentClass).getClassName())) {
+ firePropertyChange(SELECTED_PROPERTY, null, null);
+ }
+ }
+ else {
+ if (selectedEmbeddables
+ .remove(((Embeddable) currentClass).getClassName())) {
+ firePropertyChange(SELECTED_PROPERTY, null, null);
+ }
+ }
+ }
+ }
+
+ public Object getCurrentClass() {
+ return currentClass;
+ }
+
+ public void setCurrentClass(Object currentClass) {
+ this.currentClass = currentClass;
+ }
+
+ public Collection<DataMap> getDataMaps() {
+ return dataMaps;
+ }
+
+ public JLabel getItemName(Object obj) {
+ String className;
+ Icon icon;
+ if (obj instanceof Embeddable) {
+ className = ((Embeddable) obj).getClassName();
+ icon = CellRenderers.iconForObject(new Embeddable());
+ } else {
+ className = ((ObjEntity) obj).getName();
+ icon = CellRenderers.iconForObject(new ObjEntity());
+ }
+ JLabel labelIcon = new JLabel();
+ labelIcon.setIcon(icon);
+ labelIcon.setVisible(true);
+ labelIcon.setText(className);
+ return labelIcon;
+ }
+
+ public DataMap getDataMap() {
+ return dataMap;
+ }
+
+ public ProjectController getProjectController() {
+ return projectController;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/8119ffaa/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/CodeGeneratorPane.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/CodeGeneratorPane.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/CodeGeneratorPane.java
new file mode 100644
index 0000000..334931a
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/CodeGeneratorPane.java
@@ -0,0 +1,76 @@
+/*****************************************************************
+ * 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.cgen;
+
+import org.apache.cayenne.swing.components.TopBorder;
+
+import javax.swing.*;
+import java.awt.*;
+
+/**
+ */
+public class CodeGeneratorPane extends JSplitPane {
+
+ protected JSplitPane splitPane;
+
+ protected JButton generateButton;
+ protected JLabel classesCount;
+
+ public CodeGeneratorPane(Component generatorPanel, Component entitySelectorPanel) {
+ super();
+
+ splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
+
+ this.generateButton = new JButton("Generate");
+ this.classesCount = new JLabel("No classes selected");
+ classesCount.setFont(classesCount.getFont().deriveFont(10f));
+
+ JScrollPane scrollPane = new JScrollPane(
+ generatorPanel,
+ ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
+ ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+ scrollPane.setPreferredSize(new Dimension(800, 400));
+
+ // assemble
+ splitPane.setRightComponent(scrollPane);
+ splitPane.setLeftComponent(entitySelectorPanel);
+
+ JPanel messages = new JPanel(new BorderLayout());
+ messages.add(classesCount, BorderLayout.WEST);
+
+ JPanel buttons = new JPanel(new FlowLayout(FlowLayout.RIGHT));
+ buttons.setBorder(TopBorder.create());
+ buttons.add(classesCount);
+ buttons.add(Box.createHorizontalStrut(50));
+ buttons.add(generateButton);
+
+ setLayout(new BorderLayout());
+ add(splitPane, BorderLayout.CENTER);
+ add(buttons, BorderLayout.SOUTH);
+ }
+
+ public JButton getGenerateButton() {
+ return generateButton;
+ }
+
+ public JLabel getClassesCount() {
+ return classesCount;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/8119ffaa/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/CustomModeController.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/CustomModeController.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/CustomModeController.java
new file mode 100644
index 0000000..8f4dac9
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/CustomModeController.java
@@ -0,0 +1,238 @@
+/*****************************************************************
+ * 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.cgen;
+
+import org.apache.cayenne.gen.ClassGenerationAction;
+import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.modeler.CodeTemplateManager;
+import org.apache.cayenne.modeler.dialog.pref.PreferenceDialog;
+import org.apache.cayenne.modeler.pref.DataMapDefaults;
+import org.apache.cayenne.swing.BindingBuilder;
+import org.apache.cayenne.swing.ObjectBinding;
+import org.apache.cayenne.util.Util;
+
+import javax.swing.*;
+import java.awt.*;
+import java.util.*;
+import java.util.List;
+
+/**
+ * A controller for the custom generation mode.
+ */
+public class CustomModeController extends GeneratorController {
+
+ // correspond to non-public constants on MapClassGenerator.
+ static final String MODE_DATAMAP = "datamap";
+ static final String MODE_ENTITY = "entity";
+ static final String MODE_ALL = "all";
+
+ static final String DATA_MAP_MODE_LABEL = "DataMap generation";
+ static final String ENTITY_MODE_LABEL = "Entity and Embeddable generation";
+ static final String ALL_MODE_LABEL = "Generate all";
+
+ static final Map<String, String> modesByLabel = new HashMap<>();
+
+ static {
+ modesByLabel.put(DATA_MAP_MODE_LABEL, MODE_DATAMAP);
+ modesByLabel.put(ENTITY_MODE_LABEL, MODE_ENTITY);
+ modesByLabel.put(ALL_MODE_LABEL, MODE_ALL);
+ }
+
+ protected CustomModePanel view;
+ protected CodeTemplateManager templateManager;
+
+ protected ObjectBinding superTemplate;
+ protected ObjectBinding subTemplate;
+
+ private BindingBuilder builder;
+
+ private CustomPreferencesUpdater preferencesUpdater;
+
+ public CustomPreferencesUpdater getCustomPreferencesUpdater() {
+ return preferencesUpdater;
+ }
+
+ public CustomModeController(CodeGeneratorControllerBase parent) {
+ super(parent);
+ this.view = new CustomModePanel();
+ bind();
+ }
+
+ private void bind() {
+ initBindings(new BindingBuilder(getApplication().getBindingFactory(), this));
+ builder = new BindingBuilder(getApplication().getBindingFactory(), this);
+ builder.bindToAction(view.getManageTemplatesLink(), "popPreferencesAction()");
+
+ Object[] modeChoices = new Object[]{ENTITY_MODE_LABEL, DATA_MAP_MODE_LABEL, ALL_MODE_LABEL};
+ view.getGenerationMode().setModel(new DefaultComboBoxModel(modeChoices));
+ }
+
+ public void startup(DataMap dataMap) {
+ super.startup(dataMap);
+
+ // bind preferences and init defaults...
+ DataMapDefaults dataMapDefaults = getMapPreferences().get(getParentController().getDataMap());
+
+ if (Util.isEmptyString(dataMapDefaults.getSuperclassTemplate())) {
+ dataMapDefaults.setSuperclassTemplate(CodeTemplateManager.STANDARD_SERVER_SUPERCLASS);
+ }
+
+ if (Util.isEmptyString(dataMapDefaults.getSubclassTemplate())) {
+ dataMapDefaults.setSubclassTemplate(CodeTemplateManager.STANDARD_SERVER_SUBCLASS);
+ }
+
+ if (Util.isEmptyString(dataMapDefaults.getProperty("mode"))) {
+ dataMapDefaults.setProperty("mode", MODE_ENTITY);
+ }
+
+ if (Util.isEmptyString(dataMapDefaults.getProperty("overwrite"))) {
+ dataMapDefaults.setBooleanProperty("overwrite", false);
+ }
+
+ if (Util.isEmptyString(dataMapDefaults.getProperty("pairs"))) {
+ dataMapDefaults.setBooleanProperty("pairs", true);
+ }
+
+ if (Util.isEmptyString(dataMapDefaults.getProperty("usePackagePath"))) {
+ dataMapDefaults.setBooleanProperty("usePackagePath", true);
+ }
+
+ if (Util.isEmptyString(dataMapDefaults.getProperty("outputPattern"))) {
+ dataMapDefaults.setProperty("outputPattern", "*.java");
+ }
+
+ builder.bindToComboSelection(view.getGenerationMode(), "customPreferencesUpdater.mode").updateView();
+
+ builder.bindToStateChange(view.getOverwrite(), "customPreferencesUpdater.overwrite").updateView();
+
+ builder.bindToStateChange(view.getPairs(), "customPreferencesUpdater.pairs").updateView();
+
+ builder.bindToStateChange(view.getUsePackagePath(), "customPreferencesUpdater.usePackagePath").updateView();
+
+ subTemplate = builder.bindToComboSelection(view.getSubclassTemplate(),
+ "customPreferencesUpdater.subclassTemplate");
+
+ superTemplate = builder.bindToComboSelection(view.getSuperclassTemplate(),
+ "customPreferencesUpdater.superclassTemplate");
+
+ builder.bindToTextField(view.getOutputPattern(), "customPreferencesUpdater.outputPattern").updateView();
+
+ builder.bindToStateChange(view.getCreatePropertyNames(), "customPreferencesUpdater.createPropertyNames")
+ .updateView();
+
+ updateTemplates();
+ }
+
+ protected void createDefaults() {
+ TreeMap<DataMap, DataMapDefaults> map = new TreeMap<>();
+ DataMap dataMap = getParentController().getDataMap();
+ DataMapDefaults preferences;
+ preferences = getApplication().getFrameController().getProjectController()
+ .getDataMapPreferences(this.getClass().getName().replace(".", "/"), dataMap);
+ preferences.setSuperclassPackage("");
+ preferences.updateSuperclassPackage(dataMap, false);
+
+ map.put(dataMap, preferences);
+
+ if (getOutputPath() == null) {
+ setOutputPath(preferences.getOutputPath());
+ }
+
+ setMapPreferences(map);
+ preferencesUpdater = new CustomPreferencesUpdater(map);
+ }
+
+ protected GeneratorControllerPanel createView() {
+ if (getParentController().getDataMap() != view.getStandardPanelComponent().getDataMap()) {
+ DataMapDefaults dataMapDefaults = getMapPreferences().get(getParentController().getDataMap());
+ view.getStandardPanelComponent().setDataMap(getParentController().getDataMap());
+ view.getStandardPanelComponent().setPreferences(dataMapDefaults);
+ view.getStandardPanelComponent().getDataMapName().setText(view.getStandardPanelComponent().getDataMap().getName());
+ BindingBuilder builder = new BindingBuilder(getApplication().getBindingFactory(), view.getStandardPanelComponent());
+ builder.bindToTextField(view.getStandardPanelComponent().getSuperclassPackage(), "preferences.superclassPackage").updateView();
+ }
+ return view;
+ }
+
+ protected void updateTemplates() {
+ this.templateManager = getApplication().getCodeTemplateManager();
+
+ List<String> customTemplates = new ArrayList<>(templateManager.getCustomTemplates().keySet());
+ Collections.sort(customTemplates);
+
+ List<String> superTemplates = new ArrayList<>(templateManager.getStandardSuperclassTemplates());
+ Collections.sort(superTemplates);
+ superTemplates.addAll(customTemplates);
+
+ List<String> subTemplates = new ArrayList<>(templateManager.getStandardSubclassTemplates());
+ Collections.sort(subTemplates);
+ subTemplates.addAll(customTemplates);
+
+ this.view.getSubclassTemplate().setModel(new DefaultComboBoxModel(subTemplates.toArray()));
+ this.view.getSuperclassTemplate().setModel(new DefaultComboBoxModel(superTemplates.toArray()));
+
+ superTemplate.updateView();
+ subTemplate.updateView();
+ }
+
+ public Component getView() {
+ return view;
+ }
+
+ public Collection<ClassGenerationAction> createGenerator() {
+
+ mode = modesByLabel.get(view.getGenerationMode().getSelectedItem()).toString();
+
+ Collection<ClassGenerationAction> generators = super.createGenerator();
+
+ String superKey = view.getSuperclassTemplate().getSelectedItem().toString();
+ String superTemplate = templateManager.getTemplatePath(superKey);
+
+ String subKey = view.getSubclassTemplate().getSelectedItem().toString();
+ String subTemplate = templateManager.getTemplatePath(subKey);
+
+ for (ClassGenerationAction generator : generators) {
+ generator.setSuperTemplate(superTemplate);
+ generator.setTemplate(subTemplate);
+ generator.setOverwrite(view.getOverwrite().isSelected());
+ generator.setUsePkgPath(view.getUsePackagePath().isSelected());
+ generator.setMakePairs(view.getPairs().isSelected());
+ generator.setCreatePropertyNames(view.getCreatePropertyNames().isSelected());
+
+ if (!Util.isEmptyString(view.getOutputPattern().getText())) {
+ generator.setOutputPattern(view.getOutputPattern().getText());
+ }
+ }
+
+ return generators;
+ }
+
+ public void popPreferencesAction() {
+ new PreferenceDialog(getApplication().getFrameController()).startupAction(PreferenceDialog.TEMPLATES_KEY);
+ updateTemplates();
+ }
+
+ @Override
+ protected ClassGenerationAction newGenerator() {
+ ClassGenerationAction action = new ClassGenerationAction();
+ getApplication().getInjector().injectMembers(action);
+ return action;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/8119ffaa/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/CustomModePanel.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/CustomModePanel.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/CustomModePanel.java
new file mode 100644
index 0000000..538ff64
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/CustomModePanel.java
@@ -0,0 +1,189 @@
+/*****************************************************************
+ * 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.cgen;
+
+import com.jgoodies.forms.builder.DefaultFormBuilder;
+import com.jgoodies.forms.layout.FormLayout;
+import org.apache.cayenne.swing.control.ActionLink;
+
+import javax.swing.*;
+import java.awt.*;
+
+public class CustomModePanel extends GeneratorControllerPanel {
+
+ protected JComboBox generationMode;
+ protected JComboBox subclassTemplate;
+ protected JComboBox superclassTemplate;
+ protected JCheckBox pairs;
+ protected JCheckBox overwrite;
+ protected JCheckBox usePackagePath;
+ protected JTextField outputPattern;
+ protected JCheckBox createPropertyNames;
+
+ private JTextField additionalMaps;
+ private JButton selectAdditionalMaps;
+ private JCheckBox client;
+ private JTextField encoding;
+ private JComboBox embeddableTemplate;
+ private JComboBox embeddableSuperTemplate;
+ private JLabel dataMapName;
+
+ private DefaultFormBuilder builder;
+
+ protected ActionLink manageTemplatesLink;
+
+ private StandardPanelComponent standardPanelComponent;
+
+ public CustomModePanel() {
+
+ this.generationMode = new JComboBox();
+ this.superclassTemplate = new JComboBox();
+ this.subclassTemplate = new JComboBox();
+ this.pairs = new JCheckBox();
+ this.overwrite = new JCheckBox();
+ this.usePackagePath = new JCheckBox();
+ this.outputPattern = new JTextField();
+ this.createPropertyNames = new JCheckBox();
+ this.manageTemplatesLink = new ActionLink("Customize Templates...");
+ manageTemplatesLink.setFont(manageTemplatesLink.getFont().deriveFont(10f));
+
+ this.standardPanelComponent = new StandardPanelComponent();
+
+ this.additionalMaps = new JTextField();
+ this.selectAdditionalMaps = new JButton("Select");
+ this.client = new JCheckBox();
+ this.encoding = new JTextField();
+ this.embeddableTemplate = new JComboBox();
+ this.embeddableSuperTemplate = new JComboBox();
+ this.dataMapName = new JLabel();
+ this.dataMapName.setFont(dataMapName.getFont().deriveFont(1));
+
+ pairs.addChangeListener(e -> {
+ superclassTemplate.setEnabled(pairs.isSelected());
+ overwrite.setEnabled(!pairs.isSelected());
+ });
+
+ // assemble
+
+ FormLayout layout = new FormLayout(
+ "right:77dlu, 3dlu, fill:200:grow, 6dlu, fill:50dlu, 3dlu", "");
+ builder = new DefaultFormBuilder(layout);
+ builder.setDefaultDialogBorder();
+
+ builder.append("Output Directory:", outputFolder, selectOutputFolder);
+ builder.nextLine();
+
+ builder.append("Additional DataMaps", additionalMaps, selectAdditionalMaps);
+ builder.nextLine();
+
+ builder.append("Generation Mode:", generationMode);
+ builder.nextLine();
+
+ builder.append("Subclass Template:", subclassTemplate);
+ builder.nextLine();
+
+ builder.append("Superclass Template:", superclassTemplate);
+ builder.nextLine();
+
+ builder.append("Embeddable Template", embeddableTemplate);
+ builder.nextLine();
+
+ builder.append("Embeddable Super Template", embeddableSuperTemplate);
+ builder.nextLine();
+
+ builder.append("Output Pattern:", outputPattern);
+ builder.nextLine();
+
+ builder.append("Encoding", encoding);
+ builder.nextLine();
+
+ builder.append("Make Pairs:", pairs);
+ builder.nextLine();
+
+ builder.append("Use Package Path:", usePackagePath);
+ builder.nextLine();
+
+ builder.append("Overwrite Subclasses:", overwrite);
+ builder.nextLine();
+
+ builder.append("Create Property Names:", createPropertyNames);
+ builder.nextLine();
+
+ builder.append("Client", client);
+ builder.nextLine();
+
+ builder.append(standardPanelComponent, 4);
+
+ setLayout(new BorderLayout());
+ add(builder.getPanel(), BorderLayout.CENTER);
+
+ JPanel links = new JPanel(new FlowLayout(FlowLayout.TRAILING));
+ links.add(manageTemplatesLink);
+ add(links, BorderLayout.SOUTH);
+
+ add(builder.getPanel(), BorderLayout.CENTER);
+ }
+
+ public void addDataMapLine(StandardPanelComponent dataMapLine) {
+ dataMapLines.add(dataMapLine);
+ builder.append(dataMapLine, 4);
+ builder.nextLine();
+ }
+
+ public JComboBox getGenerationMode() {
+ return generationMode;
+ }
+
+ public ActionLink getManageTemplatesLink() {
+ return manageTemplatesLink;
+ }
+
+ public JComboBox getSubclassTemplate() {
+ return subclassTemplate;
+ }
+
+ public JComboBox getSuperclassTemplate() {
+ return superclassTemplate;
+ }
+
+ public JCheckBox getOverwrite() {
+ return overwrite;
+ }
+
+ public JCheckBox getPairs() {
+ return pairs;
+ }
+
+ public JCheckBox getUsePackagePath() {
+ return usePackagePath;
+ }
+
+ public JTextField getOutputPattern() {
+ return outputPattern;
+ }
+
+ public JCheckBox getCreatePropertyNames() {
+ return createPropertyNames;
+ }
+
+ public StandardPanelComponent getStandardPanelComponent() {
+ return standardPanelComponent;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/8119ffaa/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/CustomPreferencesUpdater.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/CustomPreferencesUpdater.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/CustomPreferencesUpdater.java
new file mode 100644
index 0000000..469e594
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/CustomPreferencesUpdater.java
@@ -0,0 +1,193 @@
+/*****************************************************************
+ * 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.cgen;
+
+import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.modeler.pref.DataMapDefaults;
+
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+public class CustomPreferencesUpdater {
+
+ enum Property {
+ SUBCLASS_TEMPLATE,
+ SUPERCLASS_TEMPLATE,
+ OVERWRITE,
+ PAIRS,
+ USE_PACKAGE_PATH,
+ MODE,
+ OUTPUT_PATTERN,
+ CREATE_PROPERTY_NAMES
+ }
+
+ private static final String OVERWRITE = "overwrite";
+ private static final String PAIRS = "pairs";
+ private static final String USE_PACKAGE_PATH = "usePackagePath";
+ private static final String MODE = "mode";
+ private static final String OUTPUT_PATTERN = "outputPattern";
+ private static final String CREATE_PROPERTY_NAMES = "createPropertyNames";
+
+ private Map<DataMap, DataMapDefaults> mapPreferences;
+
+
+ public CustomPreferencesUpdater(Map<DataMap, DataMapDefaults> mapPreferences) {
+ this.mapPreferences = mapPreferences;
+ }
+
+ public String getMode() {
+ return (String) getProperty(Property.MODE);
+ }
+
+ public void setMode(String mode) {
+ updatePreferences(Property.MODE, mode);
+ }
+
+ public String getSubclassTemplate() {
+ return (String) getProperty(Property.SUBCLASS_TEMPLATE);
+ }
+
+ public void setSubclassTemplate(String subclassTemplate) {
+ updatePreferences(Property.SUBCLASS_TEMPLATE, subclassTemplate);
+ }
+
+ public String getSuperclassTemplate() {
+ return (String) getProperty(Property.SUPERCLASS_TEMPLATE);
+ }
+
+ public void setSuperclassTemplate(String superclassTemplate) {
+ updatePreferences(Property.SUPERCLASS_TEMPLATE, superclassTemplate);
+ }
+
+ public Boolean getOverwrite() {
+ return (Boolean) getProperty(Property.OVERWRITE);
+ }
+
+ public void setOverwrite(Boolean overwrite) {
+ updatePreferences(Property.OVERWRITE, overwrite);
+ }
+
+ public Boolean getPairs() {
+ return (Boolean) getProperty(Property.PAIRS);
+ }
+
+ public void setPairs(Boolean pairs) {
+ updatePreferences(Property.PAIRS, pairs);
+ }
+
+ public Boolean getUsePackagePath() {
+ return (Boolean) getProperty(Property.USE_PACKAGE_PATH);
+ }
+
+ public void setUsePackagePath(Boolean usePackagePath) {
+ updatePreferences(Property.USE_PACKAGE_PATH, usePackagePath);
+ }
+
+ public String getOutputPattern() {
+ return (String) getProperty(Property.OUTPUT_PATTERN);
+ }
+
+ public void setOutputPattern(String outputPattern) {
+ updatePreferences(Property.OUTPUT_PATTERN, outputPattern);
+ }
+
+ public Boolean getCreatePropertyNames() {
+ return (Boolean) getProperty(Property.CREATE_PROPERTY_NAMES);
+ }
+
+ public void setCreatePropertyNames(Boolean createPropertyNames) {
+ updatePreferences(Property.CREATE_PROPERTY_NAMES, createPropertyNames);
+ }
+
+ private Object getProperty(Property property) {
+ Object obj = null;
+
+ Set<Entry<DataMap, DataMapDefaults>> entities = mapPreferences.entrySet();
+ for (Entry<DataMap, DataMapDefaults> entry : entities) {
+
+ switch (property) {
+ case MODE:
+ obj = entry.getValue().getProperty(MODE);
+ break;
+ case OUTPUT_PATTERN:
+ obj = entry.getValue().getProperty(OUTPUT_PATTERN);
+ break;
+ case SUBCLASS_TEMPLATE:
+ obj = entry.getValue().getSubclassTemplate();
+ break;
+ case SUPERCLASS_TEMPLATE:
+ obj = entry.getValue().getSuperclassTemplate();
+ break;
+ case OVERWRITE:
+ obj = entry.getValue().getBooleanProperty(OVERWRITE);
+ break;
+ case PAIRS:
+ obj = entry.getValue().getBooleanProperty(PAIRS);
+ break;
+ case USE_PACKAGE_PATH:
+ obj = entry.getValue().getBooleanProperty(USE_PACKAGE_PATH);
+ break;
+ case CREATE_PROPERTY_NAMES:
+ obj = entry.getValue().getBooleanProperty(CREATE_PROPERTY_NAMES);
+ break;
+ default:
+ throw new IllegalArgumentException("Bad type property: " + property);
+ }
+
+ }
+ return obj;
+ }
+
+ private void updatePreferences(Property property, Object value) {
+ Set<Entry<DataMap, DataMapDefaults>> entities = mapPreferences.entrySet();
+ for (Entry<DataMap, DataMapDefaults> entry : entities) {
+
+ switch (property) {
+ case MODE:
+ entry.getValue().setProperty(MODE, (String) value);
+ break;
+ case OUTPUT_PATTERN:
+ entry.getValue().setProperty(OUTPUT_PATTERN, (String) value);
+ break;
+ case SUBCLASS_TEMPLATE:
+ entry.getValue().setSubclassTemplate((String) value);
+ break;
+ case SUPERCLASS_TEMPLATE:
+ entry.getValue().setSuperclassTemplate((String) value);
+ break;
+ case OVERWRITE:
+ entry.getValue().setBooleanProperty(OVERWRITE, (Boolean) value);
+ break;
+ case PAIRS:
+ entry.getValue().setBooleanProperty(PAIRS, (Boolean) value);
+ break;
+ case USE_PACKAGE_PATH:
+ entry.getValue().setBooleanProperty(USE_PACKAGE_PATH, (Boolean) value);
+ break;
+ case CREATE_PROPERTY_NAMES:
+ entry.getValue().setBooleanProperty(CREATE_PROPERTY_NAMES, (Boolean) value);
+ break;
+ default:
+ throw new IllegalArgumentException("Bad type property: " + property);
+ }
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cayenne/blob/8119ffaa/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/GeneratorController.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/GeneratorController.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/GeneratorController.java
new file mode 100644
index 0000000..9370e3b
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/GeneratorController.java
@@ -0,0 +1,568 @@
+/*****************************************************************
+ * 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.cgen;
+
+import org.apache.cayenne.CayenneRuntimeException;
+import org.apache.cayenne.gen.ArtifactsGenerationMode;
+import org.apache.cayenne.gen.ClassGenerationAction;
+import org.apache.cayenne.map.*;
+import org.apache.cayenne.modeler.Application;
+import org.apache.cayenne.modeler.dialog.pref.GeneralPreferences;
+import org.apache.cayenne.modeler.pref.DataMapDefaults;
+import org.apache.cayenne.modeler.pref.FSPath;
+import org.apache.cayenne.modeler.util.CayenneController;
+import org.apache.cayenne.modeler.util.CodeValidationUtil;
+import org.apache.cayenne.swing.BindingBuilder;
+import org.apache.cayenne.util.Util;
+import org.apache.cayenne.validation.BeanValidationFailure;
+import org.apache.cayenne.validation.SimpleValidationFailure;
+import org.apache.cayenne.validation.ValidationFailure;
+import org.apache.cayenne.validation.ValidationResult;
+
+import javax.swing.*;
+import java.io.File;
+import java.util.*;
+import java.util.function.Predicate;
+import java.util.prefs.Preferences;
+
+/**
+ * A mode-specific part of the code generation dialog.
+ *
+ */
+public abstract class GeneratorController extends CayenneController {
+
+ protected String mode = ArtifactsGenerationMode.ALL.getLabel();
+ protected Map<DataMap, DataMapDefaults> mapPreferences;
+ private String outputPath;
+
+ public GeneratorController(CodeGeneratorControllerBase parent) {
+ super(parent);
+ }
+
+ public void startup(DataMap dataMap){
+ createDefaults();
+ createView();
+// initBindings(new BindingBuilder(getApplication().getBindingFactory(), this));
+ }
+
+ public String getOutputPath() {
+ return outputPath;
+ }
+
+ public void setOutputPath(String path) {
+ String old = this.outputPath;
+ this.outputPath = path;
+ if (this.outputPath != null && !this.outputPath.equals(old)) {
+ updatePreferences(path);
+ }
+ }
+
+ public void updatePreferences(String path) {
+ if (mapPreferences == null)
+ return;
+ Set<DataMap> keys = mapPreferences.keySet();
+ for (DataMap key : keys) {
+ mapPreferences
+ .get(key)
+ .setOutputPath(path);
+ }
+ }
+
+ public void setMapPreferences(Map<DataMap, DataMapDefaults> mapPreferences) {
+ this.mapPreferences = mapPreferences;
+ }
+
+ public Map<DataMap, DataMapDefaults> getMapPreferences() {
+ return this.mapPreferences;
+ }
+
+ protected void initBindings(BindingBuilder bindingBuilder) {
+
+ initOutputFolder();
+
+ JTextField outputFolder = ((GeneratorControllerPanel) getView()).getOutputFolder();
+ JButton outputSelect = ((GeneratorControllerPanel) getView()).getSelectOutputFolder();
+
+ outputFolder.setText(getOutputPath());
+ bindingBuilder.bindToAction(outputSelect, "selectOutputFolderAction()");
+ bindingBuilder.bindToTextField(outputFolder, "outputPath");
+ }
+
+ protected CodeGeneratorControllerBase getParentController() {
+ return (CodeGeneratorControllerBase) getParent();
+ }
+
+ protected abstract GeneratorControllerPanel createView();
+
+ protected abstract void createDefaults();
+
+ /**
+ * Creates an appropriate subclass of {@link ClassGenerationAction},
+ * returning it in an unconfigured state. Configuration is performed by
+ * {@link #createGenerator()} method.
+ */
+ protected abstract ClassGenerationAction newGenerator();
+
+ /**
+ * Creates a class generator for provided selections.
+ */
+ public Collection<ClassGenerationAction> createGenerator() {
+
+ File outputDir = getOutputDir();
+
+ // no destination folder
+ if (outputDir == null) {
+ JOptionPane.showMessageDialog(this.getView(), "Select directory for source files.");
+ return null;
+ }
+
+ // no such folder
+ if (!outputDir.exists() && !outputDir.mkdirs()) {
+ JOptionPane.showMessageDialog(this.getView(), "Can't create directory " + outputDir
+ + ". Select a different one.");
+ return null;
+ }
+
+ // not a directory
+ if (!outputDir.isDirectory()) {
+ JOptionPane.showMessageDialog(this.getView(), outputDir + " is not a valid directory.");
+ return null;
+ }
+
+ // remove generic entities...
+ Collection<ObjEntity> selectedEntities = new ArrayList<>(getParentController().getSelectedEntities());
+ selectedEntities.removeIf(ObjEntity::isGeneric);
+
+ Collection<ClassGenerationAction> generators = new ArrayList<>();
+ Collection<StandardPanelComponent> dataMapLines = ((GeneratorControllerPanel) getView()).getDataMapLines();
+ DataMap map = getParentController().getDataMap();
+ try {
+ ClassGenerationAction generator = newGenerator();
+ generator.setArtifactsGenerationMode(mode);
+ generator.setDataMap(map);
+
+ LinkedList<ObjEntity> objEntities = new LinkedList<>(map.getObjEntities());
+ objEntities.retainAll(selectedEntities);
+ generator.addEntities(objEntities);
+
+ LinkedList<Embeddable> embeddables = new LinkedList<>(map.getEmbeddables());
+ embeddables.retainAll(getParentController().getSelectedEmbeddables());
+ generator.addEmbeddables(embeddables);
+
+ generator.addQueries(map.getQueryDescriptors());
+
+ Preferences preferences = application.getPreferencesNode(GeneralPreferences.class, "");
+
+ if (preferences != null) {
+ generator.setEncoding(preferences.get(GeneralPreferences.ENCODING_PREFERENCE, null));
+ }
+
+ generator.setDestDir(outputDir);
+ generator.setMakePairs(true);
+ generator.setForce(true);
+
+ for (StandardPanelComponent dataMapLine : dataMapLines) {
+ if (dataMapLine.getDataMap() == map && !Util.isEmptyString(dataMapLine.getSuperclassPackage().getText())) {
+ generator.setSuperPkg(dataMapLine.getSuperclassPackage().getText());
+ break;
+ }
+ }
+
+ generators.add(generator);
+ } catch (CayenneRuntimeException exception) {
+ JOptionPane.showMessageDialog(this.getView(), exception.getUnlabeledMessage());
+ return null;
+ }
+
+
+ return generators;
+ }
+
+ public void validateEmbeddable(ValidationResult validationBuffer, Embeddable embeddable) {
+ ValidationFailure embeddableFailure = validateEmbeddable(embeddable);
+ if (embeddableFailure != null) {
+ validationBuffer.addFailure(embeddableFailure);
+ return;
+ }
+
+ for (EmbeddableAttribute attribute : embeddable.getAttributes()) {
+ ValidationFailure failure = validateEmbeddableAttribute(attribute);
+ if (failure != null) {
+ validationBuffer.addFailure(failure);
+ return;
+ }
+ }
+ }
+
+ private ValidationFailure validateEmbeddableAttribute(EmbeddableAttribute attribute) {
+ String name = attribute.getEmbeddable().getClassName();
+
+ ValidationFailure emptyName = BeanValidationFailure.validateNotEmpty(name, "attribute.name",
+ attribute.getName());
+ if (emptyName != null) {
+ return emptyName;
+ }
+
+ ValidationFailure badName = CodeValidationUtil.validateJavaIdentifier(name, "attribute.name",
+ attribute.getName());
+ if (badName != null) {
+ return badName;
+ }
+
+ ValidationFailure emptyType = BeanValidationFailure.validateNotEmpty(name, "attribute.type",
+ attribute.getType());
+ if (emptyType != null) {
+ return emptyType;
+ }
+
+ ValidationFailure badType = BeanValidationFailure.validateJavaClassName(name, "attribute.type",
+ attribute.getType());
+ if (badType != null) {
+ return badType;
+ }
+
+ return null;
+ }
+
+ protected ValidationFailure validateEmbeddable(Embeddable embeddable) {
+
+ String name = embeddable.getClassName();
+
+ ValidationFailure emptyClass = BeanValidationFailure.validateNotEmpty(name, "className",
+ embeddable.getClassName());
+ if (emptyClass != null) {
+ return emptyClass;
+ }
+
+ ValidationFailure badClass = BeanValidationFailure.validateJavaClassName(name, "className",
+ embeddable.getClassName());
+ if (badClass != null) {
+ return badClass;
+ }
+
+ return null;
+ }
+
+ public void validateEntity(ValidationResult validationBuffer, ObjEntity entity, boolean clientValidation) {
+
+ ValidationFailure entityFailure = validateEntity(clientValidation ? entity.getClientEntity() : entity);
+ if (entityFailure != null) {
+ validationBuffer.addFailure(entityFailure);
+ return;
+ }
+
+ for (ObjAttribute attribute : entity.getAttributes()) {
+ if (attribute instanceof EmbeddedAttribute) {
+ EmbeddedAttribute embeddedAttribute = (EmbeddedAttribute) attribute;
+ for (ObjAttribute subAttribute : embeddedAttribute.getAttributes()) {
+ ValidationFailure failure = validateEmbeddedAttribute(subAttribute);
+ if (failure != null) {
+ validationBuffer.addFailure(failure);
+ return;
+ }
+ }
+ } else {
+
+ ValidationFailure failure = validateAttribute(attribute);
+ if (failure != null) {
+ validationBuffer.addFailure(failure);
+ return;
+ }
+ }
+ }
+
+ for (ObjRelationship rel : entity.getRelationships()) {
+ ValidationFailure failure = validateRelationship(rel, clientValidation);
+ if (failure != null) {
+ validationBuffer.addFailure(failure);
+ return;
+ }
+ }
+ }
+
+ protected ValidationFailure validateEntity(ObjEntity entity) {
+
+ String name = entity.getName();
+
+ if (entity.isGeneric()) {
+ return new SimpleValidationFailure(name, "Generic class");
+ }
+
+ ValidationFailure emptyClass = BeanValidationFailure.validateNotEmpty(name, "className", entity.getClassName());
+ if (emptyClass != null) {
+ return emptyClass;
+ }
+
+ ValidationFailure badClass = BeanValidationFailure.validateJavaClassName(name, "className",
+ entity.getClassName());
+ if (badClass != null) {
+ return badClass;
+ }
+
+ if (entity.getSuperClassName() != null) {
+ ValidationFailure badSuperClass = BeanValidationFailure.validateJavaClassName(name, "superClassName",
+ entity.getSuperClassName());
+ if (badSuperClass != null) {
+ return badSuperClass;
+ }
+ }
+
+ return null;
+ }
+
+ protected ValidationFailure validateAttribute(ObjAttribute attribute) {
+
+ String name = attribute.getEntity().getName();
+
+ ValidationFailure emptyName = BeanValidationFailure.validateNotEmpty(name, "attribute.name",
+ attribute.getName());
+ if (emptyName != null) {
+ return emptyName;
+ }
+
+ ValidationFailure badName = CodeValidationUtil.validateJavaIdentifier(name, "attribute.name",
+ attribute.getName());
+ if (badName != null) {
+ return badName;
+ }
+
+ ValidationFailure emptyType = BeanValidationFailure.validateNotEmpty(name, "attribute.type",
+ attribute.getType());
+ if (emptyType != null) {
+ return emptyType;
+ }
+
+ ValidationFailure badType = BeanValidationFailure.validateJavaClassName(name, "attribute.type",
+ attribute.getType());
+ if (badType != null) {
+ return badType;
+ }
+
+ return null;
+ }
+
+ protected ValidationFailure validateEmbeddedAttribute(ObjAttribute attribute) {
+
+ String name = attribute.getEntity().getName();
+
+ // validate embeddedAttribute and attribute names
+ // embeddedAttribute returned attibute as
+ // [name_embeddedAttribute].[name_attribute]
+ String[] attributes = attribute.getName().split("\\.");
+ String nameEmbeddedAttribute = attributes[0];
+ int beginIndex = attributes[0].length();
+ String attr = attribute.getName().substring(beginIndex + 1);
+
+ ValidationFailure emptyEmbeddedName = BeanValidationFailure.validateNotEmpty(name, "attribute.name",
+ nameEmbeddedAttribute);
+ if (emptyEmbeddedName != null) {
+ return emptyEmbeddedName;
+ }
+
+ ValidationFailure badEmbeddedName = CodeValidationUtil.validateJavaIdentifier(name, "attribute.name",
+ nameEmbeddedAttribute);
+ if (badEmbeddedName != null) {
+ return badEmbeddedName;
+ }
+
+ ValidationFailure emptyName = BeanValidationFailure.validateNotEmpty(name, "attribute.name", attr);
+ if (emptyName != null) {
+ return emptyName;
+ }
+
+ ValidationFailure badName = CodeValidationUtil.validateJavaIdentifier(name, "attribute.name", attr);
+ if (badName != null) {
+ return badName;
+ }
+
+ ValidationFailure emptyType = BeanValidationFailure.validateNotEmpty(name, "attribute.type",
+ attribute.getType());
+ if (emptyType != null) {
+ return emptyType;
+ }
+
+ ValidationFailure badType = BeanValidationFailure.validateJavaClassName(name, "attribute.type",
+ attribute.getType());
+ if (badType != null) {
+ return badType;
+ }
+
+ return null;
+ }
+
+ protected ValidationFailure validateRelationship(ObjRelationship relationship, boolean clientValidation) {
+
+ String name = relationship.getSourceEntity().getName();
+
+ ValidationFailure emptyName = BeanValidationFailure.validateNotEmpty(name, "relationship.name",
+ relationship.getName());
+ if (emptyName != null) {
+ return emptyName;
+ }
+
+ ValidationFailure badName = CodeValidationUtil.validateJavaIdentifier(name, "relationship.name",
+ relationship.getName());
+ if (badName != null) {
+ return badName;
+ }
+
+ if (!relationship.isToMany()) {
+
+ ObjEntity targetEntity = relationship.getTargetEntity();
+
+ if (clientValidation && targetEntity != null) {
+ targetEntity = targetEntity.getClientEntity();
+ }
+
+ if (targetEntity == null) {
+
+ return new BeanValidationFailure(name, "relationship.targetEntity", "No target entity");
+ } else if (!targetEntity.isGeneric()) {
+ ValidationFailure emptyClass = BeanValidationFailure.validateNotEmpty(name,
+ "relationship.targetEntity.className", targetEntity.getClassName());
+ if (emptyClass != null) {
+ return emptyClass;
+ }
+
+ ValidationFailure badClass = BeanValidationFailure.validateJavaClassName(name,
+ "relationship.targetEntity.className", targetEntity.getClassName());
+ if (badClass != null) {
+ return badClass;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns a predicate for default entity selection in a given mode.
+ */
+ public Predicate getDefaultClassFilter() {
+ final ObjEntity selectedEntity = Application.getInstance().getFrameController().getProjectController()
+ .getCurrentObjEntity();
+
+ final Embeddable selectedEmbeddable = Application.getInstance().getFrameController().getProjectController()
+ .getCurrentEmbeddable();
+
+ if (selectedEntity != null) {
+ // select a single entity
+ final boolean hasProblem = getParentController().getProblem(selectedEntity.getName()) != null;
+ return object -> !hasProblem && object == selectedEntity;
+ } else if (selectedEmbeddable != null) {
+ // select a single embeddable
+ final boolean hasProblem = getParentController().getProblem(selectedEmbeddable.getClassName()) != null;
+ return object -> !hasProblem && object == selectedEmbeddable;
+ } else {
+ // select all entities
+ return object -> {
+ if (object instanceof ObjEntity) {
+ return getParentController().getProblem(((ObjEntity) object).getName()) == null;
+ }
+
+ if (object instanceof Embeddable) {
+ return getParentController().getProblem(((Embeddable) object).getClassName()) == null;
+ }
+
+ return false;
+ };
+ }
+ }
+
+ public File getOutputDir() {
+ String dir = ((GeneratorControllerPanel) getView()).getOutputFolder().getText();
+ return dir != null ? new File(dir) : new File(System.getProperty("user.dir"));
+ }
+
+ /**
+ * An action method that pops up a file chooser dialog to pick the
+ * generation directory.
+ */
+ public void selectOutputFolderAction() {
+
+ JTextField outputFolder = ((GeneratorControllerPanel) getView()).getOutputFolder();
+
+ String currentDir = outputFolder.getText();
+
+ JFileChooser chooser = new JFileChooser();
+ chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+ chooser.setDialogType(JFileChooser.OPEN_DIALOG);
+
+ // guess start directory
+ if (!Util.isEmptyString(currentDir)) {
+ chooser.setCurrentDirectory(new File(currentDir));
+ } else {
+ FSPath lastDir = Application.getInstance().getFrameController().getLastDirectory();
+ lastDir.updateChooser(chooser);
+ }
+
+ int result = chooser.showOpenDialog(getView());
+ if (result == JFileChooser.APPROVE_OPTION) {
+ File selected = chooser.getSelectedFile();
+
+ // update model
+ String path = selected.getAbsolutePath();
+ outputFolder.setText(path);
+ setOutputPath(path);
+ }
+ }
+
+ private void initOutputFolder() {
+ String path;
+ if (getOutputPath() == null) {
+ if (System.getProperty("cayenne.cgen.destdir") != null) {
+ setOutputPath(System.getProperty("cayenne.cgen.destdir"));
+ } else {
+ // init default directory..
+ FSPath lastPath = Application.getInstance().getFrameController().getLastDirectory();
+
+ path = checkDefaultMavenResourceDir(lastPath, "test");
+
+ if (path != null || (path = checkDefaultMavenResourceDir(lastPath, "main")) != null) {
+ setOutputPath(path);
+ } else {
+ File lastDir = (lastPath != null) ? lastPath.getExistingDirectory(false) : null;
+ setOutputPath(lastDir != null ? lastDir.getAbsolutePath() : null);
+ }
+ }
+ }
+ }
+
+ private String checkDefaultMavenResourceDir(FSPath lastPath, String dirType) {
+ String path = lastPath.getPath();
+ String resourcePath = buildFilePath("src", dirType, "resources");
+ int idx = path.indexOf(resourcePath);
+ if (idx < 0) {
+ return null;
+ }
+ return path.substring(0, idx) + buildFilePath("src", dirType, "java");
+ }
+
+ private static String buildFilePath(String... pathElements) {
+ if (pathElements.length == 0) {
+ return "";
+ }
+ StringBuilder path = new StringBuilder(pathElements[0]);
+ for (int i = 1; i < pathElements.length; i++) {
+ path.append(File.separator).append(pathElements[i]);
+ }
+ return path.toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/cayenne/blob/8119ffaa/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/GeneratorControllerPanel.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/GeneratorControllerPanel.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/GeneratorControllerPanel.java
new file mode 100644
index 0000000..9b836bd
--- /dev/null
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/cgen/GeneratorControllerPanel.java
@@ -0,0 +1,53 @@
+/*****************************************************************
+ * 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.cgen;
+
+import javax.swing.*;
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * A generic panel that is a superclass of generator panels, defining common fields.
+ *
+ */
+public class GeneratorControllerPanel extends JPanel {
+
+ protected Collection<StandardPanelComponent> dataMapLines;
+ protected JTextField outputFolder;
+ protected JButton selectOutputFolder;
+
+ public GeneratorControllerPanel() {
+ this.dataMapLines = new ArrayList<>();
+ this.outputFolder = new JTextField();
+ this.selectOutputFolder = new JButton("Select");
+ }
+
+ public JTextField getOutputFolder() {
+ return outputFolder;
+ }
+
+ public JButton getSelectOutputFolder() {
+ return selectOutputFolder;
+ }
+
+ public Collection<StandardPanelComponent> getDataMapLines() {
+ return dataMapLines;
+ }
+}