001/* An attribute that creates an editor pane to edit the icon description.
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.toolbox;
029
030import java.awt.Component;
031import java.awt.Dimension;
032import java.awt.Frame;
033import java.awt.GraphicsEnvironment;
034import java.io.Reader;
035import java.io.StringReader;
036import java.net.URL;
037import java.util.Iterator;
038import java.util.StringTokenizer;
039
040import javax.swing.JPanel;
041import javax.swing.JScrollPane;
042import javax.swing.JTextArea;
043
044import diva.canvas.toolbox.SVGParser;
045import diva.util.xml.XmlDocument;
046import diva.util.xml.XmlElement;
047import diva.util.xml.XmlReader;
048import ptolemy.actor.gui.EditorFactory;
049import ptolemy.gui.ComponentDialog;
050import ptolemy.gui.Query;
051import ptolemy.kernel.util.ConfigurableAttribute;
052import ptolemy.kernel.util.IllegalActionException;
053import ptolemy.kernel.util.InternalErrorException;
054import ptolemy.kernel.util.KernelException;
055import ptolemy.kernel.util.NameDuplicationException;
056import ptolemy.kernel.util.NamedObj;
057import ptolemy.kernel.util.SingletonConfigurableAttribute;
058import ptolemy.moml.MoMLChangeRequest;
059
060///////////////////////////////////////////////////////////////////
061//// AnnotationEditorFactory
062
063/**
064 If this class is contained by a visible attribute (one that has
065 an attribute called "_iconDescription"), then double clicking on that
066 attribute will invoke an editor for a textual annotation.
067 This class is contained by visible attribute in the Vergil
068 utilities library, which provides a facility for adding visual
069 annotations to diagrams.
070
071 @author Edward A. Lee
072 @version $Id$
073 @since Ptolemy II 2.0
074 @Pt.ProposedRating Red (eal)
075 @Pt.AcceptedRating Red (johnr)
076 @deprecated Use ptolemy.vergil.kernel.attributes.TextAttribute.
077 */
078@Deprecated
079public class AnnotationEditorFactory extends EditorFactory {
080    /** Construct a factory with the specified container and name.
081     *  @param container The container.
082     *  @param name The name of the factory.
083     *  @exception IllegalActionException If the factory is not of an
084     *   acceptable attribute for the container.
085     *  @exception NameDuplicationException If the name coincides with
086     *   an attribute already in the container.
087     */
088    public AnnotationEditorFactory(NamedObj container, String name)
089            throws IllegalActionException, NameDuplicationException {
090        super(container, name);
091        _container = container;
092    }
093
094    ///////////////////////////////////////////////////////////////////
095    ////                         public methods                    ////
096
097    /** Create an editor for configuring the specified object.
098     */
099    @Override
100    public void createEditor(NamedObj object, Frame parent) {
101        ComponentDialog dialog = new ComponentDialog(parent, "Edit Annotation",
102                createEditorPane());
103
104        String button = dialog.buttonPressed();
105
106        if (!button.equals("OK")) {
107            return;
108        }
109
110        String newText = _textArea.getText();
111
112        if (newText == null || newText.trim().equals("")) {
113            // NOTE: Should we delete the attribute... no visible text.
114            newText = "Double click to edit text.";
115        }
116
117        String moml = "<configure><svg><text x=\"20\" y=\"20\" "
118                + "style=\"font-size:"
119                + _fontProperties.getStringValue("fontSize") + "; font-family:"
120                + _fontProperties.getStringValue("fontFamily") + "; fill:"
121                + _fontProperties.getStringValue("fontColor") + "\">" + newText
122                + "</text></svg></configure>";
123        _iconDescription.requestChange(
124                new MoMLChangeRequest(this, _iconDescription, moml));
125    }
126
127    /** Return a new widget for configuring the container.
128     *  @return A JPanel that is a text editor for editing the annotation text.
129     */
130    public Component createEditorPane() {
131        _textArea = new JTextArea();
132        _iconDescription = (ConfigurableAttribute) _container
133                .getAttribute("_iconDescription");
134
135        if (_iconDescription == null) {
136            try {
137                _iconDescription = new SingletonConfigurableAttribute(
138                        _container, "_iconDescription");
139            } catch (KernelException ex) {
140                // Cannot occur.
141                throw new InternalErrorException(ex.toString());
142            }
143        }
144
145        // Parse the SVG to find the text.
146        String text = _iconDescription.getExpression();
147
148        // Default font characteristics.
149        _fontSize = "14";
150        _fontFamily = "SansSerif";
151        _fontColor = "blue";
152
153        try {
154            Reader in = new StringReader(text);
155
156            // NOTE: Do we need a base here?
157            XmlDocument document = new XmlDocument((URL) null);
158            XmlReader reader = new XmlReader();
159            reader.parse(document, in);
160
161            XmlElement root = document.getRoot();
162            String name = root.getType();
163
164            if (name.equals("svg")) {
165                Iterator children = root.elements();
166
167                while (children.hasNext()) {
168                    XmlElement child = (XmlElement) children.next();
169                    name = child.getType();
170
171                    if (name.equals("text")) {
172                        text = child.getPCData();
173
174                        String style = (String) child.getAttributeMap()
175                                .get("style");
176
177                        if (style != null) {
178                            StringTokenizer tokenizer = new StringTokenizer(
179                                    style, ";");
180
181                            while (tokenizer.hasMoreTokens()) {
182                                String token = tokenizer.nextToken();
183                                int colon = token.indexOf(":");
184
185                                if (colon > 0) {
186                                    String property = token.substring(0, colon)
187                                            .trim();
188
189                                    if (property.equals("fill")) {
190                                        _fontColor = token.substring(colon + 1);
191                                    } else if (property.equals("font-size")) {
192                                        _fontSize = token.substring(colon + 1);
193                                    } else if (property.equals("font-family")) {
194                                        _fontFamily = token
195                                                .substring(colon + 1);
196                                    }
197                                }
198                            }
199                        }
200
201                        // We are done once we find a text element.
202                        break;
203                    }
204                }
205            }
206        } catch (Exception ex) {
207            // If we fail, then we use the text as is.
208        }
209
210        _textArea.setText(text);
211
212        AnnotationTextEditor editor = new AnnotationTextEditor(_textArea);
213        return editor;
214    }
215
216    ///////////////////////////////////////////////////////////////////
217    ////                         private members                   ////
218
219    /** The container. */
220    private NamedObj _container;
221
222    /** Query box for font properties. */
223    Query _fontProperties;
224
225    /** Font characteristic. */
226    private String _fontSize = "14";
227
228    private String _fontFamily = "sanserif";
229
230    private String _fontColor = "blue";
231
232    /** The attribute containing the icon description. */
233    private ConfigurableAttribute _iconDescription;
234
235    /** The text area of the editor. */
236    private JTextArea _textArea;
237
238    ///////////////////////////////////////////////////////////////////
239    ////                         inner classes                     ////
240
241    /** A text widget for editing textual annotations (which are
242     *  visible attributes).
243     */
244    @SuppressWarnings("serial")
245    public class AnnotationTextEditor extends JPanel {
246        /** Create an annotation text editor.
247         *  @param textArea The text area.
248         */
249        public AnnotationTextEditor(JTextArea textArea) {
250            super();
251
252            JScrollPane pane = new JScrollPane(textArea);
253
254            // NOTE: Should the size be hardwired here?
255            pane.setPreferredSize(new Dimension(600, 300));
256            add(pane);
257
258            // Add a query with font properties.
259            _fontProperties = new Query();
260
261            String[] sizes = { "9", "10", "11", "12", "14", "18", "24", "32" };
262            _fontProperties.addChoice("fontSize", "font size", sizes, _fontSize,
263                    true);
264
265            // FIXME: Need a way to specify Italic, Bold (style).
266            // Check SVG standard and SVGParser.
267            // Get font family names from the Font class in Java.
268            // This includes logical font names, per Font class in Java:
269            // Dialog, DialogInput, Monospaced, Serif, SansSerif, or Symbol.
270            String[] families = GraphicsEnvironment
271                    .getLocalGraphicsEnvironment()
272                    .getAvailableFontFamilyNames();
273            _fontProperties.addChoice("fontFamily", "font family", families,
274                    _fontFamily, false);
275
276            // FIXME: Add a facility to invoke a color chooser using
277            // JColorChooser.
278            // public static Color showDialog(Component component (parent),
279            //                  String title,
280            //                  Color initialColor)
281            String[] colors = SVGParser.colorNames();
282
283            // The last argument makes this editable.
284            // Colors can be given in hex #rrggbb.
285            _fontProperties.addChoice("fontColor", "font color", colors,
286                    _fontColor, true);
287
288            add(_fontProperties);
289        }
290    }
291}