374 lines
15 KiB
Java
374 lines
15 KiB
Java
import javax.swing.*;
|
|
import java.awt.*;
|
|
import java.awt.event.MouseEvent;
|
|
import java.awt.event.MouseListener;
|
|
import java.awt.event.MouseMotionListener;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
|
|
/**
|
|
* Cette classe permet d'afficher l'ensemble des éléments du projet sous la forme d'un diagramme UML.
|
|
* @author V.BOULANGER
|
|
*/
|
|
public class UmlDiagram extends JPanel implements MouseListener, MouseMotionListener {
|
|
|
|
private Project _project;
|
|
private AppThinkerToolbar _toolbar;
|
|
private List<Class> _classes;
|
|
private List<Link> _links;
|
|
private Object _selected;
|
|
private String cornerSelection = null;
|
|
|
|
private int _shiftX;
|
|
private int _shiftY;
|
|
|
|
/**
|
|
* Constructeur - Crée un nouveau diagramme UML à partir d'un projet.
|
|
* @param p Le projet associé.
|
|
*/
|
|
public UmlDiagram(Project p){
|
|
_project = p;
|
|
this.addMouseListener(this);
|
|
this.addMouseMotionListener(this);
|
|
this.setPreferredSize(new Dimension(3000,3000));
|
|
this._toolbar = new AppThinkerToolbar(this);
|
|
}
|
|
|
|
/**
|
|
* Dessine les éléments du projet sous la forme d'un diagramme UML.
|
|
* @param g L'objet graphique
|
|
*/
|
|
@Override
|
|
public void paintComponent(Graphics g){
|
|
Font font1 = new Font("Arial", Font.PLAIN, 14);
|
|
FontMetrics metrics1 = this.getFontMetrics(font1);
|
|
Font font2 = new Font("Arial", Font.PLAIN, 10);
|
|
FontMetrics metrics2 = this.getFontMetrics(font2);
|
|
|
|
g.setColor(new Color(127, 158, 178));
|
|
g.drawString("UML Diagram", 10, 20);
|
|
for(Class a : _classes){
|
|
g.setFont(font1);
|
|
int posX = a.getPosX() - (a.getSizeX()/2);
|
|
int posY = a.getPosY() - (a.getSizeY()/2);
|
|
//Dessin du rectangle
|
|
g.setColor(new Color(127, 158, 178));
|
|
g.fillRect(posX, posY, a.getSizeX(), a.getSizeY());
|
|
g.setColor(Color.BLACK);
|
|
//Dessin du nom de la classe
|
|
g.setColor(new Color(39, 76, 94));
|
|
int posCounter = posY + font1.getSize();
|
|
g.drawString(a.getName(), posX + a.getSizeX()/2 - metrics1.stringWidth(a.getName())/2, posCounter);
|
|
posCounter += 5;
|
|
g.setColor(new Color(218, 233, 244));
|
|
//Ligne de séparation
|
|
g.drawLine(posX, posY + font1.getSize() + 5, posX + a.getSizeX()-1, posY + font1.getSize() + 5);
|
|
g.setFont(font2);
|
|
posCounter += font2.getSize();
|
|
g.drawString("attributes", posX + a.getSizeX()/2 - metrics2.stringWidth("attributes")/2, posCounter);
|
|
//Affichage des attributs
|
|
g.setColor(new Color(39, 76, 94));
|
|
for(Attribute b : a.getAttributes()){
|
|
posCounter += font2.getSize();
|
|
g.drawString(b.getAccess() + " " + b.getName() + " : " + b.getType(), posX, posCounter);
|
|
}
|
|
posCounter += 5;
|
|
g.setColor(new Color(218, 233, 244));
|
|
//Ligne de séparation
|
|
g.drawLine(posX, posCounter, posX + a.getSizeX()-1, posCounter);
|
|
posCounter += font2.getSize();
|
|
g.drawString("methods", posX + a.getSizeX()/2 - metrics2.stringWidth("methods")/2, posCounter);
|
|
//Dessin des méthodes
|
|
g.setColor(new Color(39, 76, 94));
|
|
for(Method m : a.getMethods()){
|
|
posCounter += font2.getSize();
|
|
String chain = m.getAccess() + " " + m.getName() + "(";
|
|
ArrayList<String> listArguments = new ArrayList<String>();
|
|
for(Argument ar : m.getArguments()){
|
|
listArguments.add(ar.getName() + " : " + ar.getType());
|
|
}
|
|
//chain = chain.substring(0, chain.length()-2);
|
|
chain += String.join(", ", listArguments) + ") : " + m.getType();
|
|
g.drawString(chain, posX, posCounter);
|
|
}
|
|
//Si la classe est sélectionnée
|
|
if((Class)_selected == a){
|
|
g.setColor(new Color(39, 76, 94));
|
|
AppThinker.getWindow().getStatusbar().setSizeLabel(a.getSizeX(), a.getSizeY());
|
|
//Top Left
|
|
g.fillOval(posX-4, posY-4, 8, 8);
|
|
//Top
|
|
g.fillRect(posX + (a.getSizeX()/2)-4, posY-4, 8, 8);
|
|
//Top Right
|
|
g.fillOval(posX + a.getSizeX()-4, posY-4, 8, 8);
|
|
//Right
|
|
g.fillRect(posX + a.getSizeX()-4, posY + (a.getSizeY()/2)-4, 8, 8);
|
|
//Bottom Right
|
|
g.fillOval(posX + a.getSizeX()-4, posY + a.getSizeY()-4, 8, 8);
|
|
//Bottom
|
|
g.fillRect(posX + (a.getSizeX()/2)-4, posY + a.getSizeY()-4,8, 8);
|
|
//Bottom Left
|
|
g.fillOval(posX - 4, posY + a.getSizeY()-4, 8, 8);
|
|
//Left
|
|
g.fillRect(posX -4, posY + (a.getSizeY()/2)-4, 8, 8);
|
|
//Total rectangle
|
|
g.drawRect(posX, posY, a.getSizeX(), a.getSizeY());
|
|
}
|
|
else AppThinker.getWindow().getStatusbar().setSizeLabel(0, 0);
|
|
}
|
|
AppThinker.getWindow().repaint();
|
|
}
|
|
|
|
/**
|
|
* Récupère la toolbar du diagramme.
|
|
* @return La toolbar du diagramme.
|
|
*/
|
|
public AppThinkerToolbar getToolbar(){
|
|
return this._toolbar;
|
|
}
|
|
|
|
/**
|
|
* Mets à jour graphiquement le diagramme UML.
|
|
*/
|
|
public void displayDiagram(){
|
|
_classes = _project.getClasses();
|
|
_links = _project.getLinks();
|
|
this.repaint();
|
|
}
|
|
|
|
/**
|
|
* Récupère l'élément sélectionné dans la grille.
|
|
* @return L'élément sélectionné dan sla grille.
|
|
*/
|
|
public Object getSelected(){
|
|
return this._selected;
|
|
}
|
|
|
|
/**
|
|
* Récupération de l'objet cliqué
|
|
* @param getX Les coordonnées de la souris sur l'axe X.
|
|
* @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;
|
|
}
|
|
}
|
|
}
|
|
if(classSelected == false && linkSelected == false) _selected = null;
|
|
//Si la classe est sélectionnée, on enregistre le décalage entre la souris et le centre de la classe
|
|
if(_selected instanceof Class){
|
|
Class a = (Class) _selected;
|
|
_shiftX = getX - a.getPosX();
|
|
_shiftY = getY - a.getPosY();
|
|
}
|
|
this.repaint();
|
|
}
|
|
|
|
/**
|
|
* Modifie les propriétés de la classe.
|
|
* @param a La classe a modifier.
|
|
*/
|
|
public void editClass(Class a){
|
|
ClassPropertiesWindow prop = new ClassPropertiesWindow(this, a);
|
|
}
|
|
|
|
public void removeClass(Class a){
|
|
AppThinker.getProject().getClasses().remove(a);
|
|
}
|
|
|
|
//Actions de la souris sur le diagramme UML
|
|
/**
|
|
* Action du clic de la souris sur le diagramme.
|
|
* @param e L'événement souris.
|
|
*/
|
|
@Override
|
|
public void mouseClicked(MouseEvent e) {
|
|
//Si il s'agit d'un double-clic et que l'outil sélection est sélectionné, on ouvre la fenêtre d'édition de la classe
|
|
if(e.getClickCount() == 2 && _toolbar.getCurrentTool() == AppThinkerToolbar.SELECT_TOOL){
|
|
if(_selected instanceof Class){
|
|
this.editClass((Class) _selected);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Bouton de la souris pressé sur la grille. On récupère l'outil sélectionné pour parvenir à l'action.
|
|
* @param e L'événement souris.
|
|
*/
|
|
@Override
|
|
public void mousePressed(MouseEvent e) {
|
|
int tool = _toolbar.getCurrentTool();
|
|
switch(tool){
|
|
//On essaie de sélectionner un élément
|
|
case AppThinkerToolbar.EDIT_TOOL:
|
|
System.out.println("On édite un élément.");
|
|
this.select(e.getX(), e.getY());
|
|
if(_selected instanceof Class){
|
|
this.editClass((Class) _selected);
|
|
}
|
|
break;
|
|
case AppThinkerToolbar.DELETE_TOOL:
|
|
System.out.println("On supprime un élément.");
|
|
this.select(e.getX(), e.getY());
|
|
if(_selected instanceof Class){
|
|
removeClass((Class)_selected);
|
|
}
|
|
this.displayDiagram();
|
|
break;
|
|
case AppThinkerToolbar.COPY_TOOL:
|
|
System.out.println("On copie un élément.");
|
|
break;
|
|
case AppThinkerToolbar.PASTE_TOOL:
|
|
System.out.println("On colle un élément.");
|
|
break;
|
|
//On essaie d'ajouter une classe
|
|
case AppThinkerToolbar.CLASS_TOOL:
|
|
AppThinker.getProject().addClass(new Class(e.getX(), e.getY(), Class.RECTANGLE));
|
|
break;
|
|
case AppThinkerToolbar.ASSOCIATION_TOOL:
|
|
System.out.println("On ajoute une association");
|
|
break;
|
|
case AppThinkerToolbar.LINK_TOOL:
|
|
System.out.println("On ajoute un lien");
|
|
break;
|
|
default:
|
|
this.select(e.getX(), e.getY());
|
|
break;
|
|
}
|
|
this.displayDiagram();
|
|
}
|
|
|
|
@Override
|
|
public void mouseReleased(MouseEvent e) {
|
|
|
|
}
|
|
|
|
@Override
|
|
public void mouseEntered(MouseEvent e) {
|
|
|
|
}
|
|
|
|
@Override
|
|
public void mouseExited(MouseEvent e) {
|
|
|
|
}
|
|
|
|
/**
|
|
* Déplacer un élément en cliquant et déplaçant la souris.
|
|
* @param e Evénement souris
|
|
*/
|
|
@Override
|
|
public void mouseDragged(MouseEvent e) {
|
|
//Mise à jour des coordonnées de la souris dans la statusbar
|
|
int posX = e.getX();
|
|
int posY = e.getY();
|
|
AppThinker.getWindow().getStatusbar().setPosLabel(posX, posY);
|
|
if(_selected instanceof Class){
|
|
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);
|
|
//Redimensionnement bas
|
|
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 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));
|
|
}
|
|
}
|
|
this.repaint();
|
|
}
|
|
|
|
/**
|
|
* La souris bouge dans la grille.
|
|
* @param e L'événement souris.
|
|
*/
|
|
@Override
|
|
public void mouseMoved(MouseEvent e) {
|
|
int getX = e.getX();
|
|
int getY = e.getY();
|
|
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
|
|
if (_selected instanceof Class) {
|
|
Class a = (Class) _selected;
|
|
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));
|
|
}
|
|
}
|
|
}
|
|
}
|