001/* The node controller for relations (and vertices) 002 003 Copyright (c) 1998-2016 The Regents of the University of California. 004 All rights reserved. 005 Permission is hereby granted, without written agreement and without 006 license or royalty fees, to use, copy, modify, and distribute this 007 software and its documentation for any purpose, provided that the above 008 copyright notice and the following two paragraphs appear in all copies 009 of this software. 010 011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 015 SUCH DAMAGE. 016 017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 022 ENHANCEMENTS, OR MODIFICATIONS. 023 024 PT_COPYRIGHT_VERSION_2 025 COPYRIGHTENDKEY 026 027 */ 028package ptolemy.vergil.kernel; 029 030import java.awt.Color; 031import java.awt.Font; 032import java.awt.geom.Line2D; 033import java.util.List; 034 035import javax.swing.SwingConstants; 036 037import diva.canvas.CompositeFigure; 038import diva.canvas.Figure; 039import diva.canvas.toolbox.BasicFigure; 040import diva.canvas.toolbox.LabelFigure; 041import diva.canvas.toolbox.SVGUtilities; 042import diva.graph.GraphController; 043import diva.graph.NodeRenderer; 044import diva.util.java2d.Polygon2D; 045import ptolemy.actor.IORelation; 046import ptolemy.actor.gui.ColorAttribute; 047import ptolemy.actor.gui.Configuration; 048import ptolemy.actor.gui.PtolemyPreferences; 049import ptolemy.data.DoubleToken; 050import ptolemy.data.Token; 051import ptolemy.kernel.Relation; 052import ptolemy.kernel.util.IllegalActionException; 053import ptolemy.kernel.util.InternalErrorException; 054import ptolemy.kernel.util.StringAttribute; 055import ptolemy.moml.Vertex; 056import ptolemy.vergil.actor.ActorGraphModel; 057import ptolemy.vergil.basic.GetDocumentationAction; 058import ptolemy.vergil.basic.ParameterizedNodeController; 059import ptolemy.vergil.toolbox.MenuActionFactory; 060 061/////////////////////////////////////////////////////////////////// 062//// RelationController 063 064/** 065 This class provides interaction with nodes that represent Ptolemy II 066 relations. It provides a double click binding to edit the parameters 067 of the relation, and a context menu containing a command to edit parameters 068 ("Configure"), and a command to get documentation. 069 070 @author Steve Neuendorffer and Edward A. Lee 071 @version $Id$ 072 @since Ptolemy II 2.0 073 @Pt.ProposedRating Red (eal) 074 @Pt.AcceptedRating Red (johnr) 075 */ 076public class RelationController extends ParameterizedNodeController { 077 /** Create a relation controller associated with the specified graph 078 * controller. 079 * @param controller The associated graph controller. 080 */ 081 public RelationController(GraphController controller) { 082 super(controller); 083 setNodeRenderer(new RelationRenderer()); 084 _getDocumentationAction = new GetDocumentationAction(); 085 086 // Add to the context menu. 087 _menuFactory.addMenuItemFactory( 088 new MenuActionFactory(_getDocumentationAction)); 089 } 090 091 /////////////////////////////////////////////////////////////////// 092 //// public methods //// 093 094 /** Set the configuration. This is used in derived classes to 095 * to open files (such as documentation). The configuration is 096 * is important because it keeps track of which files are already 097 * open and ensures that there is only one editor operating on the 098 * file at any one time. 099 * @param configuration The configuration. 100 */ 101 @Override 102 public void setConfiguration(Configuration configuration) { 103 super.setConfiguration(configuration); 104 _getDocumentationAction.setConfiguration(configuration); 105 } 106 107 /////////////////////////////////////////////////////////////////// 108 //// private members //// 109 110 /** The "get documentation" action. */ 111 private GetDocumentationAction _getDocumentationAction; 112 113 /** The label font. */ 114 private static Font _relationLabelFont = new Font("SansSerif", Font.PLAIN, 115 10); 116 117 /////////////////////////////////////////////////////////////////// 118 //// inner classes //// 119 120 /** The renderer for relation node. This class creates a Figure that 121 * looks like a black diamond. 122 */ 123 public class RelationRenderer implements NodeRenderer { 124 /** 125 * Render a visual representation of the given node. 126 * @param node The node to render. 127 * @return The persistent object that is drawn on the screen. 128 */ 129 @Override 130 public Figure render(Object node) { 131 // Default values. 132 double height = 12.0; 133 double width = 12.0; 134 135 Relation relation = null; 136 137 if (node != null) { 138 Vertex vertex = (Vertex) node; 139 relation = (Relation) vertex.getContainer(); 140 141 // NOTE: The preferences mechanism may set this. 142 Token relationSize = PtolemyPreferences 143 .preferenceValue(relation, "_relationSize"); 144 145 if (relationSize instanceof DoubleToken) { 146 height = ((DoubleToken) relationSize).doubleValue(); 147 width = height; 148 } 149 } 150 151 Polygon2D.Double polygon = new Polygon2D.Double(); 152 polygon.moveTo(width / 2, 0); 153 polygon.lineTo(0, height / 2); 154 polygon.lineTo(-width / 2, 0); 155 polygon.lineTo(0, -height / 2); 156 polygon.closePath(); 157 158 Figure figure = new BasicFigure(polygon, Color.black); 159 160 if (node != null) { 161 ActorGraphModel model = (ActorGraphModel) getController() 162 .getGraphModel(); 163 figure.setToolTipText( 164 relation.getName(model.getPtolemyModel())); 165 // Old way to set the color. 166 try { 167 StringAttribute colorAttr = (StringAttribute) relation 168 .getAttribute("_color", StringAttribute.class); 169 170 if (colorAttr != null) { 171 String color = colorAttr.getExpression(); 172 ((BasicFigure) figure) 173 .setFillPaint(SVGUtilities.getColor(color)); 174 ((BasicFigure) figure) 175 .setStrokePaint(SVGUtilities.getColor(color)); 176 } 177 } catch (IllegalActionException e) { 178 // Ignore. 179 } 180 // New way to set the color 181 List<ColorAttribute> colorAttributes = relation 182 .attributeList(ColorAttribute.class); 183 if (colorAttributes != null && colorAttributes.size() > 0) { 184 // Use the last color added. 185 Color color = colorAttributes 186 .get(colorAttributes.size() - 1).asColor(); 187 ((BasicFigure) figure).setFillPaint(color); 188 ((BasicFigure) figure).setStrokePaint(color); 189 } 190 } 191 192 CompositeFigure result = new CompositeFigure(figure); 193 194 if (relation instanceof IORelation) { 195 IORelation ioRelation = (IORelation) relation; 196 try { 197 boolean isWidthFixed = ioRelation.isWidthFixed(); 198 if ((isWidthFixed || !ioRelation.needsWidthInference()) 199 && ioRelation.getWidth() > 1) { 200 // Restore width and height to the default to get a reasonable slash. 201 width = 12.0; 202 height = 12.0; 203 204 Line2D.Double line = new Line2D.Double(-width / 2, 205 height / 2, width / 2, -height / 2); 206 Figure lineFigure = new BasicFigure(line, Color.black); 207 result.add(lineFigure); 208 String labelString = (isWidthFixed ? "" : "(") 209 + ((IORelation) relation).getWidth() 210 + (isWidthFixed ? "" : ")"); 211 212 LabelFigure label = new LabelFigure(labelString, 213 _relationLabelFont, 0, 214 SwingConstants.SOUTH_WEST); 215 label.translateTo(width / 2 + 1.0, -height / 2 - 1.0); 216 result.add(label); 217 } 218 } catch (IllegalActionException ex) { 219 throw new InternalErrorException(ex); 220 // At this time IllegalActionExceptions are not allowed to happen. 221 // No width inference should happen at this time 222 } 223 } 224 225 return result; 226 } 227 } 228}