Added better mouse functionality and save.
This commit is contained in:
parent
8e8b8d3302
commit
cf2a670e0b
|
@ -0,0 +1,63 @@
|
||||||
|
package nl.andrewlalis.erme.control.actions;
|
||||||
|
|
||||||
|
import lombok.Setter;
|
||||||
|
import nl.andrewlalis.erme.model.MappingModel;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import javax.swing.filechooser.FileNameExtensionFilter;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.InputEvent;
|
||||||
|
import java.awt.event.KeyEvent;
|
||||||
|
import java.io.*;
|
||||||
|
|
||||||
|
public class SaveAction extends AbstractAction {
|
||||||
|
private static SaveAction instance;
|
||||||
|
|
||||||
|
public static SaveAction getInstance() {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new SaveAction();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private File lastSelectedFile;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
private MappingModel model;
|
||||||
|
|
||||||
|
public SaveAction() {
|
||||||
|
super("Save");
|
||||||
|
this.putValue(SHORT_DESCRIPTION, "Save the current diagram to a file.");
|
||||||
|
this.putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
JFileChooser fileChooser = new JFileChooser(this.lastSelectedFile);
|
||||||
|
FileNameExtensionFilter filter = new FileNameExtensionFilter(
|
||||||
|
"ERME Serialized Files",
|
||||||
|
"erme"
|
||||||
|
);
|
||||||
|
fileChooser.setFileFilter(filter);
|
||||||
|
int choice = fileChooser.showSaveDialog((Component) e.getSource());
|
||||||
|
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);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!chosenFile.exists() && !chosenFile.getName().endsWith(".erme")) {
|
||||||
|
chosenFile = new File(chosenFile.getParent(), chosenFile.getName() + ".erme");
|
||||||
|
}
|
||||||
|
// TODO: Check for confirm before overwriting.
|
||||||
|
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(chosenFile))) {
|
||||||
|
oos.writeObject(this.model);
|
||||||
|
this.lastSelectedFile = chosenFile;
|
||||||
|
JOptionPane.showMessageDialog(fileChooser, "File saved successfully.", "Success", JOptionPane.INFORMATION_MESSAGE);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
JOptionPane.showMessageDialog(fileChooser, "An error occurred and the file could not be saved:\n" + ex.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,23 +18,32 @@ public class DiagramMouseListener extends MouseAdapter {
|
||||||
this.model = model;
|
this.model = model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles mouse presses. This is what should happen:
|
||||||
|
* - If the click occurs outside of the bounds of any relation, deselect all
|
||||||
|
* relations, if CTRL is not held down.
|
||||||
|
* - If the click occurs within at least one relation, select the first one,
|
||||||
|
* and deselect all others if CTRL is not held down.
|
||||||
|
* @param e The mouse event.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void mousePressed(MouseEvent e) {
|
public void mousePressed(MouseEvent e) {
|
||||||
DiagramPanel panel = (DiagramPanel) e.getSource();
|
DiagramPanel panel = (DiagramPanel) e.getSource();
|
||||||
final Graphics2D g2d = panel.getGraphics2D();
|
final Graphics2D g2d = panel.getGraphics2D();
|
||||||
this.mouseDragStart = e.getPoint();
|
this.mouseDragStart = e.getPoint();
|
||||||
if ((e.getModifiers() & ActionEvent.CTRL_MASK) == ActionEvent.CTRL_MASK) {
|
|
||||||
boolean hit = false;
|
boolean isCtrlDown = (e.getModifiers() & ActionEvent.CTRL_MASK) == ActionEvent.CTRL_MASK;
|
||||||
|
|
||||||
|
if (!isCtrlDown) {
|
||||||
|
this.model.getRelations().forEach(r -> r.setSelected(false));
|
||||||
|
}
|
||||||
for (Relation r : this.model.getRelations()) {
|
for (Relation r : this.model.getRelations()) {
|
||||||
if (r.getViewModel().getBounds(g2d).contains(e.getX(), e.getY())) {
|
if (r.getViewModel().getBounds(g2d).contains(e.getX(), e.getY())) {
|
||||||
r.setSelected(!r.isSelected());
|
r.setSelected(!r.isSelected());
|
||||||
hit = true;
|
break;
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!hit) {
|
|
||||||
this.model.getRelations().forEach(r -> r.setSelected(false));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.model.fireChangedEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -46,11 +55,16 @@ public class DiagramMouseListener extends MouseAdapter {
|
||||||
public void mouseDragged(MouseEvent e) {
|
public void mouseDragged(MouseEvent e) {
|
||||||
int dx = this.mouseDragStart.x - e.getX();
|
int dx = this.mouseDragStart.x - e.getX();
|
||||||
int dy = this.mouseDragStart.y - e.getY();
|
int dy = this.mouseDragStart.y - e.getY();
|
||||||
|
boolean changed = false;
|
||||||
for (Relation r : this.model.getRelations()) {
|
for (Relation r : this.model.getRelations()) {
|
||||||
if (r.isSelected()) {
|
if (r.isSelected()) {
|
||||||
r.setPosition(new Point(r.getPosition().x - dx, r.getPosition().y - dy));
|
r.setPosition(new Point(r.getPosition().x - dx, r.getPosition().y - dy));
|
||||||
|
changed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (changed) {
|
||||||
|
this.model.fireChangedEvent();
|
||||||
|
}
|
||||||
this.mouseDragStart = e.getPoint();
|
this.mouseDragStart = e.getPoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,13 +2,14 @@ package nl.andrewlalis.erme.model;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A single value that belongs to a relation.
|
* A single value that belongs to a relation.
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
public class Attribute {
|
public class Attribute implements Serializable {
|
||||||
private final Relation relation;
|
private final Relation relation;
|
||||||
private AttributeType type;
|
private AttributeType type;
|
||||||
private String name;
|
private String name;
|
||||||
|
|
|
@ -2,6 +2,7 @@ package nl.andrewlalis.erme.model;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -10,11 +11,11 @@ import java.util.Set;
|
||||||
* This model contains all the information about a single mapping diagram,
|
* This model contains all the information about a single mapping diagram,
|
||||||
* including each mapped table and the links between them.
|
* including each mapped table and the links between them.
|
||||||
*/
|
*/
|
||||||
public class MappingModel {
|
public class MappingModel implements Serializable {
|
||||||
@Getter
|
@Getter
|
||||||
private final Set<Relation> relations;
|
private final Set<Relation> relations;
|
||||||
|
|
||||||
private final Set<ModelChangeListener> changeListeners;
|
private transient final Set<ModelChangeListener> changeListeners;
|
||||||
|
|
||||||
public MappingModel() {
|
public MappingModel() {
|
||||||
this.relations = new HashSet<>();
|
this.relations = new HashSet<>();
|
||||||
|
@ -38,7 +39,7 @@ public class MappingModel {
|
||||||
listener.onModelChanged();
|
listener.onModelChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final void fireChangedEvent() {
|
public final void fireChangedEvent() {
|
||||||
this.changeListeners.forEach(ModelChangeListener::onModelChanged);
|
this.changeListeners.forEach(ModelChangeListener::onModelChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import lombok.Getter;
|
||||||
import nl.andrewlalis.erme.view.view_models.RelationViewModel;
|
import nl.andrewlalis.erme.view.view_models.RelationViewModel;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
@ -12,7 +13,7 @@ import java.util.Objects;
|
||||||
* Represents a single "relation" or table in the diagram.
|
* Represents a single "relation" or table in the diagram.
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
public class Relation {
|
public class Relation implements Serializable {
|
||||||
private final MappingModel model;
|
private final MappingModel model;
|
||||||
private Point position;
|
private Point position;
|
||||||
private String name;
|
private String name;
|
||||||
|
@ -30,24 +31,15 @@ public class Relation {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPosition(Point position) {
|
public void setPosition(Point position) {
|
||||||
if (!this.position.equals(position)) {
|
|
||||||
this.position = position;
|
this.position = position;
|
||||||
this.model.fireChangedEvent();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setName(String name) {
|
public void setName(String name) {
|
||||||
if (!this.name.equals(name)) {
|
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.model.fireChangedEvent();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSelected(boolean selected) {
|
public void setSelected(boolean selected) {
|
||||||
if (selected != this.selected) {
|
|
||||||
this.selected = selected;
|
this.selected = selected;
|
||||||
this.model.fireChangedEvent();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addAttribute(Attribute attribute) {
|
public void addAttribute(Attribute attribute) {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package nl.andrewlalis.erme.view;
|
package nl.andrewlalis.erme.view;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import nl.andrewlalis.erme.control.actions.SaveAction;
|
||||||
import nl.andrewlalis.erme.control.diagram.DiagramMouseListener;
|
import nl.andrewlalis.erme.control.diagram.DiagramMouseListener;
|
||||||
import nl.andrewlalis.erme.model.MappingModel;
|
import nl.andrewlalis.erme.model.MappingModel;
|
||||||
import nl.andrewlalis.erme.model.ModelChangeListener;
|
import nl.andrewlalis.erme.model.ModelChangeListener;
|
||||||
|
@ -35,6 +36,7 @@ public class DiagramPanel extends JPanel implements ModelChangeListener {
|
||||||
DiagramMouseListener listener = new DiagramMouseListener(newModel);
|
DiagramMouseListener listener = new DiagramMouseListener(newModel);
|
||||||
this.addMouseListener(listener);
|
this.addMouseListener(listener);
|
||||||
this.addMouseMotionListener(listener);
|
this.addMouseMotionListener(listener);
|
||||||
|
SaveAction.getInstance().setModel(newModel);
|
||||||
this.repaint();
|
this.repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
package nl.andrewlalis.erme.view;
|
package nl.andrewlalis.erme.view;
|
||||||
|
|
||||||
import nl.andrewlalis.erme.control.actions.ExitAction;
|
import nl.andrewlalis.erme.control.actions.*;
|
||||||
import nl.andrewlalis.erme.control.actions.ExportToImageAction;
|
|
||||||
import nl.andrewlalis.erme.control.actions.RedoAction;
|
|
||||||
import nl.andrewlalis.erme.control.actions.UndoAction;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
|
||||||
|
@ -18,6 +15,8 @@ public class EditorMenuBar extends JMenuBar {
|
||||||
|
|
||||||
private JMenu buildFileMenu() {
|
private JMenu buildFileMenu() {
|
||||||
JMenu menu = new JMenu("File");
|
JMenu menu = new JMenu("File");
|
||||||
|
JMenuItem saveItem = new JMenuItem(SaveAction.getInstance());
|
||||||
|
menu.add(saveItem);
|
||||||
JMenuItem exportAsImageItem = new JMenuItem(ExportToImageAction.getInstance());
|
JMenuItem exportAsImageItem = new JMenuItem(ExportToImageAction.getInstance());
|
||||||
menu.add(exportAsImageItem);
|
menu.add(exportAsImageItem);
|
||||||
JMenuItem exitItem = new JMenuItem(ExitAction.getInstance());
|
JMenuItem exitItem = new JMenuItem(ExitAction.getInstance());
|
||||||
|
|
|
@ -29,11 +29,9 @@ public class RelationViewModel implements ViewModel {
|
||||||
}
|
}
|
||||||
if (this.relation.isSelected()) {
|
if (this.relation.isSelected()) {
|
||||||
g.setColor(Color.BLUE);
|
g.setColor(Color.BLUE);
|
||||||
} else {
|
|
||||||
g.setColor(Color.CYAN);
|
|
||||||
}
|
|
||||||
g.drawRect(bounds.x, bounds.y, bounds.width, bounds.height);
|
g.drawRect(bounds.x, bounds.y, bounds.width, bounds.height);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public Rectangle getBounds(Graphics2D g) {
|
public Rectangle getBounds(Graphics2D g) {
|
||||||
Rectangle rect = new Rectangle();
|
Rectangle rect = new Rectangle();
|
||||||
|
|
Loading…
Reference in New Issue