Cleaned up singleton actions, updated instructions, etc.

This commit is contained in:
Andrew Lalis 2021-10-28 12:06:50 +02:00
parent 0be31c84ac
commit 1019654e76
30 changed files with 241 additions and 503 deletions

View File

@ -6,7 +6,7 @@
<groupId>nl.andrewlalis</groupId>
<artifactId>EntityRelationMappingEditor</artifactId>
<version>1.6.1</version>
<version>1.6.2</version>
<build>
<plugins>
<plugin>

View File

@ -1,41 +0,0 @@
package nl.andrewlalis.erme.control.actions;
import lombok.Setter;
import nl.andrewlalis.erme.EntityRelationMappingEditor;
import nl.andrewlalis.erme.view.DiagramPanel;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
public class AboutAction extends AbstractAction {
private static AboutAction instance;
public static AboutAction getInstance() {
if (instance == null) instance = new AboutAction();
return instance;
}
@Setter
private DiagramPanel diagramPanel;
public AboutAction() {
super("About");
this.putValue(SHORT_DESCRIPTION, "Show some information about this program.");
}
@Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(
this.diagramPanel,
"Entity-Relation Mapping Editor\n" +
"by Andrew Lalis\n" +
"Version " + EntityRelationMappingEditor.VERSION + "\n" +
"To report bugs or make suggestions, please visit the GitHub\n" +
"repository for this application and create a new issue.\n\n" +
"Thank you for using the ERME!",
"About ERME",
JOptionPane.INFORMATION_MESSAGE
);
}
}

View File

@ -1,7 +1,5 @@
package nl.andrewlalis.erme.control.actions;
import lombok.Setter;
import nl.andrewlalis.erme.model.MappingModel;
import nl.andrewlalis.erme.model.Relation;
import nl.andrewlalis.erme.view.DiagramPanel;
import nl.andrewlalis.erme.view.OrderableListPanel;
@ -17,31 +15,20 @@ import java.util.concurrent.atomic.AtomicInteger;
* A class that implements an AutoPositionAction. This automatically (vertically) positions all relations in the model
* based either on alphabetic ordering (by name) or an order that's set by the user
*/
public class AutoPositionAction extends AbstractAction {
public class AutoPositionAction extends DiagramPanelAction {
private final static int MARGIN = 10;
private final static int PADDING = 10;
private static AutoPositionAction instance;
@Setter
private DiagramPanel diagramPanel;
@Setter
private MappingModel model;
public AutoPositionAction() {
super("Align Relations");
this.putValue(SHORT_DESCRIPTION, "Automatically Align Relations");
}
public static AutoPositionAction getInstance() {
if (instance == null) {
instance = new AutoPositionAction();
}
return instance;
public AutoPositionAction(DiagramPanel diagramPanel) {
super("Align Relations", diagramPanel);
this.putValue(SHORT_DESCRIPTION, "Automatically Align Relations");
}
@Override
public void actionPerformed(ActionEvent actionEvent) {
if (model.getRelations().size() == 0) {
if (getDiagramPanel().getModel().getRelations().size() == 0) {
JOptionPane.showMessageDialog(
this.diagramPanel,
getDiagramPanel(),
"Cannot position all relations when there are no relations present",
"Relations Required",
JOptionPane.WARNING_MESSAGE
@ -50,7 +37,7 @@ public class AutoPositionAction extends AbstractAction {
}
String[] choices = new String[]{"Alphabeticaly", "Custom Order"};
String choice = (String) JOptionPane.showInputDialog(
this.diagramPanel,
getDiagramPanel(),
"Select how to sort the relations",
"Position Relations",
JOptionPane.PLAIN_MESSAGE,
@ -62,14 +49,14 @@ public class AutoPositionAction extends AbstractAction {
positionRelations(getAlphabeticRelationList());
} else if (choice.equals(choices[1])) {
JOptionPane.showConfirmDialog(
this.diagramPanel,
getDiagramPanel(),
OrderableListPanel.getInstance(),
"teststring",
JOptionPane.OK_CANCEL_OPTION,
JOptionPane.PLAIN_MESSAGE);
this.positionRelations(OrderableListPanel.getInstance().getOrderList());
}
diagramPanel.repaint();
getDiagramPanel().repaint();
}
/**
@ -80,23 +67,20 @@ public class AutoPositionAction extends AbstractAction {
if (orderList.isEmpty()) return;
AtomicInteger vertSpace = new AtomicInteger(0);
orderList.forEach(r -> {
int height = (int) r.getViewModel().getBounds(diagramPanel.getGraphics2D()).getHeight();
int height = (int) r.getViewModel().getBounds(getDiagramPanel().getGraphics2D()).getHeight();
vertSpace.set(Math.max(vertSpace.get(), height));
});
vertSpace.addAndGet(PADDING);
AtomicInteger vertPos = new AtomicInteger(MARGIN);
orderList.forEach(r -> {
r.setPosition(new Point(MARGIN, vertPos.getAndAdd(vertSpace.get())));
});
diagramPanel.centerModel();
orderList.forEach(r -> r.setPosition(new Point(MARGIN, vertPos.getAndAdd(vertSpace.get()))));
getDiagramPanel().centerModel();
}
/**
* Creates an orderList by grabbing all relations and sorting them
*/
private ArrayList<Relation> getAlphabeticRelationList() {
ArrayList<Relation> relationList = new ArrayList<>(model.getRelations());
ArrayList<Relation> relationList = new ArrayList<>(getDiagramPanel().getModel().getRelations());
Collections.sort(relationList);
return relationList;
}

View File

@ -0,0 +1,17 @@
package nl.andrewlalis.erme.control.actions;
import lombok.AccessLevel;
import lombok.Getter;
import nl.andrewlalis.erme.view.DiagramPanel;
import javax.swing.*;
public abstract class DiagramPanelAction extends AbstractAction {
@Getter(AccessLevel.PROTECTED)
private final DiagramPanel diagramPanel;
public DiagramPanelAction(String name, DiagramPanel diagramPanel) {
super(name);
this.diagramPanel = diagramPanel;
}
}

View File

@ -1,29 +1,15 @@
package nl.andrewlalis.erme.control.actions;
import lombok.Setter;
import nl.andrewlalis.erme.view.DiagramPanel;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
public class ExitAction extends AbstractAction {
private static ExitAction instance;
public static ExitAction getInstance() {
if (instance == null) {
instance = new ExitAction();
}
return instance;
}
@Setter
private DiagramPanel diagramPanel;
public ExitAction() {
super("Exit");
public class ExitAction extends DiagramPanelAction {
public ExitAction(DiagramPanel diagramPanel) {
super("Exit", diagramPanel);
this.putValue(Action.SHORT_DESCRIPTION, "Exit the program.");
this.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_Q, InputEvent.SHIFT_DOWN_MASK | InputEvent.CTRL_DOWN_MASK));
}
@ -31,7 +17,7 @@ public class ExitAction extends AbstractAction {
@Override
public void actionPerformed(ActionEvent e) {
int choice = JOptionPane.showConfirmDialog(
this.diagramPanel,
getDiagramPanel(),
"Are you sure you want to quit?\nAll unsaved data will be lost.",
"Confirm Exit",
JOptionPane.OK_CANCEL_OPTION,

View File

@ -1,6 +1,5 @@
package nl.andrewlalis.erme.control.actions;
import lombok.Setter;
import nl.andrewlalis.erme.model.MappingModel;
import nl.andrewlalis.erme.model.Relation;
import nl.andrewlalis.erme.view.DiagramPanel;
@ -20,33 +19,21 @@ import java.io.IOException;
import java.util.List;
import java.util.prefs.Preferences;
public class ExportToImageAction extends AbstractAction {
public class ExportToImageAction extends DiagramPanelAction {
private static final String LAST_EXPORT_LOCATION_KEY = "lastExportLocation";
private static ExportToImageAction instance;
public static ExportToImageAction getInstance() {
if (instance == null) {
instance = new ExportToImageAction();
}
return instance;
}
@Setter
private MappingModel model;
@Setter
private DiagramPanel diagramPanel;
public ExportToImageAction() {
super("Export to Image");
public ExportToImageAction(DiagramPanel diagramPanel) {
super("Export to Image", diagramPanel);
this.putValue(Action.SHORT_DESCRIPTION, "Export the current diagram to an image.");
this.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_E, InputEvent.CTRL_DOWN_MASK));
}
@Override
public void actionPerformed(ActionEvent e) {
if (this.model.getRelations().isEmpty()) {
DiagramPanel dp = getDiagramPanel();
if (dp.getModel().getRelations().isEmpty()) {
JOptionPane.showMessageDialog(
this.diagramPanel,
dp,
"Model is empty. Add some relations before exporting to an image.",
"Model Empty",
JOptionPane.WARNING_MESSAGE
@ -62,11 +49,11 @@ public class ExportToImageAction extends AbstractAction {
if (path != null) {
fileChooser.setSelectedFile(new File(path));
}
int choice = fileChooser.showSaveDialog(this.diagramPanel);
int choice = fileChooser.showSaveDialog(dp);
if (choice == JFileChooser.APPROVE_OPTION) {
File chosenFile = fileChooser.getSelectedFile();
if (chosenFile == null || chosenFile.isDirectory()) {
JOptionPane.showMessageDialog(fileChooser, "The selected file cannot be written to.", "Invalid File", JOptionPane.WARNING_MESSAGE);
JOptionPane.showMessageDialog(dp, "The selected file cannot be written to.", "Invalid File", JOptionPane.WARNING_MESSAGE);
return;
}
int i = chosenFile.getName().lastIndexOf('.');
@ -76,13 +63,13 @@ public class ExportToImageAction extends AbstractAction {
} else {
chosenFile = new File(chosenFile.getParent(), chosenFile.getName() + '.' + extension);
}
String input = JOptionPane.showInputDialog(this.diagramPanel, "Choose a scale for the image.", "3.0");
String input = JOptionPane.showInputDialog(dp, "Choose a scale for the image.", "3.0");
float scale;
try {
scale = Float.parseFloat(input);
if (scale <= 0.0f || scale > 64.0f) throw new IllegalArgumentException();
} catch (Exception ex) {
JOptionPane.showMessageDialog(this.diagramPanel, "Invalid scale value. Should be a positive number less than 64.", "Invalid Scale", JOptionPane.WARNING_MESSAGE);
JOptionPane.showMessageDialog(dp, "Invalid scale value. Should be a positive number less than 64.", "Invalid Scale", JOptionPane.WARNING_MESSAGE);
return;
}
try {
@ -92,7 +79,7 @@ public class ExportToImageAction extends AbstractAction {
ImageIO.write(render, extension, chosenFile);
prefs.put(LAST_EXPORT_LOCATION_KEY, chosenFile.getAbsolutePath());
JOptionPane.showMessageDialog(
this.diagramPanel,
dp,
"Image export completed in " + String.format("%.4f", durationSeconds) + " seconds.\n" +
"Resolution: " + render.getWidth() + "x" + render.getHeight(),
"Image Export Complete",
@ -111,11 +98,12 @@ public class ExportToImageAction extends AbstractAction {
* @return The image which was rendered.
*/
private BufferedImage renderModel(float scale) {
MappingModel model = getDiagramPanel().getModel();
// Prepare a tiny sample image that we can use to determine the bounds of the model in a graphics context.
BufferedImage bufferedImage = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = bufferedImage.createGraphics();
DiagramPanel.prepareGraphics(g2d);
final Rectangle bounds = this.model.getViewModel().getBounds(g2d);
final Rectangle bounds = model.getViewModel().getBounds(g2d);
bounds.width *= scale;
bounds.height *= scale;
@ -134,13 +122,13 @@ public class ExportToImageAction extends AbstractAction {
DiagramPanel.prepareGraphics(g2d);
// Render the model.
boolean lolcat = LolcatAction.getInstance().isLolcatEnabled(); // save previous lolcat mode
LolcatAction.getInstance().setLolcatEnabled(false);
List<Relation> selectedRelations = this.model.getSelectedRelations();
this.model.getSelectedRelations().forEach(r -> r.setSelected(false));
new MappingModelViewModel(this.model).draw(g2d);
this.model.getRelations().forEach(r -> r.setSelected(selectedRelations.contains(r)));
LolcatAction.getInstance().setLolcatEnabled(lolcat); // revert previous lolcat mode
boolean lolcat = model.isLolcatEnabled(); // save previous lolcat mode
model.setLolcatEnabled(false);
List<Relation> selectedRelations = model.getSelectedRelations();
model.getSelectedRelations().forEach(r -> r.setSelected(false));
new MappingModelViewModel(model).draw(g2d);
model.getRelations().forEach(r -> r.setSelected(selectedRelations.contains(r)));
model.setLolcatEnabled(lolcat); // revert previous lolcat mode
// Revert to the normal image space, and render a watermark.
g2d.setTransform(originalTransform);

View File

@ -1,6 +1,5 @@
package nl.andrewlalis.erme.control.actions;
import lombok.Setter;
import nl.andrewlalis.erme.view.DiagramPanel;
import javax.swing.*;
@ -16,27 +15,24 @@ import java.net.URISyntaxException;
/**
* An action which, when performed, opens a view that displays an HTML document.
*/
public abstract class HtmlDocumentViewerAction extends AbstractAction {
public abstract class HtmlDocumentViewerAction extends DiagramPanelAction {
private final String resourceFileName;
private final Dialog.ModalityType modalityType;
public HtmlDocumentViewerAction(String name, String resourceFileName) {
this(name, resourceFileName, Dialog.ModalityType.APPLICATION_MODAL);
public HtmlDocumentViewerAction(String name, String resourceFileName, DiagramPanel diagramPanel) {
this(name, resourceFileName, Dialog.ModalityType.APPLICATION_MODAL, diagramPanel);
}
public HtmlDocumentViewerAction(String name, String resourceFileName, Dialog.ModalityType modalityType) {
super(name);
public HtmlDocumentViewerAction(String name, String resourceFileName, Dialog.ModalityType modalityType, DiagramPanel diagramPanel) {
super(name, diagramPanel);
this.resourceFileName = resourceFileName;
this.modalityType = modalityType;
}
@Setter
private DiagramPanel diagramPanel;
@Override
public void actionPerformed(ActionEvent e) {
JDialog dialog = new JDialog(
SwingUtilities.getWindowAncestor(this.diagramPanel),
SwingUtilities.getWindowAncestor(getDiagramPanel()),
(String) this.getValue(NAME),
this.modalityType
);
@ -63,7 +59,7 @@ public abstract class HtmlDocumentViewerAction extends AbstractAction {
} catch (IOException ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(
this.diagramPanel,
getDiagramPanel(),
"An error occured:\n" + ex.getMessage(),
"Error",
JOptionPane.ERROR_MESSAGE
@ -77,7 +73,7 @@ public abstract class HtmlDocumentViewerAction extends AbstractAction {
dialog.setMaximumSize(new Dimension(600, 800));
dialog.setPreferredSize(new Dimension(600, 800));
dialog.pack();
dialog.setLocationRelativeTo(this.diagramPanel);
dialog.setLocationRelativeTo(getDiagramPanel());
dialog.setVisible(true);
}

View File

@ -1,15 +1,10 @@
package nl.andrewlalis.erme.control.actions;
import nl.andrewlalis.erme.view.DiagramPanel;
public class InstructionsAction extends HtmlDocumentViewerAction {
private static InstructionsAction instance;
public static InstructionsAction getInstance() {
if (instance == null) instance = new InstructionsAction();
return instance;
}
public InstructionsAction() {
super("Instructions", "html/instructions.html");
public InstructionsAction(DiagramPanel diagramPanel) {
super("Instructions", "html/instructions.html", diagramPanel);
this.putValue(SHORT_DESCRIPTION, "Instructions for how to use this program.");
}
}

View File

@ -6,7 +6,6 @@ import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.Setter;
import nl.andrewlalis.erme.model.MappingModel;
import nl.andrewlalis.erme.view.DiagramPanel;
@ -19,22 +18,11 @@ import java.io.File;
import java.io.FileInputStream;
import java.util.prefs.Preferences;
public class LoadAction extends AbstractAction {
public class LoadAction extends DiagramPanelAction {
private static final String LAST_LOAD_LOCATION_KEY = "lastLoadLocation";
private static LoadAction instance;
public static LoadAction getInstance() {
if (instance == null) {
instance = new LoadAction();
}
return instance;
}
@Setter
private DiagramPanel diagramPanel;
public LoadAction() {
super("Load");
public LoadAction(DiagramPanel diagramPanel) {
super("Load", diagramPanel);
this.putValue(SHORT_DESCRIPTION, "Load a saved diagram.");
this.putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_O, InputEvent.CTRL_DOWN_MASK));
}
@ -52,7 +40,7 @@ public class LoadAction extends AbstractAction {
if (path != null) {
fileChooser.setSelectedFile(new File(path));
}
int choice = fileChooser.showOpenDialog(this.diagramPanel);
int choice = fileChooser.showOpenDialog(getDiagramPanel());
if (choice == JFileChooser.APPROVE_OPTION) {
File chosenFile = fileChooser.getSelectedFile();
if (chosenFile == null || chosenFile.isDirectory() || !chosenFile.exists() || !chosenFile.canRead()) {
@ -65,7 +53,7 @@ public class LoadAction extends AbstractAction {
.configure(MapperFeature.PROPAGATE_TRANSIENT_MARKER, true)
.build();
JsonNode data = mapper.readValue(fis, JsonNode.class);
this.diagramPanel.setModel(MappingModel.fromJson((ObjectNode) data));
getDiagramPanel().setModel(MappingModel.fromJson((ObjectNode) data));
prefs.put(LAST_LOAD_LOCATION_KEY, chosenFile.getAbsolutePath());
} catch (Exception ex) {
ex.printStackTrace();

View File

@ -1,28 +1,14 @@
package nl.andrewlalis.erme.control.actions;
import lombok.Setter;
import nl.andrewlalis.erme.model.*;
import nl.andrewlalis.erme.view.DiagramPanel;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
public class LoadSampleModelAction extends AbstractAction {
private static LoadSampleModelAction instance;
public static LoadSampleModelAction getInstance() {
if (instance == null) {
instance = new LoadSampleModelAction();
}
return instance;
}
@Setter
private DiagramPanel diagramPanel;
public LoadSampleModelAction() {
super("Load Sample Model");
public class LoadSampleModelAction extends DiagramPanelAction {
public LoadSampleModelAction(DiagramPanel diagramPanel) {
super("Load Sample Model", diagramPanel);
this.putValue(SHORT_DESCRIPTION, "Loads a sample ER-mapping model.");
}
@ -38,6 +24,6 @@ public class LoadSampleModelAction extends AbstractAction {
r1.addAttribute(new Attribute(r1, AttributeType.PLAIN, "purchasedAt"));
r1.addAttribute(new ForeignKeyAttribute(r1, AttributeType.PLAIN, "typeName", "AirplaneType", "name"));
model.addRelation(r1);
this.diagramPanel.setModel(model);
getDiagramPanel().setModel(model);
}
}

View File

@ -1,26 +0,0 @@
package nl.andrewlalis.erme.control.actions;
import lombok.Getter;
import lombok.Setter;
import javax.swing.*;
import java.awt.*;
public abstract class LocalAction extends AbstractAction {
@Setter
@Getter
private Point location;
public LocalAction(String name, Point location) {
super(name);
this.location = location;
}
public LocalAction(String name) {
this(name, null);
}
public boolean hasLocation() {
return this.location != null;
}
}

View File

@ -1,37 +1,20 @@
package nl.andrewlalis.erme.control.actions;
import lombok.Getter;
import lombok.Setter;
import nl.andrewlalis.erme.view.DiagramPanel;
import javax.swing.*;
import java.awt.event.ActionEvent;
public class LolcatAction extends AbstractAction {
private static LolcatAction instance;
@Getter
@Setter
private boolean lolcatEnabled = false;
public static LolcatAction getInstance() {
if (instance == null) {
instance = new LolcatAction();
}
return instance;
}
@Setter
private DiagramPanel diagramPanel;
public LolcatAction() {
super("Toggle Lolcat Mode");
public class LolcatAction extends DiagramPanelAction {
public LolcatAction(DiagramPanel diagramPanel) {
super("Toggle Lolcat Mode", diagramPanel);
this.putValue(SHORT_DESCRIPTION, "Does some wacky color stuff.");
}
@Override
public void actionPerformed(ActionEvent actionEvent) {
lolcatEnabled = ((AbstractButton)actionEvent.getSource()).getModel().isSelected();
diagramPanel.repaint();
boolean lolcatEnabled = ((AbstractButton)actionEvent.getSource()).getModel().isSelected();
getDiagramPanel().getModel().setLolcatEnabled(lolcatEnabled);
getDiagramPanel().repaint();
}
}

View File

@ -1,19 +1,12 @@
package nl.andrewlalis.erme.control.actions;
import nl.andrewlalis.erme.view.DiagramPanel;
import java.awt.*;
public class MappingAlgorithmHelpAction extends HtmlDocumentViewerAction {
private static MappingAlgorithmHelpAction instance;
public static MappingAlgorithmHelpAction getInstance() {
if (instance == null) {
instance = new MappingAlgorithmHelpAction();
}
return instance;
}
public MappingAlgorithmHelpAction() {
super("Mapping Algorithm Help", "html/er_mapping_algorithm.html", Dialog.ModalityType.DOCUMENT_MODAL);
public MappingAlgorithmHelpAction(DiagramPanel diagramPanel) {
super("Mapping Algorithm Help", "html/er_mapping_algorithm.html", Dialog.ModalityType.DOCUMENT_MODAL, diagramPanel);
this.putValue(SHORT_DESCRIPTION, "Shows a quick guide on how to map from an ER model to a schema.");
}
}

View File

@ -1,6 +1,5 @@
package nl.andrewlalis.erme.control.actions;
import lombok.Setter;
import nl.andrewlalis.erme.model.MappingModel;
import nl.andrewlalis.erme.view.DiagramPanel;
@ -9,27 +8,15 @@ import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
public class NewModelAction extends AbstractAction {
private static NewModelAction instance;
public static NewModelAction getInstance() {
if (instance == null) {
instance = new NewModelAction();
}
return instance;
}
@Setter
private DiagramPanel diagramPanel;
public NewModelAction() {
super("New Model");
public class NewModelAction extends DiagramPanelAction {
public NewModelAction(DiagramPanel diagramPanel) {
super("New Model", diagramPanel);
this.putValue(SHORT_DESCRIPTION, "Create a new model.");
this.putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_N, InputEvent.CTRL_DOWN_MASK));
}
@Override
public void actionPerformed(ActionEvent e) {
this.diagramPanel.setModel(new MappingModel());
getDiagramPanel().setModel(new MappingModel());
}
}

View File

@ -4,8 +4,6 @@ import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.json.JsonMapper;
import lombok.Setter;
import nl.andrewlalis.erme.model.MappingModel;
import nl.andrewlalis.erme.view.DiagramPanel;
import javax.swing.*;
@ -18,25 +16,11 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.util.prefs.Preferences;
public class SaveAction extends AbstractAction {
public class SaveAction extends DiagramPanelAction {
private static final String LAST_SAVE_LOCATION_KEY = "lastSaveLocation";
private static SaveAction instance;
public static SaveAction getInstance() {
if (instance == null) {
instance = new SaveAction();
}
return instance;
}
@Setter
private MappingModel model;
@Setter
private DiagramPanel diagramPanel;
public SaveAction() {
super("Save");
public SaveAction(DiagramPanel diagramPanel) {
super("Save", diagramPanel);
this.putValue(SHORT_DESCRIPTION, "Save the current diagram to a file.");
this.putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK));
}
@ -54,17 +38,18 @@ public class SaveAction extends AbstractAction {
if (path != null) {
fileChooser.setSelectedFile(new File(path));
}
int choice = fileChooser.showSaveDialog(this.diagramPanel);
DiagramPanel dp = getDiagramPanel();
int choice = fileChooser.showSaveDialog(dp);
if (choice == JFileChooser.APPROVE_OPTION) {
File chosenFile = fileChooser.getSelectedFile();
if (chosenFile == null || chosenFile.isDirectory()) {
JOptionPane.showMessageDialog(this.diagramPanel, "The selected file cannot be written to.", "Invalid File", JOptionPane.WARNING_MESSAGE);
JOptionPane.showMessageDialog(dp, "The selected file cannot be written to.", "Invalid File", JOptionPane.WARNING_MESSAGE);
return;
}
if (!chosenFile.exists() && !chosenFile.getName().endsWith(".json")) {
chosenFile = new File(chosenFile.getParent(), chosenFile.getName() + ".json");
} else if (chosenFile.exists()) {
int result = JOptionPane.showConfirmDialog(this.diagramPanel, "Are you sure you want overwrite this file?", "Overwrite", JOptionPane.YES_NO_OPTION);
int result = JOptionPane.showConfirmDialog(dp, "Are you sure you want overwrite this file?", "Overwrite", JOptionPane.YES_NO_OPTION);
if (result == JOptionPane.NO_OPTION) {
return;
}
@ -74,12 +59,12 @@ public class SaveAction extends AbstractAction {
.configure(SerializationFeature.INDENT_OUTPUT, true)
.configure(MapperFeature.PROPAGATE_TRANSIENT_MARKER, true)
.build();
mapper.writeValue(fos, this.model.toJson(mapper));
mapper.writeValue(fos, dp.getModel().toJson(mapper));
prefs.put(LAST_SAVE_LOCATION_KEY, chosenFile.getAbsolutePath());
JOptionPane.showMessageDialog(fileChooser, "File saved successfully.", "Success", JOptionPane.INFORMATION_MESSAGE);
JOptionPane.showMessageDialog(dp, "File saved successfully.", "Success", JOptionPane.INFORMATION_MESSAGE);
} catch (IOException ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(fileChooser, "An error occurred and the file could not be saved:\n" + ex.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
JOptionPane.showMessageDialog(dp, "An error occurred and the file could not be saved:\n" + ex.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
}
}
}

View File

@ -1,37 +1,19 @@
package nl.andrewlalis.erme.control.actions;
import lombok.Getter;
import lombok.Setter;
import nl.andrewlalis.erme.view.DiagramPanel;
import javax.swing.*;
import java.awt.event.ActionEvent;
public class VisualizeReferencesAction extends AbstractAction {
private static VisualizeReferencesAction instance;
public static VisualizeReferencesAction getInstance() {
if (instance == null) {
instance = new VisualizeReferencesAction();
}
return instance;
}
@Getter
@Setter
private boolean referenceVisualizationEnabled = false;
@Setter
private DiagramPanel diagramPanel;
public VisualizeReferencesAction() {
super("Toggle Reference Visualization");
public class VisualizeReferencesAction extends DiagramPanelAction {
public VisualizeReferencesAction(DiagramPanel diagramPanel) {
super("Toggle Reference Visualization", diagramPanel);
this.putValue(SHORT_DESCRIPTION, "Shows/hides visualization of the references between attributes.");
}
@Override
public void actionPerformed(ActionEvent e) {
referenceVisualizationEnabled = ((AbstractButton)e.getSource()).getModel().isSelected();
diagramPanel.repaint();
getDiagramPanel().getModel().setReferenceVisualizationEnabled(((AbstractButton)e.getSource()).getModel().isSelected());
getDiagramPanel().repaint();
}
}

View File

@ -1,6 +1,6 @@
package nl.andrewlalis.erme.control.actions.edits;
import lombok.Setter;
import nl.andrewlalis.erme.control.actions.DiagramPanelAction;
import nl.andrewlalis.erme.model.*;
import nl.andrewlalis.erme.view.DiagramPanel;
@ -10,36 +10,23 @@ import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.util.List;
import java.util.Set;
import java.util.stream.Stream;
public class AddAttributeAction extends AbstractAction {
private static AddAttributeAction instance;
public static AddAttributeAction getInstance() {
if (instance == null) {
instance = new AddAttributeAction();
}
return instance;
}
@Setter
private MappingModel model;
@Setter
private DiagramPanel diagramPanel;
public AddAttributeAction() {
super("Add Attribute");
public class AddAttributeAction extends DiagramPanelAction {
public AddAttributeAction(DiagramPanel diagramPanel) {
super("Add Attribute", diagramPanel);
this.putValue(SHORT_DESCRIPTION, "Add an attribute to the selected relation.");
this.putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_T, InputEvent.CTRL_DOWN_MASK));
}
@Override
public void actionPerformed(ActionEvent e) {
List<Relation> selectedRelations = this.model.getSelectedRelations();
DiagramPanel dp = getDiagramPanel();
MappingModel model = dp.getModel();
List<Relation> selectedRelations = model.getSelectedRelations();
if (selectedRelations.size() != 1) {
JOptionPane.showMessageDialog(
this.diagramPanel,
dp,
"A single relation must be selected to add an attribute.",
"Single Relation Required",
JOptionPane.WARNING_MESSAGE
@ -48,11 +35,10 @@ public class AddAttributeAction extends AbstractAction {
}
Relation r = selectedRelations.get(0);
Attribute createdAttribute;
Component source = this.diagramPanel;
String name = JOptionPane.showInputDialog(source, "Enter the name of the attribute.", "Attribute Name", JOptionPane.PLAIN_MESSAGE);
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(
source,
dp,
"Select the index to insert this attribute at.",
"Attribute Index",
JOptionPane.PLAIN_MESSAGE,
@ -62,7 +48,7 @@ public class AddAttributeAction extends AbstractAction {
);
if (index == null) return;
AttributeType type = (AttributeType) JOptionPane.showInputDialog(
source,
dp,
"Select the type this attribute is.",
"Attribute Type",
JOptionPane.PLAIN_MESSAGE,
@ -72,7 +58,7 @@ public class AddAttributeAction extends AbstractAction {
);
if (type == null) return;
boolean shouldUseForeignKey = ((String) JOptionPane.showInputDialog(
source,
dp,
"Is this attribute a foreign key?",
"Foreign Key",
JOptionPane.PLAIN_MESSAGE,
@ -81,27 +67,27 @@ public class AddAttributeAction extends AbstractAction {
"No"
)).equalsIgnoreCase("yes");
if (shouldUseForeignKey) {
if (this.model.getRelations().size() < 2) {
JOptionPane.showMessageDialog(source, "There should be at least 2 relations present in the model.", "Not Enough Relations", JOptionPane.WARNING_MESSAGE);
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(
source,
dp,
"Select the relation that this foreign key references.",
"Foreign Key Relation Reference",
JOptionPane.PLAIN_MESSAGE,
null,
this.model.getRelations().toArray(new Relation[0]),
this.model.getRelations().stream().findFirst().orElse(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(source, "There are no referencable attributes in the selected relation.", "No Referencable Attributes", JOptionPane.WARNING_MESSAGE);
JOptionPane.showMessageDialog(dp, "There are no referencable attributes in the selected relation.", "No Referencable Attributes", JOptionPane.WARNING_MESSAGE);
return;
}
Attribute fkAttribute = (Attribute) JOptionPane.showInputDialog(
source,
dp,
"Select the attribute that this foreign key references.",
"Foreign Key Attribute Reference",
JOptionPane.PLAIN_MESSAGE,

View File

@ -1,7 +1,6 @@
package nl.andrewlalis.erme.control.actions.edits;
import lombok.Setter;
import nl.andrewlalis.erme.control.actions.LocalAction;
import nl.andrewlalis.erme.control.actions.DiagramPanelAction;
import nl.andrewlalis.erme.model.MappingModel;
import nl.andrewlalis.erme.model.Relation;
import nl.andrewlalis.erme.view.DiagramPanel;
@ -12,57 +11,45 @@ import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
public class AddRelationAction extends LocalAction {
private static AddRelationAction instance;
public static AddRelationAction getInstance() {
if (instance == null) {
instance = new AddRelationAction();
}
return instance;
}
@Setter
private MappingModel model;
@Setter
private DiagramPanel diagramPanel;
public AddRelationAction() {
super("Add Relation");
public class AddRelationAction extends DiagramPanelAction {
public AddRelationAction(DiagramPanel diagramPanel) {
super("Add Relation", diagramPanel);
this.putValue(SHORT_DESCRIPTION, "Add a new relation to the diagram.");
this.putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_R, InputEvent.CTRL_DOWN_MASK));
}
@Override
public void actionPerformed(ActionEvent e) {
DiagramPanel dp = getDiagramPanel();
MappingModel model = dp.getModel();
String name = JOptionPane.showInputDialog(
this.diagramPanel,
dp,
"Enter the name of the relation.",
"Add Relation",
JOptionPane.PLAIN_MESSAGE
);
if (name != null) {
final boolean isFirstRelation = this.model.getRelations().isEmpty();
final boolean isFirstRelation = model.getRelations().isEmpty();
Point p;
if (this.hasLocation()) {
if (model.getLastInteractionPoint() != null) {
p = new Point(
this.getLocation().x - this.diagramPanel.getPanningTranslation().x,
this.getLocation().y - this.diagramPanel.getPanningTranslation().y
model.getLastInteractionPoint().x - dp.getPanningTranslation().x,
model.getLastInteractionPoint().y - dp.getPanningTranslation().y
);
} else if (isFirstRelation) {
p = new Point(100, 100);
} else {
Rectangle bounds = this.model.getRelationBounds();
Rectangle bounds = model.getRelationBounds();
p = new Point(bounds.x + bounds.width / 2, bounds.y + bounds.height / 2);
}
Relation r = new Relation(this.model, p, name);
this.model.getSelectedRelations().forEach(rl -> rl.setSelected(false));
Relation r = new Relation(model, p, name);
model.getSelectedRelations().forEach(rl -> rl.setSelected(false));
r.setSelected(true);
this.model.addRelation(r);
model.addRelation(r);
if (isFirstRelation) {
this.model.normalizeRelationPositions();
this.diagramPanel.centerModel();
this.diagramPanel.repaint();
model.normalizeRelationPositions();
dp.centerModel();
dp.repaint();
}
}
}

View File

@ -1,8 +1,7 @@
package nl.andrewlalis.erme.control.actions.edits;
import lombok.Setter;
import nl.andrewlalis.erme.control.actions.DiagramPanelAction;
import nl.andrewlalis.erme.model.Attribute;
import nl.andrewlalis.erme.model.MappingModel;
import nl.andrewlalis.erme.model.Relation;
import nl.andrewlalis.erme.view.DiagramPanel;
@ -12,33 +11,19 @@ import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.util.List;
public class RemoveAttributeAction extends AbstractAction {
private static RemoveAttributeAction instance;
public static RemoveAttributeAction getInstance() {
if (instance == null) {
instance = new RemoveAttributeAction();
}
return instance;
}
@Setter
private MappingModel model;
@Setter
private DiagramPanel diagramPanel;
public RemoveAttributeAction() {
super("Remove Attribute");
public class RemoveAttributeAction extends DiagramPanelAction {
public RemoveAttributeAction(DiagramPanel diagramPanel) {
super("Remove Attribute", diagramPanel);
this.putValue(SHORT_DESCRIPTION, "Remove an attribute from a relation.");
this.putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_T, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK));
}
@Override
public void actionPerformed(ActionEvent e) {
List<Relation> selectedRelations = this.model.getSelectedRelations();
List<Relation> selectedRelations = getDiagramPanel().getModel().getSelectedRelations();
if (selectedRelations.size() != 1 || selectedRelations.get(0).getAttributes().isEmpty()) {
JOptionPane.showMessageDialog(
this.diagramPanel,
getDiagramPanel(),
"A single relation with at least one attribute must be selected to remove an attribute.",
"Single Relation With Attribute Required",
JOptionPane.WARNING_MESSAGE
@ -47,7 +32,7 @@ public class RemoveAttributeAction extends AbstractAction {
}
Relation r = selectedRelations.get(0);
Attribute attribute = (Attribute) JOptionPane.showInputDialog(
this.diagramPanel,
getDiagramPanel(),
"Select the attribute to remove.",
"Select Attribute",
JOptionPane.PLAIN_MESSAGE,

View File

@ -1,50 +1,36 @@
package nl.andrewlalis.erme.control.actions.edits;
import lombok.Setter;
import nl.andrewlalis.erme.control.actions.DiagramPanelAction;
import nl.andrewlalis.erme.model.MappingModel;
import nl.andrewlalis.erme.model.Relation;
import nl.andrewlalis.erme.view.DiagramPanel;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
public class RemoveRelationAction extends AbstractAction {
private static RemoveRelationAction instance;
public static RemoveRelationAction getInstance() {
if (instance == null) {
instance = new RemoveRelationAction();
}
return instance;
}
@Setter
private MappingModel model;
@Setter
private DiagramPanel diagramPanel;
public RemoveRelationAction() {
super("Remove Relation");
public class RemoveRelationAction extends DiagramPanelAction {
public RemoveRelationAction(DiagramPanel diagramPanel) {
super("Remove Relation", diagramPanel);
this.putValue(SHORT_DESCRIPTION, "Remove a relation from the diagram.");
this.putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_R, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK));
}
@Override
public void actionPerformed(ActionEvent e) {
if (this.model.getSelectedRelations().isEmpty()) {
MappingModel model = getDiagramPanel().getModel();
if (model.getSelectedRelations().isEmpty()) {
JOptionPane.showMessageDialog(
this.diagramPanel,
getDiagramPanel(),
"No relations selected. Select at least one relation to remove.",
"No Relations Selected",
JOptionPane.WARNING_MESSAGE
);
return;
}
for (Relation r : this.model.getSelectedRelations()) {
this.model.removeRelation(r);
for (Relation r : model.getSelectedRelations()) {
model.removeRelation(r);
}
}
}

View File

@ -11,11 +11,11 @@ import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class DiagramMouseListener extends MouseAdapter {
private final MappingModel model;
private final DiagramPanel diagramPanel;
private Point mouseDragStart;
public DiagramMouseListener(MappingModel model) {
this.model = model;
public DiagramMouseListener(DiagramPanel diagramPanel) {
this.diagramPanel = diagramPanel;
}
/**
@ -38,13 +38,14 @@ public class DiagramMouseListener extends MouseAdapter {
final boolean isCtrlDown = (e.getModifiers() & ActionEvent.CTRL_MASK) == ActionEvent.CTRL_MASK;
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.
this.model.getRelations().forEach(r -> r.setSelected(false));
model.getRelations().forEach(r -> r.setSelected(false));
}
if (!isShiftDown) {// If the user clicked or CTRL+clicked, try and select the relation they clicked on.
for (Relation r : this.model.getRelations()) {
for (Relation r : model.getRelations()) {
if (r.getViewModel().getBounds(g).contains(modelX, modelY)) {
r.setSelected(!r.isSelected());
break;
@ -54,11 +55,12 @@ public class DiagramMouseListener extends MouseAdapter {
// If the user right-clicked, show a popup menu.
if (e.getButton() == MouseEvent.BUTTON3) {
DiagramPopupMenu popupMenu = new DiagramPopupMenu(this.model, e);
model.setLastInteractionPoint(e.getPoint());
DiagramPopupMenu popupMenu = new DiagramPopupMenu(this.diagramPanel);
popupMenu.show(panel, e.getX(), e.getY());
}
this.model.fireChangedEvent();
model.fireChangedEvent();
}
@Override
@ -72,13 +74,14 @@ public class DiagramMouseListener extends MouseAdapter {
final int dy = this.mouseDragStart.y - e.getY();
final boolean isShiftDown = (e.getModifiers() & ActionEvent.SHIFT_MASK) == ActionEvent.SHIFT_MASK;
boolean changed = false;
MappingModel model = this.diagramPanel.getModel();
if (isShiftDown) {
final DiagramPanel panel = (DiagramPanel) e.getSource();
panel.translate(-dx, -dy);
panel.repaint();
System.out.println(e);
this.diagramPanel.translate(-dx, -dy);
this.diagramPanel.repaint();
} else {
for (Relation r : this.model.getRelations()) {
for (Relation r : model.getRelations()) {
if (r.isSelected()) {
r.setPosition(new Point(r.getPosition().x - dx, r.getPosition().y - dy));
changed = true;
@ -87,7 +90,7 @@ public class DiagramMouseListener extends MouseAdapter {
}
if (changed) {
this.model.fireChangedEvent();
model.fireChangedEvent();
}
this.mouseDragStart = e.getPoint();
}

View File

@ -5,6 +5,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.Getter;
import lombok.Setter;
import nl.andrewlalis.erme.view.view_models.MappingModelViewModel;
import nl.andrewlalis.erme.view.view_models.ViewModel;
@ -23,6 +24,16 @@ public class MappingModel implements Viewable {
private transient final Set<ModelChangeListener> changeListeners;
@Getter
@Setter
private transient Point lastInteractionPoint = null;
@Getter
@Setter
private transient boolean lolcatEnabled = false;
@Getter
@Setter
private transient boolean referenceVisualizationEnabled = false;
public MappingModel() {
this.relations = new HashSet<>();
this.changeListeners = new HashSet<>();

View File

@ -1,11 +1,6 @@
package nl.andrewlalis.erme.view;
import lombok.Getter;
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 nl.andrewlalis.erme.control.diagram.DiagramMouseListener;
import nl.andrewlalis.erme.model.MappingModel;
import nl.andrewlalis.erme.model.ModelChangeListener;
@ -21,6 +16,10 @@ import java.awt.event.MouseMotionListener;
* The main panel in which the ER Mapping diagram is displayed.
*/
public class DiagramPanel extends JPanel implements ModelChangeListener {
/**
* The model for the application. This is the main location from which to
* obtain the model for use in actions.
*/
@Getter
private MappingModel model;
@ -60,10 +59,10 @@ public class DiagramPanel extends JPanel implements ModelChangeListener {
for (MouseMotionListener listener : this.getMouseMotionListeners()) {
this.removeMouseMotionListener(listener);
}
DiagramMouseListener listener = new DiagramMouseListener(newModel);
DiagramMouseListener listener = new DiagramMouseListener(this);
this.addMouseListener(listener);
this.addMouseMotionListener(listener);
this.updateActionModels();
this.updateActionModels(); // TODO: remove this once OrderableListPanel is cleaned up.
newModel.addChangeListener(OrderableListPanel.getInstance());
this.centerModel();
this.repaint();
@ -79,6 +78,9 @@ public class DiagramPanel extends JPanel implements ModelChangeListener {
this.panningTranslation.y = 0;
}
/**
* Centers the model in the panel, by adjusting the panning translation.
*/
public void centerModel() {
if (this.getGraphics() == null) {
return;
@ -120,30 +122,7 @@ public class DiagramPanel extends JPanel implements ModelChangeListener {
* TODO: Clean this up somehow!
*/
private void updateActionModels() {
NewModelAction.getInstance().setDiagramPanel(this);
SaveAction.getInstance().setModel(this.model);
LoadAction.getInstance().setDiagramPanel(this);
ExportToImageAction.getInstance().setModel(this.model);
ExportToImageAction.getInstance().setDiagramPanel(this);
AddRelationAction.getInstance().setModel(this.model);
AddRelationAction.getInstance().setDiagramPanel(this);
RemoveRelationAction.getInstance().setModel(this.model);
RemoveRelationAction.getInstance().setDiagramPanel(this);
AddAttributeAction.getInstance().setModel(this.model);
AddAttributeAction.getInstance().setDiagramPanel(this);
RemoveAttributeAction.getInstance().setModel(this.model);
RemoveAttributeAction.getInstance().setDiagramPanel(this);
LoadSampleModelAction.getInstance().setDiagramPanel(this);
LolcatAction.getInstance().setDiagramPanel(this);
VisualizeReferencesAction.getInstance().setDiagramPanel(this);
AutoPositionAction.getInstance().setDiagramPanel(this);
AutoPositionAction.getInstance().setModel(this.model);
OrderableListPanel.getInstance().setModel(this.model);
AboutAction.getInstance().setDiagramPanel(this);
ExitAction.getInstance().setDiagramPanel(this);
InstructionsAction.getInstance().setDiagramPanel(this);
MappingAlgorithmHelpAction.getInstance().setDiagramPanel(this);
SaveAction.getInstance().setDiagramPanel(this);
}
public static void prepareGraphics(Graphics2D g) {

View File

@ -2,28 +2,27 @@ 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.MappingModel;
import nl.andrewlalis.erme.model.Relation;
import javax.swing.*;
import java.awt.event.MouseEvent;
import java.util.List;
public class DiagramPopupMenu extends JPopupMenu {
public DiagramPopupMenu(MappingModel model, MouseEvent e) {
List<Relation> selectedRelations = model.getSelectedRelations();
AddRelationAction.getInstance().setLocation(e.getPoint());
public DiagramPopupMenu(DiagramPanel diagramPanel) {
List<Relation> selectedRelations = diagramPanel.getModel().getSelectedRelations();
if (selectedRelations.size() == 0) {
this.add(AddRelationAction.getInstance());
this.add(new AddRelationAction(diagramPanel));
}
if (selectedRelations.size() > 0) {
this.add(RemoveRelationAction.getInstance());
this.add(new RemoveRelationAction(diagramPanel));
}
if (selectedRelations.size() == 1) {
this.add(AddAttributeAction.getInstance());
this.add(RemoveAttributeAction.getInstance());
Relation relation = selectedRelations.get(0);
this.add(new AddAttributeAction(diagramPanel));
if (!relation.getAttributes().isEmpty()) {
this.add(new RemoveRelationAction(diagramPanel));
}
}
}
}

View File

@ -14,8 +14,9 @@ import java.io.InputStream;
public class EditorFrame extends JFrame {
public EditorFrame() {
super("ER-Mapping Editor");
this.setContentPane(new DiagramPanel(new MappingModel()));
this.setJMenuBar(new EditorMenuBar());
DiagramPanel diagramPanel = new DiagramPanel(new MappingModel());
this.setContentPane(diagramPanel);
this.setJMenuBar(new EditorMenuBar(diagramPanel));
try {
InputStream is = getClass().getClassLoader().getResourceAsStream("icon.png");
if (is == null) {
@ -26,7 +27,7 @@ public class EditorFrame extends JFrame {
} catch (IOException e) {
e.printStackTrace();
}
this.setMinimumSize(new Dimension(400, 400));
this.setMinimumSize(new Dimension(300, 300));
this.setPreferredSize(new Dimension(800, 800));
this.pack();
this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

View File

@ -3,7 +3,6 @@ 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.*;
@ -12,51 +11,47 @@ import javax.swing.*;
* The menu bar that's visible atop the application.
*/
public class EditorMenuBar extends JMenuBar {
public EditorMenuBar() {
this.add(this.buildFileMenu());
this.add(this.buildEditMenu());
this.add(this.buildViewMenu());
this.add(this.buildHelpMenu());
public EditorMenuBar(DiagramPanel diagramPanel) {
this.add(this.buildFileMenu(diagramPanel));
this.add(this.buildEditMenu(diagramPanel));
this.add(this.buildViewMenu(diagramPanel));
this.add(this.buildHelpMenu(diagramPanel));
}
private JMenu buildFileMenu() {
private JMenu buildFileMenu(DiagramPanel diagramPanel) {
JMenu menu = new JMenu("File");
menu.add(NewModelAction.getInstance());
menu.add(SaveAction.getInstance());
menu.add(LoadAction.getInstance());
menu.add(new NewModelAction(diagramPanel));
menu.add(new SaveAction(diagramPanel));
menu.add(new LoadAction(diagramPanel));
menu.addSeparator();
menu.add(ExportToImageAction.getInstance());
menu.add(new ExportToImageAction(diagramPanel));
menu.addSeparator();
menu.add(ExitAction.getInstance());
menu.add(new ExitAction(diagramPanel));
return menu;
}
private JMenu buildEditMenu() {
private JMenu buildEditMenu(DiagramPanel diagramPanel) {
JMenu menu = new JMenu("Edit");
menu.add(AddRelationAction.getInstance());
menu.add(RemoveRelationAction.getInstance());
menu.add(AddAttributeAction.getInstance());
menu.add(RemoveAttributeAction.getInstance());
menu.add(AutoPositionAction.getInstance());
menu.addSeparator();
menu.add(UndoAction.getInstance());
menu.add(RedoAction.getInstance());
menu.add(new AddRelationAction(diagramPanel));
menu.add(new RemoveRelationAction(diagramPanel));
menu.add(new AddAttributeAction(diagramPanel));
menu.add(new RemoveRelationAction(diagramPanel));
menu.add(new AutoPositionAction(diagramPanel));
return menu;
}
private JMenu buildViewMenu() {
private JMenu buildViewMenu(DiagramPanel diagramPanel) {
JMenu menu = new JMenu("View");
menu.add(new JCheckBoxMenuItem(LolcatAction.getInstance()));
menu.add(new JCheckBoxMenuItem(VisualizeReferencesAction.getInstance()));
menu.add(new JCheckBoxMenuItem(new LolcatAction(diagramPanel)));
menu.add(new JCheckBoxMenuItem(new VisualizeReferencesAction(diagramPanel)));
return menu;
}
private JMenu buildHelpMenu() {
private JMenu buildHelpMenu(DiagramPanel diagramPanel) {
JMenu menu = new JMenu("Help");
menu.add(InstructionsAction.getInstance());
menu.add(MappingAlgorithmHelpAction.getInstance());
menu.add(LoadSampleModelAction.getInstance());
menu.add(AboutAction.getInstance());
menu.add(new InstructionsAction(diagramPanel));
menu.add(new MappingAlgorithmHelpAction(diagramPanel));
menu.add(new LoadSampleModelAction(diagramPanel));
return menu;
}
}

View File

@ -15,6 +15,7 @@ import java.util.Set;
/**
* A panel to be used in a popup that has a OrderableListModel implemented. Implements ModelChangeListener to be able
* to update the list of relations when new ones are added or ones are removed.
* TODO: Refactor this to not use static singleton instance.
*/
public class OrderableListPanel extends JPanel implements ModelChangeListener {
private static OrderableListPanel instance;

View File

@ -1,6 +1,5 @@
package nl.andrewlalis.erme.view.view_models;
import nl.andrewlalis.erme.control.actions.LolcatAction;
import nl.andrewlalis.erme.model.Attribute;
import nl.andrewlalis.erme.model.AttributeType;
import nl.andrewlalis.erme.model.ForeignKeyAttribute;
@ -46,7 +45,7 @@ public class AttributeViewModel implements ViewModel {
}
private Color getBackgroundColor(int x, int y, Graphics2D g) {
if (!LolcatAction.getInstance().isLolcatEnabled()) return BACKGROUND_COLOR;
if (!attribute.getRelation().getModel().isLolcatEnabled()) return BACKGROUND_COLOR;
Point offset = g.getClipBounds().getLocation();
g.translate(offset.x, offset.y);
Dimension viewportSize = g.getClipBounds().getSize();

View File

@ -1,13 +1,11 @@
package nl.andrewlalis.erme.view.view_models;
import nl.andrewlalis.erme.control.actions.VisualizeReferencesAction;
import nl.andrewlalis.erme.model.Attribute;
import nl.andrewlalis.erme.model.ForeignKeyAttribute;
import nl.andrewlalis.erme.model.MappingModel;
import nl.andrewlalis.erme.model.Relation;
import java.awt.*;
import java.awt.color.ColorSpace;
import java.util.Random;
/**
@ -22,9 +20,7 @@ public class MappingModelViewModel implements ViewModel {
@Override
public void draw(Graphics2D g) {
if (VisualizeReferencesAction.getInstance().isReferenceVisualizationEnabled()) {
visualizeReferences(g);
}
if (model.isReferenceVisualizationEnabled()) visualizeReferences(g);
for (Relation r : this.model.getRelations()) {
r.getViewModel().draw(g);
}

View File

@ -7,9 +7,13 @@
<body>
<h1>Entity-Relation Mapping Editor</h1>
<p>Created by <a href="https://github.com/andrewlalis">@andrewlalis</a></p>
<p><em>A simple UI for editing entity-relation mapping diagrams.</em></p>
<p>Created by <a href="https://github.com/andrewlalis">Andrew Lalis</a></p>
<p>And with generous contributions by</p>
<ul>
<li><a href="https://github.com/bjornpijnacker">Bjorn Pijnacker</a></li>
</ul>
<p>
Have you noticed any unexpected behavior? Is there something you think would make a good addition to this application?
@ -27,6 +31,9 @@
<li>
The <em>Edit</em> menu contains options for making changes to the current model, such as adding or removing relations and attributes, or undoing/redoing actions.
</li>
<li>
The <em>View</em> menu contains options for changing how the model is viewed.
</li>
<li>
The <em>Help</em> menu contains some items with additional information about the application, like this help page and a simple <em>About</em> popup with version information. There's also a <em>Load Sample Model</em> option, which will load a very basic sample model into the application that you are free to mess around with.
</li>