You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by km...@apache.org on 2008/08/01 20:42:57 UTC
svn commit: r681776 - in
/cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler:
dialog/objentity/ editor/ util/
Author: kmenard
Date: Fri Aug 1 11:42:55 2008
New Revision: 681776
URL: http://svn.apache.org/viewvc?rev=681776&view=rev
Log:
CAY-1077: ObjRelationship Mapping Dialog Improvements
Added:
cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/objentity/ObjRelationshipPathBrowser.java
cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/EntityTreeFilter.java
Modified:
cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/objentity/ObjRelationshipInfoController.java
cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/objentity/ObjRelationshipInfoDialog.java
cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/objentity/ObjRelationshipInfoModel.java
cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjEntityRelationshipTab.java
cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjRelationshipTableModel.java
cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SelectQueryPrefetchTab.java
cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/EntityTreeModel.java
cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/MultiColumnBrowser.java
Modified: cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/objentity/ObjRelationshipInfoController.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/objentity/ObjRelationshipInfoController.java?rev=681776&r1=681775&r2=681776&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/objentity/ObjRelationshipInfoController.java (original)
+++ cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/objentity/ObjRelationshipInfoController.java Fri Aug 1 11:42:55 2008
@@ -19,25 +19,32 @@
package org.apache.cayenne.modeler.dialog.objentity;
-import java.util.Collection;
-
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.map.DbRelationship;
-import org.apache.cayenne.map.ObjRelationship;
+import org.apache.cayenne.map.*;
import org.apache.cayenne.map.event.RelationshipEvent;
import org.apache.cayenne.modeler.Application;
import org.apache.cayenne.modeler.ProjectController;
import org.apache.cayenne.modeler.dialog.ResolveDbRelationshipDialog;
+import org.apache.cayenne.modeler.util.EntityTreeModel;
+import org.apache.cayenne.modeler.util.MultiColumnBrowser;
import org.apache.cayenne.project.NamedObjectFactory;
import org.scopemvc.controller.basic.BasicController;
import org.scopemvc.core.Control;
import org.scopemvc.core.ControlException;
+import javax.swing.*;
+import javax.swing.event.TreeSelectionEvent;
+import javax.swing.event.TreeSelectionListener;
+import javax.swing.tree.TreePath;
+import java.awt.*;
+import java.util.Collection;
+import java.util.List;
+import java.util.Vector;
+
/**
* @since 1.1
* @author Andrus Adamchik
*/
-public class ObjRelationshipInfoController extends BasicController {
+public class ObjRelationshipInfoController extends BasicController implements TreeSelectionListener {
public static final String SAVE_CONTROL = "cayenne.modeler.mapObjRelationship.save.button";
public static final String CANCEL_CONTROL = "cayenne.modeler.mapObjRelationship.cancel.button";
@@ -50,23 +57,41 @@
ObjRelationship relationship) {
this.mediator = mediator;
- Collection objEntities = mediator.getCurrentDataMap().getNamespace().getObjEntities();
+ Collection<ObjEntity> objEntities = mediator.getCurrentDataMap().getNamespace().getObjEntities();
ObjRelationshipInfoModel model = new ObjRelationshipInfoModel(
relationship,
objEntities);
setModel(model);
}
-
+
/**
* Creates and runs the classpath dialog.
*/
+ @Override
public void startup() {
+ /**
+ * Some workaround: need to save target first, because even if it is null,
+ * first item will be displayed in combobox. Also we do not want to have empty item
+ * in the combobox.
+ */
+ ObjRelationshipInfoModel model = (ObjRelationshipInfoModel) getModel();
+ ObjEntity target = model.getObjectTarget();
+
ObjRelationshipInfoDialog view = new ObjRelationshipInfoDialog();
setView(view);
+
+ model.setObjectTarget(target);
+
+ /**
+ * Register auto-selection of the target
+ */
+ view.getPathBrowser().addTreeSelectionListener(this);
+
view.initFromModel();
super.startup();
}
+ @Override
protected void doHandleControl(Control control) throws ControlException {
if (control.matchesID(CANCEL_CONTROL)) {
shutdown();
@@ -100,15 +125,19 @@
* name, and create joins.
*/
protected void createRelationship(boolean toMany) {
- cancelEditing();
-
ObjRelationshipInfoModel model = (ObjRelationshipInfoModel) getModel();
DbEntity source = model.getStartEntity();
DbEntity target = model.getEndEntity();
- EntityRelationshipsModel selectedPathComponent = model.getSelectedPathComponent();
- if (selectedPathComponent != null) {
- source = (DbEntity) selectedPathComponent.getSourceEntity();
+ DbRelationship dbRel = model.getLastRelationship();
+ if (dbRel != null) {
+ source = (DbEntity) dbRel.getSourceEntity();
+ }
+
+ if (target == null) {
+ JOptionPane.showMessageDialog((Component) getView(), "Please select target entity first.",
+ "Warning", JOptionPane.WARNING_MESSAGE);
+ return;
}
DbRelationship dbRelationship = (DbRelationship) NamedObjectFactory
@@ -129,20 +158,54 @@
source.removeRelationship(dbRelationship.getName());
}
else {
- if (selectedPathComponent == null) {
- selectedPathComponent = (EntityRelationshipsModel) model
- .getDbRelationshipPath()
- .get(0);
- model.setSelectedPathComponent(selectedPathComponent);
- }
-
- selectedPathComponent.setRelationshipName(dbRelationship.getName());
+ MultiColumnBrowser pathBrowser = ((ObjRelationshipInfoDialog) getView()).getPathBrowser();
+ Object[] oldPath = pathBrowser.getSelectionPath() == null ?
+ new Object[0] : pathBrowser.getSelectionPath().getPath();
+
+ /**
+ * Update the view
+ */
+ EntityTreeModel treeModel = (EntityTreeModel) pathBrowser.getModel();
+ treeModel.invalidateChildren(source);
+ treeModel.invalidateChildren(target);
+
+ Object[] path = new Object[Math.max(oldPath.length, 2)];
+ System.arraycopy(oldPath, 0, path, 0, path.length - 1);
+
+ path[path.length - 1] = dbRelationship;
+ pathBrowser.setSelectionPath(new TreePath(path));
}
dialog.dispose();
}
-
- protected void cancelEditing() {
- ((ObjRelationshipInfoDialog) getView()).cancelTableEditing();
+
+ public void valueChanged(TreeSelectionEvent e) {
+ TreePath selectedPath = e.getPath();
+
+ // first item in the path is Entity, so we must have
+ // at least two elements to constitute a valid ordering path
+ if (selectedPath == null || selectedPath.getPathCount() < 2) {
+ return;
+ }
+
+ Relationship rel = (Relationship) selectedPath.getLastPathComponent();
+ DbEntity target = (DbEntity) rel.getTargetEntity();
+
+ ObjRelationshipInfoModel model = (ObjRelationshipInfoModel) getModel();
+
+ /**
+ * Initialize root with one of mapped ObjEntities.
+ */
+ Collection<ObjEntity> objEntities = target.getDataMap().getMappedEntities(target);
+ model.setObjectTarget(objEntities.size() == 0 ? null : objEntities.iterator().next());
+
+ List<DbRelationship> relPath = new Vector<DbRelationship>(selectedPath.getPathCount() - 1);
+ for (int i = 1; i < selectedPath.getPathCount(); i++) {
+ relPath.add((DbRelationship) selectedPath.getPathComponent(i));
+ }
+ model.setDbRelationships(relPath);
+
+ ((ObjRelationshipInfoDialog) getView()).updateCollectionChoosers();
}
+
}
Modified: cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/objentity/ObjRelationshipInfoDialog.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/objentity/ObjRelationshipInfoDialog.java?rev=681776&r1=681775&r2=681776&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/objentity/ObjRelationshipInfoDialog.java (original)
+++ cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/objentity/ObjRelationshipInfoDialog.java Fri Aug 1 11:42:55 2008
@@ -19,38 +19,24 @@
package org.apache.cayenne.modeler.dialog.objentity;
-import java.awt.BorderLayout;
-import java.awt.Component;
-import java.awt.Dimension;
-import java.awt.FlowLayout;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-
-import javax.swing.DefaultCellEditor;
-import javax.swing.DefaultComboBoxModel;
-import javax.swing.JButton;
-import javax.swing.JComboBox;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JTable;
-import javax.swing.table.TableCellEditor;
-
-import org.apache.cayenne.modeler.util.PanelFactory;
-import org.scopemvc.core.Selector;
-import org.scopemvc.view.swing.SAction;
-import org.scopemvc.view.swing.SButton;
-import org.scopemvc.view.swing.SComboBox;
-import org.scopemvc.view.swing.SLabel;
-import org.scopemvc.view.swing.SListCellRenderer;
-import org.scopemvc.view.swing.SPanel;
-import org.scopemvc.view.swing.STable;
-import org.scopemvc.view.swing.STableModel;
-import org.scopemvc.view.swing.STextField;
-import org.scopemvc.view.swing.SwingView;
-
import com.jgoodies.forms.builder.PanelBuilder;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;
+import org.apache.cayenne.map.Attribute;
+import org.apache.cayenne.map.DbRelationship;
+import org.apache.cayenne.map.Relationship;
+import org.apache.cayenne.modeler.util.EntityTreeFilter;
+import org.apache.cayenne.modeler.util.EntityTreeModel;
+import org.apache.cayenne.modeler.util.MultiColumnBrowser;
+import org.apache.cayenne.modeler.util.PanelFactory;
+import org.scopemvc.view.swing.*;
+
+import javax.swing.*;
+import javax.swing.tree.TreePath;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.List;
/**
* A view of the dialog for mapping an ObjRelationship to one or more DbRelationships.
@@ -60,7 +46,12 @@
*/
public class ObjRelationshipInfoDialog extends SPanel {
- protected STable pathTable;
+ static final Dimension BROWSER_CELL_DIM = new Dimension(130, 200);
+
+ /**
+ * Browser to select path for flattened relationship
+ */
+ protected MultiColumnBrowser pathBrowser;
protected Component collectionTypeLabel;
protected SComboBox collectionTypeCombo;
@@ -110,28 +101,16 @@
mapKeysCombo = new SComboBox();
mapKeysCombo.setSelector(ObjRelationshipInfoModel.MAP_KEYS_SELECTOR);
mapKeysCombo.setSelectionSelector(ObjRelationshipInfoModel.MAP_KEY_SELECTOR);
-
- pathTable = new ObjRelationshipPathTable();
- STableModel pathTableModel = new STableModel(pathTable);
- pathTableModel
- .setSelector(ObjRelationshipInfoModel.DB_RELATIONSHIP_PATH_SELECTOR);
- pathTableModel.setColumnNames(new String[] {
- "DbRelationships"
- });
- pathTableModel.setColumnSelectors(new Selector[] {
- EntityRelationshipsModel.RELATIONSHIP_DISPLAY_NAME_SELECTOR
- });
-
- pathTable.setModel(pathTableModel);
- pathTable
- .setSelectionSelector(ObjRelationshipInfoModel.SELECTED_PATH_COMPONENT_SELECTOR);
- pathTable.getColumn("DbRelationships").setCellEditor(createRelationshipEditor());
-
+
+ pathBrowser = new ObjRelationshipPathBrowser();
+ pathBrowser.setPreferredColumnSize(BROWSER_CELL_DIM);
+ pathBrowser.setDefaultRenderer();
+
// enable/disable map keys for collection type selection
collectionTypeCombo.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent action) {
- initFromModel();
+ updateCollectionChoosers();
}
});
@@ -143,7 +122,7 @@
CellConstraints cc = new CellConstraints();
PanelBuilder builder = new PanelBuilder(
new FormLayout(
- "right:max(50dlu;pref), 3dlu, fill:min(150dlu;pref), 3dlu, fill:min(120dlu;pref)",
+ "right:max(50dlu;pref), 3dlu, fill:min(150dlu;pref), 3dlu, 120dlu, 3dlu, fill:min(120dlu;pref)",
"p, 3dlu, p, 3dlu, p, 3dlu, p, 3dlu, p, 3dlu, p, 3dlu, p, 3dlu, top:14dlu, 3dlu, top:p:grow"));
builder.setDefaultDialogBorder();
@@ -160,13 +139,16 @@
builder.add(mapKeysCombo, cc.xywh(3, 11, 1, 1));
builder.addSeparator("Mapping to DbRelationships", cc.xywh(1, 13, 5, 1));
- builder.add(new JScrollPane(pathTable), cc.xywh(1, 15, 3, 3));
+ builder.add(new JScrollPane(
+ pathBrowser,
+ JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
+ JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED), cc.xywh(1, 15, 5, 3));
JPanel newRelationshipsButtons = new JPanel(new FlowLayout(FlowLayout.LEADING));
newRelationshipsButtons.add(newToOneButton);
newRelationshipsButtons.add(newToManyButton);
- builder.add(newRelationshipsButtons, cc.xywh(5, 15, 1, 3));
+ builder.add(newRelationshipsButtons, cc.xywh(7, 15, 1, 3));
add(builder.getPanel(), BorderLayout.CENTER);
add(PanelFactory.createButtonPanel(new JButton[] {
@@ -175,112 +157,84 @@
}
/**
- * Cancels any editing that might be going on in the path table.
+ * @return relationship path browser
*/
- public void cancelTableEditing() {
- int row = pathTable.getEditingRow();
- if (row < 0) {
- return;
- }
+ public MultiColumnBrowser getPathBrowser() {
+ return pathBrowser;
+ }
- int column = pathTable.getEditingColumn();
- if (column < 0) {
+ void initFromModel() {
+ // called too early in the cycle...
+ if (!updateCollectionChoosers()) {
return;
}
- TableCellEditor editor = pathTable.getCellEditor(row, column);
- if (editor != null) {
- editor.cancelCellEditing();
+ ObjRelationshipInfoModel model = (ObjRelationshipInfoModel) getController()
+ .getModel();
+
+ if (pathBrowser.getModel() == null) {
+ EntityTreeModel treeModel = new EntityTreeModel(model.getStartEntity());
+ treeModel.setFilter(
+ new EntityTreeFilter() {
+ public boolean attributeMatch(Object node, Attribute attr) {
+ //attrs not allowed here
+ return false;
+ }
+
+ public boolean relationshipMatch(Object node, Relationship rel) {
+ if (!(node instanceof Relationship)) {
+ return true;
+ }
+
+ /**
+ * We do not allow A->B->A chains, where relationships are to-one
+ */
+ Relationship prev = (Relationship) node;
+
+ return !(!prev.isToMany() && !rel.isToMany() &&
+ rel.getTargetEntity() != null &&
+ prev.getSourceEntity() == rel.getTargetEntity() &&
+ prev.getSourceEntity() != prev.getTargetEntity());
+ }
+
+ });
+
+ pathBrowser.setModel(treeModel);
+
+ List<DbRelationship> rels = model.getDbRelationships();
+ if (rels.size() > 0) {
+ Object[] path = new Object[rels.size() + 1];
+ path[0] = model.getStartEntity();
+
+ System.arraycopy(rels.toArray(), 0, path, 1, rels.size());
+
+ pathBrowser.setSelectionPath(new TreePath(path));
+ }
}
}
-
- void initFromModel() {
- // called too early in the cycle...
+
+ /**
+ * Updates 'collection type' and 'map keys' comboboxes
+ */
+ boolean updateCollectionChoosers() {
if (getController() == null || getController().getModel() == null) {
- return;
+ return false;
}
-
+
ObjRelationshipInfoModel model = (ObjRelationshipInfoModel) getController()
.getModel();
-
+
boolean collectionTypeEnabled = model.isToMany();
collectionTypeCombo.setEnabled(collectionTypeEnabled);
collectionTypeLabel.setEnabled(collectionTypeEnabled);
-
+
boolean mapKeysEnabled = collectionTypeEnabled
&& ObjRelationshipInfoModel.COLLECTION_TYPE_MAP
.equals(collectionTypeCombo.getSelectedItem());
mapKeysCombo.setEnabled(mapKeysEnabled);
mapKeysLabel.setEnabled(mapKeysEnabled);
+
+ return true;
}
- TableCellEditor createRelationshipEditor() {
- JComboBox relationshipCombo = new JComboBox();
- relationshipCombo.setEditable(false);
-
- // enable disable collections when relationship semntics changes
- relationshipCombo.addActionListener(new ActionListener() {
-
- public void actionPerformed(ActionEvent event) {
- initFromModel();
- }
- });
-
- return new RelationshipPicker(this, relationshipCombo);
- }
-
- class ObjRelationshipPathTable extends STable {
-
- final Dimension preferredSize = new Dimension(203, 100);
-
- ObjRelationshipPathTable() {
- setRowHeight(25);
- setRowMargin(3);
- }
-
- public Dimension getPreferredScrollableViewportSize() {
- return preferredSize;
- }
- }
-
- final class RelationshipPicker extends DefaultCellEditor {
-
- JComboBox comboBox;
- SwingView view;
-
- RelationshipPicker(SwingView view, JComboBox comboBox) {
- super(comboBox);
- this.comboBox = comboBox;
- this.view = view;
- }
-
- public Component getTableCellEditorComponent(
- JTable table,
- Object value,
- boolean isSelected,
- int row,
- int column) {
-
- // initialize combo box
- ObjRelationshipInfoModel model = (ObjRelationshipInfoModel) view
- .getBoundModel();
-
- EntityRelationshipsModel relationshipWrapper = (EntityRelationshipsModel) model
- .getDbRelationshipPath()
- .get(row);
-
- DefaultComboBoxModel comboModel = new DefaultComboBoxModel(
- relationshipWrapper.getRelationshipNames());
- comboModel.setSelectedItem(value);
- comboBox.setModel(comboModel);
-
- // call super
- return super.getTableCellEditorComponent(
- table,
- value,
- isSelected,
- row,
- column);
- }
- }
}
Modified: cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/objentity/ObjRelationshipInfoModel.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/objentity/ObjRelationshipInfoModel.java?rev=681776&r1=681775&r2=681776&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/objentity/ObjRelationshipInfoModel.java (original)
+++ cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/objentity/ObjRelationshipInfoModel.java Fri Aug 1 11:42:55 2008
@@ -24,12 +24,9 @@
import org.apache.cayenne.modeler.util.Comparators;
import org.apache.cayenne.modeler.util.DeleteRuleUpdater;
import org.apache.cayenne.util.Util;
-import org.scopemvc.core.IntIndexSelector;
-import org.scopemvc.core.ModelChangeEvent;
import org.scopemvc.core.ModelChangeTypes;
import org.scopemvc.core.Selector;
import org.scopemvc.model.basic.BasicModel;
-import org.scopemvc.model.collection.ListModel;
import java.util.*;
@@ -42,14 +39,15 @@
public class ObjRelationshipInfoModel extends BasicModel {
static final String COLLECTION_TYPE_MAP = "java.util.Map";
+ static final String COLLECTION_TYPE_SET = "java.util.Set";
+ static final String COLLECTION_TYPE_COLLECTION = "java.util.Collection";
+
static final String DEFAULT_MAP_KEY = "ID (default)";
- public static final Selector DB_RELATIONSHIP_PATH_SELECTOR = Selector
- .fromString("dbRelationshipPath");
+ public static final Selector DB_RELATIONSHIPS_SELECTOR = Selector
+ .fromString("dbRelationships");
public static final Selector SOURCE_ENTITY_NAME_SELECTOR = Selector
.fromString("relationship.sourceEntity.name");
- public static final Selector SELECTED_PATH_COMPONENT_SELECTOR = Selector
- .fromString("selectedPathComponent");
public static final Selector OBJECT_TARGET_SELECTOR = Selector
.fromString("objectTarget");
public static final Selector OBJECT_TARGETS_SELECTOR = Selector
@@ -64,21 +62,25 @@
public static final Selector MAP_KEY_SELECTOR = Selector.fromString("mapKey");
protected ObjRelationship relationship;
- protected ListModel dbRelationshipPath;
- protected EntityRelationshipsModel selectedPathComponent;
+
+ /**
+ * List of DB Relationships current ObjRelationship is mapped to
+ */
+ protected List<DbRelationship> dbRelationships;
+
protected ObjEntity objectTarget;
- protected List objectTargets;
- protected List targetCollections;
+ protected List<ObjEntity> objectTargets;
+ protected List<String> targetCollections;
protected List mapKeys;
protected String relationshipName;
protected String targetCollection;
protected String mapKey;
- public ObjRelationshipInfoModel(ObjRelationship relationship, Collection objEntities) {
+ public ObjRelationshipInfoModel(ObjRelationship relationship, Collection<ObjEntity> objEntities) {
this.relationship = relationship;
this.relationshipName = relationship.getName();
- this.objectTarget = (ObjEntity) relationship.getTargetEntity();
+
this.mapKey = relationship.getMapKey();
this.targetCollection = relationship.getCollectionType();
if (targetCollection == null) {
@@ -87,14 +89,15 @@
// prepare entities - copy those that have DbEntities mapped, and then sort
- this.objectTargets = new ArrayList(objEntities.size());
- Iterator entities = objEntities.iterator();
+ this.objectTargets = new ArrayList<ObjEntity>(objEntities.size());
+ Iterator<ObjEntity> entities = objEntities.iterator();
while (entities.hasNext()) {
- ObjEntity entity = (ObjEntity) entities.next();
+ ObjEntity entity = entities.next();
if (entity.getDbEntity() != null) {
objectTargets.add(entity);
}
}
+ this.objectTarget = (ObjEntity) relationship.getTargetEntity();
Collections.sort(objectTargets, Comparators.getNamedObjectComparator());
@@ -103,52 +106,48 @@
// and target entities present, with DbEntities chosen.
validateCanMap();
- this.targetCollections = new ArrayList(4);
- targetCollections.add("java.util.Collection");
+ this.targetCollections = new ArrayList<String>(4);
+ targetCollections.add(COLLECTION_TYPE_COLLECTION);
targetCollections.add(ObjRelationship.DEFAULT_COLLECTION_TYPE);
targetCollections.add(COLLECTION_TYPE_MAP);
- targetCollections.add("java.util.Set");
+ targetCollections.add(COLLECTION_TYPE_SET);
this.mapKeys = new ArrayList();
initMapKeys();
- // wrap path
- this.dbRelationshipPath = new ListModel();
- Iterator it = relationship.getDbRelationships().iterator();
- while (it.hasNext()) {
- DbRelationship dbRelationship = (DbRelationship) it.next();
- this.dbRelationshipPath.add(new EntityRelationshipsModel(dbRelationship));
- }
+ // setup path
+ dbRelationships = new ArrayList<DbRelationship>(relationship.getDbRelationships());
// this sets the right enabled state of collection type selectors
- fireModelChange(ModelChangeTypes.VALUE_CHANGED, DB_RELATIONSHIP_PATH_SELECTOR);
+ fireModelChange(ModelChangeTypes.VALUE_CHANGED, DB_RELATIONSHIPS_SELECTOR);
// add dummy last relationship if we are not connected
connectEnds();
- this.dbRelationshipPath.addModelChangeListener(this);
}
public ObjRelationship getRelationship() {
return relationship;
}
-
- public ListModel getDbRelationshipPath() {
- return dbRelationshipPath;
+
+ /**
+ * @return list of DB Relationships current ObjRelationship is mapped to
+ */
+ public List<DbRelationship> getDbRelationships() {
+ return dbRelationships;
}
-
- public EntityRelationshipsModel getSelectedPathComponent() {
- return selectedPathComponent;
+
+ /**
+ * @return last relationship in the path, or <code>null</code> if path is empty
+ */
+ public DbRelationship getLastRelationship() {
+ return dbRelationships.size() == 0 ? null : dbRelationships.get(dbRelationships.size() - 1);
}
-
- public void setSelectedPathComponent(EntityRelationshipsModel selectedPathComponent) {
- if (this.selectedPathComponent != selectedPathComponent) {
- unlistenOldSubmodel(SELECTED_PATH_COMPONENT_SELECTOR);
- this.selectedPathComponent = selectedPathComponent;
- listenNewSubmodel(SELECTED_PATH_COMPONENT_SELECTOR);
- fireModelChange(
- ModelChangeTypes.VALUE_CHANGED,
- SELECTED_PATH_COMPONENT_SELECTOR);
- }
+
+ /**
+ * Sets list of DB Relationships current ObjRelationship is mapped to
+ */
+ public void setDbRelationships(List<DbRelationship> rels) {
+ this.dbRelationships = rels;
}
/**
@@ -168,11 +167,6 @@
listenNewSubmodel(OBJECT_TARGET_SELECTOR);
fireModelChange(ModelChangeTypes.VALUE_CHANGED, OBJECT_TARGET_SELECTOR);
- // change the list of relationships
- breakChain(-1);
- connectEnds();
- fireModelChange(ModelChangeTypes.VALUE_CHANGED, DB_RELATIONSHIP_PATH_SELECTOR);
-
// init available map keys
initMapKeys();
}
@@ -182,6 +176,13 @@
this.mapKeys.clear();
mapKeys.add(DEFAULT_MAP_KEY);
+
+ /**
+ * Object target can be null when selected target DbEntity has no ObjEntities
+ */
+ if (objectTarget == null) {
+ return;
+ }
Iterator attributes = this.objectTarget.getAttributes().iterator();
while (attributes.hasNext()) {
@@ -200,10 +201,10 @@
/**
* Returns a list of ObjEntities available for target mapping.
*/
- public List getObjectTargets() {
+ public List<ObjEntity> getObjectTargets() {
return objectTargets;
}
-
+
public String getRelationshipName() {
return relationshipName;
}
@@ -212,24 +213,6 @@
this.relationshipName = relationshipName;
}
- @Override
- public void modelChanged(ModelChangeEvent event) {
-
- // if a different relationship was selected, we may need to rebuild the list
- Selector selector = event.getSelector();
- while (selector != null) {
- if (selector instanceof IntIndexSelector) {
- IntIndexSelector indexSel = (IntIndexSelector) selector;
- relationshipChanged(indexSel.getIndex());
- break;
- }
-
- selector = selector.getNext();
- }
-
- super.modelChanged(event);
- }
-
/**
* Processes relationship path when path component at index was changed.
*/
@@ -241,18 +224,17 @@
connectEnds();
// must fire with null selector, or refresh won't happen
- dbRelationshipPath.fireModelChange(VALUE_CHANGED, null);
+ fireModelChange(VALUE_CHANGED, null);
}
public boolean isToMany() {
// copied algorithm from ObjRelationship.calculateToMany(), only iterating through
// the unsaved dbrels selection.
- Iterator dbRelIterator = dbRelationshipPath.iterator();
+ Iterator<DbRelationship> dbRelIterator = dbRelationships.iterator();
while (dbRelIterator.hasNext()) {
- EntityRelationshipsModel next = (EntityRelationshipsModel) dbRelIterator
- .next();
- Relationship relationship = next.getSelectedRelationship();
+
+ DbRelationship relationship = dbRelIterator.next();
if (relationship != null && relationship.isToMany()) {
return true;
}
@@ -273,8 +255,24 @@
hasChanges = true;
relationship.setName(relationshipName);
}
-
- if (!Util.nullSafeEquals(objectTarget.getName(), relationship
+
+ if (dbRelationships.size() > 0) {
+ DbEntity lastEntity = (DbEntity)
+ dbRelationships.get(dbRelationships.size() - 1).getTargetEntity();
+
+ if (objectTarget == null || objectTarget.getDbEntity() != lastEntity) {
+ /**
+ * Entities in combobox and path browser do not match.
+ * In this case, we rely on the browser and automatically select one
+ * of lastEntity's ObjEntities
+ */
+ Collection<ObjEntity> objEntities =
+ lastEntity.getDataMap().getMappedEntities(lastEntity);
+ objectTarget = objEntities.size() == 0 ? null : objEntities.iterator().next();
+ }
+ }
+
+ if (objectTarget == null || !Util.nullSafeEquals(objectTarget.getName(), relationship
.getTargetEntityName())) {
hasChanges = true;
@@ -285,16 +283,16 @@
}
// check for path modifications
- List oldPath = relationship.getDbRelationships();
- if (oldPath.size() != dbRelationshipPath.size()) {
+ List<DbRelationship> oldPath = relationship.getDbRelationships();
+ if (oldPath.size() != dbRelationships.size()) {
hasChanges = true;
updatePath();
}
else {
for (int i = 0; i < oldPath.size(); i++) {
- EntityRelationshipsModel next = (EntityRelationshipsModel) dbRelationshipPath
- .get(i);
- if (oldPath.get(i) != next.getSelectedRelationship()) {
+ DbRelationship next = dbRelationships.get(i);
+
+ if (oldPath.get(i) != next) {
hasChanges = true;
updatePath();
break;
@@ -332,10 +330,9 @@
private void updatePath() {
relationship.clearDbRelationships();
- Iterator it = dbRelationshipPath.iterator();
+ Iterator<DbRelationship> it = dbRelationships.iterator();
while (it.hasNext()) {
- EntityRelationshipsModel next = (EntityRelationshipsModel) it.next();
- Relationship nextPathComponent = next.getSelectedRelationship();
+ Relationship nextPathComponent = it.next();
if (nextPathComponent == null) {
break;
}
@@ -346,16 +343,10 @@
private void breakChain(int index) {
// strip everything starting from the index
- dbRelationshipPath.makeActive(false);
- try {
- while (dbRelationshipPath.size() > (index + 1)) {
- // remove last
- dbRelationshipPath.remove(dbRelationshipPath.size() - 1);
- }
- }
- finally {
- dbRelationshipPath.makeActive(true);
+ while (dbRelationships.size() > (index + 1)) {
+ // remove last
+ dbRelationships.remove(dbRelationships.size() - 1);
}
}
@@ -364,17 +355,14 @@
private void connectEnds() {
Relationship last = null;
- int size = dbRelationshipPath.size();
+ int size = dbRelationships.size();
if (size > 0) {
- EntityRelationshipsModel wrapper = (EntityRelationshipsModel) dbRelationshipPath
- .get(size - 1);
- last = wrapper.getSelectedRelationship();
-
+ last = dbRelationships.get(size - 1);
}
Entity target = getEndEntity();
- if (last == null || last.getTargetEntity() != target) {
+ if (target != null && (last == null || last.getTargetEntity() != target)) {
// try to connect automatically, if we can't use dummy connector
Entity source = (last == null) ? getStartEntity() : last.getTargetEntity();
@@ -382,43 +370,29 @@
Relationship anyConnector = source != null ? source
.getAnyRelationship(target) : null;
- EntityRelationshipsModel connector = null;
-
- connector = (anyConnector == null) ? new EntityRelationshipsModel(
- source,
- getEndEntity()) : new EntityRelationshipsModel(anyConnector);
-
- dbRelationshipPath.makeActive(false);
- try {
- dbRelationshipPath.add(connector);
- }
- finally {
- dbRelationshipPath.makeActive(true);
+
+ if (anyConnector != null) {
+ dbRelationships.add((DbRelationship) anyConnector);
}
}
}
}
+ /**
+ * Checks if the entity can be edited with this inspector.
+ * NOTE: As of CAY-1077, relationship inspector can be opened even if no target entity
+ * was set.
+ */
private void validateCanMap() {
if (relationship.getSourceEntity() == null) {
throw new CayenneRuntimeException(
"Can't map relationship without source entity.");
}
- if (relationship.getTargetEntity() == null) {
- throw new CayenneRuntimeException(
- "Can't map relationship without target entity.");
- }
-
if (getStartEntity() == null) {
throw new CayenneRuntimeException(
"Can't map relationship without source DbEntity.");
}
-
- if (getEndEntity() == null) {
- throw new CayenneRuntimeException(
- "Can't map relationship without target DbEntity.");
- }
}
public DbEntity getStartEntity() {
@@ -426,6 +400,13 @@
}
public DbEntity getEndEntity() {
+ /**
+ * Object target can be null when selected target DbEntity has no ObjEntities
+ */
+ if (objectTarget == null) {
+ return null;
+ }
+
return objectTarget.getDbEntity();
}
@@ -449,7 +430,7 @@
return mapKeys;
}
- public List getTargetCollections() {
+ public List<String> getTargetCollections() {
return targetCollections;
}
}
Added: cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/objentity/ObjRelationshipPathBrowser.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/objentity/ObjRelationshipPathBrowser.java?rev=681776&view=auto
==============================================================================
--- cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/objentity/ObjRelationshipPathBrowser.java (added)
+++ cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/dialog/objentity/ObjRelationshipPathBrowser.java Fri Aug 1 11:42:55 2008
@@ -0,0 +1,137 @@
+/*****************************************************************
+ * 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.dialog.objentity;
+
+import org.apache.cayenne.modeler.util.MultiColumnBrowser;
+
+import javax.swing.*;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.tree.TreePath;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+
+/**
+ * Multi-column browser for obj relationships
+ * @author Andrey Razumovsky
+ */
+public class ObjRelationshipPathBrowser extends MultiColumnBrowser {
+ /**
+ * Listener, which performs adding of new column
+ */
+ private MouseListener panelOpener;
+
+ /**
+ * Listener, which performs removing of columns to the right of selected row
+ */
+ private ListSelectionListener panelRemover;
+
+ public ObjRelationshipPathBrowser() {
+ this(DEFAULT_MIN_COLUMNS_COUNT);
+ }
+
+ public ObjRelationshipPathBrowser(int minColumns) {
+ super(minColumns);
+ }
+
+ @Override
+ protected void installColumn(BrowserPanel panel) {
+ panel.setToolTipText("Double-click on row to extend path");
+
+ if (panelOpener == null) {
+ panelOpener = new PanelOpener();
+ }
+
+ if (panelRemover == null) {
+ panelRemover = new PanelRemover();
+ }
+
+ panel.addMouseListener(panelOpener);
+ panel.addListSelectionListener(panelRemover);
+
+ panel.setCellRenderer(renderer);
+ }
+
+ /**
+ * Selects one path component.
+ * Need to override this method, because list selection does not cause loading
+ * in this browser.
+ */
+ @Override
+ protected void selectRow(Object row, int index, TreePath path) {
+ if (index > 0 && columns.get(index - 1).getSelectedValue() != row) {
+ columns.get(index - 1).setSelectedValue(row, true);
+ }
+
+ if (index != path.getPathCount() - 1) {
+ updateFromModel(row, index - 1);
+ }
+ }
+
+ @Override
+ protected void uninstallColumn(BrowserPanel panel) {
+ panel.removeMouseListener(panelOpener);
+ panel.removeListSelectionListener(panelRemover);
+ }
+
+ /**
+ * Listener, which performs adding of new column at double-click
+ */
+ protected class PanelOpener extends MouseAdapter {
+ /**
+ * Invoked when the mouse has been clicked on a component.
+ */
+ public void mouseClicked(MouseEvent e) {
+ if (SwingUtilities.isLeftMouseButton(e) && e.getClickCount() == 2) {
+ process(e);
+ }
+ }
+
+ private void process(MouseEvent e) {
+ BrowserPanel panel = (BrowserPanel) e.getSource();
+ Object selectedNode = panel.getSelectedValue();
+
+ // ignore unselected
+ if (selectedNode != null) {
+ updateFromModel(selectedNode, columns.indexOf(panel));
+ }
+ }
+ }
+
+ /**
+ * Listener, which performs removing columns to the right of selected row
+ */
+ protected class PanelRemover implements ListSelectionListener {
+
+ public void valueChanged(ListSelectionEvent e) {
+ // ignore "adjusting"
+ if (!e.getValueIsAdjusting()) {
+ BrowserPanel panel = (BrowserPanel) e.getSource();
+
+ Object selectedNode = panel.getSelectedValue();
+
+ if (selectedNode != null) {
+ updateFromModel(selectedNode, columns.indexOf(panel), false);
+ }
+ }
+ }
+
+ }
+}
Modified: cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjEntityRelationshipTab.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjEntityRelationshipTab.java?rev=681776&r1=681775&r2=681776&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjEntityRelationshipTab.java (original)
+++ cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjEntityRelationshipTab.java Fri Aug 1 11:42:55 2008
@@ -19,34 +19,6 @@
package org.apache.cayenne.modeler.editor;
-import java.awt.BorderLayout;
-import java.awt.Color;
-import java.awt.Component;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.util.Collection;
-import java.util.EventObject;
-import java.util.List;
-
-import javax.swing.DefaultCellEditor;
-import javax.swing.DefaultComboBoxModel;
-import javax.swing.Icon;
-import javax.swing.JButton;
-import javax.swing.JComboBox;
-import javax.swing.JLabel;
-import javax.swing.JMenuItem;
-import javax.swing.JPanel;
-import javax.swing.JPopupMenu;
-import javax.swing.JTable;
-import javax.swing.JToolBar;
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ListSelectionEvent;
-import javax.swing.event.ListSelectionListener;
-import javax.swing.event.TableModelEvent;
-import javax.swing.event.TableModelListener;
-import javax.swing.table.DefaultTableCellRenderer;
-import javax.swing.table.TableColumn;
-
import org.apache.cayenne.map.DataMap;
import org.apache.cayenne.map.DeleteRule;
import org.apache.cayenne.map.ObjEntity;
@@ -65,17 +37,22 @@
import org.apache.cayenne.modeler.event.ObjEntityDisplayListener;
import org.apache.cayenne.modeler.event.RelationshipDisplayEvent;
import org.apache.cayenne.modeler.event.TablePopupHandler;
-import org.apache.cayenne.modeler.util.CayenneAction;
-import org.apache.cayenne.modeler.util.CayenneTable;
-import org.apache.cayenne.modeler.util.CayenneWidgetFactory;
-import org.apache.cayenne.modeler.util.CellRenderers;
-import org.apache.cayenne.modeler.util.ModelerUtil;
-import org.apache.cayenne.modeler.util.PanelFactory;
-import org.apache.cayenne.modeler.util.UIUtil;
+import org.apache.cayenne.modeler.util.*;
import org.apache.cayenne.modeler.util.combo.AutoCompletion;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.table.DefaultTableCellRenderer;
+import javax.swing.table.TableColumn;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.Collection;
+import java.util.EventObject;
+import java.util.List;
+
/**
* Displays ObjRelationships for the edited ObjEntity.
*
@@ -176,6 +153,11 @@
.getModel();
new ObjRelationshipInfoController(mediator, model.getRelationship(row))
.startup();
+
+ /**
+ * This is required for a table to be updated properly
+ */
+ table.cancelEditing();
// need to refresh selected row... do this by unselecting/selecting the
// row
@@ -239,9 +221,10 @@
rels[i] = model.getRelationship(sel[i]);
}
- if (rels.length == 1 && rels[0].getTargetEntity() != null
- && ((ObjEntity) rels[0].getSourceEntity()).getDbEntity() != null
- && ((ObjEntity) rels[0].getTargetEntity()).getDbEntity() != null) {
+ /**
+ * As of CAY-1077, relationship inspector can be opened even if no target entity was set.
+ */
+ if (rels.length == 1 && ((ObjEntity) rels[0].getSourceEntity()).getDbEntity() != null) {
resolve.setEnabled(true);
}
else
Modified: cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjRelationshipTableModel.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjRelationshipTableModel.java?rev=681776&r1=681775&r2=681776&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjRelationshipTableModel.java (original)
+++ cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/ObjRelationshipTableModel.java Fri Aug 1 11:42:55 2008
@@ -19,22 +19,17 @@
package org.apache.cayenne.modeler.editor;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.map.DbRelationship;
-import org.apache.cayenne.map.DeleteRule;
-import org.apache.cayenne.map.ObjEntity;
-import org.apache.cayenne.map.ObjRelationship;
-import org.apache.cayenne.map.Relationship;
+import org.apache.cayenne.map.*;
import org.apache.cayenne.map.event.RelationshipEvent;
import org.apache.cayenne.modeler.ProjectController;
import org.apache.cayenne.modeler.util.CayenneTableModel;
import org.apache.cayenne.modeler.util.ProjectUtil;
import org.apache.cayenne.util.Util;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+
/**
* Table model to display ObjRelationships.
*
@@ -61,6 +56,7 @@
Collections.sort(objectList, new RelationshipComparator());
}
+ @Override
protected void orderList() {
// NOOP
}
@@ -72,6 +68,7 @@
/**
* Returns ObjRelationship class.
*/
+ @Override
public Class getElementsClass() {
return ObjRelationship.class;
}
@@ -80,6 +77,7 @@
return 5;
}
+ @Override
public String getColumnName(int column) {
switch (column) {
case REL_NAME:
@@ -98,6 +96,7 @@
}
}
+ @Override
public Class getColumnClass(int col) {
switch (col) {
case REL_TARGET:
@@ -155,6 +154,7 @@
}
}
+ @Override
public void setUpdatedValueAt(Object value, int row, int column) {
ObjRelationship relationship = getRelationship(row);
RelationshipEvent event = new RelationshipEvent(eventSource, relationship, entity);
@@ -168,7 +168,12 @@
else if (column == REL_TARGET) {
ObjEntity target = (ObjEntity) value;
relationship.setTargetEntity(target);
-
+
+ /**
+ * Clear existing relationships, otherwise addDbRelationship() might fail
+ */
+ relationship.clearDbRelationships();
+
// now try to connect DbEntities if we can do it in one step
if (target != null) {
DbEntity srcDB = ((ObjEntity) relationship.getSourceEntity())
@@ -214,6 +219,7 @@
return (relationship != null) ? relationship.getSourceEntity() != entity : false;
}
+ @Override
public boolean isCellEditable(int row, int col) {
return !isInherited(row) && col != REL_SEMANTICS;
}
Modified: cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SelectQueryPrefetchTab.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SelectQueryPrefetchTab.java?rev=681776&r1=681775&r2=681776&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SelectQueryPrefetchTab.java (original)
+++ cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/editor/SelectQueryPrefetchTab.java Fri Aug 1 11:42:55 2008
@@ -19,28 +19,27 @@
package org.apache.cayenne.modeler.editor;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.util.Collection;
-import java.util.Iterator;
-
-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 org.apache.cayenne.exp.Expression;
import org.apache.cayenne.exp.ExpressionException;
+import org.apache.cayenne.map.Attribute;
import org.apache.cayenne.map.Entity;
import org.apache.cayenne.map.Relationship;
import org.apache.cayenne.map.event.QueryEvent;
import org.apache.cayenne.modeler.ProjectController;
+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.query.PrefetchTreeNode;
+import javax.swing.*;
+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;
+import java.util.Collection;
+import java.util.Iterator;
+
/**
* Subclass of the SelectQueryOrderingTab configured to work with prefetches.
*
@@ -82,7 +81,16 @@
protected TreeModel createBrowserModel(Entity entity) {
EntityTreeModel treeModel = new EntityTreeModel(entity);
- treeModel.setHideAttributes(true);
+ treeModel.setFilter(
+ new EntityTreeFilter() {
+ public boolean attributeMatch(Object node, Attribute attr) {
+ return false;
+ }
+
+ public boolean relationshipMatch(Object node, Relationship rel) {
+ return true;
+ }
+ });
return treeModel;
}
Added: cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/EntityTreeFilter.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/EntityTreeFilter.java?rev=681776&view=auto
==============================================================================
--- cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/EntityTreeFilter.java (added)
+++ cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/EntityTreeFilter.java Fri Aug 1 11:42:55 2008
@@ -0,0 +1,39 @@
+/*****************************************************************
+ * 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.util;
+
+import org.apache.cayenne.map.Attribute;
+import org.apache.cayenne.map.Relationship;
+
+/**
+ * EntityTreeFilter is an interface for deciding which attributes or
+ * relationships should appear in the tree
+ * @author Andrey Razumovsky
+ */
+public interface EntityTreeFilter {
+ /**
+ * Checks if attribute should appear in the tree
+ */
+ public boolean attributeMatch(Object node, Attribute attr);
+
+ /**
+ * Checks if relationship should appear in the tree
+ */
+ public boolean relationshipMatch(Object node, Relationship rel);
+}
Modified: cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/EntityTreeModel.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/EntityTreeModel.java?rev=681776&r1=681775&r2=681776&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/EntityTreeModel.java (original)
+++ cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/EntityTreeModel.java Fri Aug 1 11:42:55 2008
@@ -19,20 +19,14 @@
package org.apache.cayenne.modeler.util;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
+import org.apache.cayenne.map.Attribute;
+import org.apache.cayenne.map.Entity;
+import org.apache.cayenne.map.Relationship;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
-
-import org.apache.cayenne.map.Attribute;
-import org.apache.cayenne.map.Entity;
-import org.apache.cayenne.map.Relationship;
+import java.util.*;
/**
* Swing TreeModel for Entity attributes and relationships
@@ -42,29 +36,22 @@
*/
public class EntityTreeModel implements TreeModel {
protected Entity root;
- protected Map<String, Object[]> sortedChildren;
-
- // TODO: in the future replace with a more generic filter
- // to allow arbitrary tree customization
- protected boolean hideAttributes;
+ protected Map<Object, Object[]> sortedChildren;
+ /**
+ * Filter for checking attributes and relationships
+ */
+ protected EntityTreeFilter filter;
+
public EntityTreeModel(Entity root) {
this.root = root;
- sortedChildren = Collections.synchronizedMap(new HashMap<String, Object[]>());
+ sortedChildren = Collections.synchronizedMap(new HashMap<Object, Object[]>());
}
public Object getRoot() {
return root;
}
- public boolean isHideAttributes() {
- return hideAttributes;
- }
-
- public void setHideAttributes(boolean hideAttributes) {
- this.hideAttributes = hideAttributes;
- }
-
public Object getChild(Object node, int index) {
return sortedChildren(node)[index];
}
@@ -111,30 +98,36 @@
}
synchronized (sortedChildren) {
- String key = entity.getName();
- Object[] sortedForNode = (Object[]) sortedChildren.get(key);
+ Object key = node;
+ Object[] sortedForNode = sortedChildren.get(key);
if (sortedForNode == null) {
Collection<? extends Attribute> attributes = entity.getAttributes();
Collection<? extends Relationship> relationships = entity.getRelationships();
+ List<Object> nodes = new Vector<Object>();
+
// combine two collections in an array
- int alen = (hideAttributes) ? 0 : attributes.size();
- int rlen = relationships.size();
- sortedForNode = new Object[alen + rlen];
-
- if (!hideAttributes) {
- Iterator<? extends Attribute> ait = attributes.iterator();
- for (int i = 0; i < alen; i++) {
- sortedForNode[i] = ait.next();
+ Iterator<? extends Attribute> ait = attributes.iterator();
+ while (ait.hasNext()) {
+ Attribute attr = ait.next();
+
+ if (filter == null || filter.attributeMatch(node, attr)) {
+ nodes.add(attr);
}
}
Iterator<? extends Relationship> rit = relationships.iterator();
- for (int i = 0; i < rlen; i++) {
- sortedForNode[alen + i] = rit.next();
+ while (rit.hasNext()) {
+ Relationship rel = rit.next();
+
+ if (filter == null || filter.relationshipMatch(node, rel)) {
+ nodes.add(rel);
+ }
}
+ sortedForNode = nodes.toArray();
+
Arrays.sort(sortedForNode, Comparators.getEntityChildrenComparator());
sortedChildren.put(key, sortedForNode);
}
@@ -142,6 +135,15 @@
return sortedForNode;
}
}
+
+ /**
+ * Removes children cache for specified entity.
+ */
+ public void invalidateChildren(Entity entity) {
+ synchronized (sortedChildren) {
+ sortedChildren.remove(entity.getName());
+ }
+ }
private Entity entityForNonLeafNode(Object node) {
if (node instanceof Entity) {
@@ -154,4 +156,18 @@
String className = (node != null) ? node.getClass().getName() : "null";
throw new IllegalArgumentException("Unexpected non-leaf node: " + className);
}
+
+ /**
+ * Sets filter for attrs and rels
+ */
+ public void setFilter(EntityTreeFilter filter) {
+ this.filter = filter;
+ }
+
+ /**
+ * Returns filter for attrs and rels
+ */
+ public EntityTreeFilter getFilter() {
+ return filter;
+ }
}
Modified: cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/MultiColumnBrowser.java
URL: http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/MultiColumnBrowser.java?rev=681776&r1=681775&r2=681776&view=diff
==============================================================================
--- cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/MultiColumnBrowser.java (original)
+++ cayenne/main/trunk/framework/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/MultiColumnBrowser.java Fri Aug 1 11:42:55 2008
@@ -19,26 +19,7 @@
package org.apache.cayenne.modeler.util;
-import java.awt.BorderLayout;
-import java.awt.Component;
-import java.awt.Dimension;
-import java.awt.GridLayout;
-import java.awt.Rectangle;
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-import javax.swing.AbstractListModel;
-import javax.swing.DefaultListCellRenderer;
-import javax.swing.ImageIcon;
-import javax.swing.JLabel;
-import javax.swing.JList;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JViewport;
-import javax.swing.ListCellRenderer;
-import javax.swing.ListSelectionModel;
+import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
@@ -46,6 +27,11 @@
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
+import java.awt.*;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
/**
@@ -71,7 +57,7 @@
*/
public class MultiColumnBrowser extends JPanel {
- private static final ImageIcon rightArrow =
+ protected static final ImageIcon rightArrow =
ModelerUtil.buildIcon("scroll_right.gif");
public static final int DEFAULT_MIN_COLUMNS_COUNT = 3;
@@ -82,9 +68,14 @@
protected Object[] selectionPath;
protected Dimension preferredColumnSize;
- private List<BrowserPanel> columns;
- private ListSelectionListener browserSelector;
- private List<TreeSelectionListener> treeSelectionListeners;
+ protected List<BrowserPanel> columns;
+ protected ListSelectionListener browserSelector;
+ protected List<TreeSelectionListener> treeSelectionListeners;
+
+ /**
+ * Whether firing of TreeSelectionListeners is disabled now
+ */
+ private boolean fireDisabled;
public MultiColumnBrowser() {
this(DEFAULT_MIN_COLUMNS_COUNT);
@@ -123,16 +114,15 @@
* Notifies listeners of a tree selection change.
*/
protected void fireTreeSelectionEvent(Object[] selectionPath) {
+ if (fireDisabled) {
+ return;
+ }
+
TreeSelectionEvent e =
new TreeSelectionEvent(this, new TreePath(selectionPath), false, null, null);
synchronized (treeSelectionListeners) {
for (TreeSelectionListener listener : treeSelectionListeners)
listener.valueChanged(e);
-// Iterator<TreeSelectionListener> it = treeSelectionListeners.iterator();
-// while (it.hasNext()) {
-// TreeSelectionListener listener = (TreeSelectionListener) it.next();
-// listener.valueChanged(e);
-// }
}
}
@@ -142,6 +132,34 @@
public TreePath getSelectionPath() {
return new TreePath(selectionPath);
}
+
+ /**
+ * Sets new selection path and fires an event
+ */
+ public void setSelectionPath(TreePath path) {
+ try {
+ fireDisabled = true;
+
+ for (int i = 0; i < path.getPathCount(); i++) {
+ selectRow(path.getPathComponent(i), i, path);
+ }
+ }
+ finally {
+ fireDisabled = false;
+ }
+ }
+
+ /**
+ * Selects one path component
+ */
+ protected void selectRow(Object row, int index, TreePath path) {
+ if (index > 0 && columns.get(index - 1).getSelectedValue() != row) {
+ columns.get(index - 1).setSelectedValue(row, true);
+ }
+ else { //update
+ updateFromModel(row, index - 1);
+ }
+ }
/**
* Returns the minumum number of displayed columns.
@@ -198,11 +216,6 @@
if (columns != null && columns.size() > 0) {
for (JList column : columns)
column.setCellRenderer(renderer);
-// Iterator it = columns.iterator();
-// while (it.hasNext()) {
-// JList column = (JList) it.next();
-// column.setCellRenderer(renderer);
-// }
}
}
}
@@ -273,8 +286,7 @@
private BrowserPanel appendColumn() {
BrowserPanel panel = new BrowserPanel();
- panel.addListSelectionListener(browserSelector);
- panel.setCellRenderer(renderer);
+ installColumn(panel);
columns.add(panel);
JScrollPane scroller =
@@ -292,6 +304,14 @@
add(scroller);
return panel;
}
+
+ /**
+ * Installs all needed columns and renderers to a new column
+ */
+ protected void installColumn(BrowserPanel panel) {
+ panel.addListSelectionListener(browserSelector);
+ panel.setCellRenderer(renderer);
+ }
private BrowserPanel removeLastColumn() {
if (columns.size() == 0) {
@@ -300,13 +320,20 @@
int index = columns.size() - 1;
- BrowserPanel panel = (BrowserPanel) columns.remove(index);
- panel.removeListSelectionListener(browserSelector);
+ BrowserPanel panel = columns.remove(index);
+ uninstallColumn(panel);
// remove ansestor of the column (JScrollPane)
remove(index);
return panel;
}
+
+ /**
+ * Removes all local listeners from the column
+ */
+ protected void uninstallColumn(BrowserPanel panel) {
+ panel.removeListSelectionListener(browserSelector);
+ }
/**
* Refreshes preferred size of the browser to
@@ -346,11 +373,19 @@
viewport.scrollRectToVisible(rectangle);
}
}
+
+ /**
+ * Rebuilds view for the new object selection.
+ */
+ protected synchronized void updateFromModel(Object selectedNode, int panelIndex) {
+ updateFromModel(selectedNode, panelIndex, true);
+ }
/**
* Rebuilds view for the new object selection.
+ * @param load Whether children are loaded automatically
*/
- private synchronized void updateFromModel(Object selectedNode, int panelIndex) {
+ protected synchronized void updateFromModel(Object selectedNode, int panelIndex, boolean load) {
if(selectionPath == null) {
selectionPath = new Object[0];
}
@@ -362,7 +397,7 @@
for (int i = panelIndex + 1;
i <= lastIndex && i >= 0 && i < columns.size();
i++) {
- BrowserPanel column = (BrowserPanel) columns.get(i);
+ BrowserPanel column = columns.get(i);
column.getSelectionModel().clearSelection();
column.setRootNode(null);
}
@@ -370,18 +405,22 @@
// build path to selected node
this.selectionPath = rebuildPath(selectionPath, selectedNode, panelIndex);
- // a selectedNode is contained in "panelIndex" column,
- // but its children are in the next column.
- panelIndex++;
-
+ if (load) {
+ // a selectedNode is contained in "panelIndex" column,
+ // but its children are in the next column.
+ panelIndex++;
+ }
+
// expand/contract columns as needed
adjustViewColumns(panelIndex + 1 - columns.size());
- // selectedNode becomes the root of columns[panelIndex]
- if (!model.isLeaf(selectedNode)) {
- BrowserPanel lastPanel = (BrowserPanel) columns.get(panelIndex);
- lastPanel.setRootNode(selectedNode);
- scrollToColumn(panelIndex);
+ if (load) {
+ // selectedNode becomes the root of columns[panelIndex]
+ if (!model.isLeaf(selectedNode)) {
+ BrowserPanel lastPanel = columns.get(panelIndex);
+ lastPanel.setRootNode(selectedNode);
+ scrollToColumn(panelIndex);
+ }
}
fireTreeSelectionEvent(selectionPath);
@@ -436,7 +475,7 @@
// ====================================================
// Represents a single browser column
// ====================================================
- final class BrowserPanel extends JList {
+ protected final class BrowserPanel extends JList {
BrowserPanel() {
BrowserPanel.this.setModel(new ColumnListModel());
BrowserPanel.this.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
@@ -487,6 +526,7 @@
leafRenderer = CellRenderers.listRenderer();
nonLeafTextRenderer = new DefaultListCellRenderer() {
+ @Override
public Border getBorder() {
return null;
}