001/* Singleton class for displaying exceptions, errors, warnings, and messages that
002includes a button to open the actor that caused the problem
003
004 Copyright (c) 2010-2014 The Regents of the University of California.
005 All rights reserved.
006 Permission is hereby granted, without written agreement and without
007 license or royalty fees, to use, copy, modify, and distribute this
008 software and its documentation for any purpose, provided that the above
009 copyright notice and the following two paragraphs appear in all copies
010 of this software.
011
012 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
013 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
014 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
015 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
016 SUCH DAMAGE.
017
018 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
019 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
020 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
021 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
022 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
023 ENHANCEMENTS, OR MODIFICATIONS.
024
025 PT_COPYRIGHT_VERSION_2
026 COPYRIGHTENDKEY
027 */
028package ptolemy.actor.gui;
029
030import java.util.Iterator;
031
032import ptolemy.gui.GraphicalMessageHandler;
033import ptolemy.kernel.CompositeEntity;
034import ptolemy.kernel.util.InternalErrorException;
035import ptolemy.kernel.util.KernelException;
036import ptolemy.kernel.util.KernelRuntimeException;
037import ptolemy.kernel.util.Nameable;
038import ptolemy.kernel.util.NamedObj;
039
040///////////////////////////////////////////////////////////////////
041//// GraphicalMessageHandler
042
043/**
044 A message handler that optionally includes a button that opens the model
045 that contains the actor that caused the exception.
046
047 @author  Christopher Brooks
048 @version $Id$
049 @since Ptolemy II 10.0
050 @Pt.ProposedRating Red (cxh)
051 @Pt.AcceptedRating Red (cxh)
052 */
053public class ActorGraphicalMessageHandler extends GraphicalMessageHandler {
054
055    /** Under certain circumstances, add a "Go To Actor" button to the
056     *  options array.  The button is added to the array if the
057     *  throwable is a KernelException or a KernelRuntimeException
058     *  with a non-null Nameable and the Nameable is not at the
059     *  toplevel.
060     *  @param options An array of Strings, suitable for passing to
061     *  JOptionPane.showOptionDialog().
062     *  @param throwable The throwable.
063     *  @return An array of Strings.  If the throwable is an instance
064     *  of KernelException and non-null, then the String "Go To Actor"
065     *  is added to the array as the last element.  Otherwise, the
066     *  options argument is returned.
067     */
068    @Override
069    protected Object[] _checkThrowableNameable(Object[] options,
070            Throwable throwable) {
071
072        Object[] result = options;
073        Nameable nameable1 = _getNameable(throwable);
074        // If the throwable has a Nameable, and is not the top level,
075        // then add a button
076        if (nameable1 != null && nameable1 instanceof NamedObj
077                && ((NamedObj) nameable1).toplevel() != nameable1) {
078            result = new Object[options.length + 1];
079            System.arraycopy(options, 0, result, 0, options.length);
080            result[options.length] = "Go To Actor";
081        }
082        return result;
083    }
084
085    /** Given a throwable, return the first Nameable (if any).
086     *  @param throwable The throwable that may or may not
087     *  be an instance of KernelException or KernelRuntimeException.
088     *  @return The first Nameable or null if the throwable
089     *  is not a KernelException or KernelRuntimeException.
090     */
091    protected Nameable _getNameable(Throwable throwable) {
092        Nameable nameable1 = null;
093        if (throwable instanceof KernelException) {
094            nameable1 = ((KernelException) throwable).getNameable1();
095        } else if (throwable instanceof KernelRuntimeException) {
096            Iterator nameables = ((KernelRuntimeException) throwable)
097                    .getNameables().iterator();
098            while (nameables.hasNext()) {
099                Object object = nameables.next();
100                if (object instanceof NamedObj) {
101                    nameable1 = (NamedObj) object;
102                    break;
103                }
104            }
105
106        }
107        return nameable1;
108    }
109
110    /** Open the level of hierarchy of the model that contains the
111     *  Nameable referred to by the KernelException or KernelRuntimeException.
112     *  @param throwable The throwable that may be a KernelException
113     *  or KernelRuntimeException.
114     */
115    @Override
116    protected void _showNameable(Throwable throwable) {
117        Nameable nameable1 = _getNameable(throwable);
118        if (nameable1 != null) {
119            Effigy effigy = Configuration
120                    .findEffigy(((NamedObj) nameable1).toplevel());
121            Configuration configuration = (Configuration) effigy.toplevel();
122            try {
123                Nameable container = nameable1;
124                while (container != null
125                        && !(container instanceof CompositeEntity)) {
126                    container = container.getContainer();
127                }
128                if (container == null) {
129                    // Hmm.  Could not find container?
130                    container = nameable1;
131                }
132                configuration.openModel((NamedObj) container);
133            } catch (KernelException ex) {
134                // FIXME: Could be an endless loop here if
135                // we keep failing to open container.
136                throw new InternalErrorException(nameable1, ex,
137                        "Could not open " + nameable1.getFullName());
138            }
139            return;
140        }
141
142        message("Internal Error: The throwable \"" + throwable
143                + "\" is not a KernelException or KernelRuntimeException?");
144    }
145}