diff --git a/AppThinker.mdzip b/AppThinker.mdzip index 5c5bbad..38545cf 100644 Binary files a/AppThinker.mdzip and b/AppThinker.mdzip differ diff --git a/AppThinker.mdzip.bak b/AppThinker.mdzip.bak new file mode 100644 index 0000000..e60c8cf Binary files /dev/null and b/AppThinker.mdzip.bak differ diff --git a/AppThinker/src/AppThinker.java b/AppThinker/src/AppThinker.java index ce671f9..11b071f 100644 --- a/AppThinker/src/AppThinker.java +++ b/AppThinker/src/AppThinker.java @@ -37,8 +37,8 @@ public class AppThinker { _window.getToolbar().enableEditing(); _window.getStatusbar().setStatusMessage("Le projet a été créé."); _window.getStatusbar().setFileMessage(_project.getName()); - _window.setGrid(_project.getGrid()); - AppThinker.getProject().getGrid().getDiagram().displayDiagram(); + _window.setDiagram(_project.getUmlDiagram()); + AppThinker.getProject().getUmlDiagram().displayDiagram(); } /** @@ -71,7 +71,7 @@ public class AppThinker { _window.getToolbar().disableEditing(); _window.getStatusbar().setStatusMessage("Le projet a été fermé."); _window.getStatusbar().setFileMessage("Aucun projet ouvert"); - _window.remove(_project.getGrid()); + _window.remove(_project.getUmlDiagram()); _project = null; } diff --git a/AppThinker/src/AppThinkerGrid.java b/AppThinker/src/AppThinkerGrid.java deleted file mode 100644 index 67621d0..0000000 --- a/AppThinker/src/AppThinkerGrid.java +++ /dev/null @@ -1,41 +0,0 @@ -import javax.swing.*; -import java.awt.*; - -/** - * Affiche une grille de projet pour l'affichage du diagramme. - * @author V.BOULANGER - */ -public class AppThinkerGrid extends JPanel { - - private Project _project; - private UmlDiagram _umlDiagram; - - /** - * Constructeur de la classe AppThinkerGrid. - * @param project Le projet associé. - */ - public AppThinkerGrid(Project project){ - this._project = project; - this.setBackground(new Color(192, 192, 192)); - this._umlDiagram = new UmlDiagram(_project); - - _umlDiagram.setPreferredSize(new Dimension(30000,30000)); - - this.setLayout(new BorderLayout()); - - JScrollPane scrollPane = new JScrollPane(_umlDiagram); - scrollPane.setVisible(true); - scrollPane.setBackground(new Color(60, 158, 163)); - - this.add(scrollPane, BorderLayout.CENTER); - this._umlDiagram.displayDiagram(); - } - - /** - * Récupère le diagramme de la grille. - * @return Le diagramme de la grille. - */ - public UmlDiagram getDiagram(){ - return _umlDiagram; - } -} diff --git a/AppThinker/src/AppThinkerToolbar.java b/AppThinker/src/AppThinkerToolbar.java index 2882595..0e228f7 100644 --- a/AppThinker/src/AppThinkerToolbar.java +++ b/AppThinker/src/AppThinkerToolbar.java @@ -275,17 +275,17 @@ public class AppThinkerToolbar extends JPanel { */ public void setCurrentTool(int currentTool){ this._currentTool = currentTool; - if(this._currentTool == AppThinkerToolbar.SELECT_TOOL) AppThinker.getProject().getGrid().getDiagram().setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); - else AppThinker.getProject().getGrid().getDiagram().setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR)); + if(this._currentTool == AppThinkerToolbar.SELECT_TOOL) AppThinker.getProject().getUmlDiagram().setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); + else AppThinker.getProject().getUmlDiagram().setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR)); switch(currentTool){ case 1: AppThinker.getWindow().getStatusbar().setStatusMessage("Outil édition - Cliquez sur un élément pour l'éditer."); break; case 2: - Object a = AppThinker.getProject().getGrid().getDiagram().getSelected(); + Object a = AppThinker.getProject().getUmlDiagram().getSelected(); if(a instanceof Class){ AppThinker.getProject().getClasses().remove(a); - AppThinker.getProject().getGrid().getDiagram().displayDiagram(); + AppThinker.getProject().getUmlDiagram().displayDiagram(); } AppThinker.getWindow().getStatusbar().setStatusMessage("Outil suppression - Cliquez sur un élément pour le supprimer."); break; diff --git a/AppThinker/src/AppThinkerWindow.java b/AppThinker/src/AppThinkerWindow.java index 8ee0b7e..9d6e5f6 100644 --- a/AppThinker/src/AppThinkerWindow.java +++ b/AppThinker/src/AppThinkerWindow.java @@ -36,6 +36,23 @@ public class AppThinkerWindow extends JFrame { _toolbar = new AppThinkerToolbar(); this.add(_toolbar, BorderLayout.NORTH); + + /*JTabbedPane tabbedPane = new JTabbedPane(); + + JPanel panel1 = new JPanel(); + panel1.add(new JLabel("Panel #1")); + tabbedPane.addTab("Start", panel1); + + JPanel panel2 = new JPanel(); + panel2.add(new JLabel("Projet #1")); + tabbedPane.addTab("Mon Projet 1", panel2); + + JPanel panel3 = new JPanel(); + panel3.add(new JLabel("Projet #1")); + tabbedPane.addTab("Mon Projet 2", panel3); + + this.add(tabbedPane, BorderLayout.CENTER);*/ + //Ajout de la statusbar à la fenêtre _statusbar = new AppThinkerStatusbar(); this.add(_statusbar, BorderLayout.SOUTH); @@ -52,8 +69,14 @@ public class AppThinkerWindow extends JFrame { return this._menubar; } - public void setGrid(AppThinkerGrid grid){ - this.add(grid, BorderLayout.CENTER); + public void setDiagram(UmlDiagram umlDiagram){ + + JScrollPane scrollPane = new JScrollPane(umlDiagram); + scrollPane.setVisible(true); + scrollPane.setBackground(new Color(218, 233, 244)); + + this.add(scrollPane, BorderLayout.CENTER); + umlDiagram.displayDiagram(); } /** diff --git a/AppThinker/src/Class.java b/AppThinker/src/Class.java index 418ad43..eb34878 100644 --- a/AppThinker/src/Class.java +++ b/AppThinker/src/Class.java @@ -140,7 +140,8 @@ public class Class { * @param sizeX La taille sur l'axe X de la classe. */ public void setSizeX(int sizeX) { - this._sizeX = sizeX; + if(sizeX < this.getMinSizeX()) this._sizeX = this.getMinSizeX(); + else this._sizeX = sizeX; } /** @@ -156,7 +157,8 @@ public class Class { * @param sizeY La taille sur l'axe Y de la classe. */ public void setSizeY(int sizeY) { - this._sizeY = sizeY; + if(sizeY < this.getMinSizeY()) this._sizeY = this.getMinSizeY(); + else this._sizeY = sizeY; } /** @@ -195,7 +197,8 @@ public class Class { * Paramètre les tailles minimum de la classe sur les axes X et Y en fonction de son contenu */ public void computeMinSize(){ - Font font = new Font("Arial",Font.PLAIN,14); + Font font1 = new Font("Arial", Font.PLAIN, 14); + Font font2 = new Font("Arial", Font.PLAIN, 10); Canvas c = new Canvas(); int space = 5; //Calcul de la taille en X @@ -215,13 +218,14 @@ public class Class { chain += ") : " + m.getType(); if(chain.length() > maxChain.length()) maxChain = chain; } - FontMetrics fm = c.getFontMetrics(font); + if("attributes".length() > maxChain.length()) maxChain = "attributes"; + if("methods".length() > maxChain.length()) maxChain = "methods"; + FontMetrics fm = c.getFontMetrics(font1); this.setMinSizeX(fm.stringWidth(maxChain)); //Calcul de la taille en Y int attributes = this.getAttributes().size(); int methods = this.getMethods().size(); - this.setMinSizeY((attributes + methods + 2) * font.getSize()); - //this.setMinSizeY((attributes + methods + 1) * fontSize + (attributes + methods + 4) * space); + this.setMinSizeY((attributes + methods + 5) * font2.getSize()); //Réadaptation éventuelle de la taille de la classe if(this.getSizeX() < this.getMinSizeX()) this.setSizeX(this.getMinSizeX()); if(this.getSizeY() < this.getMinSizeY()) this.setSizeY(this.getMinSizeY()); @@ -328,4 +332,44 @@ public class Class { this._methods.clear(); this.computeMinSize(); } + + /** + * Permet de redimensionner la classe vers le haut. + * @param posY La position en ordonnée du curseur. + */ + public void resizeUp(int posY){ + int shiftY = this.getPosY() - this.getSizeY()/2 - posY; + this.setSizeY(this.getSizeY() + shiftY); + if(this.getSizeY() > this.getMinSizeY()) this.setPosY(posY + this.getSizeY()/2); + } + + /** + * Permet de redimensionner la classe vers le bas. + * @param posY La position en ordonnée du curseur. + */ + public void resizeDown(int posY){ + int shiftY = posY - this.getPosY() - this.getSizeY()/2; + this.setSizeY(this.getSizeY() + shiftY); + if(this.getSizeY() > this.getMinSizeY()) this.setPosY(posY - this.getSizeY()/2); + } + + /** + * Permet de redimensionner la classe vers la gauche. + * @param posX La position en abscisse du curseur. + */ + public void resizeLeft(int posX){ + int shiftX = this.getPosX() - this.getSizeX()/2 - posX; + this.setSizeX(this.getSizeX() + shiftX); + if(this.getSizeX() > this.getMinSizeX()) this.setPosX(posX + this.getSizeX()/2); + } + + /** + * Permet de redimensionner la classe vers la droite. + * @param posX La position en abscisse du curseur. + */ + public void resizeRight(int posX){ + int shiftX = posX - this.getPosX() - this.getSizeX()/2; + this.setSizeX(this.getSizeX() + shiftX); + if(this.getSizeX() > this.getMinSizeX()) this.setPosX(posX - this.getSizeX()/2); + } } diff --git a/AppThinker/src/Project.java b/AppThinker/src/Project.java index 67e3025..33e56b5 100644 --- a/AppThinker/src/Project.java +++ b/AppThinker/src/Project.java @@ -16,7 +16,7 @@ public class Project { private String _designation; private String _path; - private AppThinkerGrid _grid; + private UmlDiagram _umlDiagram; private List _classes; private List _links; @@ -34,7 +34,7 @@ public class Project { _path = null; _classes = new ArrayList(); _links = new ArrayList(); - _grid = new AppThinkerGrid(this); + _umlDiagram = new UmlDiagram(this); } /** @@ -57,14 +57,15 @@ public class Project { _path = path; _classes = classes; _links = links; + _umlDiagram = new UmlDiagram(this); } /** - * Récupère l'objet grille du projet. - * @return L'objet grille du projet. + * Récupère le diagramme UML associé au projet. + * @return Le diagramme UML associé au projet. */ - public AppThinkerGrid getGrid(){ - return this._grid; + public UmlDiagram getUmlDiagram(){ + return this._umlDiagram; } /** diff --git a/AppThinker/src/Selectpoint.java b/AppThinker/src/Selectpoint.java deleted file mode 100644 index 68d4ea0..0000000 --- a/AppThinker/src/Selectpoint.java +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Gère un point de sélection d'un élément. - * @author V.BOULANGER - */ -public class Selectpoint { - - public static int _selectpointsId = 0; - public static final int TOP_LEFT = 0; - public static final int TOP = 1; - public static final int TOP_RIGHT = 2; - public static final int LEFT = 3; - public static final int RIGHT = 4; - public static final int BOTTOM_LEFT = 5; - public static final int BOTTOM = 6; - public static final int BOTTOM_RIGHT = 7; - - private int _id; - private int _location; - - /** - * Constructeur - Crée un point de sélection pour un élément. - * @param location L'endroit où doit apparaître le point de sélection sur l'élément. - */ - public Selectpoint(int location){ - _selectpointsId++; - _id = _selectpointsId; - _location = location; - } - - /** - * Récupère le numéro du point de sélection. - * @return Le numéro du point de sélection. - */ - public int getId(){ - return this._id; - } - - /** - * Récupère l'endroit où est affiché le point de sélection. - * @return L'endroit où est affiché le point de sélection. - */ - public int getLocation(){ - return this._location; - } - - /** - * Paramètre l'endroit où doit être afficher le point de sélection. - * @param location L'endroit où doit être affiché le point de sélection. - */ - public void setLocation(int location){ - this._location = location; - } - -} diff --git a/AppThinker/src/UmlDiagram.java b/AppThinker/src/UmlDiagram.java index 846ea4b..f2a50d4 100644 --- a/AppThinker/src/UmlDiagram.java +++ b/AppThinker/src/UmlDiagram.java @@ -14,6 +14,10 @@ public class UmlDiagram extends JPanel implements MouseListener, MouseMotionList private List _classes; private List _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. @@ -23,6 +27,7 @@ public class UmlDiagram extends JPanel implements MouseListener, MouseMotionList _project = p; this.addMouseListener(this); this.addMouseMotionListener(this); + this.setPreferredSize(new Dimension(3000,3000)); } /** @@ -31,34 +36,48 @@ public class UmlDiagram extends JPanel implements MouseListener, MouseMotionList */ @Override public void paintComponent(Graphics g){ - Font font = new Font("Arial", Font.PLAIN, 14); + 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(Color.GRAY); - g.fillRoundRect(posX, posY, a.getSizeX(), a.getSizeY(), 10, 10); + 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 - int posCounter = posY + font.getSize(); - - FontMetrics metrics = this.getFontMetrics(font); - g.setFont(font); - g.drawString(a.getName(), posX + a.getSizeX()/2 - metrics.stringWidth(a.getName())/2, posCounter); + 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 + font.getSize() + 5, posX + a.getSizeX()-1, posY + font.getSize() + 5); + 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 += font.getSize(); + 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 += font.getSize(); + posCounter += font2.getSize(); String chain = m.getAccess() + " " + m.getName() + "("; for(Argument ar : m.getArguments()){ chain += ar.getName() + " : " + ar.getType() + ", "; @@ -69,6 +88,7 @@ public class UmlDiagram extends JPanel implements MouseListener, MouseMotionList } //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); @@ -91,7 +111,7 @@ public class UmlDiagram extends JPanel implements MouseListener, MouseMotionList } else AppThinker.getWindow().getStatusbar().setSizeLabel(0, 0); } - AppThinker.getProject().getGrid().updateUI(); + AppThinker.getWindow().repaint(); } /** @@ -123,8 +143,11 @@ public class UmlDiagram extends JPanel implements MouseListener, MouseMotionList for(Class a : _classes){ int posX = a.getPosX()-(a.getSizeX()/2); int posY = a.getPosY()-(a.getSizeY()/2); - if(getX >= posX && getX <= (posX + a.getSizeX())){ - if(getY >= posY && getY <= (posY + a.getSizeY())){ + //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; @@ -132,6 +155,12 @@ public class UmlDiagram extends JPanel implements MouseListener, MouseMotionList } } 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(); } @@ -177,6 +206,7 @@ public class UmlDiagram extends JPanel implements MouseListener, MouseMotionList //On essaie d'ajouter une classe case AppThinkerToolbar.CLASS_TOOL: Class newClass = new Class(e.getX(), e.getY(), Class.RECTANGLE); + newClass.addAttribute(new Attribute("_TestAttribut1", Attribute.PROTECTED, "int")); AppThinker.getProject().addClass(newClass); break; case AppThinkerToolbar.ASSOCIATION_TOOL: @@ -190,7 +220,6 @@ public class UmlDiagram extends JPanel implements MouseListener, MouseMotionList break; } this.displayDiagram(); - } @Override @@ -214,20 +243,102 @@ public class UmlDiagram extends JPanel implements MouseListener, MouseMotionList */ @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; - a.setPosX(e.getX()); - a.setPosY(e.getY()); + 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. On affiche les coordonnées de la souris dans la statusbar. + * 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)); + } + } } }