Each class, interface, nested class and nested interface has its own separate page. Each of these pages has three sections consisting of a class/interface description, summary tables, and detailed member descriptions:
Constructeur - Crée une instance de Method avec des paramètres donnés.
diff --git a/AppThinker/src/AboutWindow.java b/AppThinker/src/AboutWindow.java
index 25a54c2..557eb91 100644
--- a/AppThinker/src/AboutWindow.java
+++ b/AppThinker/src/AboutWindow.java
@@ -1,5 +1,3 @@
-import javafx.scene.control.TextFormatter;
-
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
diff --git a/AppThinker/src/AppThinker.java b/AppThinker/src/AppThinker.java
index 1c7986b..83029a4 100644
--- a/AppThinker/src/AppThinker.java
+++ b/AppThinker/src/AppThinker.java
@@ -1,5 +1,3 @@
-import javax.swing.*;
-import javax.swing.filechooser.FileNameExtensionFilter;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
diff --git a/AppThinker/src/AppThinkerSplashscreen.java b/AppThinker/src/AppThinkerSplashscreen.java
index e9ab657..7b2693d 100644
--- a/AppThinker/src/AppThinkerSplashscreen.java
+++ b/AppThinker/src/AppThinkerSplashscreen.java
@@ -1,8 +1,6 @@
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
-import java.io.File;
-import java.io.IOException;
/**
* Ecran de démarrage du logiciel
@@ -27,6 +25,8 @@ public class AppThinkerSplashscreen extends JFrame {
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
+ RenderingHints rh = new RenderingHints(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+ g2.setRenderingHints(rh);
Image img = null;
try { img = ImageIO.read(AppThinker.class.getResource("img/splashscreen.png")); } catch (Exception ex) { }
g2.drawImage(img, 0, 0, 533, 300, this);
diff --git a/AppThinker/src/Attribute.java b/AppThinker/src/Attribute.java
index 74d57ca..06f3625 100644
--- a/AppThinker/src/Attribute.java
+++ b/AppThinker/src/Attribute.java
@@ -1,5 +1,3 @@
-import org.w3c.dom.Attr;
-
import java.io.Serializable;
/**
diff --git a/AppThinker/src/Class.java b/AppThinker/src/Class.java
index 0816306..e032291 100644
--- a/AppThinker/src/Class.java
+++ b/AppThinker/src/Class.java
@@ -1,8 +1,6 @@
-import javax.swing.*;
import java.awt.*;
import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Collections;
+import java.util.*;
import java.util.List;
/**
@@ -12,8 +10,6 @@ import java.util.List;
public class Class implements Serializable {
public static int _classId = 0;
- public static final int RECTANGLE = 0;
- public static final int CIRCLE = 1;
private int _id;
private String _name;
@@ -23,7 +19,6 @@ public class Class implements Serializable {
private int _sizeY;
private int _minSizeX;
private int _minSizeY;
- private int _shape;
private List _attributes;
private List _methods;
@@ -32,9 +27,8 @@ public class Class implements Serializable {
* Constructeur - Crée une instance de Class.
* @param posX La position sur l'axe X de la nouvelle classe.
* @param posY La position sur l'axe Y de la nouvelle classe.
- * @param shape La forme de la nouvelle classe (Class.RECTANGLE ou Class.CIRCLE)
*/
- public Class(int posX, int posY, int shape){
+ public Class(int posX, int posY){
_classId++;
this._id = _classId;
this._name = "Class" + _id;
@@ -42,7 +36,6 @@ public class Class implements Serializable {
this._posY = posY;
this._sizeX = 90;
this._sizeY = 50;
- this._shape = shape;
this._attributes = new ArrayList();
this._methods = new ArrayList();
this.computeMinSize();
@@ -55,11 +48,10 @@ public class Class implements Serializable {
* @param posY La position sur l'axe Y de la classe importée.
* @param sizeX La taille sur l'axe X de la classe importée.
* @param sizeY La taille sur l'axe Y de la classe importée.
- * @param shape La forme de la classe importée (Class.RECTANGLE ou Class.CIRCLE).
* @param attributes La liste des attributs de la classe importée.
* @param methods La liste des méthodes de la classe importée.
*/
- public Class(String name, int posX, int posY, int sizeX, int sizeY, int shape, ArrayList attributes, ArrayList methods){
+ public Class(String name, int posX, int posY, int sizeX, int sizeY, ArrayList attributes, ArrayList methods){
_classId++;
this._id = _classId;
this._name = name;
@@ -67,7 +59,6 @@ public class Class implements Serializable {
this._posY = posY;
this._sizeX = sizeX;
this._sizeY = sizeY;
- this._shape = shape;
this._attributes = attributes;
this._methods = methods;
this.computeMinSize();
@@ -211,13 +202,13 @@ public class Class implements Serializable {
int maxWidth = fm1.stringWidth(this.getName());
//Parcours des attributs
for(Attribute a : this.getAttributes()){
- String chain = a.getAccess() + " " + a.getName() + " : " + a.getType();
+ String chain = " " + a.getAccess() + " " + a.getName() + " : " + a.getType();
int temp = fm2.stringWidth(chain);
if(temp > maxWidth) maxWidth = temp;
}
//Parcours des méthodes
for(Method m : this.getMethods()){
- String chain = m.getAccess() + " " + m.getName() + "(";
+ String chain = " " + m.getAccess() + " " + m.getName() + "(";
ArrayList listArguments = new ArrayList();
for(Argument ar : m.getArguments()){
listArguments.add(ar.getName() + " : " + ar.getType());
@@ -238,22 +229,6 @@ public class Class implements Serializable {
if(this.getSizeY() < this.getMinSizeY()) this.setSizeY(this.getMinSizeY());
}
- /**
- * Récupère la forme graphique de la classe.
- * @return La forme graphique de la classe (Class.RECTANGLE ou Class.CIRCLE).
- */
- public int getShape() {
- return _shape;
- }
-
- /**
- * Paramètre la forme graphique de la classe.
- * @param shape La forme graphique de la classe (Class.RECTANGLE ou Class.CIRCLE).
- */
- public void setShape(int shape) {
- this._shape = shape;
- }
-
/**
* Récupère tous les attributs de la classe.
* @return Les attributs de la classe.
@@ -431,4 +406,34 @@ public class Class implements Serializable {
this.setSizeX(this.getSizeX() + shiftX);
if(this.getSizeX() > this.getMinSizeX()) this.setPosX(posX - this.getSizeX()/2);
}
+
+ /**
+ * Retourne l'ensemble des positions pour dessiner les points d'accroche.
+ * @return La liste des positions des points d'accroche pour la classe.
+ */
+ public List> getGripsPosition(int gripSize){
+ List> positions = new ArrayList>();
+ List gripPos = new ArrayList();
+ int posX = this.getPosX();
+ int posY = this.getPosY();
+ int sizeX = this.getSizeX();
+ int sizeY = this.getSizeY();
+ //Calcul des positions pour le grip N
+ positions.add(Arrays.asList(posX - gripSize / 2, posY - sizeY / 2 - gripSize / 2));
+ //Calcul des positions pour le grip NE
+ positions.add(Arrays.asList(posX + sizeX / 2 - gripSize / 2, posY - sizeY / 2 - gripSize / 2));
+ //Calcul des positions pour le grip E
+ positions.add(Arrays.asList(posX + sizeX / 2 - gripSize / 2, posY - gripSize / 2));
+ //Calcul des positions pour le grip SE
+ positions.add(Arrays.asList(posX + sizeX / 2 - gripSize / 2, posY + sizeY / 2 - gripSize / 2));
+ //Calcul des positions pour le grip S
+ positions.add(Arrays.asList(posX - gripSize / 2, posY + sizeY / 2 - gripSize / 2));
+ //Calcul des positions pour le grip SW
+ positions.add(Arrays.asList(posX - sizeX / 2 - gripSize / 2, posY + sizeY / 2 - gripSize / 2));
+ //Calcul des positions pour le grip W
+ positions.add(Arrays.asList(posX - sizeX / 2 - gripSize / 2, posY - gripSize / 2));
+ //Calcul des positions pour le grip NW
+ positions.add(Arrays.asList(posX - sizeX / 2 - gripSize / 2, posY - sizeY / 2 - gripSize / 2));
+ return positions;
+ }
}
diff --git a/AppThinker/src/ClassPropertiesWindow.java b/AppThinker/src/ClassPropertiesWindow.java
index 89b7e9c..5fdfa76 100644
--- a/AppThinker/src/ClassPropertiesWindow.java
+++ b/AppThinker/src/ClassPropertiesWindow.java
@@ -1,12 +1,9 @@
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
-import javax.swing.table.TableColumn;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
import java.util.Vector;
/**
diff --git a/AppThinker/src/Link.java b/AppThinker/src/Link.java
index 5c84871..70166f1 100644
--- a/AppThinker/src/Link.java
+++ b/AppThinker/src/Link.java
@@ -17,13 +17,19 @@ public class Link implements Serializable{
public static final int CARD_ONE = 1;
private int _id;
+ private int _type;
+ private String _name;
+
private Class _start;
private int _minCardinalityStart;
private int _maxCardinalityStart;
+ private String _gripStart;
+
private Class _end;
private int _minCardinalityEnd;
private int _maxCardinalityEnd;
- private int _type;
+ private String _gripEnd;
+
/**
* Constructeur - Crée une instance d'une classe.
@@ -35,6 +41,7 @@ public class Link implements Serializable{
this._id = _linkId;
this._start = start;
this._end = end;
+ this._name = "relation" + _linkId;
this._minCardinalityStart = Link.CARD_NULL;
this._maxCardinalityStart = Link.CARD_UNLIMITED;
this._minCardinalityEnd = Link.CARD_NULL;
@@ -52,16 +59,19 @@ public class Link implements Serializable{
* @param maxCardinalityEnd La cardinalité maximum de la classe d'arrivée.
* @param type Le type de lien.
*/
- public Link(Class start, Class end, int minCardinalityStart, int maxCardinalityStart, int minCardinalityEnd, int maxCardinalityEnd, int type){
+ public Link(Class start, Class end, String gripStart, String gripEnd, int minCardinalityStart, int maxCardinalityStart, int minCardinalityEnd, int maxCardinalityEnd, int type){
_linkId++;
this._id = _linkId;
this._start = start;
this._end = end;
+ this._gripStart = gripStart;
+ this._gripEnd = gripEnd;
this._minCardinalityStart = minCardinalityStart;
this._maxCardinalityStart = maxCardinalityStart;
this._minCardinalityEnd = minCardinalityEnd;
this._maxCardinalityEnd = maxCardinalityEnd;
this._type = type;
+ this._name = "relation" + _linkId;
}
/**
@@ -88,22 +98,6 @@ public class Link implements Serializable{
this._start = start;
}
- /**
- * Récupère la classe d'arrivée du lien.
- * @return La classe d'arrivée du lien.
- */
- public Class getEnd() {
- return _end;
- }
-
- /**
- * Paramètre la classe d'arrivée.
- * @param end La classe d'arrivée.
- */
- public void setEnd(Class end) {
- this._end = end;
- }
-
/**
* Récupère la cardinalité minimum de la classe de départ.
* @return La cardinalité minimum de la classe de départ.
@@ -136,6 +130,38 @@ public class Link implements Serializable{
this._maxCardinalityStart = maxCardinalityStart;
}
+ /**
+ * Retourne le point d'accroche du lien sur la classe de départ.
+ * @return Le point d'accroche du lien sur la classe de départ.
+ */
+ public String getGripStart(){
+ return _gripStart;
+ }
+
+ /**
+ * Paramètre le point d'accroche du lien sur la classe de départ.
+ * @param gripStart Le point d'accroche du lien sur la classe de départ.
+ */
+ public void setGripStart(String gripStart){
+ _gripStart = gripStart;
+ }
+
+ /**
+ * Récupère la classe d'arrivée du lien.
+ * @return La classe d'arrivée du lien.
+ */
+ public Class getEnd() {
+ return _end;
+ }
+
+ /**
+ * Paramètre la classe d'arrivée.
+ * @param end La classe d'arrivée.
+ */
+ public void setEnd(Class end) {
+ this._end = end;
+ }
+
/**
* Récupère la cardinalité minimum de la classe d'arrivée.
* @return La cardinalité minimum de la classe d'arrivée.
@@ -168,6 +194,22 @@ public class Link implements Serializable{
this._maxCardinalityEnd = maxCardinalityEnd;
}
+ /**
+ * Retourne le point d'accroche du lien sur la classe d'arrivée.
+ * @return Le point d'accroche du lien sur la classe d'arrivée.
+ */
+ public String getGripEnd(){
+ return _gripEnd;
+ }
+
+ /**
+ * Paramètre le point d'accroche du lien sur la classe d'arrivée.
+ * @param gripEnd Le point d'accroche du lien sur la classe d'arrivée.
+ */
+ public void setGripEnd(String gripEnd){
+ _gripEnd = gripEnd;
+ }
+
/**
* Récupère le type du lien.
* @return Le type du lien.
@@ -184,6 +226,22 @@ public class Link implements Serializable{
this._type = type;
}
+ /**
+ * Récupère le nom du lien.
+ * @return Le nom du lien.
+ */
+ public String getName() {
+ return _name;
+ }
+
+ /**
+ * Paramètre le nom du lien
+ * @param name Le nom du lien.
+ */
+ public void setName(String name) {
+ this._name = name;
+ }
+
/**
* Modifie la direction du lien (permute les classes de départ et d'arrivée).
*/
diff --git a/AppThinker/src/Project.java b/AppThinker/src/Project.java
index 8e79991..acb5005 100644
--- a/AppThinker/src/Project.java
+++ b/AppThinker/src/Project.java
@@ -4,8 +4,6 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.List;
/**
* Gère un projet.
diff --git a/AppThinker/src/UmlDiagram.java b/AppThinker/src/UmlDiagram.java
index a3838f8..9b64110 100644
--- a/AppThinker/src/UmlDiagram.java
+++ b/AppThinker/src/UmlDiagram.java
@@ -1,7 +1,8 @@
import java.awt.*;
import java.awt.event.MouseEvent;
-import java.util.ArrayList;
+import java.util.*;
import java.util.List;
+import java.lang.Math;
/**
* Cette classe permet d'afficher les éléments UML du projet.
@@ -10,8 +11,24 @@ public class UmlDiagram extends Composition {
private UmlToolbar _umlToolbar;
private Object _selected;
- private String cornerSelection = null;
+ private Object _hovered;
+ private String _gripHovered = null;
+ private String _gripSelected = null;
+ private boolean _viewGrips = false;
+ private int gripSize = 8;
+ public static final String GRIP_N = "N";
+ public static final String GRIP_NE = "NE";
+ public static final String GRIP_E = "E";
+ public static final String GRIP_SE = "SE";
+ public static final String GRIP_S = "S";
+ public static final String GRIP_SW = "SW";
+ public static final String GRIP_W = "W";
+ public static final String GRIP_NW = "NW";
+
+ //Type de liens
+ final static float dash[] = {5.0f};
+ final static BasicStroke dashed = new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10.0f, dash, 0.0f);
private int _shiftX;
private int _shiftY;
@@ -26,8 +43,8 @@ public class UmlDiagram extends Composition {
public UmlDiagram(Project project){
super(project);
this._toolbar = new UmlToolbar(this);
- this._type = UML_DIAGRAM;
- this._name = "Composition " + _compositionId + " (" + _type + ")";
+ this._type = Composition.UML_DIAGRAM;
+ this._name = "Composition " + Composition._compositionId + " (" + _type + ")";
_classes = new ArrayList();
_links = new ArrayList();
}
@@ -78,7 +95,7 @@ public class UmlDiagram extends Composition {
g2.setColor(new Color(39, 76, 94));
for(Attribute b : a.getAttributes()){
posCounter += font2.getSize();
- g2.drawString(b.getAccess() + " " + b.getName() + " : " + b.getType(), posX, posCounter);
+ g2.drawString(b.getAccess() + " " + b.getName() + " : " + b.getType(), posX+5, posCounter);
//Si l'attribut est statique, on le souligne
if(b.isStatic()) g2.drawLine(a.getPosX()-a.getSizeX()/2+10, posCounter+1, a.getPosX()+a.getSizeX()/2-10, posCounter+1);
}
@@ -101,35 +118,172 @@ public class UmlDiagram extends Composition {
listArguments.add(ar.getName() + " : " + ar.getType());
}
chain += String.join(", ", listArguments) + ") : " + m.getType();
- g2.drawString(chain, posX, posCounter);
+ g2.drawString(chain, posX+5, posCounter);
//Si l'attribut est statique, on le souligne
if(m.isStatic()) g2.drawLine(a.getPosX()-a.getSizeX()/2+10, posCounter+1, a.getPosX()+a.getSizeX()/2-10, posCounter+1);
}
- //Si la classe est sélectionnée
- if(a == (Class)_selected){
- g2.setColor(new Color(39, 76, 94));
- //Top Left
- g2.fillOval(posX-4, posY-4, 8, 8);
+ //Affichage du lien temporaire rouge
+ if(_selected != null && _gripSelected != null){
+ Class b = (Class) _selected;
+ System.out.println(b.getName());
+ List grips = Arrays.asList(GRIP_N, GRIP_NE, GRIP_E, GRIP_SE, GRIP_S, GRIP_SW, GRIP_W, GRIP_NW);
+ List> gripsPositions = b.getGripsPosition(gripSize);
+ g2.setColor(Color.RED);
+ g2.drawLine(gripsPositions.get(grips.indexOf(_gripSelected)).get(0) + gripSize/2, gripsPositions.get(grips.indexOf(_gripSelected)).get(1) + gripSize/2, this.getMousePosition().x, this.getMousePosition().y);
+ }
+ //Récupération de la liste des positions des points d'accroche pour la classe en cours
+ List> gripsPositions = a.getGripsPosition(gripSize);
+ for(Link l : _links){
+ List grips = Arrays.asList(GRIP_N, GRIP_NE, GRIP_E, GRIP_SE, GRIP_S, GRIP_SW, GRIP_W, GRIP_NW);
+ List> gripsPositionsStart = l.getStart().getGripsPosition(gripSize);
+ List> gripsPositionsEnd = l.getEnd().getGripsPosition(gripSize);
+ int startX = gripsPositionsStart.get(grips.indexOf(l.getGripStart())).get(0) + gripSize / 2;
+ int startY = gripsPositionsStart.get(grips.indexOf(l.getGripStart())).get(1) + gripSize / 2;
+ int endX = gripsPositionsEnd.get(grips.indexOf(l.getGripEnd())).get(0) + gripSize / 2;
+ int endY = gripsPositionsEnd.get(grips.indexOf(l.getGripEnd())).get(1) + gripSize / 2;
+ //Dessin du lien en fonction du type de la relation
+ g2.setColor(Color.BLACK);
+ g2.setStroke(new BasicStroke(1f));
+ //Dessin de la ligne en pointillés si le lien est faible
+ if(l.getType() == Link.WEAK){
+ g2.setStroke(dashed);
+ g2.drawLine(startX, startY, endX, endY);
+ }
+ else if (l.getType() == Link.STRONG) g2.drawLine(startX, startY, endX, endY);
+
+ //Si lien de composition, d'agrégation ou d'héritage, on dessine soit un carré ou un triangle
+ else{
+ //On crée le carré ou le rectangle
+ int[][] posGrip = {{startX, startY}};
+ //Détermination de l'angle pour que la figure s'adapte à la direction du lien
+ float angle = (float) Math.atan2(endX - startX, startY - endY);
+ //Détermination des points des polygones en fonction de l'angle et de la position du point d'accroche
+ float[][] posPol = getPolygonPoints(posGrip, -angle, l.getType());
+ int[] polygonX = new int[posPol.length];
+ int[] polygonY = new int[posPol.length];
+ for(int i = 0; i < posPol.length; i++){
+ polygonX[i] = (int)posPol[i][0];
+ polygonY[i] = (int)posPol[i][1];
+ }
+ //On dessine un polygone vide en agrégation
+ if(l.getType() == Link.AGGREGATION || l.getType() == Link.INHERITANCE) g2.drawPolygon(polygonX, polygonY, posPol.length);
+ //On dessine un polygone plein sinon
+ else g2.fillPolygon(polygonX, polygonY, posPol.length);
+ //Adaptation de la ligne sur le 3e point du polygone
+ g2.drawLine(polygonX[2], polygonY[2], endX, endY);
+ }
+ //Affichage des informations du lien
+ if(l.getType() != Link.INHERITANCE){
+ //Décalage des positions pour mettre en évidence les écritures
+ if(l.getGripStart() == GRIP_NE || l.getGripStart() == GRIP_E || l.getGripStart() == GRIP_SE) startX += 20;
+ else if(l.getGripStart() == GRIP_NW || l.getGripStart() == GRIP_W || l.getGripStart() == GRIP_SW) startX -= 20;
+ else if(l.getGripStart() == GRIP_S) startY += 20;
+ if(l.getGripEnd() == GRIP_NE || l.getGripEnd() == GRIP_E || l.getGripEnd() == GRIP_SE) endX += 20;
+ else if(l.getGripEnd() == GRIP_NW || l.getGripEnd() == GRIP_W || l.getGripEnd() == GRIP_SW) endX -= 20;
+ else if(l.getGripEnd() == GRIP_S) endY += 20;
+ //Affichage des cardinalités sur la fin du lien
+ g2.drawString(l.getMinCardinalityEnd() + ".." + l.getMaxCardinalityEnd(), endX, endY);
+ if(l.getType() == Link.STRONG || l.getType() == Link.WEAK){
+ g2.drawString(l.getMinCardinalityStart() + ".." + l.getMaxCardinalityStart(), startX, startY);
+ g2.drawString(l.getName(), (startX + endX)/2, (startY + endY)/2);
+ }
+ }
+ }
+ g2.setStroke(new BasicStroke(1f));
+ //Affichage des points d'accroche
+ if(_viewGrips || (a == (Class)_selected)) {
+ //Changement de la couleur en fonction du mode
+ g2.setColor((_viewGrips) ? Color.GREEN : new Color(39, 76, 94));
//Top
- g2.fillRect(posX + (a.getSizeX()/2)-4, posY-4, 8, 8);
+ g2.fillOval(gripsPositions.get(0).get(0), gripsPositions.get(0).get(1), gripSize, gripSize);
//Top Right
- g2.fillOval(posX + a.getSizeX()-4, posY-4, 8, 8);
+ g2.fillOval(gripsPositions.get(1).get(0), gripsPositions.get(1).get(1), gripSize, gripSize);
//Right
- g2.fillRect(posX + a.getSizeX()-4, posY + (a.getSizeY()/2)-4, 8, 8);
+ g2.fillOval(gripsPositions.get(2).get(0), gripsPositions.get(2).get(1), gripSize, gripSize);
//Bottom Right
- g2.fillOval(posX + a.getSizeX()-4, posY + a.getSizeY()-4, 8, 8);
+ g2.fillOval(gripsPositions.get(3).get(0), gripsPositions.get(3).get(1), gripSize, gripSize);
//Bottom
- g2.fillRect(posX + (a.getSizeX()/2)-4, posY + a.getSizeY()-4,8, 8);
+ g2.fillOval(gripsPositions.get(4).get(0), gripsPositions.get(4).get(1),gripSize, gripSize);
//Bottom Left
- g2.fillOval(posX - 4, posY + a.getSizeY()-4, 8, 8);
+ g2.fillOval(gripsPositions.get(5).get(0), gripsPositions.get(5).get(1), gripSize, gripSize);
//Left
- g2.fillRect(posX -4, posY + (a.getSizeY()/2)-4, 8, 8);
- //Total rectangle
- g2.drawRect(posX, posY, a.getSizeX(), a.getSizeY());
+ g2.fillOval(gripsPositions.get(6).get(0), gripsPositions.get(6).get(1), gripSize, gripSize);
+ //Top Left
+ g2.fillOval(gripsPositions.get(7).get(0), gripsPositions.get(7).get(1), gripSize, gripSize);
}
}
}
+ /**
+ * Calcule les points du polygone à tracer.
+ * @param position La position du point d'accroche.
+ * @param type Le type de relation.
+ * @return Les points du polygone à tracer.
+ */
+ public float[][] getPolygonPoints(int[][] position, double angle, int type){
+ //Patterns de polygon : carré pour composition et agrégation, triangle pour héritage
+ int[][] squarePattern = {{0,0},{-10,-10},{0,-20},{10,-10},{0,0}};
+ int[][] trianglePattern = {{0,0},{-10,-20},{0,-20},{10,-20},{0,0}};
+
+ //Demande d'un carré ou d'un triangle selon le type de lien
+ float[][] points = null;
+ switch(type){
+ case Link.INHERITANCE:
+ points = rotateMatrice(trianglePattern, angle);
+ break;
+ default:
+ points = rotateMatrice(squarePattern, angle);
+ break;
+ }
+ //Déplacement du pattern à la position du point d'accroche
+ for(int i = 0; i < points.length; i++){
+ points[i][0] += position[0][0];
+ points[i][1] += position[0][1];
+ }
+ return points;
+ }
+
+ /**
+ * Rotate le polygone sous forme de matrice.
+ * @param matrice Les points du pattern de polygone.
+ * @param angle L'angle de rotation.
+ * @return La matrice tournée correspondant au polygone final.
+ */
+ public float[][] rotateMatrice(int[][] matrice, double angle){
+ //Matrice de rotation en fonction de l'angle
+ double[][] rotate = {{Math.cos(angle), (-1)*Math.sin(angle)},{Math.sin(angle), Math.cos(angle)}};
+ //Matrice finale
+ float[][] finalMatrice = new float[matrice.length][2];
+ //Multiplication de rotate * finalMatrice
+ for(int i=0; i < matrice.length; i++){
+ for(int j=0; j < 2; j++){
+ finalMatrice[i][j] = 0;
+ for(int k=0; k<2 ;k++)
+ {
+ finalMatrice[i][j] += matrice[i][k] * rotate[k][j];
+ }
+ }
+ }
+ return finalMatrice;
+ }
+
+ /**
+ * Retourne si la vue des points d'accroches est activée pour le diagramme
+ * @return true : la vue des points d'accroche est activée, false sinon.
+ */
+ public boolean viewGripsEnabled(){
+ return _viewGrips;
+ }
+
+ /**
+ * Active/Désactive la vue des points d'accroches pour les classes.
+ * @param enabled La vue des points d'accroches pour les classes.
+ */
+ public void setViewGripsEnabled(boolean enabled){
+ _viewGrips = enabled;
+ this.repaint();
+ }
+
/**
* Retourne la classe principale du diagramme.
* @return La classe principale du diagramme.
@@ -177,6 +331,12 @@ public class UmlDiagram extends Composition {
* @param c La classe à retirer.
*/
public void removeClass(Class c){
+ //On supprime les liens associés à cette classe
+ Iterator iter = _links.iterator();
+ while(iter.hasNext()){
+ Link link = iter.next();
+ if(c.equals(link.getStart()) || c.equals(link.getEnd())) iter.remove();
+ }
//On supprime la classe principale. Par défaut, la 1ère classe créée devient la classe principale.
this._classes.remove(c);
if(_mainClass == c && _classes.size() != 0) _mainClass = _classes.get(0);
@@ -188,6 +348,7 @@ public class UmlDiagram extends Composition {
*/
public void clearClasses(){
this._classes.clear();
+ this.clearLinks();
}
/**
@@ -244,33 +405,32 @@ public class UmlDiagram extends Composition {
* @param getY Les coordonnées de la souris sur l'axe Y.
*/
public void select(int getX, int getY){
- //On cherche l'objet sélectionné
- boolean classSelected = false;
- boolean linkSelected = false;
- for(Class a : _classes){
- int posX = a.getPosX()-(a.getSizeX()/2);
- int posY = a.getPosY()-(a.getSizeY()/2);
- //Si la souris est dans la classe
- if (getX >= posX && getX <= (posX + a.getSizeX())) {
- if (getY >= posY && getY <= (posY + a.getSizeY())) {
- this.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
- //On sélectionne la classe
- classSelected = true;
- _selected = a;
- break;
+ //Si un élément est survolé, on le sélectionne
+ for(Class c : _classes){
+ int posX = c.getPosX();
+ int posY = c.getPosY();
+ int sizeX = c.getSizeX();
+ int sizeY = c.getSizeY();
+ //Si cette classe est survolée, on affiche son nom dans la barre de statut et on la sauvegarde temporairement
+ _selected = null;
+ if(getX >= posX - sizeX/2 - gripSize && getX <= posX + sizeX/2 + gripSize && getY >= posY - sizeY/2 - gripSize && getY <= posY + sizeY/2 + gripSize){
+ AppThinker.getWindow().getStatusbar().setStatusMessage("Selected class : " + c.getName());
+ _selected = c;
+ //Si on est en mode édition de liens, on recherche le point d'accroche survolé
+ if(_viewGrips) {
+ checkHoveredGrip((Class) _selected, getX, getY);
+ _gripSelected = _gripHovered;
}
+ break;
}
}
- if(classSelected == false && linkSelected == false && cornerSelection == null) _selected = null;
//Si la classe est sélectionnée, on enregistre le décalage entre la souris et le centre de la classe
- AppThinker.getWindow().getStatusbar().setSizeLabel(0, 0);
if(_selected instanceof Class){
Class a = (Class) _selected;
AppThinker.getWindow().getStatusbar().setSizeLabel(a.getSizeX(), a.getSizeY());
_shiftX = getX - a.getPosX();
_shiftY = getY - a.getPosY();
}
- this.repaint();
}
/**
@@ -281,6 +441,49 @@ public class UmlDiagram extends Composition {
ClassPropertiesWindow prop = new ClassPropertiesWindow(this, a);
}
+ /**
+ * Vérifie si le curseur est à proximité d'un point d'accroche. Dans ce cas, il enregistre le point survolé.
+ * @param a La classe à vérifier.
+ * @param x L'abscisse du curseur.
+ * @param y L'ordonnée du curseur.
+ */
+ public void checkHoveredGrip(Class a, int x, int y){
+ int sensibility = 5;
+ int posX = a.getPosX();
+ int posY = a.getPosY();
+ int sizeX = a.getSizeX();
+ int sizeY = a.getSizeY();
+ //Si la souris est à proximité d'un point d'accroche, on affiche le curseur de redimensionnement
+ if (x >= posX - sensibility && x <= posX + sensibility && y >= posY - sizeY/2 - sensibility && y <= posY - sizeY/2 + sensibility) {
+ _gripHovered = GRIP_N;
+ this.setCursor(new Cursor(Cursor.N_RESIZE_CURSOR));
+ } else if (x >= posX + sizeX/2 - sensibility && x <= posX + sizeX/2 + sensibility && y >= posY - sizeY/2 - sensibility && y <= posY - sizeY/2 + sensibility) {
+ _gripHovered = GRIP_NE;
+ this.setCursor(new Cursor(Cursor.NE_RESIZE_CURSOR));
+ } else if (x >= posX + sizeX/2 - sensibility && x <= posX + sizeX/2 + sensibility && y >= posY - sensibility && y <= posY + sensibility) {
+ _gripHovered = GRIP_E;
+ this.setCursor(new Cursor(Cursor.E_RESIZE_CURSOR));
+ } else if (x >= posX + sizeX/2 - sensibility && x <= posX + sizeX/2 + sensibility && y >= posY + sizeY/2 - sensibility && y <= posY + sizeY/2 + sensibility) {
+ _gripHovered = GRIP_SE;
+ this.setCursor(new Cursor(Cursor.SE_RESIZE_CURSOR));
+ } else if (x >= posX - sensibility && x <= posX + sensibility && y >= posY + sizeY/2 - sensibility && y <= posY + sizeY/2 + sensibility) {
+ _gripHovered = GRIP_S;
+ this.setCursor(new Cursor(Cursor.S_RESIZE_CURSOR));
+ } else if (x >= posX - sizeX/2 - sensibility && x <= posX - sizeX/2 + sensibility && y >= posY + sizeY/2 - sensibility && y <= posY + sizeY/2 + sensibility) {
+ _gripHovered = GRIP_SW;
+ this.setCursor(new Cursor(Cursor.SW_RESIZE_CURSOR));
+ } else if (x >= posX - sizeX/2 - sensibility && x <= posX - sizeX/2 + sensibility && y >= posY - sensibility && y <= posY + sensibility) {
+ _gripHovered = GRIP_W;
+ this.setCursor(new Cursor(Cursor.W_RESIZE_CURSOR));
+ } else if (x >= posX - sizeX/2 - sensibility && x <= posX - sizeX/2 + sensibility && y >= posY - sizeY/2 - sensibility && y <= posY - sizeY/2 + sensibility) {
+ _gripHovered = GRIP_NW;
+ this.setCursor(new Cursor(Cursor.NW_RESIZE_CURSOR));
+ } else {
+ _gripHovered = null;
+ this.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
+ }
+ }
+
//Actions de la souris sur le diagramme UML
/**
* Action du clic de la souris sur le diagramme.
@@ -325,22 +528,27 @@ public class UmlDiagram extends Composition {
break;
//On essaie d'ajouter une classe
case UmlToolbar.CLASS_TOOL:
- this.addClass(new Class(e.getX(), e.getY(), Class.RECTANGLE));
+ this.addClass(new Class(e.getX(), e.getY()));
break;
case UmlToolbar.STRONG_TOOL:
System.out.println("On ajoute une relation forte.");
+ this.select(e.getX(), e.getY());
break;
case UmlToolbar.WEAK_TOOL:
System.out.println("On ajoute une relation faible.");
+ this.select(e.getX(), e.getY());
break;
case UmlToolbar.COMPOSITION_TOOL:
System.out.println("On ajoute une relation de composition.");
+ this.select(e.getX(), e.getY());
break;
case UmlToolbar.AGGREGATION_TOOL:
System.out.println("On ajoute une relation d'agrégation.");
+ this.select(e.getX(), e.getY());
break;
case UmlToolbar.INHERITANCE_TOOL:
System.out.println("On ajoute une relation d'héritage.");
+ this.select(e.getX(), e.getY());
break;
default:
this.select(e.getX(), e.getY());
@@ -351,7 +559,15 @@ public class UmlDiagram extends Composition {
@Override
public void mouseReleased(MouseEvent e) {
-
+ //Si on lâche le curseur en cours de création de liens, on annule la saisie.
+ if(_viewGrips){
+ if(_gripSelected != null){
+ _gripSelected = null;
+ _selected = null;
+ this.setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
+ }
+ this.repaint();
+ }
}
@Override
@@ -378,51 +594,87 @@ public class UmlDiagram extends Composition {
Class a = (Class)_selected;
int shiftX = 0;
int shiftY = 0;
- //Si un coin est sélectionné, on redimensionne
- if(cornerSelection != null){
- switch(cornerSelection){
- case "N":
- a.resizeUp(posY);
- break;
- case "NE":
- a.resizeUp(posY);
- a.resizeRight(posX);
- case "E":
- a.resizeRight(posX);
- break;
- case "SE":
- a.resizeDown(posY);
- a.resizeRight(posX);
- case "S":
- a.resizeDown(posY);
- break;
- case "SW":
- a.resizeDown(posY);
- a.resizeLeft(posX);
- break;
- case "W":
- a.resizeLeft(posX);
- break;
- case "NW":
- a.resizeUp(posY);
- a.resizeLeft(posX);
- break;
+ //Sinon, soit on redimensionne une classe ou on la déplace.
+ if(!_viewGrips){
+ if(_gripHovered != null){
+ switch(_gripHovered){
+ case GRIP_N:
+ a.resizeUp(posY);
+ break;
+ case GRIP_NE:
+ a.resizeUp(posY);
+ a.resizeRight(posX);
+ case GRIP_E:
+ a.resizeRight(posX);
+ break;
+ case GRIP_SE:
+ a.resizeDown(posY);
+ a.resizeRight(posX);
+ case GRIP_S:
+ a.resizeDown(posY);
+ break;
+ case GRIP_SW:
+ a.resizeDown(posY);
+ a.resizeLeft(posX);
+ break;
+ case GRIP_W:
+ a.resizeLeft(posX);
+ break;
+ case GRIP_NW:
+ a.resizeUp(posY);
+ a.resizeLeft(posX);
+ break;
+ }
+ AppThinker.getWindow().getStatusbar().setSizeLabel(a.getSizeX(), a.getSizeY());
+ }
+ //Sinon on déplace
+ else{
+ //On repositionne la classe en prenant en compte le décalage mesuré au clic de la souris
+ a.setPosX(posX - _shiftX);
+ a.setPosY(posY - _shiftY);
+ this.setCursor(new Cursor(Cursor.MOVE_CURSOR));
}
- AppThinker.getWindow().getStatusbar().setSizeLabel(a.getSizeX(), a.getSizeY());
}
- //Sinon on déplace
- else{
- //On repositionne la classe en prenant en compte le décalage mesuré au clic de la souris
- a.setPosX(posX - _shiftX);
- a.setPosY(posY - _shiftY);
- this.setCursor(new Cursor(Cursor.MOVE_CURSOR));
+ }
+ //On est en train de créer un lien, on recherche le point d'accroche d'arrivée
+ if(_selected != null && _gripSelected != null){
+ Class selected = (Class) _selected;
+ for(Class hovered : _classes){
+ int posXSelected = hovered.getPosX();
+ int posYSelected = hovered.getPosY();
+ int sizeXSelected = hovered.getSizeX();
+ int sizeYSelected = hovered.getSizeY();
+ //Si cette classe est survolée, on affiche son nom dans la barre de statut et on la sauvegarde temporairement
+ _hovered = null;
+ if(posX >= posXSelected - sizeXSelected/2 - gripSize && posX <= posXSelected + sizeXSelected/2 + gripSize && posY >= posYSelected - sizeYSelected/2 - gripSize && posY <= posYSelected + sizeYSelected/2 + gripSize){
+ AppThinker.getWindow().getStatusbar().setStatusMessage("Approach a target grip on this class to create the link : " + hovered.getName());
+ if(hovered != _selected){
+ _hovered = hovered;
+ //On recherche le point survolé
+ checkHoveredGrip((Class) _hovered, posX, posY);
+ //Si toutes les conditions sont réunies, on crée le lien
+ if(_hovered != null && _gripHovered != null && _selected != null && _gripSelected != null){
+ //Récupération du type de lien
+ UmlToolbar toolbar = (UmlToolbar) _toolbar;
+ int currentTool = toolbar.getCurrentTool();
+ int type = (currentTool == UmlToolbar.STRONG_TOOL) ? Link.STRONG : (currentTool == UmlToolbar.WEAK_TOOL) ? Link.WEAK : (currentTool == UmlToolbar.COMPOSITION_TOOL) ? Link.COMPOSITION : (currentTool == UmlToolbar.AGGREGATION_TOOL) ? Link.AGGREGATION : Link.INHERITANCE;
+ _links.add(new Link((Class) _selected, (Class) _hovered, _gripSelected, _gripHovered, 0, 0, 0, 0, type));
+ _selected = null;
+ _gripSelected = null;
+ _gripHovered = null;
+ _hovered = null;
+ this.setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
+ }
+ }
+ break;
+ }
}
}
this.repaint();
}
/**
- * La souris bouge dans la grille.
+ * Déclenchée par le mouvement de la souris, cette fonction permet de récupérer la classe actuellement survolée.
* @param e L'événement souris.
*/
@Override
@@ -432,41 +684,12 @@ public class UmlDiagram extends Composition {
int sens = 5;
//Mise à jour des coordonnées de la souris dans la statusbar
AppThinker.getWindow().getStatusbar().setPosLabel(e.getX(), e.getY());
- //Si une classe est sélectionnée
+ //Si une classe est sélectionnée, on recherche si le curseur est à proximité d'un point d'accroche
if (_selected instanceof Class) {
Class a = (Class) _selected;
AppThinker.getWindow().getStatusbar().setSizeLabel(a.getSizeX(), a.getSizeY());
- int posX = a.getPosX() - (a.getSizeX() / 2);
- int posY = a.getPosY() - (a.getSizeY() / 2);
- //Si la souris est à proximité d'un lien, on affiche le curseur de redimensionnement
- if (getX >= posX - sens && getX <= posX + sens && getY >= posY - sens && getY <= posY + sens) {
- cornerSelection = "NW";
- this.setCursor(new Cursor(Cursor.NW_RESIZE_CURSOR));
- } else if (getX >= posX + a.getSizeX() / 2 - sens && getX <= posX + a.getSizeX() / 2 + sens && getY >= posY - sens && getY <= posY + sens) {
- cornerSelection = "N";
- this.setCursor(new Cursor(Cursor.N_RESIZE_CURSOR));
- } else if (getX >= posX + a.getSizeX() - sens && getX <= posX + a.getSizeX() + sens && getY >= posY - sens && getY <= posY + sens) {
- cornerSelection = "NE";
- this.setCursor(new Cursor(Cursor.NE_RESIZE_CURSOR));
- } else if (getX >= posX + a.getSizeX() - sens && getX <= posX + a.getSizeX() + sens && getY >= posY + a.getSizeY() / 2 - sens && getY <= posY + a.getSizeY() / 2 + sens) {
- cornerSelection = "E";
- this.setCursor(new Cursor(Cursor.E_RESIZE_CURSOR));
- } else if (getX >= posX + a.getSizeX() - sens && getX <= posX + a.getSizeX() + sens && getY >= posY + a.getSizeY() - sens && getY <= posY + a.getSizeY() + sens) {
- cornerSelection = "SE";
- this.setCursor(new Cursor(Cursor.SE_RESIZE_CURSOR));
- } else if (getX >= posX + a.getSizeX() / 2 - sens && getX <= posX + a.getSizeX() / 2 + sens && getY >= posY + a.getSizeY() - sens && getY <= posY + a.getSizeY() + sens) {
- cornerSelection = "S";
- this.setCursor(new Cursor(Cursor.S_RESIZE_CURSOR));
- } else if (getX >= posX - sens && getX <= posX + sens && getY >= posY + a.getSizeY() - sens && getY <= posY + a.getSizeY() + sens) {
- cornerSelection = "SW";
- this.setCursor(new Cursor(Cursor.SW_RESIZE_CURSOR));
- } else if (getX >= posX - sens && getX <= posX + sens && getY >= posY + a.getSizeY() / 2 - sens && getY <= posY + a.getSizeY() / 2 + sens) {
- cornerSelection = "W";
- this.setCursor(new Cursor(Cursor.W_RESIZE_CURSOR));
- } else {
- cornerSelection = null;
- this.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
- }
+ //Si une classe est sélectionnée, on recherche si le curseur est à proximité d'un point d'accroche
+ checkHoveredGrip(a, getX, getY);
}
}
}
diff --git a/AppThinker/src/UmlToolbar.java b/AppThinker/src/UmlToolbar.java
index 1af645b..81c43c0 100644
--- a/AppThinker/src/UmlToolbar.java
+++ b/AppThinker/src/UmlToolbar.java
@@ -259,6 +259,7 @@ public class UmlToolbar extends JPanel {
this._currentTool = currentTool;
if(this._currentTool == UmlToolbar.SELECT_TOOL) _umlDiagram.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
else _umlDiagram.setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
+ _umlDiagram.setViewGripsEnabled(false);
switch(currentTool){
case EDIT_TOOL:
if(_umlDiagram.getSelected() instanceof Class){
@@ -282,18 +283,23 @@ public class UmlToolbar extends JPanel {
AppThinker.getWindow().getStatusbar().setStatusMessage("Class tool - Click everywhere to add a new class.");
break;
case STRONG_TOOL:
+ _umlDiagram.setViewGripsEnabled(true);
AppThinker.getWindow().getStatusbar().setStatusMessage("Strong relation tool - Click on a class, hold, and release on another class.");
break;
case WEAK_TOOL:
+ _umlDiagram.setViewGripsEnabled(true);
AppThinker.getWindow().getStatusbar().setStatusMessage("Weak relation tool - Click on a class, hold, and release on another class.");
break;
case COMPOSITION_TOOL:
+ _umlDiagram.setViewGripsEnabled(true);
AppThinker.getWindow().getStatusbar().setStatusMessage("Composition relation tool - Click on a class, hold, and release on another class.");
break;
case AGGREGATION_TOOL:
+ _umlDiagram.setViewGripsEnabled(true);
AppThinker.getWindow().getStatusbar().setStatusMessage("Aggregation relation tool - Click on a class, hold, and release on another class.");
break;
case INHERITANCE_TOOL:
+ _umlDiagram.setViewGripsEnabled(true);
AppThinker.getWindow().getStatusbar().setStatusMessage("Inheritance relation tool - Click on a class, hold, and release on another class.");
break;
default: