001/* A representative of a web browser
002
003 Copyright (c) 2002-2014 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 */
027package ptolemy.actor.gui;
028
029import java.net.URL;
030import java.net.URLConnection;
031
032import ptolemy.kernel.CompositeEntity;
033import ptolemy.kernel.util.IllegalActionException;
034import ptolemy.kernel.util.NameDuplicationException;
035import ptolemy.kernel.util.Workspace;
036
037///////////////////////////////////////////////////////////////////
038//// BrowserEffigy
039
040/**
041 An effigy for a web browser.
042
043 <p> We invoke the user's web browser for certain files such as pdf files
044
045 @author Christopher Hylands
046 @version $Id$
047 @since Ptolemy II 2.0
048 @Pt.ProposedRating Red (cxh)
049 @Pt.AcceptedRating Red (cxh)
050 */
051public class BrowserEffigy extends Effigy {
052    /** Create a new effigy in the specified workspace with an empty string
053     *  for its name.
054     *  @param workspace The workspace for this effigy.
055     */
056    public BrowserEffigy(Workspace workspace) {
057        super(workspace);
058
059        // Indicate that we cannot save to URL.
060        setModifiable(false);
061    }
062
063    /** Create a new effigy in the given directory with the given name.
064     *  @param container The directory that contains this effigy.
065     *  @param name The name of this effigy.
066     *  @exception IllegalActionException If the entity cannot be contained
067     *   by the proposed container.
068     *  @exception NameDuplicationException If the name coincides with
069     *   an entity already in the container.
070     */
071    public BrowserEffigy(CompositeEntity container, String name)
072            throws IllegalActionException, NameDuplicationException {
073        super(container, name);
074
075        // Indicate that we cannot save to URL.
076        setModifiable(false);
077    }
078
079    ///////////////////////////////////////////////////////////////////
080    ////                         public methods                    ////
081
082    /** Create a new effigy in the given container by reading the specified
083     *  URL. If the specified URL is null, then create a blank effigy.
084     *  The extension of the URL is not checked, so this will open any file.
085     *  The new effigy will have a new instance of
086     *  DefaultStyledDocument associated with it.
087     *  @param container The container for the effigy.
088     *  @param base The base for relative file references, or null if
089     *   there are no relative file references.  This is ignored in this
090     *   class.
091     *  @param in The input URL.
092     *  @return A new instance of BrowserEffigy.
093     *  @exception Exception If the URL cannot be read, or if the data
094     *   is malformed in some way.
095     */
096    public static BrowserEffigy newBrowserEffigy(CompositeEntity container,
097            URL base, URL in) throws Exception {
098        // Create a new effigy.
099        BrowserEffigy effigy = new BrowserEffigy(container,
100                container.uniqueName("browserEffigy"));
101
102        // We cannot easily communicate with the Browser once we launch
103        // it, so mark this effigy as unmodifiable
104        effigy.setModifiable(false);
105
106        // The BrowserLauncher will read the URL for us, so no need
107        // to read it here.
108        effigy.uri.setURL(in);
109        return effigy;
110    }
111
112    ///////////////////////////////////////////////////////////////////
113    ////                         public variables                  ////
114
115    /** A reference to the most recently created factory for this effigy.
116     *  This is provided for use by HTMLViewer and Configuration
117     *  when following hyperlinks
118     *  that specify that they should be opened by a browser.
119     */
120    public static BrowserEffigy.Factory staticFactory = null;
121
122    ///////////////////////////////////////////////////////////////////
123    ////                         inner classes                     ////
124
125    /** A factory for creating new effigies.
126     */
127    public static class Factory extends EffigyFactory {
128        /** Create a factory with the given name and container.
129         *  @param container The container.
130         *  @param name The name.
131         *  @exception IllegalActionException If the container is incompatible
132         *   with this entity.
133         *  @exception NameDuplicationException If the name coincides with
134         *   an entity already in the container.
135         */
136        public Factory(CompositeEntity container, String name)
137                throws IllegalActionException, NameDuplicationException {
138            super(container, name);
139
140            // Record the latest factory for use by HTMLViewer.
141            staticFactory = this;
142        }
143
144        ///////////////////////////////////////////////////////////////
145        ////                     public methods                    ////
146
147        /** Return true, indicating that this effigy factory is
148         *  capable of creating an effigy without a URL being specified.
149         *  @return True.
150         */
151        @Override
152        public boolean canCreateBlankEffigy() {
153            return false;
154        }
155
156        /** Create a new effigy in the given container by reading the specified
157         *  URL. If the specified URL is null, then create a blank effigy.
158         *  The extension of the URL is not
159         *  checked, so this will open any file.  Thus, this factory
160         *  should be last on the list of effigy factories in the
161         *  configuration.
162         *  The new effigy will have a new instance of
163         *  DefaultStyledDocument associated with it.
164         *  @param container The container for the effigy.
165         *  @param base The base for relative file references, or null if
166         *   there are no relative file references.  This is ignored in this
167         *   class.
168         *  @param in The input URL.
169         *  @return A new instance of BrowserEffigy.
170         *  @exception Exception If the URL cannot be read, or if the data
171         *   is malformed in some way.
172         */
173        @Override
174        public Effigy createEffigy(CompositeEntity container, URL base, URL in)
175                throws Exception {
176            if (in == null) {
177                return null;
178            }
179
180            String extension = getExtension(in);
181
182            // This could be a list, or a user preference
183            if (extension.equals("pdf") || extension.startsWith("htm")
184                    || extension.startsWith("shtm")) {
185                Effigy effigy = newBrowserEffigy(container, base, in);
186                return effigy;
187            }
188
189            // The extension doesn't match.  Try the content type.
190            URLConnection connection = in.openConnection();
191
192            if (connection == null) {
193                return null;
194            }
195
196            String contentType = connection.getContentType();
197
198            if (contentType == null) {
199                return null;
200            }
201
202            if (contentType.startsWith("text/html")
203                    || contentType.startsWith("text/rtf")
204                    || contentType.startsWith("image/")) {
205                Effigy effigy = newBrowserEffigy(container, base, in);
206                return effigy;
207            }
208
209            return null;
210        }
211    }
212}