Giter Club home page Giter Club logo

uml-editor's Introduction

UML Editor

How to build and run the project

# Clone the repository
$ git clone [email protected]:1chooo/uml-editor.git

$ ./scripts/run.sh

CONTACT INFO.

AWS Educate Cloud Ambassador, Technical Support
Hugo ChunHo Lin

๐Ÿ“ฉ E-mail: [email protected]
๐Ÿงณ Linkedin: Hugo ChunHo Lin
๐Ÿ‘จ๐Ÿปโ€๐Ÿ’ป GitHub: 1chooo

License

Released under MIT by Hugo ChunHo Lin.

This software can be modified and reused without restriction. The original license must be included with any copies of this software. If a significant portion of the source code is used, please provide a link back to this repository.

uml-editor's People

Contributors

1chooo avatar

Stargazers

 avatar

Watchers

 avatar

Forkers

alexeyleping

uml-editor's Issues

[Enhancement] Using Polymorphism to Simplify Object Storage in `Canvas`

Since all the objects inherit from Shape, we can use polymorphism to store all the objects in a single shapes list, instead of separating them into shapes and lines.

private List<Shape> shapes = new ArrayList<Shape>();
// private List<Line> lines = new ArrayList<Line>(); // This can be removed

private List<Shape> shapes = new ArrayList<Shape>();
private List<Line> lines = new ArrayList<Line>();

[Enhancement] change to enum or Action Class as aggregation

In the program, we need to avoid using variables as strings because we might change the names of these variables in the future. Renaming them everywhere would be time-consuming. Instead, we should use enums or an Action class for aggregation.

public void mousePressed(MouseEvent e) {
System.out.println("x: " + e.getX() + " y: " + e.getY());
Shape obj = null;
switch (shapeType) {
case "Class":
obj = new ClassObj(e.getX(), e.getY(), "Class");
break;
case "Use Case":
obj = new UseCaseObj(e.getX(), e.getY(), "Use Case");
break;
default:
System.out.println("Unsupported shape type");
break;
}
if (obj != null) {
canvas.addShape(obj);
}
}

public Line createLine(String type, Point start, Point end) {
Line line = null;
switch (type) {
case "AssociationLine":
line = new AssociationLine(start.x, start.y, end.x, end.y);
break;
case "GeneralizationLine":
line = new GeneralizationLine(start.x, start.y, end.x, end.y);
break;
case "CompositionLine":
line = new CompositionLine(start.x, start.y, end.x, end.y);
break;
}
return line;
}

[Enhancement] Method to Determine if a Point is Inside a Shape

Take BasicObject as an example, All the Shapes are inheriented from Shape which means Shape is considered as the Base class; however, some object we need to redefine the isInside maybe we could have a better method to implement this.

@Override
public int isInside(Point p) {
Point c = new Point();
c.x = (x1 + x2) / 2;
c.y = (y1 + y2) / 2;
Point[] points = {
new Point(x1, y1), new Point(x2, y1),
new Point(x2, y2), new Point(x1, y2) };
for (int i = 0; i < points.length; i++) {
Polygon polygon = new Polygon();
int next = ((i + 1) % 4);
polygon.addPoint(points[i].x, points[i].y);
polygon.addPoint(points[next].x, points[next].y);
polygon.addPoint(c.x, c.y);
if (polygon.contains(p))
return i;
}
return -1;
}

[Enhancement] Separate paint method into multiple methods

Separate paint method into multiple methods. Plus, we can extract this method from Canvas

// TODO: Separate paint method into multiple methods
@Override
public void paint(Graphics graphics) {
super.paint(graphics);
Dimension dimension = getSize();
graphics.setColor(new Color(200, 200, 200));
graphics.fillRect(0, 0, dimension.width, dimension.height);
graphics.setColor(new Color(0, 0, 0));
Graphics2D graphics2D = (Graphics2D) graphics;
graphics2D.setStroke(new BasicStroke(4));
for (int i = shapes.size() - 1; i >= 0; i--) {
Shape shape = shapes.get(i);
shape.draw(graphics);
shape.drawGroup(graphics);
if (shape.isSelected == true)
shape.drawPort(graphics);
}
graphics.setColor(new Color(0, 0, 0));
for (int i = lines.size() - 1; i >= 0; i--) {
Line line = lines.get(i);
line.draw(graphics);
}
graphics.setColor(new Color(0, 0, 0));
if (selectedObject != null)
selectedObject.drawPort(graphics);
if (tmpLine != null)
tmpLine.draw(graphics);
if (selectedArea != null) {
graphics.setColor(new Color(242, 242, 242, 50));
graphics.fillRect(
selectedArea.x, selectedArea.y,
selectedArea.width, selectedArea.height);
graphics.setColor(new Color(242, 242, 242));
graphics.drawRect(
selectedArea.x, selectedArea.y,
selectedArea.width, selectedArea.height);
}
repaint();
}

Separate Actions from Components

addActionListener(new MenuItemAction());

Currently, we need to use 'if' statements to perform Actions. In the future, we should be able to separate Actions from Components, and also provide enum Actions for direct use, similar to the concept of STATUS_CODE.

Current Action Class:

package src.Actions;

import javax.swing.*;
import java.awt.event.*;
import src.Utils.StatusCode;

public class MenuItemAction extends JMenu implements ActionListener {
    public MenuItemAction() { }

    public void actionPerformed(ActionEvent e) {
        if (e.getActionCommand().equals("About XML Editor")) {
            aboutAction(e);
        } else if (e.getActionCommand().equals("Quit (Control + Q)")) {
            exitAction(e);
        }
    }

    private void aboutAction(ActionEvent e) {
        String message = "Hello World! This is a simple XML Editor.";
        JOptionPane.showMessageDialog(null, message);
    }

    private void exitAction(ActionEvent e) {
        System.exit(StatusCode.EXIT);
    }
}

[Enhancement] Change the arrow of Generalization Line to hollow (outline)

Change the arrow to hollow (outline), ensuring the line does not pass through the arrow.

// TODO: Change the arrow to hollow (outline), ensuring the line does not pass through the arrow.
public void draw(Graphics g) {
int width = 10, height = 10;
int dx = x2 - x1, dy = y2 - y1;
double D = Math.sqrt(dx * dx + dy * dy);
double xm = D - width, xn = xm;
double ym = height, yn = -height;
double x;
double sin = dy / D, cos = dx / D;
x = xm * cos - ym * sin + x1;
ym = xm * sin + ym * cos + y1;
xm = x;
x = xn * cos - yn * sin + x1;
yn = xn * sin + yn * cos + y1;
xn = x;
int[] xpoints = { x2, (int) xm, (int) xn };
int[] ypoints = { y2, (int) ym, (int) yn };
g.drawLine(x1, y1, x2, y2);
g.drawPolygon(xpoints, ypoints, 3);
}

[Enhancement] Give the meaning of Calculation formula to draw line, or object

Take Generalization Line as an example, the current "calculation formula" containing in the draw(); however, at the first glance, we cannot identify what this calculation formula doing; therefore, we can wrap them as the function to be called by draw().

// TODO: Change the arrow to hollow (outline), ensuring the line does not pass through the arrow.
public void draw(Graphics g) {
int width = 10, height = 10;
int dx = x2 - x1, dy = y2 - y1;
double D = Math.sqrt(dx * dx + dy * dy);
double xm = D - width, xn = xm;
double ym = height, yn = -height;
double x;
double sin = dy / D, cos = dx / D;
x = xm * cos - ym * sin + x1;
ym = xm * sin + ym * cos + y1;
xm = x;
x = xn * cos - yn * sin + x1;
yn = xn * sin + yn * cos + y1;
xn = x;
int[] xpoints = { x2, (int) xm, (int) xn };
int[] ypoints = { y2, (int) ym, (int) yn };
g.drawLine(x1, y1, x2, y2);
g.drawPolygon(xpoints, ypoints, 3);
}

related: #11

[Enhancement] Remove `final` from `enum` type variables

According to the article "Why can't a Java enum be final?", the answer states, "Java does not allow you to create a class that extends an enum type. Therefore, enums themselves are always final, so using the final keyword is superfluous." Consequently, we can remove the final keyword from our enum type variables.

package Utils;
public class CONFIG {
public static final String APP_NAME = "UML Editor";
public static final String APP_VERSION = "Version";
public static final String MENU_FILE = "File";
public static final String MENU_EDIT = "Edit";
public static final String MENU_ITEM_ABOUT = "About UML Editor";
public static final String MENU_ITEM_QUIT = "Quit (Control + Q)";
public static final String MENU_ITEM_CHANGE_OBJ_NAME = "Change Object Name";
public static final String MENU_ITEM_GROUP = "Group";
public static final String MENU_ITEM_UNGROUP = "UnGroup";
}

package Utils;
public class HELPER {
public static final String RENAME_LENGTH_WARNING = "Please enter a name with less than 10 characters.";
public static final String SELECT_OBJECT_WARNING = "You must select exactly a object !";
public static final String GET_GROUP_WARNING = "You must select two or more objects !";
public static final String GET_UNGROUP_WARNING = "You must select exactly a group object !";
public static final String ABOUT_UML_MESSAGE = "Hi There ! This is a simple UML Editor by Hugo. ๐Ÿ™‰";
public static final String UML_VERSION_MESSAGE = "Version 0.0.2";
public static final String RENAME_MESSAGE = "Please enter a new name for the object.";
public static final String RENAME_PROMPT = "New Object Name : ";
}

package Utils;
public class MODES {
public static final String SELECT = "Select";
public static final String ASSOCIATION_LINE = "AssociationLine";
public static final String GENERALIZATION_LINE = "GeneralizationLine";
public static final String COMPOSITION_LINE = "CompositionLine";
public static final String CLASS = "Class";
public static final String USE_CASE = "Use Case";
public static String getModeButtonName(String mode) {
switch (mode) {
case SELECT:
return "Select";
case ASSOCIATION_LINE:
return "<html>Association<br>Line</html>";
case GENERALIZATION_LINE:
return "<html>Generalization<br>Line</html>";
case COMPOSITION_LINE:
return "<html>Composition<br>Line</html>";
case CLASS:
return "Class";
case USE_CASE:
return "Use Case";
default:
return "";
}
}
public static String getModeImagePath(String mode) {
switch (mode) {
case SELECT:
return "imgs/select.png";
case ASSOCIATION_LINE:
return "imgs/association-line.png";
case GENERALIZATION_LINE:
return "imgs/generation-line.png";
case COMPOSITION_LINE:
return "imgs/composition-line.png";
case CLASS:
return "imgs/class.png";
case USE_CASE:
return "imgs/use-case.png";
default:
return "";
}
}
}

[Enhancement] there's no meaning about `i--`

The meaning of i-- may result in the difficulty of maintenance in the future, we have to add some meaning of this function.

public void createGroup() {
Group group = new Group();
for (int i = 0; i < shapes.size(); i++) {
Shape shape = shapes.get(i);
if (shape.isSelected == true) {
shape.isSelected = false;
group.addShape(shape);
shapes.remove(i);
i--;
}
}
group.setEdge();
shapes.add(group);
selectedObj = null;
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.