Added a selection model, and attribute selection, and cleaned up foreign key referencing.
This commit is contained in:
parent
1019654e76
commit
cea15d872b
|
@ -124,10 +124,10 @@ public class ExportToImageAction extends DiagramPanelAction {
|
|||
// Render the model.
|
||||
boolean lolcat = model.isLolcatEnabled(); // save previous lolcat mode
|
||||
model.setLolcatEnabled(false);
|
||||
List<Relation> selectedRelations = model.getSelectedRelations();
|
||||
model.getSelectedRelations().forEach(r -> r.setSelected(false));
|
||||
List<Relation> selectedRelations = model.getSelectionModel().getSelectedRelations();
|
||||
model.getSelectionModel().clearSelection();
|
||||
new MappingModelViewModel(model).draw(g2d);
|
||||
model.getRelations().forEach(r -> r.setSelected(selectedRelations.contains(r)));
|
||||
model.getSelectionModel().selectAll(selectedRelations);
|
||||
model.setLolcatEnabled(lolcat); // revert previous lolcat mode
|
||||
|
||||
// Revert to the normal image space, and render a watermark.
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
package nl.andrewlalis.erme.control.actions;
|
||||
|
||||
import nl.andrewlalis.erme.model.*;
|
||||
import nl.andrewlalis.erme.model.Attribute;
|
||||
import nl.andrewlalis.erme.model.AttributeType;
|
||||
import nl.andrewlalis.erme.model.MappingModel;
|
||||
import nl.andrewlalis.erme.model.Relation;
|
||||
import nl.andrewlalis.erme.view.DiagramPanel;
|
||||
|
||||
import java.awt.*;
|
||||
|
@ -22,7 +25,9 @@ public class LoadSampleModelAction extends DiagramPanelAction {
|
|||
Relation r1 = new Relation(model, new Point(50, 100), "Airplane");
|
||||
r1.addAttribute(new Attribute(r1, AttributeType.ID_KEY, "id"));
|
||||
r1.addAttribute(new Attribute(r1, AttributeType.PLAIN, "purchasedAt"));
|
||||
r1.addAttribute(new ForeignKeyAttribute(r1, AttributeType.PLAIN, "typeName", "AirplaneType", "name"));
|
||||
Attribute fk = new Attribute(r1, AttributeType.PLAIN, "typeName");
|
||||
fk.setReference(model.findAttribute("AirplaneType", "name"));
|
||||
r1.addAttribute(fk);
|
||||
model.addRelation(r1);
|
||||
getDiagramPanel().setModel(model);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package nl.andrewlalis.erme.control.actions.edits;
|
|||
import nl.andrewlalis.erme.control.actions.DiagramPanelAction;
|
||||
import nl.andrewlalis.erme.model.*;
|
||||
import nl.andrewlalis.erme.view.DiagramPanel;
|
||||
import nl.andrewlalis.erme.view.EditAttributePopupDialog;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
|
@ -23,7 +24,7 @@ public class AddAttributeAction extends DiagramPanelAction {
|
|||
public void actionPerformed(ActionEvent e) {
|
||||
DiagramPanel dp = getDiagramPanel();
|
||||
MappingModel model = dp.getModel();
|
||||
List<Relation> selectedRelations = model.getSelectedRelations();
|
||||
List<Relation> selectedRelations = model.getSelectionModel().getSelectedRelations();
|
||||
if (selectedRelations.size() != 1) {
|
||||
JOptionPane.showMessageDialog(
|
||||
dp,
|
||||
|
@ -34,72 +35,74 @@ public class AddAttributeAction extends DiagramPanelAction {
|
|||
return;
|
||||
}
|
||||
Relation r = selectedRelations.get(0);
|
||||
Attribute createdAttribute;
|
||||
String name = JOptionPane.showInputDialog(dp, "Enter the name of the attribute.", "Attribute Name", JOptionPane.PLAIN_MESSAGE);
|
||||
if (name == null) return;
|
||||
Integer index = (Integer) JOptionPane.showInputDialog(
|
||||
dp,
|
||||
"Select the index to insert this attribute at.",
|
||||
"Attribute Index",
|
||||
JOptionPane.PLAIN_MESSAGE,
|
||||
null,
|
||||
Stream.iterate(0, n -> n + 1).limit(r.getAttributes().size() + 1).toArray(),
|
||||
r.getAttributes().size()
|
||||
);
|
||||
if (index == null) return;
|
||||
AttributeType type = (AttributeType) JOptionPane.showInputDialog(
|
||||
dp,
|
||||
"Select the type this attribute is.",
|
||||
"Attribute Type",
|
||||
JOptionPane.PLAIN_MESSAGE,
|
||||
null,
|
||||
AttributeType.values(),
|
||||
AttributeType.PLAIN
|
||||
);
|
||||
if (type == null) return;
|
||||
boolean shouldUseForeignKey = ((String) JOptionPane.showInputDialog(
|
||||
dp,
|
||||
"Is this attribute a foreign key?",
|
||||
"Foreign Key",
|
||||
JOptionPane.PLAIN_MESSAGE,
|
||||
null,
|
||||
new String[]{"Yes", "No"},
|
||||
"No"
|
||||
)).equalsIgnoreCase("yes");
|
||||
if (shouldUseForeignKey) {
|
||||
if (model.getRelations().size() < 2) {
|
||||
JOptionPane.showMessageDialog(dp, "There should be at least 2 relations present in the model.", "Not Enough Relations", JOptionPane.WARNING_MESSAGE);
|
||||
return;
|
||||
}
|
||||
Relation fkRelation = (Relation) JOptionPane.showInputDialog(
|
||||
dp,
|
||||
"Select the relation that this foreign key references.",
|
||||
"Foreign Key Relation Reference",
|
||||
JOptionPane.PLAIN_MESSAGE,
|
||||
null,
|
||||
model.getRelations().toArray(new Relation[0]),
|
||||
model.getRelations().stream().findFirst().orElse(null)
|
||||
);
|
||||
if (fkRelation == null) return;
|
||||
List<Attribute> eligibleAttributes = fkRelation.getAttributes();
|
||||
if (eligibleAttributes.isEmpty()) {
|
||||
JOptionPane.showMessageDialog(dp, "There are no referencable attributes in the selected relation.", "No Referencable Attributes", JOptionPane.WARNING_MESSAGE);
|
||||
return;
|
||||
}
|
||||
Attribute fkAttribute = (Attribute) JOptionPane.showInputDialog(
|
||||
dp,
|
||||
"Select the attribute that this foreign key references.",
|
||||
"Foreign Key Attribute Reference",
|
||||
JOptionPane.PLAIN_MESSAGE,
|
||||
null,
|
||||
eligibleAttributes.toArray(new Attribute[0]),
|
||||
eligibleAttributes.get(0)
|
||||
);
|
||||
if (fkAttribute == null) return;
|
||||
createdAttribute = new ForeignKeyAttribute(r, type, name, fkAttribute);
|
||||
} else {
|
||||
createdAttribute = new Attribute(r, type, name);
|
||||
}
|
||||
r.addAttribute(createdAttribute, index);
|
||||
EditAttributePopupDialog popup = new EditAttributePopupDialog((JFrame) SwingUtilities.getWindowAncestor(dp), r, null);
|
||||
popup.setVisible(true);
|
||||
// Attribute createdAttribute;
|
||||
// String name = JOptionPane.showInputDialog(dp, "Enter the name of the attribute.", "Attribute Name", JOptionPane.PLAIN_MESSAGE);
|
||||
// if (name == null) return;
|
||||
// Integer index = (Integer) JOptionPane.showInputDialog(
|
||||
// dp,
|
||||
// "Select the index to insert this attribute at.",
|
||||
// "Attribute Index",
|
||||
// JOptionPane.PLAIN_MESSAGE,
|
||||
// null,
|
||||
// Stream.iterate(0, n -> n + 1).limit(r.getAttributes().size() + 1).toArray(),
|
||||
// r.getAttributes().size()
|
||||
// );
|
||||
// if (index == null) return;
|
||||
// AttributeType type = (AttributeType) JOptionPane.showInputDialog(
|
||||
// dp,
|
||||
// "Select the type this attribute is.",
|
||||
// "Attribute Type",
|
||||
// JOptionPane.PLAIN_MESSAGE,
|
||||
// null,
|
||||
// AttributeType.values(),
|
||||
// AttributeType.PLAIN
|
||||
// );
|
||||
// if (type == null) return;
|
||||
// boolean shouldUseForeignKey = ((String) JOptionPane.showInputDialog(
|
||||
// dp,
|
||||
// "Is this attribute a foreign key?",
|
||||
// "Foreign Key",
|
||||
// JOptionPane.PLAIN_MESSAGE,
|
||||
// null,
|
||||
// new String[]{"Yes", "No"},
|
||||
// "No"
|
||||
// )).equalsIgnoreCase("yes");
|
||||
// if (shouldUseForeignKey) {
|
||||
// if (model.getRelations().size() < 2) {
|
||||
// JOptionPane.showMessageDialog(dp, "There should be at least 2 relations present in the model.", "Not Enough Relations", JOptionPane.WARNING_MESSAGE);
|
||||
// return;
|
||||
// }
|
||||
// Relation fkRelation = (Relation) JOptionPane.showInputDialog(
|
||||
// dp,
|
||||
// "Select the relation that this foreign key references.",
|
||||
// "Foreign Key Relation Reference",
|
||||
// JOptionPane.PLAIN_MESSAGE,
|
||||
// null,
|
||||
// model.getRelations().toArray(new Relation[0]),
|
||||
// model.getRelations().stream().findFirst().orElse(null)
|
||||
// );
|
||||
// if (fkRelation == null) return;
|
||||
// List<Attribute> eligibleAttributes = fkRelation.getAttributes();
|
||||
// if (eligibleAttributes.isEmpty()) {
|
||||
// JOptionPane.showMessageDialog(dp, "There are no referencable attributes in the selected relation.", "No Referencable Attributes", JOptionPane.WARNING_MESSAGE);
|
||||
// return;
|
||||
// }
|
||||
// Attribute fkAttribute = (Attribute) JOptionPane.showInputDialog(
|
||||
// dp,
|
||||
// "Select the attribute that this foreign key references.",
|
||||
// "Foreign Key Attribute Reference",
|
||||
// JOptionPane.PLAIN_MESSAGE,
|
||||
// null,
|
||||
// eligibleAttributes.toArray(new Attribute[0]),
|
||||
// eligibleAttributes.get(0)
|
||||
// );
|
||||
// if (fkAttribute == null) return;
|
||||
// createdAttribute = new ForeignKeyAttribute(r, type, name, fkAttribute);
|
||||
// } else {
|
||||
// createdAttribute = new Attribute(r, type, name);
|
||||
// }
|
||||
// r.addAttribute(createdAttribute, index);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,9 +43,9 @@ public class AddRelationAction extends DiagramPanelAction {
|
|||
p = new Point(bounds.x + bounds.width / 2, bounds.y + bounds.height / 2);
|
||||
}
|
||||
Relation r = new Relation(model, p, name);
|
||||
model.getSelectedRelations().forEach(rl -> rl.setSelected(false));
|
||||
r.setSelected(true);
|
||||
model.addRelation(r);
|
||||
model.getSelectionModel().clearSelection();
|
||||
model.getSelectionModel().select(r);
|
||||
if (isFirstRelation) {
|
||||
model.normalizeRelationPositions();
|
||||
dp.centerModel();
|
||||
|
|
|
@ -2,7 +2,6 @@ package nl.andrewlalis.erme.control.actions.edits;
|
|||
|
||||
import nl.andrewlalis.erme.control.actions.DiagramPanelAction;
|
||||
import nl.andrewlalis.erme.model.Attribute;
|
||||
import nl.andrewlalis.erme.model.Relation;
|
||||
import nl.andrewlalis.erme.view.DiagramPanel;
|
||||
|
||||
import javax.swing.*;
|
||||
|
@ -20,28 +19,22 @@ public class RemoveAttributeAction extends DiagramPanelAction {
|
|||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
List<Relation> selectedRelations = getDiagramPanel().getModel().getSelectedRelations();
|
||||
if (selectedRelations.size() != 1 || selectedRelations.get(0).getAttributes().isEmpty()) {
|
||||
List<Attribute> selectedAttributes = getDiagramPanel().getModel().getSelectionModel().getSelectedAttributes();
|
||||
if (selectedAttributes.isEmpty()) {
|
||||
JOptionPane.showMessageDialog(
|
||||
getDiagramPanel(),
|
||||
"A single relation with at least one attribute must be selected to remove an attribute.",
|
||||
"Single Relation With Attribute Required",
|
||||
"At least one attribute must be selected to remove.",
|
||||
"Select Attributes to Remove Them",
|
||||
JOptionPane.WARNING_MESSAGE
|
||||
);
|
||||
return;
|
||||
}
|
||||
Relation r = selectedRelations.get(0);
|
||||
Attribute attribute = (Attribute) JOptionPane.showInputDialog(
|
||||
getDiagramPanel(),
|
||||
"Select the attribute to remove.",
|
||||
"Select Attribute",
|
||||
JOptionPane.PLAIN_MESSAGE,
|
||||
null,
|
||||
r.getAttributes().toArray(new Attribute[0]),
|
||||
r.getAttributes().get(0)
|
||||
);
|
||||
if (attribute != null) {
|
||||
r.removeAttribute(attribute);
|
||||
int choice = JOptionPane.showConfirmDialog(getDiagramPanel(), "Are you sure you want to remove these attributes?", "Confirm", JOptionPane.OK_CANCEL_OPTION);
|
||||
if (choice == JOptionPane.YES_OPTION) {
|
||||
for (Attribute a : selectedAttributes) {
|
||||
a.getRelation().removeAttribute(a);
|
||||
}
|
||||
getDiagramPanel().getModel().getSelectionModel().clearAttributes();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import javax.swing.*;
|
|||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.List;
|
||||
|
||||
public class RemoveRelationAction extends DiagramPanelAction {
|
||||
public RemoveRelationAction(DiagramPanel diagramPanel) {
|
||||
|
@ -20,7 +21,8 @@ public class RemoveRelationAction extends DiagramPanelAction {
|
|||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
MappingModel model = getDiagramPanel().getModel();
|
||||
if (model.getSelectedRelations().isEmpty()) {
|
||||
List<Relation> selectedRelations = model.getSelectionModel().getSelectedRelations();
|
||||
if (selectedRelations.isEmpty()) {
|
||||
JOptionPane.showMessageDialog(
|
||||
getDiagramPanel(),
|
||||
"No relations selected. Select at least one relation to remove.",
|
||||
|
@ -29,8 +31,12 @@ public class RemoveRelationAction extends DiagramPanelAction {
|
|||
);
|
||||
return;
|
||||
}
|
||||
for (Relation r : model.getSelectedRelations()) {
|
||||
model.removeRelation(r);
|
||||
int choice = JOptionPane.showConfirmDialog(getDiagramPanel(), "Are you sure you want to remove these relations?", "Confirm", JOptionPane.YES_NO_OPTION);
|
||||
if (choice == JOptionPane.YES_OPTION) {
|
||||
for (Relation r : selectedRelations) {
|
||||
model.removeRelation(r);
|
||||
}
|
||||
model.getSelectionModel().clearRelations();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package nl.andrewlalis.erme.control.diagram;
|
||||
|
||||
import nl.andrewlalis.erme.model.Attribute;
|
||||
import nl.andrewlalis.erme.model.MappingModel;
|
||||
import nl.andrewlalis.erme.model.Relation;
|
||||
import nl.andrewlalis.erme.view.DiagramPanel;
|
||||
|
@ -25,7 +26,7 @@ public class DiagramMouseListener extends MouseAdapter {
|
|||
* - If the click occurs within at least one relation, select the first one,
|
||||
* and deselect all others if CTRL is not held down.
|
||||
* - If the user did a right-click, try to open a popup menu with some
|
||||
* possible actions.
|
||||
* possible actions, based on what entity we're over.
|
||||
* @param e The mouse event.
|
||||
*/
|
||||
@Override
|
||||
|
@ -40,15 +41,24 @@ public class DiagramMouseListener extends MouseAdapter {
|
|||
final boolean isShiftDown = (e.getModifiers() & ActionEvent.SHIFT_MASK) == ActionEvent.SHIFT_MASK;
|
||||
MappingModel model = this.diagramPanel.getModel();
|
||||
|
||||
if (!isShiftDown && !isCtrlDown) {// A simple click anywhere should reset selection.
|
||||
model.getRelations().forEach(r -> r.setSelected(false));
|
||||
if (!isShiftDown && !isCtrlDown) {// A simple left-click anywhere should reset selection.
|
||||
model.getSelectionModel().clearSelection();
|
||||
}
|
||||
|
||||
if (!isShiftDown) {// If the user clicked or CTRL+clicked, try and select the relation they clicked on.
|
||||
for (Relation r : model.getRelations()) {
|
||||
if (r.getViewModel().getBounds(g).contains(modelX, modelY)) {
|
||||
r.setSelected(!r.isSelected());
|
||||
break;
|
||||
boolean anyAttributeSelected = false;
|
||||
for (Attribute a : r.getAttributes()) {
|
||||
if (a.getViewModel().getBounds(g).contains(modelX, modelY)) {
|
||||
model.getSelectionModel().toggle(a);
|
||||
}
|
||||
anyAttributeSelected = anyAttributeSelected || a.isSelected();
|
||||
}
|
||||
if (!anyAttributeSelected) {
|
||||
model.getSelectionModel().toggle(r);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -77,12 +87,11 @@ public class DiagramMouseListener extends MouseAdapter {
|
|||
MappingModel model = this.diagramPanel.getModel();
|
||||
|
||||
if (isShiftDown) {
|
||||
System.out.println(e);
|
||||
this.diagramPanel.translate(-dx, -dy);
|
||||
this.diagramPanel.repaint();
|
||||
} else {
|
||||
for (Relation r : model.getRelations()) {
|
||||
if (r.isSelected()) {
|
||||
if (model.getSelectionModel().isSelected(r)) {
|
||||
r.setPosition(new Point(r.getPosition().x - dx, r.getPosition().y - dy));
|
||||
changed = true;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ public class Attribute {
|
|||
private final Relation relation;
|
||||
private AttributeType type;
|
||||
private String name;
|
||||
private Attribute reference;
|
||||
|
||||
private transient AttributeViewModel viewModel;
|
||||
|
||||
|
@ -20,6 +21,7 @@ public class Attribute {
|
|||
this.relation = relation;
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
this.reference = null;
|
||||
}
|
||||
|
||||
public void setType(AttributeType type) {
|
||||
|
@ -31,6 +33,14 @@ public class Attribute {
|
|||
this.name = name;
|
||||
this.relation.getModel().fireChangedEvent();
|
||||
}
|
||||
|
||||
public boolean hasReference() {
|
||||
return this.reference != null;
|
||||
}
|
||||
|
||||
public void setReference(Attribute attribute) {
|
||||
this.reference = attribute;
|
||||
}
|
||||
|
||||
public AttributeViewModel getViewModel() {
|
||||
if (this.viewModel == null) {
|
||||
|
@ -39,6 +49,10 @@ public class Attribute {
|
|||
return this.viewModel;
|
||||
}
|
||||
|
||||
public boolean isSelected() {
|
||||
return this.relation.getModel().getSelectionModel().isSelected(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
package nl.andrewlalis.erme.model;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class ForeignKeyAttribute extends Attribute {
|
||||
private Attribute reference;
|
||||
|
||||
public ForeignKeyAttribute(Relation relation, AttributeType type, String name, Attribute reference) {
|
||||
super(relation, type, name);
|
||||
this.reference = reference;
|
||||
}
|
||||
|
||||
public ForeignKeyAttribute(Relation relation, AttributeType type, String name, String referencedRelationName, String referencedAttributeName) {
|
||||
this(relation, type, name, relation.getModel().findAttribute(referencedRelationName, referencedAttributeName));
|
||||
if (this.getReference() == null) {
|
||||
throw new IllegalArgumentException("Unknown attribute name.");
|
||||
}
|
||||
}
|
||||
|
||||
public void setReference(Attribute reference) {
|
||||
this.reference = reference;
|
||||
this.getRelation().getModel().fireChangedEvent();
|
||||
}
|
||||
|
||||
public String getFullReferenceName() {
|
||||
return this.getReference().getRelation().getName() + "." + this.getReference().getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + "->" + this.getFullReferenceName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ForeignKeyAttribute copy(Relation newRelation) {
|
||||
return new ForeignKeyAttribute(newRelation, this.getType(), this.getName(), this.getReference());
|
||||
}
|
||||
}
|
|
@ -10,9 +10,7 @@ import nl.andrewlalis.erme.view.view_models.MappingModelViewModel;
|
|||
import nl.andrewlalis.erme.view.view_models.ViewModel;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* This model contains all the information about a single mapping diagram,
|
||||
|
@ -33,10 +31,13 @@ public class MappingModel implements Viewable {
|
|||
@Getter
|
||||
@Setter
|
||||
private transient boolean referenceVisualizationEnabled = false;
|
||||
@Getter
|
||||
private transient final SelectionModel selectionModel;
|
||||
|
||||
public MappingModel() {
|
||||
this.relations = new HashSet<>();
|
||||
this.changeListeners = new HashSet<>();
|
||||
this.selectionModel = new SelectionModel(this);
|
||||
}
|
||||
|
||||
public void addRelation(Relation r) {
|
||||
|
@ -51,14 +52,6 @@ public class MappingModel implements Viewable {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of relations which are currently selected.
|
||||
* @return The list of relations which are selected.
|
||||
*/
|
||||
public List<Relation> getSelectedRelations() {
|
||||
return this.relations.stream().filter(Relation::isSelected).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds an attribute in this model, or returns null otherwise.
|
||||
* @param relationName The name of the relation the attribute is in.
|
||||
|
@ -86,11 +79,8 @@ public class MappingModel implements Viewable {
|
|||
for (Relation r : this.getRelations()) {
|
||||
Set<Attribute> removalSet = new HashSet<>();
|
||||
for (Attribute a : r.getAttributes()) {
|
||||
if (a instanceof ForeignKeyAttribute) {
|
||||
ForeignKeyAttribute fkA = (ForeignKeyAttribute) a;
|
||||
if (fkA.getReference().equals(referenced)) {
|
||||
removalSet.add(fkA);
|
||||
}
|
||||
if (a.hasReference() && a.getReference().equals(referenced)) {
|
||||
removalSet.add(a);
|
||||
}
|
||||
}
|
||||
removalSet.forEach(r::removeAttribute);
|
||||
|
@ -196,12 +186,11 @@ public class MappingModel implements Viewable {
|
|||
ObjectNode attributeNode = mapper.createObjectNode()
|
||||
.put("name", a.getName())
|
||||
.put("type", a.getType().name());
|
||||
if (a instanceof ForeignKeyAttribute) {
|
||||
ForeignKeyAttribute fk = (ForeignKeyAttribute) a;
|
||||
if (a.hasReference()) {
|
||||
ObjectNode referenceNode = mapper.createObjectNode()
|
||||
.put("relation", fk.getReference().getRelation().getName())
|
||||
.put("attribute", fk.getReference().getName());
|
||||
attributeNode.set("references", referenceNode);
|
||||
.put("relation", a.getReference().getRelation().getName())
|
||||
.put("attribute", a.getReference().getName());
|
||||
attributeNode.set("reference", referenceNode);
|
||||
}
|
||||
attributesArray.add(attributeNode);
|
||||
}
|
||||
|
@ -245,7 +234,8 @@ public class MappingModel implements Viewable {
|
|||
Attribute referencedAttribute = model.findAttribute(referencedRelation, referencedName);
|
||||
if (referencedAttribute == null) throw new IllegalArgumentException("Foreign key referenced unknown attribute.");
|
||||
if (!references.containsKey(referencedAttribute)) {
|
||||
ForeignKeyAttribute fk = new ForeignKeyAttribute(attribute.getRelation(), attribute.getType(), attribute.getName(), referencedAttribute);
|
||||
Attribute fk = new Attribute(attribute.getRelation(), attribute.getType(), attribute.getName());
|
||||
fk.setReference(referencedAttribute);
|
||||
attribute.getRelation().removeAttribute(attribute);
|
||||
attribute.getRelation().addAttribute(fk);
|
||||
references.remove(attribute);
|
||||
|
@ -270,8 +260,8 @@ public class MappingModel implements Viewable {
|
|||
Map<Attribute, ObjectNode> references = new HashMap<>();
|
||||
for (JsonNode r : node.withArray("relations")) {
|
||||
for (JsonNode a : r.withArray("attributes")) {
|
||||
if (a.has("references") && a.get("references").isObject()) {
|
||||
ObjectNode referenceNode = (ObjectNode) a.get("references");
|
||||
if (a.has("reference") && a.get("reference").isObject()) {
|
||||
ObjectNode referenceNode = (ObjectNode) a.get("reference");
|
||||
String attributeName = a.get("name").asText();
|
||||
String relationName = r.get("name").asText();
|
||||
Attribute attribute = model.findAttribute(relationName, attributeName);
|
||||
|
|
|
@ -20,7 +20,6 @@ public class Relation implements Viewable, Comparable<Relation> {
|
|||
private String name;
|
||||
private final List<Attribute> attributes;
|
||||
|
||||
private transient boolean selected;
|
||||
private transient RelationViewModel viewModel;
|
||||
|
||||
public Relation(MappingModel model, Point position, String name, List<Attribute> attributes) {
|
||||
|
@ -42,10 +41,6 @@ public class Relation implements Viewable, Comparable<Relation> {
|
|||
this.name = name;
|
||||
}
|
||||
|
||||
public void setSelected(boolean selected) {
|
||||
this.selected = selected;
|
||||
}
|
||||
|
||||
public void addAttribute(Attribute attribute) {
|
||||
this.attributes.add(attribute);
|
||||
this.model.fireChangedEvent();
|
||||
|
@ -63,6 +58,10 @@ public class Relation implements Viewable, Comparable<Relation> {
|
|||
}
|
||||
}
|
||||
|
||||
public boolean isSelected() {
|
||||
return this.model.getSelectionModel().isSelected(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewModel getViewModel() {
|
||||
if (this.viewModel == null) {
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
package nl.andrewlalis.erme.model;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* A model that keeps track of the application's set of selected elements.
|
||||
*/
|
||||
public class SelectionModel {
|
||||
private final MappingModel model;
|
||||
private final Set<Relation> selectedRelations;
|
||||
private final Set<Attribute> selectedAttributes;
|
||||
|
||||
public SelectionModel(MappingModel model) {
|
||||
this.model = model;
|
||||
this.selectedRelations = new HashSet<>();
|
||||
this.selectedAttributes = new HashSet<>();
|
||||
}
|
||||
|
||||
public boolean isSelected(Relation relation) {
|
||||
return this.selectedRelations.contains(relation);
|
||||
}
|
||||
|
||||
public boolean isSelected(Attribute attribute) {
|
||||
return this.selectedAttributes.contains(attribute);
|
||||
}
|
||||
|
||||
public List<Relation> getSelectedRelations() {
|
||||
return new ArrayList<>(this.selectedRelations);
|
||||
}
|
||||
|
||||
public List<Attribute> getSelectedAttributes() {
|
||||
return new ArrayList<>(this.selectedAttributes);
|
||||
}
|
||||
|
||||
public void select(Relation relation) {
|
||||
this.selectedRelations.add(relation);
|
||||
}
|
||||
|
||||
public void selectAll(Collection<Relation> relations) {
|
||||
this.selectedRelations.addAll(relations);
|
||||
}
|
||||
|
||||
public void select(Attribute attribute) {
|
||||
this.selectedAttributes.add(attribute);
|
||||
}
|
||||
|
||||
public void toggle(Relation relation) {
|
||||
if (selectedRelations.contains(relation)) {
|
||||
selectedRelations.remove(relation);
|
||||
} else {
|
||||
selectedRelations.add(relation);
|
||||
}
|
||||
}
|
||||
|
||||
public void toggle(Attribute attribute) {
|
||||
if (selectedAttributes.contains(attribute)) {
|
||||
selectedAttributes.remove(attribute);
|
||||
} else {
|
||||
selectedAttributes.add(attribute);
|
||||
}
|
||||
}
|
||||
|
||||
public void clearSelection() {
|
||||
this.selectedRelations.clear();
|
||||
this.selectedAttributes.clear();
|
||||
}
|
||||
|
||||
public void clearRelations() {
|
||||
this.selectedRelations.clear();
|
||||
}
|
||||
|
||||
public void clearAttributes() {
|
||||
this.selectedAttributes.clear();
|
||||
}
|
||||
}
|
|
@ -2,7 +2,9 @@ package nl.andrewlalis.erme.view;
|
|||
|
||||
import nl.andrewlalis.erme.control.actions.edits.AddAttributeAction;
|
||||
import nl.andrewlalis.erme.control.actions.edits.AddRelationAction;
|
||||
import nl.andrewlalis.erme.control.actions.edits.RemoveAttributeAction;
|
||||
import nl.andrewlalis.erme.control.actions.edits.RemoveRelationAction;
|
||||
import nl.andrewlalis.erme.model.Attribute;
|
||||
import nl.andrewlalis.erme.model.Relation;
|
||||
|
||||
import javax.swing.*;
|
||||
|
@ -10,19 +12,19 @@ import java.util.List;
|
|||
|
||||
public class DiagramPopupMenu extends JPopupMenu {
|
||||
public DiagramPopupMenu(DiagramPanel diagramPanel) {
|
||||
List<Relation> selectedRelations = diagramPanel.getModel().getSelectedRelations();
|
||||
if (selectedRelations.size() == 0) {
|
||||
List<Relation> selectedRelations = diagramPanel.getModel().getSelectionModel().getSelectedRelations();
|
||||
List<Attribute> selectedAttributes = diagramPanel.getModel().getSelectionModel().getSelectedAttributes();
|
||||
if (selectedRelations.isEmpty() && selectedAttributes.isEmpty()) {
|
||||
this.add(new AddRelationAction(diagramPanel));
|
||||
}
|
||||
if (selectedRelations.size() > 0) {
|
||||
if (selectedRelations.size() > 0 && selectedAttributes.isEmpty()) {
|
||||
this.add(new RemoveRelationAction(diagramPanel));
|
||||
}
|
||||
if (selectedRelations.size() == 1) {
|
||||
Relation relation = selectedRelations.get(0);
|
||||
if (selectedRelations.size() == 1 && selectedAttributes.isEmpty()) {
|
||||
this.add(new AddAttributeAction(diagramPanel));
|
||||
if (!relation.getAttributes().isEmpty()) {
|
||||
this.add(new RemoveRelationAction(diagramPanel));
|
||||
}
|
||||
}
|
||||
if (!selectedAttributes.isEmpty() && selectedRelations.isEmpty()) {
|
||||
this.add(new RemoveAttributeAction(diagramPanel));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
package nl.andrewlalis.erme.view;
|
||||
|
||||
import nl.andrewlalis.erme.model.Attribute;
|
||||
import nl.andrewlalis.erme.model.AttributeType;
|
||||
import nl.andrewlalis.erme.model.Relation;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* A popup that's shown when creating or editing an attribute of a relation.
|
||||
*/
|
||||
public class EditAttributePopupDialog extends JDialog {
|
||||
private final Relation relation;
|
||||
private final Attribute attribute;
|
||||
|
||||
private final JTextField nameField;
|
||||
private final JComboBox<AttributeType> attributeTypeComboBox;
|
||||
private final JSpinner orderSpinner;
|
||||
|
||||
public EditAttributePopupDialog(Frame owner, Relation relation, Attribute attribute) {
|
||||
super(owner, "Edit Attribute", true);
|
||||
this.relation = relation;
|
||||
this.attribute = attribute;
|
||||
JPanel mainPanel = new JPanel(new GridBagLayout());
|
||||
GridBagConstraints gc = new GridBagConstraints();
|
||||
gc.ipadx = 2;
|
||||
gc.ipady = 2;
|
||||
gc.gridx = 0;
|
||||
gc.gridy = 0;
|
||||
gc.anchor = GridBagConstraints.LINE_START;
|
||||
mainPanel.add(new JLabel("Name"), gc);
|
||||
gc.gridx = 1;
|
||||
gc.anchor = GridBagConstraints.LINE_END;
|
||||
this.nameField = new JTextField(20);
|
||||
mainPanel.add(nameField, gc);
|
||||
gc.gridx = 0;
|
||||
gc.gridy++;
|
||||
gc.anchor = GridBagConstraints.LINE_START;
|
||||
mainPanel.add(new JLabel("Type"), gc);
|
||||
gc.gridx = 1;
|
||||
gc.anchor = GridBagConstraints.LINE_END;
|
||||
this.attributeTypeComboBox = new JComboBox<>(AttributeType.values());
|
||||
mainPanel.add(attributeTypeComboBox, gc);
|
||||
gc.gridx = 0;
|
||||
gc.gridy++;
|
||||
gc.anchor = GridBagConstraints.LINE_START;
|
||||
mainPanel.add(new JLabel("Order"), gc);
|
||||
gc.gridx = 1;
|
||||
gc.anchor = GridBagConstraints.LINE_END;
|
||||
this.orderSpinner = new JSpinner(new SpinnerNumberModel(1, 1, relation.getAttributes().size() + 1, 1));
|
||||
mainPanel.add(orderSpinner, gc);
|
||||
|
||||
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
|
||||
JButton okayButton = new JButton("Okay");
|
||||
okayButton.addActionListener(e -> this.submit());
|
||||
JButton cancelButton = new JButton("Cancel");
|
||||
cancelButton.addActionListener(e -> this.dispose());
|
||||
buttonPanel.add(okayButton);
|
||||
buttonPanel.add(cancelButton);
|
||||
gc.gridx = 0;
|
||||
gc.gridy++;
|
||||
gc.gridwidth = 2;
|
||||
mainPanel.add(buttonPanel, gc);
|
||||
|
||||
if (this.attribute != null) {
|
||||
this.nameField.setText(this.attribute.getName());
|
||||
this.attributeTypeComboBox.setSelectedItem(this.attribute.getType());
|
||||
this.orderSpinner.setValue(this.relation.getAttributes().indexOf(this.attribute));
|
||||
} else {
|
||||
this.orderSpinner.setValue(this.relation.getAttributes().size() + 1);
|
||||
}
|
||||
|
||||
this.setContentPane(mainPanel);
|
||||
this.pack();
|
||||
this.setLocationRelativeTo(owner);
|
||||
}
|
||||
|
||||
private void submit() {
|
||||
String name = this.nameField.getText().trim();
|
||||
AttributeType type = (AttributeType) this.attributeTypeComboBox.getSelectedItem();
|
||||
int order = (int) this.orderSpinner.getValue();
|
||||
if (name.isEmpty()) {
|
||||
JOptionPane.showMessageDialog(this, "The attribute must have a name.", "Missing Name", JOptionPane.WARNING_MESSAGE);
|
||||
return;
|
||||
}
|
||||
if (this.attribute != null) {
|
||||
this.attribute.setName(name);
|
||||
this.attribute.setType(type);
|
||||
} else {
|
||||
Attribute a = new Attribute(this.relation, type, name);
|
||||
this.relation.addAttribute(a, order - 1);
|
||||
}
|
||||
this.dispose();
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@ package nl.andrewlalis.erme.view;
|
|||
import nl.andrewlalis.erme.control.actions.*;
|
||||
import nl.andrewlalis.erme.control.actions.edits.AddAttributeAction;
|
||||
import nl.andrewlalis.erme.control.actions.edits.AddRelationAction;
|
||||
import nl.andrewlalis.erme.control.actions.edits.RemoveAttributeAction;
|
||||
import nl.andrewlalis.erme.control.actions.edits.RemoveRelationAction;
|
||||
|
||||
import javax.swing.*;
|
||||
|
@ -35,7 +36,7 @@ public class EditorMenuBar extends JMenuBar {
|
|||
menu.add(new AddRelationAction(diagramPanel));
|
||||
menu.add(new RemoveRelationAction(diagramPanel));
|
||||
menu.add(new AddAttributeAction(diagramPanel));
|
||||
menu.add(new RemoveRelationAction(diagramPanel));
|
||||
menu.add(new RemoveAttributeAction(diagramPanel));
|
||||
menu.add(new AutoPositionAction(diagramPanel));
|
||||
return menu;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package nl.andrewlalis.erme.view.view_models;
|
|||
|
||||
import nl.andrewlalis.erme.model.Attribute;
|
||||
import nl.andrewlalis.erme.model.AttributeType;
|
||||
import nl.andrewlalis.erme.model.ForeignKeyAttribute;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.font.TextAttribute;
|
||||
|
@ -16,6 +15,7 @@ public class AttributeViewModel implements ViewModel {
|
|||
public static final int PADDING_X = 5;
|
||||
public static final int PADDING_Y = 5;
|
||||
public static final Color BACKGROUND_COLOR = new Color(192, 192, 192, 127);
|
||||
public static final Color SELECTED_COLOR = new Color(148, 255, 176, 127);
|
||||
public static final Color FONT_COLOR = Color.BLACK;
|
||||
public static final float FK_FONT_SIZE = 11.0f;
|
||||
private static final float LOLCAT_SAT = 0.75f;
|
||||
|
@ -35,16 +35,16 @@ public class AttributeViewModel implements ViewModel {
|
|||
g.setColor(FONT_COLOR);
|
||||
g.drawRect(r.x, r.y, r.width, r.height);
|
||||
g.drawString(as.getIterator(), r.x + PADDING_X, r.y + (r.height - PADDING_Y));
|
||||
if (this.attribute instanceof ForeignKeyAttribute) {
|
||||
ForeignKeyAttribute fkAttribute = (ForeignKeyAttribute) this.attribute;
|
||||
if (this.attribute.hasReference() && !this.attribute.getRelation().getModel().isReferenceVisualizationEnabled()) {
|
||||
Font originalFont = g.getFont();
|
||||
g.setFont(g.getFont().deriveFont(Font.ITALIC, FK_FONT_SIZE));
|
||||
g.drawString(fkAttribute.getFullReferenceName(), r.x + PADDING_X, r.y - PADDING_Y);
|
||||
g.drawString(getFullReferenceName(), r.x + PADDING_X, r.y - PADDING_Y);
|
||||
g.setFont(originalFont);
|
||||
}
|
||||
}
|
||||
|
||||
private Color getBackgroundColor(int x, int y, Graphics2D g) {
|
||||
if (attribute.isSelected()) return SELECTED_COLOR;
|
||||
if (!attribute.getRelation().getModel().isLolcatEnabled()) return BACKGROUND_COLOR;
|
||||
Point offset = g.getClipBounds().getLocation();
|
||||
g.translate(offset.x, offset.y);
|
||||
|
@ -82,11 +82,10 @@ public class AttributeViewModel implements ViewModel {
|
|||
Rectangle2D nameRect = g.getFontMetrics().getStringBounds(as.getIterator(), 0, this.attribute.getName().length(), g);
|
||||
int width = (int) nameRect.getWidth() + (2 * PADDING_X);
|
||||
int height = (int) nameRect.getHeight() + (2 * PADDING_Y);
|
||||
if (this.attribute instanceof ForeignKeyAttribute) {
|
||||
ForeignKeyAttribute fkAttribute = (ForeignKeyAttribute) this.attribute;
|
||||
if (this.attribute.hasReference()) {
|
||||
Font originalFont = g.getFont();
|
||||
g.setFont(g.getFont().deriveFont(Font.ITALIC, FK_FONT_SIZE));
|
||||
Rectangle referenceNameBounds = g.getFontMetrics().getStringBounds(fkAttribute.getFullReferenceName(), g).getBounds();
|
||||
Rectangle referenceNameBounds = g.getFontMetrics().getStringBounds(getFullReferenceName(), g).getBounds();
|
||||
g.setFont(originalFont);
|
||||
width = Math.max(width, referenceNameBounds.width + (2 * PADDING_X));
|
||||
}
|
||||
|
@ -103,4 +102,9 @@ public class AttributeViewModel implements ViewModel {
|
|||
}
|
||||
return as;
|
||||
}
|
||||
|
||||
private String getFullReferenceName() {
|
||||
if (!this.attribute.hasReference()) return "";
|
||||
return this.attribute.getReference().getRelation().getName() + "." + this.attribute.getReference().getName();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package nl.andrewlalis.erme.view.view_models;
|
||||
|
||||
import nl.andrewlalis.erme.model.Attribute;
|
||||
import nl.andrewlalis.erme.model.ForeignKeyAttribute;
|
||||
import nl.andrewlalis.erme.model.MappingModel;
|
||||
import nl.andrewlalis.erme.model.Relation;
|
||||
|
||||
|
@ -32,13 +31,12 @@ public class MappingModelViewModel implements ViewModel {
|
|||
g2.setStroke(dashedStroke);
|
||||
for (Relation r : this.model.getRelations()) {
|
||||
for (Attribute a : r.getAttributes()) {
|
||||
if (a instanceof ForeignKeyAttribute) {
|
||||
ForeignKeyAttribute fk = (ForeignKeyAttribute) a;
|
||||
if (a.hasReference()) {
|
||||
// Generate a random HSB color for the line, seeded using the referenced attribute's hash code.
|
||||
Random random = new Random(fk.getReference().hashCode());
|
||||
Random random = new Random(a.getReference().hashCode());
|
||||
g2.setColor(Color.getHSBColor(random.nextFloat(), 1.0f, 0.8f));
|
||||
Rectangle sourceBounds = fk.getViewModel().getBounds(g);
|
||||
Rectangle targetBounds = fk.getReference().getViewModel().getBounds(g);
|
||||
Rectangle sourceBounds = a.getViewModel().getBounds(g);
|
||||
Rectangle targetBounds = a.getReference().getViewModel().getBounds(g);
|
||||
Point sourcePoint = new Point(sourceBounds.x + sourceBounds.width / 2, sourceBounds.y + 3 * targetBounds.height / 4);
|
||||
Point targetPoint = new Point(targetBounds.x + targetBounds.width / 2, targetBounds.y + 3 * targetBounds.height / 4);
|
||||
g2.drawLine(sourcePoint.x, sourcePoint.y, targetPoint.x, targetPoint.y);
|
||||
|
|
Loading…
Reference in New Issue