From 0725100aa298e0b827f79666edeaaf801ece85d5 Mon Sep 17 00:00:00 2001 From: Ludovic Apvrille <ludovic.apvrille@telecom-paristech.fr> Date: Tue, 23 Jan 2018 13:15:46 +0000 Subject: [PATCH] Adding icons in the FT diagram --- .idea/misc.xml | 2 +- src/main/java/ui/avatarbd/AvatarBDBlock.java | 693 +++++++++--------- src/main/java/ui/ftd/FTDConstraint.java | 103 +-- src/main/java/ui/util/IconManager.java | 36 +- .../java/ui/window/JDialogConstraintText.java | 4 + src/main/resources/ui/util/AfterFT.png | Bin 0 -> 4275 bytes src/main/resources/ui/util/AndFT.png | Bin 0 -> 3860 bytes src/main/resources/ui/util/BeforeFT.png | Bin 0 -> 4299 bytes src/main/resources/ui/util/NotFT.png | Bin 0 -> 4239 bytes src/main/resources/ui/util/SequenceFT.png | Bin 0 -> 4126 bytes 10 files changed, 443 insertions(+), 395 deletions(-) create mode 100644 src/main/resources/ui/util/AfterFT.png create mode 100644 src/main/resources/ui/util/AndFT.png create mode 100644 src/main/resources/ui/util/BeforeFT.png create mode 100644 src/main/resources/ui/util/NotFT.png create mode 100644 src/main/resources/ui/util/SequenceFT.png diff --git a/.idea/misc.xml b/.idea/misc.xml index b755d8ca46..51e5191ed4 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -38,7 +38,7 @@ <property name="caretWidth" class="java.lang.Integer" /> </properties> </component> - <component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="false" project-jdk-name="1.7" project-jdk-type="JavaSDK"> + <component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="false" project-jdk-name="1.8" project-jdk-type="JavaSDK"> <output url="file://$PROJECT_DIR$/build" /> </component> </project> \ No newline at end of file diff --git a/src/main/java/ui/avatarbd/AvatarBDBlock.java b/src/main/java/ui/avatarbd/AvatarBDBlock.java index f2bbe53002..cad86936ec 100644 --- a/src/main/java/ui/avatarbd/AvatarBDBlock.java +++ b/src/main/java/ui/avatarbd/AvatarBDBlock.java @@ -1,26 +1,26 @@ /* Copyright or (C) or Copr. GET / ENST, Telecom-Paris, Ludovic Apvrille - * + * * ludovic.apvrille AT enst.fr - * + * * This software is a computer program whose purpose is to allow the * edition of TURTLE analysis, design and deployment diagrams, to * allow the generation of RT-LOTOS or Java code from this diagram, * and at last to allow the analysis of formal validation traces * obtained from external tools, e.g. RTL from LAAS-CNRS and CADP * from INRIA Rhone-Alpes. - * + * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, * modify and/ or redistribute the software under the terms of the CeCILL * license as circulated by CEA, CNRS and INRIA at the following URL * "http://www.cecill.info". - * + * * As a counterpart to the access to the source code and rights to copy, * modify and redistribute granted by the license, users are provided only * with a limited warranty and the software's author, the holder of the * economic rights, and the successive licensors have only limited * liability. - * + * * In this respect, the user's attention is drawn to the risks associated * with loading, using, modifying and/or developing or reproducing the * software by the user in light of its specific status of free software, @@ -31,14 +31,12 @@ * requirements in conditions enabling the security of their systems and/or * data to be ensured and, more generally, to use and operate it in the * same conditions as regards security. - * + * * The fact that you are presently reading this means that you have had * knowledge of the CeCILL license and that you accept its terms. */ - - package ui.avatarbd; import myutil.Conversion; @@ -60,11 +58,12 @@ import java.util.LinkedList; /** - * Class AvatarBDBlock - * Node. To be used in AVATAR Block Diagrams - * Creation: 06/04/2010 - * @version 1.1 06/04/2010 - * @author Ludovic APVRILLE + * Class AvatarBDBlock + * Node. To be used in AVATAR Block Diagrams + * Creation: 06/04/2010 + * + * @author Ludovic APVRILLE + * @version 1.1 06/04/2010 */ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements SwallowTGComponent, SwallowedTGComponent, GenericTree, AvatarBDStateMachineOwner { @@ -95,12 +94,12 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S protected LinkedList<TAttribute> myAttributes; protected LinkedList<AvatarMethod> myMethods; protected LinkedList<AvatarSignal> mySignals; - protected String [] globalCode; + protected String[] globalCode; public String oldValue; - public AvatarBDBlock(int _x, int _y, int _minX, int _maxX, int _minY, int _maxY, boolean _pos, TGComponent _father, TDiagramPanel _tdp) { + public AvatarBDBlock(int _x, int _y, int _minX, int _maxX, int _minY, int _maxY, boolean _pos, TGComponent _father, TDiagramPanel _tdp) { super(_x, _y, _minX, _maxX, _minY, _maxY, _pos, _father, _tdp); width = 250; @@ -144,64 +143,64 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S oldValue = value; oldScaleFactor = tdp.getZoom(); - currentFontSize = (int) (maxFontSize*oldScaleFactor); + currentFontSize = (int) (maxFontSize * oldScaleFactor); myImageIcon = IconManager.imgic700; - this.myAttributes = new LinkedList<TAttribute> (); - this.myMethods = new LinkedList<AvatarMethod> (); - this.mySignals = new LinkedList<AvatarSignal> (); + this.myAttributes = new LinkedList<TAttribute>(); + this.myMethods = new LinkedList<AvatarMethod>(); + this.mySignals = new LinkedList<AvatarSignal>(); actionOnAdd(); } @Override - public void internalDrawing (Graphics graph) { - Font font = graph.getFont (); - this.internalDrawingAux (graph); - graph.setFont (font); + public void internalDrawing(Graphics graph) { + Font font = graph.getFont(); + this.internalDrawingAux(graph); + graph.setFont(font); } public void setSignalsAsNonAttached() { - for (AvatarSignal mySig: mySignals) mySig.attachedToARelation = false; + for (AvatarSignal mySig : mySignals) mySig.attachedToARelation = false; } - - public void addSignal(AvatarSignal sig){ - this.mySignals.add(sig); + + public void addSignal(AvatarSignal sig) { + this.mySignals.add(sig); } - - public void internalDrawingAux (Graphics graph) { - //TraceManager.addDev("Block drawing aux = " + this); - + public void internalDrawingAux(Graphics graph) { + + //TraceManager.addDev("Block drawing aux = " + this); + // Draw outer rectangle (for border) - Color c = graph.getColor (); - graph.drawRect (this.x, this.y, this.width, this.height); + Color c = graph.getColor(); + graph.drawRect(this.x, this.y, this.width, this.height); // Draw inner rectangle - graph.setColor (ColorManager.AVATAR_BLOCK); - graph.fillRect (this.x+1, this.y+1, this.width-1, this.height-1); - graph.setColor (c); + graph.setColor(ColorManager.AVATAR_BLOCK); + graph.fillRect(this.x + 1, this.y + 1, this.width - 1, this.height - 1); + graph.setColor(c); // limits this.limitName = -1; this.limitAttr = -1; this.limitMethod = -1; - this.limitSignal = y + height; + this.limitSignal = y + height; // h retains the coordinate along X where an element was last drawn int h = 0; - int textY1 = (int) (this.textY1 * this.tdp.getZoom ()); - int textX = (int) (this.textX * this.tdp.getZoom ()); + int textY1 = (int) (this.textY1 * this.tdp.getZoom()); + int textX = (int) (this.textX * this.tdp.getZoom()); // Draw icon - this.iconIsDrawn = this.width > IconManager.iconSize + 2*textX && height > IconManager.iconSize + 2*textX; + this.iconIsDrawn = this.width > IconManager.iconSize + 2 * textX && height > IconManager.iconSize + 2 * textX; if (this.iconIsDrawn) - graph.drawImage (IconManager.img5100, this.x + this.width - IconManager.iconSize - textX, this.y + textX, null); + graph.drawImage(IconManager.img5100, this.x + this.width - IconManager.iconSize - textX, this.y + textX, null); - Font font = graph.getFont (); + Font font = graph.getFont(); String ster; if (!this.isCryptoBlock) @@ -209,56 +208,56 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S else ster = "<<" + stereotypeCrypto + ">>"; - if (this.rescaled && !this.tdp.isScaled ()) { + if (this.rescaled && !this.tdp.isScaled()) { this.rescaled = false; // Must set the font size... // Incrementally find the biggest font not greater than max_font size // If font is less than min_font, no text is displayed // This is the maximum font size possible - int maxCurrentFontSize = Math.max (0, Math.min (this.height, (int) (this.maxFontSize*this.tdp.getZoom ()))); - font = font.deriveFont ((float) maxCurrentFontSize); + int maxCurrentFontSize = Math.max(0, Math.min(this.height, (int) (this.maxFontSize * this.tdp.getZoom()))); + font = font.deriveFont((float) maxCurrentFontSize); // Try to decrease font size until we get below the minimum - while (maxCurrentFontSize > (this.minFontSize*this.tdp.getZoom () - 1)) { + while (maxCurrentFontSize > (this.minFontSize * this.tdp.getZoom() - 1)) { // Compute width of name of the function - int w0 = graph.getFontMetrics (font).stringWidth (this.value); + int w0 = graph.getFontMetrics(font).stringWidth(this.value); // Compute width of string stereotype - int w1 = graph.getFontMetrics (font).stringWidth (ster); + int w1 = graph.getFontMetrics(font).stringWidth(ster); // if one of the two width is small enough use this font size - if (Math.min (w0, w1) < this.width - (2*this.textX)) + if (Math.min(w0, w1) < this.width - (2 * this.textX)) break; // Decrease font size - maxCurrentFontSize --; + maxCurrentFontSize--; // Scale the font - font = font.deriveFont ((float) maxCurrentFontSize); + font = font.deriveFont((float) maxCurrentFontSize); } // Box is too damn small - if (this.currentFontSize < this.minFontSize*this.tdp.getZoom ()) { - maxCurrentFontSize ++; + if (this.currentFontSize < this.minFontSize * this.tdp.getZoom()) { + maxCurrentFontSize++; // Scale the font - font = font.deriveFont ((float) maxCurrentFontSize); + font = font.deriveFont((float) maxCurrentFontSize); } // Use this font - graph.setFont (font); + graph.setFont(font); this.currentFontSize = maxCurrentFontSize; } else - font = font.deriveFont (this.currentFontSize); + font = font.deriveFont(this.currentFontSize); - graph.setFont (font.deriveFont (Font.BOLD)); - h = graph.getFontMetrics ().getAscent () + graph.getFontMetrics ().getLeading () + textY1; + graph.setFont(font.deriveFont(Font.BOLD)); + h = graph.getFontMetrics().getAscent() + graph.getFontMetrics().getLeading() + textY1; - if (h + graph.getFontMetrics ().getDescent () + textY1 >= this.height) + if (h + graph.getFontMetrics().getDescent() + textY1 >= this.height) return; // Write stereotype if small enough - int w = graph.getFontMetrics ().stringWidth (ster); - if (w + 2*textX < this.width) - graph.drawString (ster, this.x + (this.width - w)/2, this.y + h); + int w = graph.getFontMetrics().stringWidth(ster); + if (w + 2 * textX < this.width) + graph.drawString(ster, this.x + (this.width - w) / 2, this.y + h); else { // try to draw with "..." instead if (!this.isCryptoBlock) @@ -266,38 +265,38 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S else ster = stereotypeCrypto; - for (int stringLength = ster.length ()-1; stringLength >= 0; stringLength--) { - String abbrev = "<<" + ster.substring (0, stringLength) + "...>>"; - w = graph.getFontMetrics ().stringWidth (abbrev); - if (w + 2*textX < this.width) { - graph.drawString (abbrev, this.x + (this.width - w)/2, this.y + h); + for (int stringLength = ster.length() - 1; stringLength >= 0; stringLength--) { + String abbrev = "<<" + ster.substring(0, stringLength) + "...>>"; + w = graph.getFontMetrics().stringWidth(abbrev); + if (w + 2 * textX < this.width) { + graph.drawString(abbrev, this.x + (this.width - w) / 2, this.y + h); break; } } } // Write value if small enough - graph.setFont (font); - h += graph.getFontMetrics ().getHeight () + textY1; - if (h + graph.getFontMetrics ().getDescent () + textY1 >= this.height) + graph.setFont(font); + h += graph.getFontMetrics().getHeight() + textY1; + if (h + graph.getFontMetrics().getDescent() + textY1 >= this.height) return; - w = graph.getFontMetrics ().stringWidth (this.value); - if (w + 2*textX < this.width) - graph.drawString (this.value, this.x + (this.width - w)/2, this.y + h); + w = graph.getFontMetrics().stringWidth(this.value); + if (w + 2 * textX < this.width) + graph.drawString(this.value, this.x + (this.width - w) / 2, this.y + h); else { // try to draw with "..." instead - for (int stringLength = this.value.length ()-1; stringLength >= 0; stringLength--) { - String abbrev = this.value.substring (0, stringLength) + "..."; - w = graph.getFontMetrics ().stringWidth (abbrev); - if (w + 2*textX < this.width) { - graph.drawString (abbrev, this.x + (this.width - w)/2, this.y + h); + for (int stringLength = this.value.length() - 1; stringLength >= 0; stringLength--) { + String abbrev = this.value.substring(0, stringLength) + "..."; + w = graph.getFontMetrics().stringWidth(abbrev); + if (w + 2 * textX < this.width) { + graph.drawString(abbrev, this.x + (this.width - w) / 2, this.y + h); break; } } } - h += graph.getFontMetrics ().getDescent () + textY1; + h += graph.getFontMetrics().getDescent() + textY1; // Update lower bound of text this.limitName = this.y + h; @@ -306,22 +305,22 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S return; // Draw separator - graph.drawLine (this.x, this.y+h, this.x+this.width, this.y+h); + graph.drawLine(this.x, this.y + h, this.x + this.width, this.y + h); - if (! this.tdp.areAttributesVisible ()) + if (!this.tdp.areAttributesVisible()) return; // Set font size // int attributeFontSize = Math.min (12, this.currentFontSize - 2); - int attributeFontSize = this.currentFontSize*5/6; - graph.setFont (font.deriveFont ((float) attributeFontSize)); - int step = graph.getFontMetrics ().getHeight (); + int attributeFontSize = this.currentFontSize * 5 / 6; + graph.setFont(font.deriveFont((float) attributeFontSize)); + int step = graph.getFontMetrics().getHeight(); h += textY1; // Attributes - limitAttr = limitName; - for (TAttribute attr: this.myAttributes) { + limitAttr = limitName; + for (TAttribute attr : this.myAttributes) { h += step; if (h >= this.height - textX) { this.limitAttr = this.y + this.height; @@ -329,22 +328,22 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S } // Get the string for this parameter - String attrString = attr.toAvatarString (); + String attrString = attr.toAvatarString(); // Try to draw it - w = graph.getFontMetrics ().stringWidth (attrString); - if (w + 2*textX < this.width) { - graph.drawString (attrString, this.x + textX, this.y + h); - this.drawConfidentialityVerification (attr.getConfidentialityVerification (), graph, this.x, this.y + h); + w = graph.getFontMetrics().stringWidth(attrString); + if (w + 2 * textX < this.width) { + graph.drawString(attrString, this.x + textX, this.y + h); + this.drawConfidentialityVerification(attr.getConfidentialityVerification(), graph, this.x, this.y + h); } else { // If we can't, try to draw with "..." instead int stringLength; - for (stringLength = attrString.length ()-1; stringLength >= 0; stringLength--) { - String abbrev = attrString.substring (0, stringLength) + "..."; - w = graph.getFontMetrics ().stringWidth (abbrev); - if (w + 2*textX < this.width) { - graph.drawString (abbrev, this.x + textX, this.y + h); - this.drawConfidentialityVerification (attr.getConfidentialityVerification (), graph, this.x, this.y + h); + for (stringLength = attrString.length() - 1; stringLength >= 0; stringLength--) { + String abbrev = attrString.substring(0, stringLength) + "..."; + w = graph.getFontMetrics().stringWidth(abbrev); + if (w + 2 * textX < this.width) { + graph.drawString(abbrev, this.x + textX, this.y + h); + this.drawConfidentialityVerification(attr.getConfidentialityVerification(), graph, this.x, this.y + h); break; } } @@ -355,7 +354,7 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S } } - h += graph.getFontMetrics ().getDescent () + textY1; + h += graph.getFontMetrics().getDescent() + textY1; // Remember the end of attributes this.limitAttr = this.y + h; @@ -363,34 +362,34 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S if (h + textY1 >= this.height) return; - graph.drawLine (this.x, this.y+h, this.x+this.width, this.y+h); + graph.drawLine(this.x, this.y + h, this.x + this.width, this.y + h); h += textY1; // Methods - limitMethod = limitAttr; - limitSignal = limitAttr; - for (AvatarMethod method: this.myMethods) { + limitMethod = limitAttr; + limitSignal = limitAttr; + for (AvatarMethod method : this.myMethods) { h += step; if (h >= this.height - textX) { this.limitMethod = this.y + this.height; - this.limitSignal = limitMethod; + this.limitSignal = limitMethod; return; } // Get the string for this method - String methodString = "- " + method.toString (); + String methodString = "- " + method.toString(); - w = graph.getFontMetrics ().stringWidth (methodString); - if (w + 2*textX < this.width) - graph.drawString (methodString, this.x + textX, this.y + h); + w = graph.getFontMetrics().stringWidth(methodString); + if (w + 2 * textX < this.width) + graph.drawString(methodString, this.x + textX, this.y + h); else { // If we can't, try to draw with "..." instead int stringLength; - for (stringLength = methodString.length ()-1; stringLength >= 0; stringLength--) { - String abbrev = methodString.substring (0, stringLength) + "..."; - w = graph.getFontMetrics ().stringWidth (abbrev); - if (w + 2*textX < this.width) { - graph.drawString (abbrev, this.x + textX, this.y + h); + for (stringLength = methodString.length() - 1; stringLength >= 0; stringLength--) { + String abbrev = methodString.substring(0, stringLength) + "..."; + w = graph.getFontMetrics().stringWidth(abbrev); + if (w + 2 * textX < this.width) { + graph.drawString(abbrev, this.x + textX, this.y + h); break; } } @@ -401,47 +400,46 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S } } - h += graph.getFontMetrics ().getDescent () + textY1; + h += graph.getFontMetrics().getDescent() + textY1; if (h + textY1 >= this.height) { - limitMethod = this.y + this.height; - limitSignal = this.y + this.height; + limitMethod = this.y + this.height; + limitSignal = this.y + this.height; return; - } + } - // Remember limit of methods + // Remember limit of methods this.limitMethod = this.y + h; - this.limitSignal = this.y + h; + this.limitSignal = this.y + h; - graph.drawLine (this.x, this.y+h, this.x+this.width, this.y+h); + graph.drawLine(this.x, this.y + h, this.x + this.width, this.y + h); h += textY1; // Signals - for (AvatarSignal signal: this.mySignals) { + for (AvatarSignal signal : this.mySignals) { h += step; if (h >= this.height - textX) { - limitSignal = this.height + this.y; + limitSignal = this.height + this.y; return; - } - - String signalString = "~ " + signal.toString (); - w = graph.getFontMetrics ().stringWidth (signalString); - if (w + 2*textX < this.width) { - graph.drawString (signalString, this.x + textX, this.y + h); - drawInfoAttachement(signal, graph, x, y+h); - - } - else { + } + + String signalString = "~ " + signal.toString(); + w = graph.getFontMetrics().stringWidth(signalString); + if (w + 2 * textX < this.width) { + graph.drawString(signalString, this.x + textX, this.y + h); + drawInfoAttachement(signal, graph, x, y + h); + + } else { // If we can't, try to draw with "..." instead int stringLength; - for (stringLength = signalString.length ()-1; stringLength >= 0; stringLength--) { - String abbrev = signalString.substring (0, stringLength) + "..."; - w = graph.getFontMetrics ().stringWidth (abbrev); - if (w + 2*textX < this.width) { - graph.drawString (abbrev, this.x + textX, this.y + h); - drawInfoAttachement(signal, graph, x, y+h); - - + for (stringLength = signalString.length() - 1; stringLength >= 0; stringLength--) { + String abbrev = signalString.substring(0, stringLength) + "..."; + w = graph.getFontMetrics().stringWidth(abbrev); + if (w + 2 * textX < this.width) { + graph.drawString(abbrev, this.x + textX, this.y + h); + drawInfoAttachement(signal, graph, x, y + h); + + break; } } @@ -452,83 +450,83 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S } } - h += graph.getFontMetrics ().getDescent () + textY1; + h += graph.getFontMetrics().getDescent() + textY1; if (h + textY1 >= this.height) { - limitSignal = this.height + this.y; + limitSignal = this.height + this.y; return; - } + } // Global code - limitSignal = this.y+h; + limitSignal = this.y + h; if (hasGlobalCode()) { - if (h+textY1+step >= this.height - textX) + if (h + textY1 + step >= this.height - textX) return; - graph.drawLine (this.x, this.y+h, this.x+this.width, this.y+h); - h += textY1+step; - - w = graph.getFontMetrics ().stringWidth (GLOBAL_CODE_INFO); - if (w + 2*textX < this.width) - graph.drawString (GLOBAL_CODE_INFO, this.x + (this.width - w)/2, this.y + h); + graph.drawLine(this.x, this.y + h, this.x + this.width, this.y + h); + h += textY1 + step; + + w = graph.getFontMetrics().stringWidth(GLOBAL_CODE_INFO); + if (w + 2 * textX < this.width) + graph.drawString(GLOBAL_CODE_INFO, this.x + (this.width - w) / 2, this.y + h); } else { - limitSignal = height; - } + limitSignal = height; + } } - private void drawInfoAttachement(AvatarSignal _as, Graphics g, int _x, int _y) { - if (_as.attachedToARelation) { - return; - } - Color c = g.getColor(); - g.setColor(Color.RED); - int []xA = new int[3]; - int []yA = new int[3]; - //top of triangle - xA[0] = _x + 5; - yA[0] = _y - 7; - - // Right bottom point - xA[1] = _x + 2; - yA[1] = _y; + private void drawInfoAttachement(AvatarSignal _as, Graphics g, int _x, int _y) { + if (_as.attachedToARelation) { + return; + } + Color c = g.getColor(); + g.setColor(Color.RED); + int[] xA = new int[3]; + int[] yA = new int[3]; + //top of triangle + xA[0] = _x + 5; + yA[0] = _y - 7; + + // Right bottom point + xA[1] = _x + 2; + yA[1] = _y; - // Left bottom point - xA[2] = _x + 8; - yA[2] = _y; + // Left bottom point + xA[2] = _x + 8; + yA[2] = _y; - g.fillPolygon(xA, yA, 3); + g.fillPolygon(xA, yA, 3); - g.setColor(c); + g.setColor(c); } private void drawConfidentialityVerification(int confidentialityVerification, Graphics g, int _x, int _y) { Color c = g.getColor(); Color c1; - int xc=(int)(6*tdp.getZoom()); - int yc=(int)(10*tdp.getZoom()); - int lockwidth=(int) (9*tdp.getZoom()); - int lockheight=(int) (7*tdp.getZoom()); - int ovalwidth=(int) (6*tdp.getZoom()); - int ovalheight=(int) (9*tdp.getZoom()); - switch(confidentialityVerification) { - case TAttribute.CONFIDENTIALITY_OK: - c1 = Color.green; - break; - case TAttribute.CONFIDENTIALITY_KO: - c1 = Color.red; - break; - case TAttribute.COULD_NOT_VERIFY_CONFIDENTIALITY: - c1 = Color.orange; - break; - default: - return; + int xc = (int) (6 * tdp.getZoom()); + int yc = (int) (10 * tdp.getZoom()); + int lockwidth = (int) (9 * tdp.getZoom()); + int lockheight = (int) (7 * tdp.getZoom()); + int ovalwidth = (int) (6 * tdp.getZoom()); + int ovalheight = (int) (9 * tdp.getZoom()); + switch (confidentialityVerification) { + case TAttribute.CONFIDENTIALITY_OK: + c1 = Color.green; + break; + case TAttribute.CONFIDENTIALITY_KO: + c1 = Color.red; + break; + case TAttribute.COULD_NOT_VERIFY_CONFIDENTIALITY: + c1 = Color.orange; + break; + default: + return; } - g.drawOval(_x+xc, _y-yc, ovalwidth, ovalheight); + g.drawOval(_x + xc, _y - yc, ovalwidth, ovalheight); g.setColor(c1); - g.fillRect(_x+xc*2/3, _y-yc*2/3, lockwidth, lockheight); + g.fillRect(_x + xc * 2 / 3, _y - yc * 2 / 3, lockwidth, lockheight); g.setColor(c); - g.drawRect(_x+xc*2/3, _y-yc*2/3, lockwidth, lockheight); + g.drawRect(_x + xc * 2 / 3, _y - yc * 2 / 3, lockwidth, lockheight); } @@ -550,11 +548,9 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S return name; } - public String getFullyQualifiedName() - { + public String getFullyQualifiedName() { String result = ""; - if (this.father != null && (this.father instanceof AvatarBDBlock)) - { + if (this.father != null && (this.father instanceof AvatarBDBlock)) { result = ((AvatarBDBlock) this.father).getFullyQualifiedName() + "."; } result += this.value; @@ -563,39 +559,39 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S } public boolean editOndoubleClick(JFrame frame, int _x, int _y) { - int textX = (int) (this.textX * this.tdp.getZoom ()); + int textX = (int) (this.textX * this.tdp.getZoom()); if (iconIsDrawn) { if (GraphicLib.isInRectangle(_x, _y, x + width - iconSize - textX, y + textX, iconSize, iconSize)) { - tdp.getMouseManager().setSelection(-1, -1); + tdp.getMouseManager().setSelection(-1, -1); tdp.selectTab(getValue()); return true; } } // On the name ? - if ((limitName == -1 && _y <= y + 2*currentFontSize) || _y < limitName) { + if ((limitName == -1 && _y <= y + 2 * currentFontSize) || _y < limitName) { oldValue = value; //String text = getName() + ": "; - String s = (String)JOptionPane.showInputDialog(frame, "Block name", - "setting value", JOptionPane.PLAIN_MESSAGE, IconManager.imgic101, - null, - getValue()); + String s = (String) JOptionPane.showInputDialog(frame, "Block name", + "setting value", JOptionPane.PLAIN_MESSAGE, IconManager.imgic101, + null, + getValue()); if ((s != null) && (s.length() > 0) && (!s.equals(oldValue))) { //boolean b; if (!TAttribute.isAValidId(s, false, false)) { JOptionPane.showMessageDialog(frame, - "Could not change the name of the Block: the new name is not a valid name", - "Error", - JOptionPane.INFORMATION_MESSAGE); + "Could not change the name of the Block: the new name is not a valid name", + "Error", + JOptionPane.INFORMATION_MESSAGE); return false; } if (!tdp.isAvatarBlockNameUnique(s)) { JOptionPane.showMessageDialog(frame, - "Could not change the name of the Block: the new name is already in use", - "Error", - JOptionPane.INFORMATION_MESSAGE); + "Could not change the name of the Block: the new name is already in use", + "Error", + JOptionPane.INFORMATION_MESSAGE); return false; } @@ -606,9 +602,9 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S return true; } else { JOptionPane.showMessageDialog(frame, - "Could not change the name of the Block: frame error", - "Error", - JOptionPane.INFORMATION_MESSAGE); + "Could not change the name of the Block: frame error", + "Error", + JOptionPane.INFORMATION_MESSAGE); setValue(oldValue); } } @@ -616,34 +612,34 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S } // And so -> attributes! - + int tab = 0; - //TraceManager.addDev("limitAttr=" + limitAttr + " method=" + limitMethod + " limitSignal=" + limitSignal + " y=" + _y + " height=" + height); + //TraceManager.addDev("limitAttr=" + limitAttr + " method=" + limitMethod + " limitSignal=" + limitSignal + " y=" + _y + " height=" + height); - if (limitMethod == -1) { - limitMethod = limitAttr; - } + if (limitMethod == -1) { + limitMethod = limitAttr; + } - if (limitSignal == -1) { - limitSignal = limitMethod; - } - - if (limitAttr == -1) { - tab = 0; - } else { - if (_y < limitAttr) { - tab = 0; - } else if (_y < limitMethod){ - tab = 1; - } else if (_y < limitSignal) { - tab = 2; - } else if (_y > limitSignal && hasGlobalCode()) { - tab = 3; - } else if (_y > limitSignal && !hasGlobalCode()) { - tab = 2; - } - } + if (limitSignal == -1) { + limitSignal = limitMethod; + } + + if (limitAttr == -1) { + tab = 0; + } else { + if (_y < limitAttr) { + tab = 0; + } else if (_y < limitMethod) { + tab = 1; + } else if (_y < limitSignal) { + tab = 2; + } else if (_y > limitSignal && hasGlobalCode()) { + tab = 3; + } else if (_y > limitSignal && !hasGlobalCode()) { + tab = 2; + } + } /*if (limitAttr != -1) { if (_y > limitAttr) { @@ -669,7 +665,7 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S String mainCode = null; TDiagramPanel ttdp = getTDiagramPanel(); if (ttdp instanceof AvatarBDPanel) { - mainCode = ((AvatarBDPanel)(ttdp)).getMainCode(); + mainCode = ((AvatarBDPanel) (ttdp)).getMainCode(); } JDialogAvatarBlock jdab = new JDialogAvatarBlock(this.myAttributes, this.myMethods, this.mySignals, null, frame, "Setting attributes of " + value, "Attribute", tab, globalCode, true, mainCode); setJDialogOptions(jdab); @@ -685,11 +681,11 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S globalCode = jdab.getGlobalCode(); String tmp = jdab.getMainCode(); if (tmp != null) { - ((AvatarBDPanel)(ttdp)).setMainCode(tmp); + ((AvatarBDPanel) (ttdp)).setMainCode(tmp); } } - ((AvatarBDPanel)tdp).updateAllSignalsOnConnectors(); + ((AvatarBDPanel) tdp).updateAllSignalsOnConnectors(); rescaled = true; return true; } @@ -702,7 +698,7 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S _jdab.addType(TAttribute.getStringAvatarType(TAttribute.INTEGER), true); _jdab.addType(TAttribute.getStringType(TAttribute.TIMER), false); - for(String s: tdp.getAllDataTypes()) { + for (String s : tdp.getAllDataTypes()) { _jdab.addType(s, false); } @@ -725,11 +721,11 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S public boolean addSwallowedTGComponent(TGComponent tgc, int x, int y) { boolean swallowed = false; - for(int i=0; i<nbInternalTGComponent; i++) { + for (int i = 0; i < nbInternalTGComponent; i++) { if (tgcomponent[i] instanceof SwallowTGComponent) { if (tgcomponent[i].isOnMe(x, y) != null) { swallowed = true; - ((SwallowTGComponent)tgcomponent[i]).addSwallowedTGComponent(tgc, x, y); + ((SwallowTGComponent) tgcomponent[i]).addSwallowedTGComponent(tgc, x, y); break; } } @@ -758,10 +754,8 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S tgc.resizeWithFather(); //tgc.setCdRectangle(0, width - tgc.getWidth(), 0, height - tgc.getHeight()); //tgc.setCd(x, y); - } - - else if (tgc instanceof AvatarBDLibraryFunction) - tgc.resizeWithFather (); + } else if (tgc instanceof AvatarBDLibraryFunction) + tgc.resizeWithFather(); // else unknown*/ @@ -777,19 +771,19 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S public boolean removeMyInternalComponent(TGComponent tgc, boolean actionOnRemove) { //TGComponent tgc; - for(int i=0; i<nbInternalTGComponent; i++) { + for (int i = 0; i < nbInternalTGComponent; i++) { if (tgcomponent[i] == tgc) { nbInternalTGComponent = nbInternalTGComponent - 1; if (nbInternalTGComponent == 0) { tgcomponent = null; } else { - TGComponent [] tgcomponentbis = new TGComponent[nbInternalTGComponent]; - for(int j=0; j<nbInternalTGComponent; j++) { - if (j<i) { + TGComponent[] tgcomponentbis = new TGComponent[nbInternalTGComponent]; + for (int j = 0; j < nbInternalTGComponent; j++) { + if (j < i) { tgcomponentbis[j] = tgcomponent[j]; } - if (j>=i) { - tgcomponentbis[j] = tgcomponent[j+1]; + if (j >= i) { + tgcomponentbis[j] = tgcomponent[j + 1]; } } tgcomponent = tgcomponentbis; @@ -800,7 +794,7 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S } return true; } else { - if (((AvatarBDBlock)tgcomponent[i]).removeMyInternalComponent(tgc, false)) { + if (((AvatarBDBlock) tgcomponent[i]).removeMyInternalComponent(tgc, false)) { return true; } } @@ -811,7 +805,7 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S protected String translateExtraParam() { StringBuffer sb = new StringBuffer("<extraparam>\n"); sb.append("<CryptoBlock value=\"" + isCryptoBlock + "\" />\n"); - for (TAttribute a: this.myAttributes) { + for (TAttribute a : this.myAttributes) { sb.append("<Attribute access=\""); sb.append(a.getAccess()); sb.append("\" id=\""); @@ -824,20 +818,20 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S sb.append(a.getTypeOther()); sb.append("\" />\n"); } - for (AvatarMethod am: this.myMethods) { + for (AvatarMethod am : this.myMethods) { sb.append("<Method value=\""); sb.append(am.toSaveString()); sb.append("\" />\n"); } - for (AvatarSignal as: this.mySignals) { + for (AvatarSignal as : this.mySignals) { sb.append("<Signal value=\""); sb.append(as.toString()); - sb.append("\" attached=\""); - sb.append(as.attachedToARelation); + sb.append("\" attached=\""); + sb.append(as.attachedToARelation); sb.append("\" />\n"); } if (hasGlobalCode()) { - for(int i=0; i<globalCode.length; i++) { + for (int i = 0; i < globalCode.length; i++) { sb.append("<globalCode value=\""); sb.append(GTURTLEModeling.transformString(globalCode[i])); sb.append("\" />\n"); @@ -848,7 +842,7 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S } @Override - public void loadExtraParam(NodeList nl, int decX, int decY, int decId) throws MalformedModelingException{ + public void loadExtraParam(NodeList nl, int decX, int decY, int decId) throws MalformedModelingException { String s; String tmpGlobalCode = ""; @@ -867,21 +861,21 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S boolean implementation = false; String crypt; String attached; - //boolean mustAddCryptoFunctions = false; + //boolean mustAddCryptoFunctions = false; //System.out.println("Loading attributes"); //System.out.println(nl.toString()); - //TraceManager.addDev("LEP Begin Block = " + this + " trace="); - //Thread.currentThread().dumpStack(); + //TraceManager.addDev("LEP Begin Block = " + this + " trace="); + //Thread.currentThread().dumpStack(); - for(int i=0; i<nl.getLength(); i++) { + for (int i = 0; i < nl.getLength(); i++) { n1 = nl.item(i); //System.out.println(n1); if (n1.getNodeType() == Node.ELEMENT_NODE) { nli = n1.getChildNodes(); - for(int j=0; j<nli.getLength(); j++) { + for (int j = 0; j < nli.getLength(); j++) { n2 = nli.item(j); //System.out.println(n2); if (n2.getNodeType() == Node.ELEMENT_NODE) { @@ -914,7 +908,7 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S } TAttribute ta = new TAttribute(access, id, valueAtt, type, typeOther); ta.isAvatar = true; - this.myAttributes.add (ta); + this.myAttributes.add(ta); } } if (elt.getTagName().equals("Method")) { @@ -931,25 +925,25 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S implementation = false; } - //TraceManager.addDev("Method = " + method + ". Starting with aencrypt?"); + //TraceManager.addDev("Method = " + method + ". Starting with aencrypt?"); if (method.startsWith("bool verifyMAC(")) { isCryptoBlock = true; - //TraceManager.addDev("Add crypto methods"); - //addCryptoElements(); + //TraceManager.addDev("Add crypto methods"); + //addCryptoElements(); } am = AvatarMethod.isAValidMethod(method); if (am != null) { //TraceManager.addDev("Setting to " + implementation + " the implementation of " + am); am.setImplementationProvided(implementation); - //addMethodIfApplicable(am); + //addMethodIfApplicable(am); this.myMethods.add(am); } } if (elt.getTagName().equals("Signal")) { //System.out.println("Analyzing attribute"); signal = elt.getAttribute("value"); - attached = elt.getAttribute("attached"); + attached = elt.getAttribute("attached"); if (signal.equals("null")) { signal = ""; @@ -957,9 +951,9 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S as = AvatarSignal.isAValidSignal(signal); if (as != null) { this.mySignals.add(as); - if (attached != null) { - as.attachedToARelation = (attached.compareTo("true") == 0); - } + if (attached != null) { + as.attachedToARelation = (attached.compareTo("true") == 0); + } } else { TraceManager.addDev("Invalid signal:" + signal); } @@ -980,20 +974,20 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S } catch (Exception e) { throw new MalformedModelingException(); } - - if (isCryptoBlock()) { - addCryptoElements(); - } + + if (isCryptoBlock()) { + addCryptoElements(); + } if (tmpGlobalCode.trim().length() == 0) { globalCode = null; } else { globalCode = Conversion.wrapText(tmpGlobalCode); } - - //TraceManager.addDev("LEP End Block = " + this); - + + //TraceManager.addDev("LEP End Block = " + this); + } public String getBlockName() { @@ -1010,9 +1004,9 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S } String tmp; - for(int i=0; i<globalCode.length; i++) { + for (int i = 0; i < globalCode.length; i++) { tmp = globalCode[i].trim(); - if (tmp.length()>0) { + if (tmp.length() > 0) { if (!(tmp.equals("\n"))) { return true; } @@ -1027,20 +1021,18 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S return null; } String ret = ""; - for(int i=0; i<globalCode.length; i++) { + for (int i = 0; i < globalCode.length; i++) { ret += globalCode[i] + "\n"; } return ret; } - public void hasBeenResized() { - for(int i=0; i<nbInternalTGComponent; i++) { + for (int i = 0; i < nbInternalTGComponent; i++) { if (tgcomponent[i] instanceof AvatarBDBlock) { tgcomponent[i].resizeWithFather(); - } - else if (tgcomponent[i] instanceof AvatarBDLibraryFunction) { + } else if (tgcomponent[i] instanceof AvatarBDLibraryFunction) { tgcomponent[i].resizeWithFather(); } } @@ -1063,9 +1055,9 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S public LinkedList<AvatarBDBlock> getBlockList() { LinkedList<AvatarBDBlock> list = new LinkedList<AvatarBDBlock>(); - for(int i=0; i<nbInternalTGComponent; i++) { + for (int i = 0; i < nbInternalTGComponent; i++) { if (tgcomponent[i] instanceof AvatarBDBlock) { - list.add((AvatarBDBlock)(tgcomponent[i])); + list.add((AvatarBDBlock) (tgcomponent[i])); } } return list; @@ -1073,21 +1065,20 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S public LinkedList<AvatarBDBlock> getFullBlockList() { LinkedList<AvatarBDBlock> list = new LinkedList<AvatarBDBlock>(); - for(int i=0; i<nbInternalTGComponent; i++) { + for (int i = 0; i < nbInternalTGComponent; i++) { if (tgcomponent[i] instanceof AvatarBDBlock) { - list.add((AvatarBDBlock)(tgcomponent[i])); - list.addAll(((AvatarBDBlock)tgcomponent[i]).getFullBlockList()); + list.add((AvatarBDBlock) (tgcomponent[i])); + list.addAll(((AvatarBDBlock) tgcomponent[i]).getFullBlockList()); } } return list; } - public LinkedList<AvatarBDLibraryFunction> getFullLibraryFunctionList () { - LinkedList<AvatarBDLibraryFunction> list = new LinkedList<AvatarBDLibraryFunction> (); - for (int i=0; i<nbInternalTGComponent; i++) - { + public LinkedList<AvatarBDLibraryFunction> getFullLibraryFunctionList() { + LinkedList<AvatarBDLibraryFunction> list = new LinkedList<AvatarBDLibraryFunction>(); + for (int i = 0; i < nbInternalTGComponent; i++) { if (this.tgcomponent[i] instanceof AvatarBDLibraryFunction) - list.add ((AvatarBDLibraryFunction) this.tgcomponent[i]); + list.add((AvatarBDLibraryFunction) this.tgcomponent[i]); else if (this.tgcomponent[i] instanceof AvatarBDBlock) list.addAll(((AvatarBDBlock) this.tgcomponent[i]).getFullLibraryFunctionList()); } @@ -1096,15 +1087,15 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S } public boolean hasInternalBlockWithName(String name) { - LinkedList<AvatarBDBlock> list = getFullBlockList(); - for(AvatarBDBlock b: list) { - if (b.getValue().compareTo(name) ==0) { + LinkedList<AvatarBDBlock> list = getFullBlockList(); + for (AvatarBDBlock b : list) { + if (b.getValue().compareTo(name) == 0) { return true; } } - LinkedList<AvatarBDLibraryFunction> llist = getFullLibraryFunctionList (); - for(AvatarBDLibraryFunction b: llist) { - if (b.getFunctionName().compareTo(name) ==0) { + LinkedList<AvatarBDLibraryFunction> llist = getFullLibraryFunctionList(); + for (AvatarBDLibraryFunction b : llist) { + if (b.getFunctionName().compareTo(name) == 0) { return true; } } @@ -1113,7 +1104,6 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S } - public int getDefaultConnector() { return TGComponentManager.AVATARBD_PORT_CONNECTOR; } @@ -1123,13 +1113,14 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S } public TAttribute getAttributeByName(String _name) { - for (TAttribute a: this.myAttributes) + for (TAttribute a : this.myAttributes) if (a.getId().compareTo(_name) == 0) return a; return null; } - public void addAttribute(TAttribute ta){ - this.myAttributes.add(ta); + + public void addAttribute(TAttribute ta) { + this.myAttributes.add(ta); } public LinkedList<AvatarMethod> getMethodList() { @@ -1141,16 +1132,16 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S } public LinkedList<AvatarSignal> getOutSignalList() { - LinkedList<AvatarSignal> v = new LinkedList<AvatarSignal> (); - for(AvatarSignal s: this.mySignals) + LinkedList<AvatarSignal> v = new LinkedList<AvatarSignal>(); + for (AvatarSignal s : this.mySignals) if (s.getInOut() == AvatarSignal.OUT) v.add(s); return v; } public LinkedList<AvatarSignal> getInSignalList() { - LinkedList<AvatarSignal> v = new LinkedList<AvatarSignal> (); - for(AvatarSignal s: this.mySignals) + LinkedList<AvatarSignal> v = new LinkedList<AvatarSignal>(); + for (AvatarSignal s : this.mySignals) if (s.getInOut() == AvatarSignal.IN) v.add(s); return v; @@ -1161,7 +1152,7 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S return this.myMethods; } - LinkedList<AvatarMethod> v = new LinkedList<AvatarMethod> (); + LinkedList<AvatarMethod> v = new LinkedList<AvatarMethod>(); v.addAll(this.myMethods); v.addAll(((AvatarBDBlock) getFather()).getAllMethodList()); return v; @@ -1172,38 +1163,38 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S return this.mySignals; } - LinkedList<AvatarSignal> v = new LinkedList<AvatarSignal> (); + LinkedList<AvatarSignal> v = new LinkedList<AvatarSignal>(); v.addAll(this.mySignals); - v.addAll(((AvatarBDBlock)getFather()).getAllSignalList()); + v.addAll(((AvatarBDBlock) getFather()).getAllSignalList()); return v; } public LinkedList<String> getAllTimerList() { - LinkedList<String> v = new LinkedList<String> (); + LinkedList<String> v = new LinkedList<String>(); - for (TAttribute a: this.myAttributes) + for (TAttribute a : this.myAttributes) if (a.getType() == TAttribute.TIMER) v.add(a.getId()); return v; } public AvatarSignal getAvatarSignalFromName(String _name) { - for (AvatarSignal as: this.mySignals) + for (AvatarSignal as : this.mySignals) if (as.getId().compareTo(_name) == 0) return as; return null; } public LinkedList<AvatarSignal> getListOfAvailableSignals() { - return ((AvatarBDPanel)(tdp)).getListOfAvailableSignals(this); + return ((AvatarBDPanel) (tdp)).getListOfAvailableSignals(this); } public LinkedList<AvatarSignal> getListOfAvailableOutSignals() { - return ((AvatarBDPanel)(tdp)).getListOfAvailableOutSignals(this); + return ((AvatarBDPanel) (tdp)).getListOfAvailableOutSignals(this); } public LinkedList<AvatarSignal> getListOfAvailableInSignals() { - return ((AvatarBDPanel)(tdp)).getListOfAvailableInSignals(this); + return ((AvatarBDPanel) (tdp)).getListOfAvailableInSignals(this); } @@ -1215,28 +1206,28 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S } _id = _id.trim(); //TraceManager.addDev("Searching for signal with id=" + _id); - for (AvatarSignal as: this.mySignals){ - // System.out.println(as.getId() + " " + for (AvatarSignal as : this.mySignals) { + // System.out.println(as.getId() + " " if (as.getId().compareTo(_id) == 0) return as; - } + } //TraceManager.addDev("Not found"); return null; } public AvatarSignal getAvatarSignalFromFullName(String _id) { - if(_id.startsWith("in ")) { + if (_id.startsWith("in ")) { return getSignalNameBySignalDef(_id.substring(3, _id.length()).trim()); } - if(_id.startsWith("out ")) { + if (_id.startsWith("out ")) { return getSignalNameBySignalDef(_id.substring(4, _id.length()).trim()); } return null; } public AvatarSMDPanel getAvatarSMDPanel() { - return ((AvatarDesignPanel)(tdp.tp)).getAvatarSMDPanel(getBlockName()); + return ((AvatarDesignPanel) (tdp.tp)).getAvatarSMDPanel(getBlockName()); } public boolean isCryptoBlock() { @@ -1246,42 +1237,42 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S public void removeCryptoElements() { isCryptoBlock = false; - for (String method: AvatarMethod.cryptoMethods) - this.removeMethodIfApplicable (method); + for (String method : AvatarMethod.cryptoMethods) + this.removeMethodIfApplicable(method); } public void addCryptoElements() { isCryptoBlock = true; - for (String method: AvatarMethod.cryptoMethods) - this.addMethodIfApplicable (method); + for (String method : AvatarMethod.cryptoMethods) + this.addMethodIfApplicable(method); } private void removeMethodIfApplicable(String methodString) { - Iterator<AvatarMethod> iterator = this.myMethods.iterator (); - while (iterator.hasNext ()) { - AvatarMethod am = iterator.next (); + Iterator<AvatarMethod> iterator = this.myMethods.iterator(); + while (iterator.hasNext()) { + AvatarMethod am = iterator.next(); // TODO: replace by a more OO way... - if (am.toString ().equals (methodString)) { - iterator.remove (); + if (am.toString().equals(methodString)) { + iterator.remove(); break; } } } - public void addMethodIfApplicable (String methodString) { - for (AvatarMethod am: this.myMethods) + public void addMethodIfApplicable(String methodString) { + for (AvatarMethod am : this.myMethods) // TODO: replace by a more OO way... - if (am.toString ().equals (methodString)) - return; + if (am.toString().equals(methodString)) + return; - AvatarMethod am = AvatarMethod.isAValidMethod (methodString); + AvatarMethod am = AvatarMethod.isAValidMethod(methodString); if (am != null) - this.myMethods.add (am); + this.myMethods.add(am); } public boolean hasDefinitions() { - return ((this.myAttributes.size() + this.myMethods.size() + this.mySignals.size() + nbInternalTGComponent)>0); + return ((this.myAttributes.size() + this.myMethods.size() + this.mySignals.size() + nbInternalTGComponent) > 0); } // Main Tree @@ -1317,7 +1308,7 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S public int getIndexOfChild(Object child) { if (child instanceof AvatarBDBlock) { - for(int i=0; i<nbInternalTGComponent; i++) { + for (int i = 0; i < nbInternalTGComponent; i++) { if (tgcomponent[i] == child) { return i; } @@ -1344,17 +1335,17 @@ public class AvatarBDBlock extends TGCScalableWithInternalComponent implements S } public void resetConfidentialityOfAttributes() { - for (TAttribute a: this.myAttributes) + for (TAttribute a : this.myAttributes) a.setConfidentialityVerification(TAttribute.NOT_VERIFIED); } @Override - public String getOwnerName () { - return this.getBlockName (); + public String getOwnerName() { + return this.getBlockName(); } - + public String toString() { - return "Block: " + getValue(); + return "Block: " + getValue(); } - + } diff --git a/src/main/java/ui/ftd/FTDConstraint.java b/src/main/java/ui/ftd/FTDConstraint.java index a66f860980..adaf5d2510 100644 --- a/src/main/java/ui/ftd/FTDConstraint.java +++ b/src/main/java/ui/ftd/FTDConstraint.java @@ -1,26 +1,26 @@ /* Copyright or (C) or Copr. GET / ENST, Telecom-Paris, Ludovic Apvrille - * + * * ludovic.apvrille AT enst.fr - * + * * This software is a computer program whose purpose is to allow the * edition of TURTLE analysis, design and deployment diagrams, to * allow the generation of RT-LOTOS or Java code from this diagram, * and at last to allow the analysis of formal validation traces * obtained from external tools, e.g. RTL from LAAS-CNRS and CADP * from INRIA Rhone-Alpes. - * + * * This software is governed by the CeCILL license under French law and * abiding by the rules of distribution of free software. You can use, * modify and/ or redistribute the software under the terms of the CeCILL * license as circulated by CEA, CNRS and INRIA at the following URL * "http://www.cecill.info". - * + * * As a counterpart to the access to the source code and rights to copy, * modify and redistribute granted by the license, users are provided only * with a limited warranty and the software's author, the holder of the * economic rights, and the successive licensors have only limited * liability. - * + * * In this respect, the user's attention is drawn to the risks associated * with loading, using, modifying and/or developing or reproducing the * software by the user in light of its specific status of free software, @@ -31,14 +31,12 @@ * requirements in conditions enabling the security of their systems and/or * data to be ensured and, more generally, to use and operate it in the * same conditions as regards security. - * + * * The fact that you are presently reading this means that you have had * knowledge of the CeCILL license and that you accept its terms. */ - - package ui.ftd; import myutil.GraphicLib; @@ -51,19 +49,25 @@ import ui.window.JDialogConstraintText; import javax.swing.*; import java.awt.*; +import myutil.*;; /** - * Class FTDConstraint - * Constraint of SysML Parametric diagrams, adapted to fault trees - * Creation: 14/12/2017 - * @version 1.0 14/12/2017 - * @author Ludovic APVRILLE + * Class FTDConstraint + * Constraint of SysML Parametric diagrams, adapted to fault trees + * Creation: 14/12/2017 + * + * @author Ludovic APVRILLE + * @version 1.0 14/12/2017 */ -public class FTDConstraint extends TGCScalableWithInternalComponent implements SwallowedTGComponent, ConstraintListInterface { +public class FTDConstraint extends TGCScalableWithInternalComponent implements SwallowedTGComponent, ConstraintListInterface { private int textY1 = 5; //private int textY2 = 30; - public static final String[] STEREOTYPES = {"<<OR>>", "<<XOR>>", "<<AND>>", "<<NOT>>", "<<SEQUENCE>>", "<<AFTER>>", "<<BEFORE>>", "<<VOTE>>"}; + public static final String[] STEREOTYPES = {"<<OR>>", "<<XOR>>", "<<AND>>", "<<NOT>>", "<<SEQUENCE>>", "<<AFTER>>", + "<<BEFORE>>", "<<VOTE>>"}; + public static final Image[] ICONS = {IconManager.img1400, IconManager.img1400, IconManager.img1400, + IconManager.img1408, IconManager.img1402, IconManager.img1404 + , IconManager.img1406, IconManager.img1400}; protected String oldValue = ""; @@ -71,17 +75,19 @@ public class FTDConstraint extends TGCScalableWithInternalComponent implements private static int minFontSize = 4; private int currentFontSize = -1; private boolean displayText = true; - // private int textX = 1; + // private int textX = 1; private static int arc = 7; + private int index; + private String equation; - public FTDConstraint(int _x, int _y, int _minX, int _maxX, int _minY, int _maxY, boolean _pos, TGComponent _father, TDiagramPanel _tdp) { + public FTDConstraint(int _x, int _y, int _minX, int _maxX, int _minY, int _maxY, boolean _pos, TGComponent _father, TDiagramPanel _tdp) { super(_x, _y, _minX, _maxX, _minY, _maxY, _pos, _father, _tdp); - width = (int)(150* tdp.getZoom()); - height = (int)(50 * tdp.getZoom()); + width = (int) (150 * tdp.getZoom()); + height = (int) (50 * tdp.getZoom()); minWidth = 100; nbConnectingPoint = 12; @@ -106,6 +112,7 @@ public class FTDConstraint extends TGCScalableWithInternalComponent implements removable = true; value = "<<OR>>"; + index = 0; equation = ""; currentFontSize = -1; @@ -117,7 +124,7 @@ public class FTDConstraint extends TGCScalableWithInternalComponent implements public void internalDrawing(Graphics g) { Font f = g.getFont(); - // Font fold = f; + // Font fold = f; if (currentFontSize == -1) { currentFontSize = f.getSize(); @@ -127,9 +134,9 @@ public class FTDConstraint extends TGCScalableWithInternalComponent implements rescaled = false; - float scale = (float)(f.getSize()*tdp.getZoom()); + float scale = (float) (f.getSize() * tdp.getZoom()); scale = Math.min(maxFontSize, scale); - currentFontSize = (int)scale; + currentFontSize = (int) scale; displayText = !(scale < minFontSize); } @@ -145,25 +152,33 @@ public class FTDConstraint extends TGCScalableWithInternalComponent implements g.setColor(c); + if (height > (IconManager.iconSize * 2 + 10)) { + g.drawImage(ICONS[index], this.x + this.width - IconManager.iconSize * 2 - 6, this.y + 10, null); + } + Font f0 = g.getFont(); if (displayText) { f = f.deriveFont(currentFontSize); g.setFont(f.deriveFont(Font.BOLD)); - int w = g.getFontMetrics().stringWidth(value); - g.drawString(value, x + (width - w)/2, y + currentFontSize + (int)(textY1*tdp.getZoom())); - g.setFont(f0.deriveFont(f0.getSize()-2).deriveFont(Font.ITALIC)); - w = g.getFontMetrics().stringWidth(equation); + int w = g.getFontMetrics().stringWidth(value); + g.drawString(value, x + (width - w) / 2, y + currentFontSize + (int) (textY1 * tdp.getZoom())); + + + g.setFont(f0.deriveFont(f0.getSize() - 2).deriveFont(Font.ITALIC)); + w = g.getFontMetrics().stringWidth(equation); if (w >= width) { - w = g.getFontMetrics().stringWidth("..."); - g.drawString("...", x + (width - w)/2, y + (2*currentFontSize) + (int)(textY1*tdp.getZoom())); + w = g.getFontMetrics().stringWidth("..."); + g.drawString("...", x + (width - w) / 2, y + (2 * currentFontSize) + (int) (textY1 * tdp.getZoom())); } else { - g.drawString(equation, x + (width - w)/2, y + (2*currentFontSize) + (int)(textY1*tdp.getZoom())); + g.drawString(equation, x + (width - w) / 2, y + (2 * currentFontSize) + (int) (textY1 * tdp.getZoom())); } g.setFont(f0); } } + + /* public void setValue(String val, Graphics g) { oldValue = value; int w = g.getFontMetrics().stringWidth(value); @@ -178,16 +193,14 @@ public class FTDConstraint extends TGCScalableWithInternalComponent implements }*/ - - public boolean editOndoubleClick(JFrame frame) { // String tmp; // boolean error = false; JDialogConstraintText dialog = new JDialogConstraintText(frame, "Setting constraint attributes", this, equation, "Equation"); - // dialog.setSize(450, 350); + // dialog.setSize(450, 350); GraphicLib.centerOnParent(dialog, 450, 350); - dialog.setVisible( true ); // blocked until dialog has been closed + dialog.setVisible(true); // blocked until dialog has been closed if (!dialog.isRegularClose()) { return false; @@ -199,6 +212,7 @@ public class FTDConstraint extends TGCScalableWithInternalComponent implements if (dialog.getStereotype().length() > 0) { value = dialog.getStereotype(); + index = dialog.getSelectedIndex(); } equation = dialog.getText(); @@ -233,62 +247,67 @@ public class FTDConstraint extends TGCScalableWithInternalComponent implements } public boolean isOR() { - return (value.compareTo(STEREOTYPES[0]) == 0); + return (value.compareTo(STEREOTYPES[0]) == 0); } public boolean isXOR() { - return (value.compareTo(STEREOTYPES[1]) == 0); + return (value.compareTo(STEREOTYPES[1]) == 0); } public boolean isAND() { - return (value.compareTo(STEREOTYPES[2]) == 0); + return (value.compareTo(STEREOTYPES[2]) == 0); } public boolean isSequence() { - return (value.compareTo(STEREOTYPES[3]) == 0); + return (value.compareTo(STEREOTYPES[3]) == 0); } public boolean isBefore() { - return (value.compareTo(STEREOTYPES[4]) == 0); + return (value.compareTo(STEREOTYPES[4]) == 0); } public boolean isAfter() { - return (value.compareTo(STEREOTYPES[5]) == 0); + return (value.compareTo(STEREOTYPES[5]) == 0); } protected String translateExtraParam() { StringBuffer sb = new StringBuffer("<extraparam>\n"); sb.append("<info equation=\"" + GTURTLEModeling.transformString(getEquation())); + sb.append("\" index=\"" + GTURTLEModeling.transformString("" + index)); sb.append("\" />\n"); sb.append("</extraparam>\n"); return new String(sb); } @Override - public void loadExtraParam(NodeList nl, int decX, int decY, int decId) throws MalformedModelingException{ + public void loadExtraParam(NodeList nl, int decX, int decY, int decId) throws MalformedModelingException { //System.out.println("*** load extra synchro ***"); try { NodeList nli; Node n1, n2; Element elt; + String tmp; // int t1id; // String sdescription = null; // String prio; // String isRoot = null; - for(int i=0; i<nl.getLength(); i++) { + for (int i = 0; i < nl.getLength(); i++) { n1 = nl.item(i); //System.out.println(n1); if (n1.getNodeType() == Node.ELEMENT_NODE) { nli = n1.getChildNodes(); - for(int j=0; j<nli.getLength(); j++) { + for (int j = 0; j < nli.getLength(); j++) { n2 = nli.item(j); //System.out.println(n2); if (n2.getNodeType() == Node.ELEMENT_NODE) { elt = (Element) n2; if (elt.getTagName().equals("info")) { equation = elt.getAttribute("equation"); + tmp = elt.getAttribute("index"); + //TraceManager.addDev("index=" + tmp); + index = Integer.decode(tmp).intValue(); } } } diff --git a/src/main/java/ui/util/IconManager.java b/src/main/java/ui/util/IconManager.java index 04048501f6..20e7c6cd44 100755 --- a/src/main/java/ui/util/IconManager.java +++ b/src/main/java/ui/util/IconManager.java @@ -119,6 +119,10 @@ public class IconManager { public static ImageIcon imgic1070, imgic1072, imgic1074, imgic1076, imgic1078; public static ImageIcon imgic1080, imgic1082, imgic1084; + // Fault Tree Diagrams + public static ImageIcon imgic1400, imgic1402, imgic1404, imgic1406, imgic1408; + public static Image img1400, img1402, img1404, img1406, img1408; + // TMLDD public static ImageIcon imgic1100, imgic1102, imgic1104, imgic1106, imgic1108; public static ImageIcon imgic1110, imgic1112, imgic1114, imgic1116, imgic1118; @@ -487,6 +491,13 @@ public class IconManager { private static String icon1082 = "atdcountermeasure.gif"; private static String icon1084 = "atdcountermeasureconnector.gif"; + // Fault trees + private static String icon1400 = "AndFT.png"; + private static String icon1402 = "SequenceFT.png"; + private static String icon1404 = "AfterFT.png"; + private static String icon1406 = "BeforeFT.png"; + private static String icon1408 = "NotFT.png"; + // DIPLODOCUS architecture private static String icon1100 = "tmlcpunode.gif"; private static String icon1102 = "tmlbusnode.gif"; @@ -624,9 +635,12 @@ public class IconManager { //Attacker Scenarios private static String icon7008 = "attacker.gif"; - private static String icon7009 = "uppaal.gif"; + // + + + public IconManager() { @@ -921,6 +935,26 @@ public class IconManager { imgic1082 = getIcon(icon1082); imgic1084 = getIcon(icon1084); + imgic1400 = getIcon(icon1400); + if (imgic1400 != null) { + img1400 = imgic1400.getImage(); + } + imgic1402 = getIcon(icon1402); + if (imgic1402 != null) { + img1402 = imgic1402.getImage(); + } + imgic1404 = getIcon(icon1404); + if (imgic1404 != null) { + img1404 = imgic1404.getImage(); + } + imgic1408 = getIcon(icon1408); + if (imgic1408 != null) { + img1408 = imgic1408.getImage(); + } + imgic1406 = getIcon(icon1406); + if (imgic1406 != null) { + img1406 = imgic1406.getImage(); + } imgic1100 = getIcon(icon1100); imgic1102 = getIcon(icon1102); imgic1104 = getIcon(icon1104); diff --git a/src/main/java/ui/window/JDialogConstraintText.java b/src/main/java/ui/window/JDialogConstraintText.java index d35d73e2d6..52def0b2f7 100755 --- a/src/main/java/ui/window/JDialogConstraintText.java +++ b/src/main/java/ui/window/JDialogConstraintText.java @@ -171,6 +171,10 @@ public class JDialogConstraintText extends JDialogBase implements ActionListener return (String)(stereotype.getSelectedItem()); } + public int getSelectedIndex() { + return stereotype.getSelectedIndex(); + } + public String getText() { return textEdition.getText(); diff --git a/src/main/resources/ui/util/AfterFT.png b/src/main/resources/ui/util/AfterFT.png new file mode 100644 index 0000000000000000000000000000000000000000..3f0d3d554143a170c3507679ee21bcbc559343ed GIT binary patch literal 4275 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/ui/util/AndFT.png b/src/main/resources/ui/util/AndFT.png new file mode 100644 index 0000000000000000000000000000000000000000..7788cb863fca328ffebd3f69551893a2037b3d0f GIT binary patch literal 3860 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 SFBljY7(8A5T-G@yGywoF19NWx literal 0 HcmV?d00001 diff --git a/src/main/resources/ui/util/BeforeFT.png b/src/main/resources/ui/util/BeforeFT.png new file mode 100644 index 0000000000000000000000000000000000000000..5cec1eaac6dbf90e551169d96b148030e201aa53 GIT binary patch literal 4299 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 L>gTe~DWM4f6bw$3 literal 0 HcmV?d00001 diff --git a/src/main/resources/ui/util/NotFT.png b/src/main/resources/ui/util/NotFT.png new file mode 100644 index 0000000000000000000000000000000000000000..32468a26f41e805f964d21ab84e6ba5e42c2f94f GIT binary patch literal 4239 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 Cj6Bx> literal 0 HcmV?d00001 diff --git a/src/main/resources/ui/util/SequenceFT.png b/src/main/resources/ui/util/SequenceFT.png new file mode 100644 index 0000000000000000000000000000000000000000..45f9d4beed5d4d7275870ff47b109debf9fd590f GIT binary patch literal 4126 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 literal 0 HcmV?d00001 -- GitLab