Added base UI
This commit is contained in:
parent
af5928d24a
commit
8e8b8d3302
|
@ -0,0 +1,115 @@
|
||||||
|
# Created by .ignore support plugin (hsz.mobi)
|
||||||
|
### JetBrains template
|
||||||
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
||||||
|
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||||
|
|
||||||
|
# User-specific stuff
|
||||||
|
.idea/**/workspace.xml
|
||||||
|
.idea/**/tasks.xml
|
||||||
|
.idea/**/usage.statistics.xml
|
||||||
|
.idea/**/dictionaries
|
||||||
|
.idea/**/shelf
|
||||||
|
|
||||||
|
# Generated files
|
||||||
|
.idea/**/contentModel.xml
|
||||||
|
|
||||||
|
# Sensitive or high-churn files
|
||||||
|
.idea/**/dataSources/
|
||||||
|
.idea/**/dataSources.ids
|
||||||
|
.idea/**/dataSources.local.xml
|
||||||
|
.idea/**/sqlDataSources.xml
|
||||||
|
.idea/**/dynamic.xml
|
||||||
|
.idea/**/uiDesigner.xml
|
||||||
|
.idea/**/dbnavigator.xml
|
||||||
|
|
||||||
|
# Gradle
|
||||||
|
.idea/**/gradle.xml
|
||||||
|
.idea/**/libraries
|
||||||
|
|
||||||
|
# Gradle and Maven with auto-import
|
||||||
|
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||||
|
# since they will be recreated, and may cause churn. Uncomment if using
|
||||||
|
# auto-import.
|
||||||
|
# .idea/artifacts
|
||||||
|
# .idea/compiler.xml
|
||||||
|
# .idea/jarRepositories.xml
|
||||||
|
# .idea/modules.xml
|
||||||
|
# .idea/*.iml
|
||||||
|
# .idea/modules
|
||||||
|
# *.iml
|
||||||
|
# *.ipr
|
||||||
|
|
||||||
|
# CMake
|
||||||
|
cmake-build-*/
|
||||||
|
|
||||||
|
# Mongo Explorer plugin
|
||||||
|
.idea/**/mongoSettings.xml
|
||||||
|
|
||||||
|
# File-based project format
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
out/
|
||||||
|
|
||||||
|
# mpeltonen/sbt-idea plugin
|
||||||
|
.idea_modules/
|
||||||
|
|
||||||
|
# JIRA plugin
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
|
||||||
|
# Cursive Clojure plugin
|
||||||
|
.idea/replstate.xml
|
||||||
|
|
||||||
|
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||||
|
com_crashlytics_export_strings.xml
|
||||||
|
crashlytics.properties
|
||||||
|
crashlytics-build.properties
|
||||||
|
fabric.properties
|
||||||
|
|
||||||
|
# Editor-based Rest Client
|
||||||
|
.idea/httpRequests
|
||||||
|
|
||||||
|
# Android studio 3.1+ serialized cache file
|
||||||
|
.idea/caches/build_file_checksums.ser
|
||||||
|
|
||||||
|
### Maven template
|
||||||
|
target/
|
||||||
|
pom.xml.tag
|
||||||
|
pom.xml.releaseBackup
|
||||||
|
pom.xml.versionsBackup
|
||||||
|
pom.xml.next
|
||||||
|
release.properties
|
||||||
|
dependency-reduced-pom.xml
|
||||||
|
buildNumber.properties
|
||||||
|
.mvn/timing.properties
|
||||||
|
# https://github.com/takari/maven-wrapper#usage-without-binary-jar
|
||||||
|
.mvn/wrapper/maven-wrapper.jar
|
||||||
|
|
||||||
|
### Java template
|
||||||
|
# Compiled class file
|
||||||
|
*.class
|
||||||
|
|
||||||
|
# Log file
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# BlueJ files
|
||||||
|
*.ctxt
|
||||||
|
|
||||||
|
# Mobile Tools for Java (J2ME)
|
||||||
|
.mtj.tmp/
|
||||||
|
|
||||||
|
# Package Files #
|
||||||
|
*.jar
|
||||||
|
*.war
|
||||||
|
*.nar
|
||||||
|
*.ear
|
||||||
|
*.zip
|
||||||
|
*.tar.gz
|
||||||
|
*.rar
|
||||||
|
|
||||||
|
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||||
|
hs_err_pid*
|
||||||
|
|
||||||
|
.idea/
|
||||||
|
*.iml
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>nl.andrewlalis</groupId>
|
||||||
|
<artifactId>EntityRelationMappingEditor</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<source>8</source>
|
||||||
|
<target>8</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.formdev</groupId>
|
||||||
|
<artifactId>flatlaf</artifactId>
|
||||||
|
<version>1.0-rc3</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<version>1.18.16</version>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
|
@ -0,0 +1,15 @@
|
||||||
|
package nl.andrewlalis.erme;
|
||||||
|
|
||||||
|
import com.formdev.flatlaf.FlatLightLaf;
|
||||||
|
import nl.andrewlalis.erme.view.EditorFrame;
|
||||||
|
|
||||||
|
public class EntityRelationMappingEditor {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
if (!FlatLightLaf.install()) {
|
||||||
|
System.err.println("Could not install FlatLight Look and Feel.");
|
||||||
|
}
|
||||||
|
final EditorFrame frame = new EditorFrame();
|
||||||
|
frame.setVisible(true);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
package nl.andrewlalis.erme.control.actions;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExitAction() {
|
||||||
|
super("Exit");
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
package nl.andrewlalis.erme.control.actions;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.InputEvent;
|
||||||
|
import java.awt.event.KeyEvent;
|
||||||
|
|
||||||
|
public class ExportToImageAction extends AbstractAction {
|
||||||
|
private static ExportToImageAction instance;
|
||||||
|
|
||||||
|
public static ExportToImageAction getInstance() {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new ExportToImageAction();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExportToImageAction() {
|
||||||
|
super("Export to Image");
|
||||||
|
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) {
|
||||||
|
System.out.println("Export to image.");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
package nl.andrewlalis.erme.control.actions;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.InputEvent;
|
||||||
|
import java.awt.event.KeyEvent;
|
||||||
|
|
||||||
|
public class RedoAction extends AbstractAction {
|
||||||
|
private static RedoAction instance;
|
||||||
|
|
||||||
|
public static RedoAction getInstance() {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new RedoAction();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RedoAction() {
|
||||||
|
super("Redo");
|
||||||
|
this.putValue(Action.SHORT_DESCRIPTION, "Redoes a previously undone action.");
|
||||||
|
this.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_Z, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
System.out.println("Redo");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
package nl.andrewlalis.erme.control.actions;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.InputEvent;
|
||||||
|
import java.awt.event.KeyEvent;
|
||||||
|
|
||||||
|
public class UndoAction extends AbstractAction {
|
||||||
|
private static UndoAction instance;
|
||||||
|
|
||||||
|
public static UndoAction getInstance() {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new UndoAction();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UndoAction() {
|
||||||
|
super("Undo");
|
||||||
|
this.putValue(Action.SHORT_DESCRIPTION, "Undo the last action.");
|
||||||
|
this.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_Z, InputEvent.CTRL_DOWN_MASK));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
System.out.println("Undo");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
package nl.andrewlalis.erme.control.diagram;
|
||||||
|
|
||||||
|
import nl.andrewlalis.erme.model.MappingModel;
|
||||||
|
import nl.andrewlalis.erme.model.Relation;
|
||||||
|
import nl.andrewlalis.erme.view.DiagramPanel;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.InputEvent;
|
||||||
|
import java.awt.event.MouseAdapter;
|
||||||
|
import java.awt.event.MouseEvent;
|
||||||
|
|
||||||
|
public class DiagramMouseListener extends MouseAdapter {
|
||||||
|
private final MappingModel model;
|
||||||
|
private Point mouseDragStart;
|
||||||
|
|
||||||
|
public DiagramMouseListener(MappingModel model) {
|
||||||
|
this.model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mousePressed(MouseEvent e) {
|
||||||
|
DiagramPanel panel = (DiagramPanel) e.getSource();
|
||||||
|
final Graphics2D g2d = panel.getGraphics2D();
|
||||||
|
this.mouseDragStart = e.getPoint();
|
||||||
|
if ((e.getModifiers() & ActionEvent.CTRL_MASK) == ActionEvent.CTRL_MASK) {
|
||||||
|
boolean hit = false;
|
||||||
|
for (Relation r : this.model.getRelations()) {
|
||||||
|
if (r.getViewModel().getBounds(g2d).contains(e.getX(), e.getY())) {
|
||||||
|
r.setSelected(!r.isSelected());
|
||||||
|
hit = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!hit) {
|
||||||
|
this.model.getRelations().forEach(r -> r.setSelected(false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseEntered(MouseEvent e) {
|
||||||
|
super.mouseEntered(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseDragged(MouseEvent e) {
|
||||||
|
int dx = this.mouseDragStart.x - e.getX();
|
||||||
|
int dy = this.mouseDragStart.y - e.getY();
|
||||||
|
for (Relation r : this.model.getRelations()) {
|
||||||
|
if (r.isSelected()) {
|
||||||
|
r.setPosition(new Point(r.getPosition().x - dx, r.getPosition().y - dy));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.mouseDragStart = e.getPoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseMoved(MouseEvent e) {
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
package nl.andrewlalis.erme.model;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A single value that belongs to a relation.
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
public class Attribute {
|
||||||
|
private final Relation relation;
|
||||||
|
private AttributeType type;
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public Attribute(Relation relation, AttributeType type, String name) {
|
||||||
|
this.relation = relation;
|
||||||
|
this.type = type;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(AttributeType type) {
|
||||||
|
this.type = type;
|
||||||
|
this.relation.getModel().fireChangedEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
this.relation.getModel().fireChangedEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
Attribute attribute = (Attribute) o;
|
||||||
|
return type == attribute.type &&
|
||||||
|
name.equals(attribute.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(type, name);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
package nl.andrewlalis.erme.model;
|
||||||
|
|
||||||
|
public enum AttributeType {
|
||||||
|
PLAIN,
|
||||||
|
ID_KEY,
|
||||||
|
PARTIAL_ID_KEY,
|
||||||
|
FOREIGN_KEY
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
package nl.andrewlalis.erme.model;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This model contains all the information about a single mapping diagram,
|
||||||
|
* including each mapped table and the links between them.
|
||||||
|
*/
|
||||||
|
public class MappingModel {
|
||||||
|
@Getter
|
||||||
|
private final Set<Relation> relations;
|
||||||
|
|
||||||
|
private final Set<ModelChangeListener> changeListeners;
|
||||||
|
|
||||||
|
public MappingModel() {
|
||||||
|
this.relations = new HashSet<>();
|
||||||
|
this.changeListeners = new HashSet<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addRelation(Relation r) {
|
||||||
|
if (this.relations.add(r)) {
|
||||||
|
this.fireChangedEvent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeRelation(Relation r) {
|
||||||
|
if (this.relations.remove(r)) {
|
||||||
|
this.fireChangedEvent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addChangeListener(ModelChangeListener listener) {
|
||||||
|
this.changeListeners.add(listener);
|
||||||
|
listener.onModelChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final void fireChangedEvent() {
|
||||||
|
this.changeListeners.forEach(ModelChangeListener::onModelChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || this.getClass() != o.getClass()) return false;
|
||||||
|
MappingModel that = (MappingModel) o;
|
||||||
|
return this.getRelations().equals(that.getRelations());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(this.getRelations());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
package nl.andrewlalis.erme.model;
|
||||||
|
|
||||||
|
public interface ModelChangeListener {
|
||||||
|
void onModelChanged();
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
package nl.andrewlalis.erme.model;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import nl.andrewlalis.erme.view.view_models.RelationViewModel;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a single "relation" or table in the diagram.
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
public class Relation {
|
||||||
|
private final MappingModel model;
|
||||||
|
private Point position;
|
||||||
|
private String name;
|
||||||
|
private final List<Attribute> attributes;
|
||||||
|
|
||||||
|
private transient boolean selected;
|
||||||
|
private final transient RelationViewModel viewModel;
|
||||||
|
|
||||||
|
public Relation(MappingModel model, Point position, String name) {
|
||||||
|
this.model = model;
|
||||||
|
this.position = position;
|
||||||
|
this.name = name;
|
||||||
|
this.attributes = new ArrayList<>();
|
||||||
|
this.viewModel = new RelationViewModel(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPosition(Point position) {
|
||||||
|
if (!this.position.equals(position)) {
|
||||||
|
this.position = position;
|
||||||
|
this.model.fireChangedEvent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
if (!this.name.equals(name)) {
|
||||||
|
this.name = name;
|
||||||
|
this.model.fireChangedEvent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSelected(boolean selected) {
|
||||||
|
if (selected != this.selected) {
|
||||||
|
this.selected = selected;
|
||||||
|
this.model.fireChangedEvent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addAttribute(Attribute attribute) {
|
||||||
|
this.attributes.add(attribute);
|
||||||
|
this.model.fireChangedEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeAttribute(Attribute attribute) {
|
||||||
|
if (this.attributes.remove(attribute)) {
|
||||||
|
this.model.fireChangedEvent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
Relation relation = (Relation) o;
|
||||||
|
return Objects.equals(this.getName(), relation.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return this.getName().hashCode();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
package nl.andrewlalis.erme.view;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import nl.andrewlalis.erme.control.diagram.DiagramMouseListener;
|
||||||
|
import nl.andrewlalis.erme.model.MappingModel;
|
||||||
|
import nl.andrewlalis.erme.model.ModelChangeListener;
|
||||||
|
import nl.andrewlalis.erme.view.view_models.MappingModelViewModel;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.event.MouseListener;
|
||||||
|
import java.awt.event.MouseMotionListener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The main panel in which the ER Mapping diagram is displayed.
|
||||||
|
*/
|
||||||
|
public class DiagramPanel extends JPanel implements ModelChangeListener {
|
||||||
|
@Getter
|
||||||
|
private MappingModel model;
|
||||||
|
|
||||||
|
public DiagramPanel(MappingModel model) {
|
||||||
|
super(true);
|
||||||
|
this.setModel(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setModel(MappingModel newModel) {
|
||||||
|
this.model = newModel;
|
||||||
|
newModel.addChangeListener(this);
|
||||||
|
for (MouseListener listener : this.getMouseListeners()) {
|
||||||
|
this.removeMouseListener(listener);
|
||||||
|
}
|
||||||
|
for (MouseMotionListener listener : this.getMouseMotionListeners()) {
|
||||||
|
this.removeMouseMotionListener(listener);
|
||||||
|
}
|
||||||
|
DiagramMouseListener listener = new DiagramMouseListener(newModel);
|
||||||
|
this.addMouseListener(listener);
|
||||||
|
this.addMouseMotionListener(listener);
|
||||||
|
this.repaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void paintComponent(Graphics g) {
|
||||||
|
super.paintComponent(g);
|
||||||
|
new MappingModelViewModel(this.model).draw(this.getGraphics2D(g));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Graphics2D getGraphics2D(Graphics g) {
|
||||||
|
Graphics2D g2d = (Graphics2D) g;
|
||||||
|
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
||||||
|
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||||
|
g.setFont(g.getFont().deriveFont(14.0f));
|
||||||
|
return g2d;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Graphics2D getGraphics2D() {
|
||||||
|
return this.getGraphics2D(this.getGraphics());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onModelChanged() {
|
||||||
|
this.revalidate();
|
||||||
|
this.repaint();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
package nl.andrewlalis.erme.view;
|
||||||
|
|
||||||
|
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 javax.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The main JFrame for the editor.
|
||||||
|
*/
|
||||||
|
public class EditorFrame extends JFrame {
|
||||||
|
public EditorFrame() {
|
||||||
|
super("ER-Mapping Editor");
|
||||||
|
MappingModel model = new MappingModel();
|
||||||
|
Relation usersRelation = new Relation(model, new Point(50, 50), "Users");
|
||||||
|
usersRelation.addAttribute(new Attribute(usersRelation, AttributeType.ID_KEY, "username"));
|
||||||
|
usersRelation.addAttribute(new Attribute(usersRelation, AttributeType.PLAIN, "fullName"));
|
||||||
|
usersRelation.addAttribute(new Attribute(usersRelation, AttributeType.PLAIN, "language"));
|
||||||
|
usersRelation.addAttribute(new Attribute(usersRelation, AttributeType.PLAIN, "verified"));
|
||||||
|
usersRelation.addAttribute(new Attribute(usersRelation, AttributeType.PARTIAL_ID_KEY, "partialKey"));
|
||||||
|
model.addRelation(usersRelation);
|
||||||
|
Relation tokensRelation = new Relation(model, new Point(50, 120), "Tokens");
|
||||||
|
tokensRelation.addAttribute(new Attribute(tokensRelation, AttributeType.ID_KEY, "tokenCode"));
|
||||||
|
tokensRelation.addAttribute(new Attribute(tokensRelation, AttributeType.FOREIGN_KEY, "username"));
|
||||||
|
tokensRelation.addAttribute(new Attribute(tokensRelation, AttributeType.PLAIN, "expirationDate"));
|
||||||
|
model.addRelation(tokensRelation);
|
||||||
|
|
||||||
|
this.setContentPane(new DiagramPanel(model));
|
||||||
|
this.setJMenuBar(new EditorMenuBar());
|
||||||
|
this.setMinimumSize(new Dimension(500, 500));
|
||||||
|
this.pack();
|
||||||
|
this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
|
||||||
|
this.setLocationRelativeTo(null);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package nl.andrewlalis.erme.view;
|
||||||
|
|
||||||
|
import nl.andrewlalis.erme.control.actions.ExitAction;
|
||||||
|
import nl.andrewlalis.erme.control.actions.ExportToImageAction;
|
||||||
|
import nl.andrewlalis.erme.control.actions.RedoAction;
|
||||||
|
import nl.andrewlalis.erme.control.actions.UndoAction;
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
private JMenu buildFileMenu() {
|
||||||
|
JMenu menu = new JMenu("File");
|
||||||
|
JMenuItem exportAsImageItem = new JMenuItem(ExportToImageAction.getInstance());
|
||||||
|
menu.add(exportAsImageItem);
|
||||||
|
JMenuItem exitItem = new JMenuItem(ExitAction.getInstance());
|
||||||
|
menu.add(exitItem);
|
||||||
|
return menu;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JMenu buildEditMenu() {
|
||||||
|
JMenu menu = new JMenu("Edit");
|
||||||
|
JMenuItem undoItem = new JMenuItem(UndoAction.getInstance());
|
||||||
|
menu.add(undoItem);
|
||||||
|
JMenuItem redoItem = new JMenuItem(RedoAction.getInstance());
|
||||||
|
menu.add(redoItem);
|
||||||
|
return menu;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
package nl.andrewlalis.erme.view.view_models;
|
||||||
|
|
||||||
|
import nl.andrewlalis.erme.model.Attribute;
|
||||||
|
import nl.andrewlalis.erme.model.AttributeType;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.font.TextAttribute;
|
||||||
|
import java.awt.geom.Rectangle2D;
|
||||||
|
import java.text.AttributedString;
|
||||||
|
|
||||||
|
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 = Color.LIGHT_GRAY;
|
||||||
|
public static final Color FONT_COLOR = Color.BLACK;
|
||||||
|
|
||||||
|
private final Attribute attribute;
|
||||||
|
|
||||||
|
public AttributeViewModel(Attribute attribute) {
|
||||||
|
this.attribute = attribute;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void draw(Graphics2D g) {
|
||||||
|
AttributedString as = this.getAttributedString(g);
|
||||||
|
Rectangle r = this.getBounds(g, as);
|
||||||
|
g.setColor(BACKGROUND_COLOR);
|
||||||
|
g.fillRect(r.x, r.y, r.width, r.height);
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Rectangle getBounds(Graphics2D g, AttributedString as) {
|
||||||
|
int x = this.attribute.getRelation().getPosition().x + RelationViewModel.PADDING_X;
|
||||||
|
int y = this.attribute.getRelation().getPosition().y + this.attribute.getRelation().getViewModel().getNameBounds(g).height + PADDING_Y;
|
||||||
|
int i = 0;
|
||||||
|
while (!this.attribute.getRelation().getAttributes().get(i).equals(this.attribute)) {
|
||||||
|
x += g.getFontMetrics().stringWidth(this.attribute.getRelation().getAttributes().get(i).getName()) + (2 * PADDING_X);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
Rectangle2D rect = g.getFontMetrics().getStringBounds(as.getIterator(), 0, this.attribute.getName().length(), g);
|
||||||
|
return new Rectangle(
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
(int) rect.getWidth() + (2 * PADDING_X),
|
||||||
|
(int) rect.getHeight() + (2 * PADDING_Y)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Rectangle getBounds(Graphics2D g) {
|
||||||
|
return this.getBounds(g, this.getAttributedString(g));
|
||||||
|
}
|
||||||
|
|
||||||
|
private AttributedString getAttributedString(Graphics2D g) {
|
||||||
|
AttributedString as = new AttributedString(this.attribute.getName());
|
||||||
|
as.addAttribute(TextAttribute.FONT, g.getFont());
|
||||||
|
if (this.attribute.getType().equals(AttributeType.ID_KEY)) {
|
||||||
|
as.addAttribute(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);
|
||||||
|
} else if (this.attribute.getType().equals(AttributeType.PARTIAL_ID_KEY)) {
|
||||||
|
as.addAttribute(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_LOW_DASHED);
|
||||||
|
}
|
||||||
|
return as;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package nl.andrewlalis.erme.view.view_models;
|
||||||
|
|
||||||
|
import nl.andrewlalis.erme.model.MappingModel;
|
||||||
|
import nl.andrewlalis.erme.model.Relation;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
public class MappingModelViewModel implements ViewModel {
|
||||||
|
private final MappingModel model;
|
||||||
|
|
||||||
|
public MappingModelViewModel(MappingModel model) {
|
||||||
|
this.model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void draw(Graphics2D g) {
|
||||||
|
for (Relation r : this.model.getRelations()) {
|
||||||
|
r.getViewModel().draw(g);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
package nl.andrewlalis.erme.view.view_models;
|
||||||
|
|
||||||
|
import nl.andrewlalis.erme.model.Attribute;
|
||||||
|
import nl.andrewlalis.erme.model.Relation;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.font.TextAttribute;
|
||||||
|
import java.awt.geom.Rectangle2D;
|
||||||
|
import java.text.AttributedString;
|
||||||
|
|
||||||
|
public class RelationViewModel implements ViewModel {
|
||||||
|
public static final int PADDING_X = 5;
|
||||||
|
public static final int PADDING_Y = 5;
|
||||||
|
|
||||||
|
private final Relation relation;
|
||||||
|
|
||||||
|
public RelationViewModel(Relation relation) {
|
||||||
|
this.relation = relation;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void draw(Graphics2D g) {
|
||||||
|
AttributedString as = this.getAttributedString(g);
|
||||||
|
Rectangle bounds = this.getBounds(g);
|
||||||
|
g.setColor(Color.BLACK);
|
||||||
|
g.drawString(as.getIterator(), bounds.x + PADDING_X, bounds.y + this.getNameBounds(g).height - PADDING_Y);
|
||||||
|
for (Attribute a : this.relation.getAttributes()) {
|
||||||
|
new AttributeViewModel(a).draw(g);
|
||||||
|
}
|
||||||
|
if (this.relation.isSelected()) {
|
||||||
|
g.setColor(Color.BLUE);
|
||||||
|
} else {
|
||||||
|
g.setColor(Color.CYAN);
|
||||||
|
}
|
||||||
|
g.drawRect(bounds.x, bounds.y, bounds.width, bounds.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Rectangle getBounds(Graphics2D g) {
|
||||||
|
Rectangle rect = new Rectangle();
|
||||||
|
rect.x = this.relation.getPosition().x;
|
||||||
|
rect.y = this.relation.getPosition().y;
|
||||||
|
int totalAttributeWidth = 0;
|
||||||
|
int maxAttributeHeight = 0;
|
||||||
|
for (Attribute a : this.relation.getAttributes()) {
|
||||||
|
Rectangle attributeBounds = new AttributeViewModel(a).getBounds(g);
|
||||||
|
totalAttributeWidth += attributeBounds.width;
|
||||||
|
maxAttributeHeight = Math.max(maxAttributeHeight, attributeBounds.height);
|
||||||
|
}
|
||||||
|
Rectangle nameBounds = this.getNameBounds(g);
|
||||||
|
rect.width = Math.max(totalAttributeWidth, nameBounds.width) + (2 * PADDING_X);
|
||||||
|
rect.height = nameBounds.height + maxAttributeHeight + (2 * PADDING_Y);
|
||||||
|
return rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Rectangle getNameBounds(Graphics2D g) {
|
||||||
|
AttributedString as = this.getAttributedString(g);
|
||||||
|
Rectangle2D nameBounds = g.getFontMetrics().getStringBounds(as.getIterator(), 0, this.relation.getName().length(), g);
|
||||||
|
return nameBounds.getBounds();
|
||||||
|
}
|
||||||
|
|
||||||
|
private AttributedString getAttributedString(Graphics2D g) {
|
||||||
|
AttributedString as = new AttributedString(this.relation.getName());
|
||||||
|
as.addAttribute(TextAttribute.FONT, g.getFont());
|
||||||
|
as.addAttribute(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD);
|
||||||
|
return as;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package nl.andrewlalis.erme.view.view_models;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
public interface ViewModel {
|
||||||
|
void draw(Graphics2D g);
|
||||||
|
}
|
Loading…
Reference in New Issue