~ubuntu-branches/ubuntu/quantal/netbeans/quantal

« back to all changes in this revision

Viewing changes to utilities/src/org/netbeans/modules/pdf/LinkProcessor.java

  • Committer: Bazaar Package Importer
  • Author(s): Marek Slama
  • Date: 2008-01-29 14:11:22 UTC
  • Revision ID: james.westby@ubuntu.com-20080129141122-fnzjbo11ntghxfu7
Tags: upstream-6.0.1
ImportĀ upstreamĀ versionĀ 6.0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 
3
 *
 
4
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 
5
 *
 
6
 * The contents of this file are subject to the terms of either the GNU
 
7
 * General Public License Version 2 only ("GPL") or the Common
 
8
 * Development and Distribution License("CDDL") (collectively, the
 
9
 * "License"). You may not use this file except in compliance with the
 
10
 * License. You can obtain a copy of the License at
 
11
 * http://www.netbeans.org/cddl-gplv2.html
 
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
 
13
 * specific language governing permissions and limitations under the
 
14
 * License.  When distributing the software, include this License Header
 
15
 * Notice in each file and include the License file at
 
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
 
17
 * particular file as subject to the "Classpath" exception as provided
 
18
 * by Sun in the GPL Version 2 section of the License file that
 
19
 * accompanied this code. If applicable, add the following below the
 
20
 * License Header, with the fields enclosed by brackets [] replaced by
 
21
 * your own identifying information:
 
22
 * "Portions Copyrighted [year] [name of copyright owner]"
 
23
 *
 
24
 * Contributor(s):
 
25
 *
 
26
 * The Original Software is NetBeans. The Initial Developer of the Original
 
27
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
 
28
 * Microsystems, Inc. All Rights Reserved.
 
29
 *
 
30
 * If you wish your version of this file to be governed by only the CDDL
 
31
 * or only the GPL Version 2, indicate your decision by adding
 
32
 * "[Contributor] elects to include this software in this distribution
 
33
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
 
34
 * single choice of license, a recipient has the option to distribute
 
35
 * your version of this file under either the CDDL, the GPL Version 2 or
 
36
 * to extend the choice of license to its licensees as provided above.
 
37
 * However, if you add GPL Version 2 code and therefore, elected the GPL
 
38
 * Version 2 license, then the option applies only if the new code is
 
39
 * made subject to such option by the copyright holder.
 
40
 */
 
41
 
 
42
package org.netbeans.modules.pdf;
 
43
 
 
44
import java.awt.event.ActionEvent;
 
45
import java.awt.event.ActionListener;
 
46
import java.io.File;
 
47
import java.io.IOException;
 
48
import java.net.MalformedURLException;
 
49
import java.net.URI;
 
50
import java.net.URISyntaxException;
 
51
import java.net.URL;
 
52
import javax.swing.JMenuItem;
 
53
import org.openide.DialogDisplayer;
 
54
import org.openide.ErrorManager;
 
55
import org.openide.NotifyDescriptor;
 
56
import org.openide.awt.Mnemonics;
 
57
import org.openide.cookies.InstanceCookie;
 
58
import org.openide.filesystems.FileObject;
 
59
import org.openide.filesystems.FileUtil;
 
60
import org.openide.loaders.XMLDataObject;
 
61
import org.openide.modules.InstalledFileLocator;
 
62
import org.openide.util.NbBundle;
 
63
import org.w3c.dom.Document;
 
64
import org.w3c.dom.Element;
 
65
import org.w3c.dom.Node;
 
66
import org.w3c.dom.NodeList;
 
67
 
 
68
 
 
69
/**
 
70
 * Permits a special kind of .xml file to be used for PDF links.
 
71
 * After this processor is registered, any .xml file which matches
 
72
 * the specified DTD (it must declare a <code>&lt;!DOCTYPE&gt;</code>)
 
73
 * will provide an instance of a {@link JMenuItem}.
 
74
 * This menu item will be named according to the XML file's display
 
75
 * name (which may be controlled via localized filenames from a
 
76
 * bundle as elsewhere).
 
77
 * Selecting it will try to show the mentioned PDF file.
 
78
 * The PDF file may be referred to as an absolute file name,
 
79
 * or as a localized path within the IDE installation,
 
80
 * or (in the future) as an arbitrary URL.
 
81
 * The XML file is suitable for direct inclusion in a menu
 
82
 * bar folder, for example <samp>..../system/Menu/Help/</samp>.
 
83
 *
 
84
 * @author Jesse Glick
 
85
 * @author  Marian Petras
 
86
 * @see org.openide.loaders.XMLDataObject.Processor
 
87
 */
 
88
public class LinkProcessor implements InstanceCookie,
 
89
                                      XMLDataObject.Processor,
 
90
                                      ActionListener {
 
91
 
 
92
    /** Public ID of catalog. */
 
93
    public static final String PUBLIC_ID
 
94
            = "-//NetBeans//DTD PDF Document Menu Link 1.0//EN";        //NOI18N
 
95
    /** */
 
96
    public static final String PUBLIC_WWW
 
97
            = "http://www.netbeans.org/dtds/pdf_link-1_0.dtd";          //NOI18N
 
98
 
 
99
    /** <code>XMLDataObject</code> this processor is linked to. */
 
100
    private XMLDataObject xmlDataObject;
 
101
    
 
102
    
 
103
    /* JST: Replaced with registration in xml layer.
 
104
    * Initilializes <code>LinkProcessor</code>. *
 
105
    public static void init () {
 
106
        // Registering of catalog is in xml layer, see org/netbeans/modules/utilities/Layer.xml.
 
107
        
 
108
        XMLDataObject.Info xmlInfo = new XMLDataObject.Info ();
 
109
        
 
110
        xmlInfo.setIconBase("/org/netbeans/modules/pdf/PDFDataIcon"); // NOI18N
 
111
        xmlInfo.addProcessorClass(LinkProcessor.class);
 
112
        XMLDataObject.registerInfo(PUBLIC_ID, xmlInfo);
 
113
    }
 
114
     */
 
115
 
 
116
    /* Implements interface <code>XMLDataObject.Processor</code>. */
 
117
    /**
 
118
     * Attaches this processor to specified XML data object.
 
119
     *
 
120
     * @param  xmlDataObject  XML data object to which attach this processor
 
121
     */
 
122
    public void attachTo(XMLDataObject xmlDataObject) {
 
123
        this.xmlDataObject = xmlDataObject;
 
124
    }
 
125
 
 
126
    /* Implements interface <code>InstanceCookie</code>. */
 
127
    /**
 
128
     * @return <code>JMenuItem</code> class
 
129
     */
 
130
    public Class instanceClass() throws IOException, ClassNotFoundException {
 
131
        return JMenuItem.class;
 
132
    }
 
133
 
 
134
    /* Implements interface <code>InstanceCookie</code>. */
 
135
    public Object instanceCreate() throws IOException, ClassNotFoundException {
 
136
        /*
 
137
        Image icon = Utilities.loadImage(
 
138
                "org/netbeans/modules/pdf/PDFDataIcon.gif");           //NOI18N
 
139
        try {
 
140
            FileObject file = xmlDataObject.getPrimaryFile();
 
141
            FileSystem.Status fsStatus = file.getFileSystem().getStatus();
 
142
            icon = fsStatus.annotateIcon(icon,
 
143
                                         BeanInfo.ICON_COLOR_16x16,
 
144
                                         xmlDataObject.files());
 
145
        } catch (FileStateInvalidException fsie) {
 
146
            // OK, so we use the default icon
 
147
        } */
 
148
            
 
149
        String name = xmlDataObject.getNodeDelegate().getDisplayName();
 
150
        
 
151
        JMenuItem menuItem = new JMenuItem(/*new ImageIcon(icon)*/);
 
152
        Mnemonics.setLocalizedText(menuItem, name);
 
153
        menuItem.addActionListener(this);
 
154
        
 
155
        return menuItem;
 
156
    }
 
157
    
 
158
    /* Implements interface <code>InstanceCookie</code>. */
 
159
    /**
 
160
     * @return  name of the <code>xmlDataObject</code>
 
161
     */
 
162
    public String instanceName() {
 
163
        return xmlDataObject.getName();
 
164
    }
 
165
 
 
166
    /**
 
167
     * Retrieves the name of a file describing the XML data object
 
168
     *
 
169
     * @return  as much precious path to the file as possible
 
170
     */
 
171
    private String getXMLFileName() {
 
172
        FileObject fileObject = xmlDataObject.getPrimaryFile();
 
173
        return FileUtil.getFileDisplayName(fileObject);
 
174
    }
 
175
 
 
176
    /**
 
177
     * Notifies the user that the XML file is broken.
 
178
     */
 
179
    private void notifyXMLFileBroken() {
 
180
        String msg = NbBundle.getMessage(LinkProcessor.class,
 
181
                                         "EXC_file_not_matching_DTD",   //NOI18N
 
182
                                         getXMLFileName());
 
183
        ErrorManager.getDefault().log(ErrorManager.USER, msg);
 
184
    }
 
185
    
 
186
    /**
 
187
     * Notifies the user about some problem with the XML file.
 
188
     *
 
189
     * @param  msgKey  resource bundle key for the message
 
190
     * @param  urlSpec  url that caused the problem
 
191
     * @param  isError  type of the message - use <code>true</code> for
 
192
     *                  an error message, <code>false</code> for
 
193
     *                  an information message
 
194
     */
 
195
    private void notifyBadFileSpec(String msgKey,
 
196
                                   String urlSpec,
 
197
                                   boolean isError) {
 
198
        String msg = NbBundle.getMessage(LinkProcessor.class,
 
199
                                         msgKey,
 
200
                                         getXMLFileName(),
 
201
                                         urlSpec);
 
202
        ErrorManager.getDefault().log(isError ? ErrorManager.WARNING
 
203
                                              : ErrorManager.USER,
 
204
                                      msg);
 
205
    }
 
206
    
 
207
    /**
 
208
     */
 
209
    private void notifyFileDoesNotExist(String path) {
 
210
        String msg = NbBundle.getMessage(LinkProcessor.class,
 
211
                                         "MSG_File_does_not_exist",     //NOI18N
 
212
                                         path);
 
213
        DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message(
 
214
                msg, NotifyDescriptor.WARNING_MESSAGE));
 
215
    }
 
216
    
 
217
    /**
 
218
     * Grabs a file from a specification in an element of an XML file.
 
219
     *
 
220
     * @param  innerElement  element containing specification of a PDF file
 
221
     * @return  file corresponding to the specification,
 
222
     *          or <code>null</code> if the specification was illegal
 
223
     *          or unsupported
 
224
     */
 
225
    private File grabFile(Element innerElement) {
 
226
        String linkType = innerElement.getTagName();
 
227
        
 
228
        /* handle element "file": */
 
229
        if (linkType.equals("file")) {                                  //NOI18N
 
230
            if (!innerElement.hasAttribute("path")) {                   //NOI18N
 
231
                notifyXMLFileBroken();
 
232
                return null;
 
233
            }
 
234
            return new File(innerElement.getAttribute("path"));         //NOI18N
 
235
            
 
236
        /* handle element "idefile": */
 
237
        } else if (linkType.equals("idefile")) {                        //NOI18N
 
238
            if (!innerElement.hasAttribute("base")) {                   //NOI18N
 
239
                notifyXMLFileBroken();
 
240
                return null;
 
241
            }
 
242
            String base = innerElement.getAttribute("base");            //NOI18N
 
243
            String path = base.replace('.', '/') + ".pdf";              //NOI18N
 
244
            File file = InstalledFileLocator.getDefault()
 
245
                        .locate(path, null, true);
 
246
            if (file == null) {
 
247
                notifyFileDoesNotExist(path);
 
248
                return null;
 
249
            }
 
250
            return file;
 
251
            
 
252
        /* handle element "url": */
 
253
        } else if (linkType.equals("url")) {                            //NOI18N
 
254
            if (!innerElement.hasAttribute("name")) {                   //NOI18N
 
255
                notifyXMLFileBroken();
 
256
                return null;
 
257
            }
 
258
            String urlSpec = innerElement.getAttribute("name");         //NOI18N
 
259
            URL url;
 
260
            try {
 
261
                url = new URL(urlSpec);
 
262
            } catch (MalformedURLException ex) {
 
263
                notifyBadFileSpec(
 
264
                        "MSG_Cannot_open_malformed_URL",                //NOI18N
 
265
                        urlSpec,
 
266
                        true);
 
267
                return null;
 
268
            }
 
269
            if (!url.getProtocol().equals("file")) {                    //NOI18N
 
270
                notifyBadFileSpec(
 
271
                        "MSG_Cannot_open_unsupported_URL",              //NOI18N
 
272
                        urlSpec,
 
273
                        false);
 
274
            }
 
275
            try {
 
276
                return new File(new URI("file://" + url.getPath()));    //NOI18N
 
277
            } catch (URISyntaxException ex1) {
 
278
                ErrorManager.getDefault().notify(ex1);
 
279
                return null;
 
280
            } catch (IllegalArgumentException ex2) {
 
281
                ErrorManager.getDefault().notify(ex2);
 
282
                return null;
 
283
            }
 
284
            
 
285
        } else {
 
286
            notifyXMLFileBroken();
 
287
            return null;
 
288
        }
 
289
    }
 
290
    
 
291
    /* Implements interface <code>ActionListener</code>. */
 
292
    /**
 
293
     * Performs an action. Retrieves a PDF data object from the specified
 
294
     * XML data object and opens it.
 
295
     */
 
296
    public void actionPerformed(ActionEvent evt) {
 
297
        try {
 
298
            
 
299
            /* Grab the element containing the link: */
 
300
            Element innerElement;
 
301
            Document document = xmlDataObject.getDocument();
 
302
            Element pdfLinkElement = document.getDocumentElement();
 
303
            NodeList nodeList = pdfLinkElement.getChildNodes();
 
304
            int count = nodeList.getLength();
 
305
            Node node = null;
 
306
            for (int i = 0; i < count; i++) {
 
307
                Node nextNode = nodeList.item(i);
 
308
                if (nextNode.getNodeType() == Node.ELEMENT_NODE) {
 
309
                    if (node == null) {
 
310
                        node = nextNode;
 
311
                    } else {
 
312
                        /* there should be just one element */
 
313
                        notifyXMLFileBroken();
 
314
                        return;
 
315
                    }
 
316
                }
 
317
            }
 
318
            if (node == null) {
 
319
                /* there should be exactly one element within 'pdfLink' */
 
320
                notifyXMLFileBroken();
 
321
                return;
 
322
            }
 
323
            innerElement = (Element) node;
 
324
            
 
325
            /* Retrieve the PDF file: */
 
326
            File file = grabFile(innerElement);
 
327
            
 
328
            /* Try to open the file in an external viewer: */
 
329
            if (file != null) {
 
330
                try {
 
331
                    // [PENDING] in-process PDF viewer support
 
332
                    new PDFOpenSupport(file).open();
 
333
                    return;
 
334
                } catch (IllegalArgumentException ex) {
 
335
                    notifyFileDoesNotExist(file.getPath());
 
336
                }
 
337
            }
 
338
        } catch (Exception e) {
 
339
            ErrorManager.getDefault().notify(e);
 
340
        }
 
341
    }
 
342
    
 
343
}