001/* An icon that displays specified text. 002 003 Copyright (c) 2003-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.icon; 029 030import java.awt.Color; 031import java.awt.Font; 032import java.util.Iterator; 033 034import javax.swing.SwingConstants; 035import javax.swing.SwingUtilities; 036 037import diva.canvas.Figure; 038import diva.canvas.toolbox.LabelFigure; 039import diva.gui.toolbox.FigureIcon; 040import ptolemy.gui.Top; 041import ptolemy.kernel.util.IllegalActionException; 042import ptolemy.kernel.util.NameDuplicationException; 043import ptolemy.kernel.util.NamedObj; 044import ptolemy.kernel.util.Workspace; 045 046/////////////////////////////////////////////////////////////////// 047//// TextIcon 048 049/** 050 An icon that displays specified text. 051 052 @author Edward A. Lee 053 @version $Id$ 054 @since Ptolemy II 4.0 055 @Pt.ProposedRating Yellow (eal) 056 @Pt.AcceptedRating Red (johnr) 057 */ 058public class TextIcon extends DynamicEditorIcon { 059 /** Create a new icon with the given name in the given container. 060 * @param container The container. 061 * @param name The name of the attribute. 062 * @exception IllegalActionException If the attribute is not of an 063 * acceptable class for the container. 064 * @exception NameDuplicationException If the name coincides with 065 * an attribute already in the container. 066 */ 067 public TextIcon(NamedObj container, String name) 068 throws IllegalActionException, NameDuplicationException { 069 super(container, name); 070 } 071 072 /////////////////////////////////////////////////////////////////// 073 //// public methods //// 074 075 /** Clone the object into the specified workspace. The new object is 076 * <i>not</i> added to the directory of that workspace (you must do this 077 * yourself if you want it there). 078 * The result is an object with no container. 079 * @param workspace The workspace for the cloned object. 080 * @exception CloneNotSupportedException Not thrown in this base class 081 * @return The new Attribute. 082 */ 083 @Override 084 public Object clone(Workspace workspace) throws CloneNotSupportedException { 085 TextIcon newObject = (TextIcon) super.clone(workspace); 086 return newObject; 087 } 088 089 /** Create a new default background figure, which is the text set 090 * by setText, if it has been called, or default text if not. 091 * This must be called in the Swing thread, or a concurrent 092 * modification exception could occur. 093 * @return A figure representing the specified shape. 094 */ 095 @Override 096 public Figure createBackgroundFigure() { 097 // NOTE: This gets called every time that the graph gets 098 // repainted, which seems excessive to me. This will happen 099 // every time there is a modification to the model that is 100 // carried out by a MoMLChangeRequest. 101 // The Diva graph package implements a model-view-controller 102 // architecture, which implies that this needs to return a new 103 // figure each time it is called. The reason is that the figure 104 // may go into a different view, and transformations may be applied 105 // to that figure in that view. However, this class needs to be 106 // able to update that figure when setShape() is called. Hence, 107 // this class keeps a list of all the figures it has created. 108 // The references to these figures, however, have to be weak 109 // references, so that this class does not interfere with garbage 110 // collection of the figure when the view is destroyed. 111 LabelFigure newFigure; 112 113 if (_text != null) { 114 newFigure = new LabelFigure(_text, _font); 115 } else { 116 newFigure = new LabelFigure(_DEFAULT_TEXT, _font); 117 } 118 119 newFigure.setAnchor(_anchor); 120 newFigure.setFillPaint(_textColor); 121 122 _addLiveFigure(newFigure); 123 return newFigure; 124 } 125 126 /** Create a new Swing icon. This returns an icon with the text 127 * "-A-", or if it has been called, the text specified by 128 * setIconText(). 129 * @see #setIconText(String) 130 * @return A new Swing Icon. 131 */ 132 @Override 133 public javax.swing.Icon createIcon() { 134 // In this class, we cache the rendered icon, since creating icons from 135 // figures is expensive. 136 if (_iconCache != null) { 137 return _iconCache; 138 } 139 140 // No cached object, so rerender the icon. 141 LabelFigure figure = new LabelFigure(_iconText, _font); 142 figure.setFillPaint(_textColor); 143 _iconCache = new FigureIcon(figure, 20, 15); 144 return _iconCache; 145 } 146 147 /** Specify origin of the text. The anchor should be one of the constants 148 * defined in {@link SwingConstants}. 149 * @param anchor The anchor of the text. 150 */ 151 public void setAnchor(final int anchor) { 152 _anchor = anchor; 153 154 Runnable doSet = new Runnable() { 155 @Override 156 public void run() { 157 synchronized (_figures) { 158 Iterator figures = _liveFigureIterator(); 159 160 while (figures.hasNext()) { 161 Object figure = figures.next(); 162 ((LabelFigure) figure).setAnchor(anchor); 163 } 164 } 165 } 166 }; 167 168 Top.deferIfNecessary(doSet); 169 } 170 171 /** Specify the font to use. This is deferred and executed 172 * in the Swing thread. 173 * @param font The font to use. 174 */ 175 public void setFont(Font font) { 176 _font = font; 177 178 // Update the shapes of all the figures that this icon has 179 // created (which may be in multiple views). This has to be 180 // done in the Swing thread. Assuming that createBackgroundFigure() 181 // is also called in the Swing thread, there is no possibility of 182 // conflict here where that method is trying to add to the _figures 183 // list while this method is traversing it. 184 Runnable doSet = new Runnable() { 185 @Override 186 public void run() { 187 synchronized (_figures) { 188 Iterator figures = _liveFigureIterator(); 189 190 while (figures.hasNext()) { 191 Object figure = figures.next(); 192 ((LabelFigure) figure).setFont(_font); 193 } 194 } 195 } 196 }; 197 198 SwingUtilities.invokeLater(doSet); 199 } 200 201 /** Specify the text to display in the icon. 202 * If this is not called, then the text displayed 203 * is "-A-". 204 * @param text The text to display in the icon. 205 */ 206 public void setIconText(String text) { 207 _iconText = text; 208 } 209 210 /** Specify text to display. This is deferred and executed 211 * in the Swing thread. 212 * @param text The text to display. 213 */ 214 public void setText(String text) { 215 _text = text; 216 217 // Update the shapes of all the figures that this icon has 218 // created (which may be in multiple views). This has to be 219 // done in the Swing thread. Assuming that createBackgroundFigure() 220 // is also called in the Swing thread, there is no possibility of 221 // conflict here where that method is trying to add to the _figures 222 // list while this method is traversing it. 223 Runnable doSet = new Runnable() { 224 @Override 225 public void run() { 226 synchronized (_figures) { 227 Iterator figures = _liveFigureIterator(); 228 229 while (figures.hasNext()) { 230 Object figure = figures.next(); 231 ((LabelFigure) figure).setString(_text); 232 } 233 } 234 } 235 }; 236 237 Top.deferIfNecessary(doSet); 238 } 239 240 /** Specify the text color to use. This is deferred and executed 241 * in the Swing thread. 242 * @param textColor The fill color to use. 243 */ 244 public void setTextColor(Color textColor) { 245 _textColor = textColor; 246 247 // Update the shapes of all the figures that this icon has 248 // created (which may be in multiple views). This has to be 249 // done in the Swing thread. Assuming that createBackgroundFigure() 250 // is also called in the Swing thread, there is no possibility of 251 // conflict here in adding the figure to the list of live figures. 252 Runnable doSet = new Runnable() { 253 @Override 254 public void run() { 255 synchronized (_figures) { 256 Iterator figures = _liveFigureIterator(); 257 258 while (figures.hasNext()) { 259 Object figure = figures.next(); 260 ((LabelFigure) figure).setFillPaint(_textColor); 261 } 262 } 263 } 264 }; 265 266 SwingUtilities.invokeLater(doSet); 267 } 268 269 /////////////////////////////////////////////////////////////////// 270 //// private variables //// 271 // Default text. 272 private String _DEFAULT_TEXT = "Double click to edit text."; 273 274 // The origin of the text. By default, the origin should be the upper left. 275 private int _anchor = SwingConstants.NORTH_WEST; 276 277 // The font to use. 278 private Font _font = new Font("SansSerif", Font.PLAIN, 12); 279 280 // Default text. 281 private String _iconText = "-A-"; 282 283 // The text that is rendered. 284 private String _text; 285 286 // The specified text color. 287 private Color _textColor = Color.blue; 288}