001/* An attribute that creates an editor pane to configure its container.
002
003 Copyright (c) 1998-2018 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.actor.gui;
029
030import java.awt.Color;
031import java.awt.Component;
032import java.util.LinkedList;
033import java.util.List;
034import java.util.Set;
035
036import javax.swing.JLabel;
037import javax.swing.JTabbedPane;
038
039import ptolemy.kernel.util.Attribute;
040import ptolemy.kernel.util.Decorator;
041import ptolemy.kernel.util.DecoratorAttributes;
042import ptolemy.kernel.util.IllegalActionException;
043import ptolemy.kernel.util.NameDuplicationException;
044import ptolemy.kernel.util.NamedObj;
045import ptolemy.kernel.util.Settable;
046import ptolemy.util.MessageHandler;
047
048///////////////////////////////////////////////////////////////////
049//// EditorPaneFactory
050
051/**
052 This is an attribute that can create a pane (called a "configuration
053 widget") for interactively configuring its container.  To use this,
054 place an instance of this class (or a derived class) inside a Ptolemy II
055 object.  When the user double clicks on the icon for that object,
056 or selects Configure from the context menu, then a dialog is opened
057 containing the pane returned by createEditorPane().
058 <p>
059 In this base class, the createEditorPane() method creates an
060 instance of PtolemyQuery with one entry for each parameter in
061 the container. This is the default mechanism
062 for editing parameters.  Derived classes may override this
063 method to present radically different interfaces to the user.
064 For example, a digital filter actor could present a filter
065 design interface.  A plotter actor could present a panel for
066 configuring a plot.  A file reader actor could present a file
067 browser.
068
069 @see Configurer
070 @author Steve Neuendorffer and Edward A. Lee
071 @version $Id$
072 @since Ptolemy II 0.4
073 @Pt.ProposedRating Red (eal)
074 @Pt.AcceptedRating Red (johnr)
075 */
076public class EditorPaneFactory extends Attribute {
077    /** Construct a factory with the specified container and name.
078     *  @param container The container.
079     *  @param name The name of the factory.
080     *  @exception IllegalActionException If the factory is not of an
081     *   acceptable attribute for the container.
082     *  @exception NameDuplicationException If the name coincides with
083     *   an attribute already in the container.
084     */
085    public EditorPaneFactory(NamedObj container, String name)
086            throws IllegalActionException, NameDuplicationException {
087        super(container, name);
088    }
089
090    ///////////////////////////////////////////////////////////////////
091    ////                         public methods                    ////
092
093    /** Return a new widget for configuring the container.  In this
094     *  base class, this method defers to the static createEditorPane method.
095     *  Subclasses that implement specialized interaction should override
096     *  this method to create an appropriate type of component.
097     *  @return A new widget for configuring the container.
098     */
099    public Component createEditorPane() {
100        return createEditorPane(getContainer());
101    }
102
103    /** Return a new default widget for configuring the specified object.
104     *  This is used by the Configurer for objects that do not contain
105     *  an instance of EditorPaneFactory as an attribute.  The resulting
106     *  component is an instance of the PtolemyQuery class that can be
107     *  used to edit the parameters of the object.
108     *  @param object The object to be configured.
109     *  @return An instance of the PtolemyQuery class that is created
110     *  with styles according to the type given in each visible attribute.
111     */
112    public static Component createEditorPane(NamedObj object) {
113        // If there are decorators for the specified object, then we
114        // want to return a JTabbedPane with one tab for the parameters
115        // of the object, and one tab for parameters provided by each
116        // decorator. If there are no decorators, we can simply return
117        // a PtolemyQuery for the specified object.
118        JTabbedPane tabs = null;
119        try {
120            Set<Decorator> decorators = object.decorators();
121            for (Decorator decorator : decorators) {
122                DecoratorAttributes decoratorAttributes = object
123                        .getDecoratorAttributes(decorator);
124
125                if (decoratorAttributes != null) {
126                    decoratorAttributes.updateContent();
127                    PtolemyQuery decoratorQuery = new PtolemyQuery(object);
128                    decoratorQuery.setAlignmentY(Component.TOP_ALIGNMENT);
129                    decoratorQuery.setTextWidth(DEFAULT_QUERY_WIDTH);
130                    decoratorQuery
131                            .addText(
132                                    "Decorator providing the parameters below: "
133                                            + decorator.getFullName(),
134                                    Color.BLACK, 0);
135                    boolean foundDecoratorAttribute = false;
136
137                    for (Object attribute : decoratorAttributes
138                            .attributeList()) {
139                        if (attribute instanceof Settable) {
140                            Settable settable = (Settable) attribute;
141                            if (Configurer.isVisible(object, settable)) {
142                                foundDecoratorAttribute = true;
143                                decoratorQuery.addStyledEntry(settable);
144
145                            }
146                        }
147                    }
148                    if (foundDecoratorAttribute) {
149                        if (tabs == null) {
150                            tabs = new JTabbedPane();
151                            Component mainTab = createEditorPane(object,
152                                    new PtolemyQuery(object));
153                            tabs.addTab(object.getDisplayName(), mainTab);
154                        }
155                        tabs.addTab(decorator.getName(), decoratorQuery);
156                    }
157                }
158            }
159        } catch (IllegalActionException e) {
160            MessageHandler.error("Invalid decorator value", e);
161        }
162
163        if (tabs == null) {
164            // No decorators.
165            PtolemyQuery query = new PtolemyQuery(object);
166            query.setTextWidth(DEFAULT_QUERY_WIDTH);
167            return createEditorPane(object, query);
168        } else {
169            return tabs;
170        }
171    }
172
173    /** Return a new default widget for configuring the specified object.
174     *  This is used by the Configurer for objects that do not contain
175     *  an instance of EditorPaneFactory as an attribute.  The resulting
176     *  component is an instance of the PtolemyQuery class that
177     *  @param object The object to be configured.
178     *  @param query The query to which new entries for the object are to be
179     *  added.
180     *  @return An instance of the PtolemyQuery class that is created
181     *  with styles according to the type given in each visible attribute.
182     */
183    public static Component createEditorPane(NamedObj object,
184            PtolemyQuery query) {
185        query.setTextWidth(DEFAULT_QUERY_WIDTH);
186        boolean foundOne = false;
187        List<Settable> parameters = new LinkedList<Settable>(
188                object.attributeList(Settable.class));
189
190        for (Settable parameter : parameters) {
191            if (Configurer.isVisible(object, parameter)) {
192                foundOne = true;
193                query.addStyledEntry(parameter);
194            }
195        }
196
197        if (!foundOne) {
198            return new JLabel(object.getName() + " has no parameters.");
199        }
200
201        return query;
202    }
203
204    /** Default width for a query. */
205    public static int DEFAULT_QUERY_WIDTH = 40;
206}