001/*
002 * Copyright (c) 2012 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: crawl $'
006 * '$Date: 2015-02-09 18:04:51 +0000 (Mon, 09 Feb 2015) $' 
007 * '$Revision: 33224 $'
008 * 
009 * Permission is hereby granted, without written agreement and without
010 * license or royalty fees, to use, copy, modify, and distribute this
011 * software and its documentation for any purpose, provided that the above
012 * copyright notice and the following two paragraphs appear in all copies
013 * of this software.
014 *
015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
019 * SUCH DAMAGE.
020 *
021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
026 * ENHANCEMENTS, OR MODIFICATIONS.
027 *
028 */
029
030package org.kepler.gui.frame;
031
032import java.awt.Color;
033
034import org.kepler.gui.ModelToFrameManager;
035import org.kepler.gui.TabbedLookInsideAction;
036
037import ptolemy.actor.CompositeActor;
038import ptolemy.actor.gui.Effigy;
039import ptolemy.actor.gui.PtolemyEffigy;
040import ptolemy.actor.gui.Tableau;
041import ptolemy.actor.gui.TableauFactory;
042import ptolemy.kernel.CompositeEntity;
043import ptolemy.kernel.util.IllegalActionException;
044import ptolemy.kernel.util.InternalErrorException;
045import ptolemy.kernel.util.NameDuplicationException;
046import ptolemy.kernel.util.NamedObj;
047import ptolemy.moml.LibraryAttribute;
048
049/** An editor tableau for multiple composite actors.
050 * 
051 @author Daniel Crawl
052 @version $Id: TabbedKeplerGraphTableau.java 33224 2015-02-09 18:04:51Z crawl $
053 */
054public class TabbedKeplerGraphTableau extends KeplerGraphTableau {
055    /** Create a new TabbedKeplerGraphTableau with the specified
056     *  container and name.
057     *  @param container The container.
058     *  @param name The name.
059     *  @exception IllegalActionException If the model associated with
060     *   the container effigy is not an instance of CompositeEntity.
061     *  @exception NameDuplicationException If the container already
062     *   contains an object with the specified name.
063     */
064    public TabbedKeplerGraphTableau(PtolemyEffigy container, String name)
065            throws IllegalActionException, NameDuplicationException {
066        this(container, name, null);
067    }
068
069    /** Create a new TabbedKeplerGraphTableau with the specified
070     *  container, name, and default library.
071     *  @param container The container.
072     *  @param name The name.
073     *  @param defaultLibrary The default library, or null to not specify one.
074     *  @exception IllegalActionException If the model associated with
075     *   the container effigy is not an instance of CompositeEntity.
076     *  @exception NameDuplicationException If the container already
077     *   contains an object with the specified name.
078     */
079    public TabbedKeplerGraphTableau(PtolemyEffigy container, String name,
080            LibraryAttribute defaultLibrary) throws IllegalActionException,
081            NameDuplicationException {
082        super(container, name);
083    }
084
085    ///////////////////////////////////////////////////////////////////
086    ////                         public methods                    ////
087
088    /** Create the graph frame that displays the model associated with
089     *  this tableau. This method creates a MultiCompositeGraphFrame.
090     *  @param model The Ptolemy II model to display in the graph frame.
091     */
092    public void createGraphFrame(CompositeEntity model) {
093        createGraphFrame(model, null);
094    }
095    
096    /** Create the graph frame that displays the model associated with
097     *  this tableau together with the specified library.
098     *  @param model The Ptolemy II model to display in the graph frame.
099     *  @param defaultLibrary The default library, or null to not specify
100     *   one.
101     */
102     @Override
103     public void createGraphFrame(CompositeEntity model,
104            LibraryAttribute defaultLibrary)
105     {
106        TabbedKeplerGraphFrame frame = null;
107        NamedObj container = model.getContainer();
108 
109        // if model is top-level or the action for opening in new tab is not
110        // running, then open in a new frame
111        if(container == null || !TabbedLookInsideAction.actionIsRunning()) {
112            frame = new TabbedKeplerGraphFrame((CompositeActor) model, this,
113                defaultLibrary);
114            _createdNewFrame = true;
115        } else {
116            frame = _addCompositeToExistingFrame(model, defaultLibrary);
117            _createdNewFrame = false;
118        }
119                
120        _configureFrame(frame, model);
121        
122     }
123    
124     /** Override the parent class so that if the new container is null and we did
125      *  not create a new frame, then set the frame to null so that it is not
126      *  disposed of by the parent class.
127      */
128     @Override
129     public void setContainer(CompositeEntity container)
130             throws IllegalActionException, NameDuplicationException {
131
132         if(container == null && !_createdNewFrame) {
133             setFrame(null);
134         }
135         super.setContainer(container);
136     }
137
138     /** Make this tableau visible by calling setVisible(true), and
139      *  raising or deiconifying its window.
140      *  If no frame has been set, then do nothing.
141      */
142     @Override
143     public void show() {
144         
145         // make the tableau visible
146         super.show();
147         
148         // set the selected tab to the model for this tableau.
149         // if the model is not one of the tabs, then setSelectedTab() does nothing.
150         final PtolemyEffigy effigy = (PtolemyEffigy)getContainer();
151         final NamedObj model = effigy.getModel();
152         final TabbedKeplerGraphFrame frame =
153             (TabbedKeplerGraphFrame) ModelToFrameManager.getInstance().getFrame(model);
154         frame.setSelectedTab(model);
155     }
156     
157     protected TabbedKeplerGraphFrame _addCompositeToExistingFrame(CompositeEntity model,
158             LibraryAttribute defaultLibrary) {
159         
160         TabbedKeplerGraphFrame frame = null;
161         NamedObj container = model.getContainer();
162         
163         // get the frame for the container. if the container does not have a frame,
164         // e.g., we're opening a sub-workflow whose parent was not opened, then go
165         // up the hierarchy to find the frame.
166         while(frame == null && container != null) {
167             frame = (TabbedKeplerGraphFrame) ModelToFrameManager.getInstance().getFrame(container);
168             if(frame == null) {
169                 container = container.getContainer();
170             }
171         }
172         if(frame == null) {
173             throw new InternalErrorException("Unable to find frame for " + model.getFullName());
174         }
175         frame.addComposite(model, this, defaultLibrary);
176         return frame;
177     }
178     
179     /** Configure the frame for the opened model. */
180     protected void _configureFrame(TabbedKeplerGraphFrame frame, CompositeEntity model) {
181         
182         NamedObj container = model.getContainer();
183         
184         // setFrame() sets the title to be the name of the model. if the model
185         // is a tab in an existing frame, set the name back to the top level model
186         String oldTitle = null;
187         if(container != null) {
188             oldTitle = frame.getTitle();
189         }
190          
191         try {
192             setFrame(frame);
193         } catch (IllegalActionException e) {
194             throw new InternalErrorException(e);
195         }
196         
197         if(container != null) {
198             frame.setTitle(oldTitle);
199         }
200          
201         frame.setBackground(BACKGROUND_COLOR);       
202
203     }
204     
205    ///////////////////////////////////////////////////////////////////
206    ////                         private variables                 ////
207
208    /** Background color. */
209    private final static Color BACKGROUND_COLOR = new Color(0xe5e5e5);
210    
211    /** If true, a new frame was created in createGraphFrame(). */
212    protected boolean _createdNewFrame;
213
214    // /////////////////////////////////////////////////////////////////
215    // // public inner classes ////
216
217    /**
218     * A factory that creates graph editing tableaux for Ptolemy models.
219     */
220    public static class Factory extends TableauFactory {
221        /**
222         * Create an factory with the given name and container.
223         * 
224         * @param container
225         *            The container.
226         * @param name
227         *            The name.
228         * @exception IllegalActionException
229         *                If the container is incompatible with this attribute.
230         * @exception NameDuplicationException
231         *                If the name coincides with an attribute already in the
232         *                container.
233         */
234        public Factory(NamedObj container, String name)
235                throws IllegalActionException, NameDuplicationException {
236            super(container, name);
237        }
238
239        /**
240         * Create a tableau in the default workspace with no name for the given
241         * Effigy. The tableau will created with a new unique name in the given
242         * model effigy. If this factory cannot create a tableau for the given
243         * effigy (perhaps because the effigy is not of the appropriate
244         * subclass) then return null. It is the responsibility of callers of
245         * this method to check the return value and call show().
246         * 
247         * @param effigy
248         *            The model effigy.
249         * @return A new KeplerGraphTableau, if the effigy is a PtolemyEffigy,
250         *         or null otherwise.
251         * @exception Exception
252         *                If an exception occurs when creating the tableau.
253         */
254        @Override
255        public Tableau createTableau(Effigy effigy) throws Exception {
256            if (effigy instanceof PtolemyEffigy) {
257                // First see whether the effigy already contains a graphTableau.
258                TabbedKeplerGraphTableau tableau = (TabbedKeplerGraphTableau) effigy
259                        .getEntity("graphTableau");
260
261                if (tableau == null) {
262                    // Check to see whether this factory contains a
263                    // default library.
264                    LibraryAttribute library = (LibraryAttribute) getAttribute(
265                            "_library", LibraryAttribute.class);
266                    tableau = new TabbedKeplerGraphTableau((PtolemyEffigy) effigy,
267                            "graphTableau", library);
268                }
269
270                // Don't call show() here, it is called for us in
271                // TableauFrame.ViewMenuListener.actionPerformed()
272                return tableau;
273            } else {
274                return null;
275            }
276        }
277    }
278}