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