View | Details | Raw Unified | Return to bug 42741
Collapse All | Expand All

(-)sources/org/apache/batik/dom/AbstractDocument.java (+24 lines)
Lines 137-142 Link Here
137
    protected transient WeakHashMap elementsByTagNamesNS;
137
    protected transient WeakHashMap elementsByTagNamesNS;
138
138
139
    /**
139
    /**
140
     * The Imported Nodes lists.
141
     */
142
    protected transient WeakHashMap importedNodes;
143
    
144
    /**
140
     * Input encoding of this document.
145
     * Input encoding of this document.
141
     */
146
     */
142
    protected String inputEncoding;
147
    protected String inputEncoding;
Lines 414-419 Link Here
414
                result.appendChild(importNode(n, true));
419
                result.appendChild(importNode(n, true));
415
            }
420
            }
416
        }
421
        }
422
        
423
        // Store in importedNodes hashmap so that the original
424
        // node is available
425
        putImportedNode(result, importedNode);
426
        
417
        return result;
427
        return result;
418
    }
428
    }
419
429
Lines 675-680 Link Here
675
        }
685
        }
676
        t.put(ns, ln, l);
686
        t.put(ns, ln, l);
677
    }
687
    }
688
    
689
    public Node getImportedNode(Node clone) {
690
    	if (importedNodes == null) {
691
    		return null;
692
    	}
693
    	return (Node)importedNodes.get(clone);
694
    }
695
    
696
    public void putImportedNode(Node clone, Node importedNode) {
697
    	if (importedNodes == null) {
698
    		importedNodes = new WeakHashMap();
699
    	}
700
    	importedNodes.put(clone, importedNode);
701
    }
678
702
679
    // DocumentEvent /////////////////////////////////////////////////////////
703
    // DocumentEvent /////////////////////////////////////////////////////////
680
704
(-)sources/org/apache/batik/dom/svg/SVGContext.java (+5 lines)
Lines 94-97 Link Here
94
     * Returns the font-size on the associated element.
94
     * Returns the font-size on the associated element.
95
     */
95
     */
96
    float getFontSize();
96
    float getFontSize();
97
    
98
    /**
99
     * Whether parsing should be strict (throw exception on error) or not
100
     */
101
    boolean strictParsing = false;
97
}
102
}
(-)sources/org/apache/batik/dom/util/DocumentDescriptor.java (-3 / +3 lines)
Lines 18-27 Link Here
18
 */
18
 */
19
package org.apache.batik.dom.util;
19
package org.apache.batik.dom.util;
20
20
21
import org.apache.batik.dom.AbstractDocument;
22
import org.apache.batik.util.CleanerThread;
21
import org.w3c.dom.Element;
23
import org.w3c.dom.Element;
22
24
23
import org.apache.batik.util.CleanerThread;
24
25
/**
25
/**
26
 * This class contains informations about a document.
26
 * This class contains informations about a document.
27
 *
27
 *
Lines 87-93 Link Here
87
     */
87
     */
88
    public int getLocationColumn(Element elt) {
88
    public int getLocationColumn(Element elt) {
89
        synchronized (this) {
89
        synchronized (this) {
90
            int hash = elt.hashCode() & 0x7FFFFFFF;
90
        	int hash = elt.hashCode() & 0x7FFFFFFF;
91
            int index = hash % table.length;
91
            int index = hash % table.length;
92
92
93
            for (Entry e = table[index]; e != null; e = e.next) {
93
            for (Entry e = table[index]; e != null; e = e.next) {
(-)sources/org/apache/batik/dom/util/SAXDocumentFactory.java (-665 / +711 lines)
Lines 1-19 Link Here
1
/*
1
/*
2
2
3
   Licensed to the Apache Software Foundation (ASF) under one or more
3
 Licensed to the Apache Software Foundation (ASF) under one or more
4
   contributor license agreements.  See the NOTICE file distributed with
4
 contributor license agreements.  See the NOTICE file distributed with
5
   this work for additional information regarding copyright ownership.
5
 this work for additional information regarding copyright ownership.
6
   The ASF licenses this file to You under the Apache License, Version 2.0
6
 The ASF licenses this file to You under the Apache License, Version 2.0
7
   (the "License"); you may not use this file except in compliance with
7
 (the "License"); you may not use this file except in compliance with
8
   the License.  You may obtain a copy of the License at
8
 the License.  You may obtain a copy of the License at
9
9
10
       http://www.apache.org/licenses/LICENSE-2.0
10
 http://www.apache.org/licenses/LICENSE-2.0
11
11
12
   Unless required by applicable law or agreed to in writing, software
12
 Unless required by applicable law or agreed to in writing, software
13
   distributed under the License is distributed on an "AS IS" BASIS,
13
 distributed under the License is distributed on an "AS IS" BASIS,
14
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
   See the License for the specific language governing permissions and
15
 See the License for the specific language governing permissions and
16
   limitations under the License.
16
 limitations under the License.
17
17
18
 */
18
 */
19
package org.apache.batik.dom.util;
19
package org.apache.batik.dom.util;
Lines 30-35 Link Here
30
import javax.xml.parsers.SAXParser;
30
import javax.xml.parsers.SAXParser;
31
import javax.xml.parsers.SAXParserFactory;
31
import javax.xml.parsers.SAXParserFactory;
32
32
33
import org.apache.batik.dom.svg.SVGOMRectElement;
33
import org.apache.batik.util.HaltingThread;
34
import org.apache.batik.util.HaltingThread;
34
import org.apache.batik.util.XMLConstants;
35
import org.apache.batik.util.XMLConstants;
35
36
Lines 51-792 Link Here
51
import org.w3c.dom.Node;
52
import org.w3c.dom.Node;
52
53
53
/**
54
/**
54
 * This class contains methods for creating Document instances
55
 * This class contains methods for creating Document instances from an URI using
55
 * from an URI using SAX2.
56
 * SAX2.
56
 *
57
 * 
57
 * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
58
 * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
58
 * @version $Id$
59
 * @version $Id$
59
 */
60
 */
60
public class SAXDocumentFactory
61
public class SAXDocumentFactory extends DefaultHandler implements
61
    extends    DefaultHandler
62
		LexicalHandler, DocumentFactory {
62
    implements LexicalHandler,
63
               DocumentFactory {
64
63
65
    /**
64
	/**
66
     * The DOM implementation used to create the document.
65
	 * The DOM implementation used to create the document.
67
     */
66
	 */
68
    protected DOMImplementation implementation;
67
	protected DOMImplementation implementation;
69
68
70
    /**
69
	/**
71
     * The SAX2 parser classname.
70
	 * The SAX2 parser classname.
72
     */
71
	 */
73
    protected String parserClassName;
72
	protected String parserClassName;
74
73
75
    /**
74
	/**
76
     * The SAX2 parser object.
75
	 * The SAX2 parser object.
77
     */
76
	 */
78
    protected XMLReader parser;
77
	protected XMLReader parser;
79
78
80
    /**
79
	/**
81
     * The created document.
80
	 * The created document.
82
     */
81
	 */
83
    protected Document document;
82
	protected Document document;
84
83
85
    /**
84
	/**
86
     * The created document descriptor.
85
	 * The created document descriptor.
87
     */
86
	 */
88
    protected DocumentDescriptor documentDescriptor;
87
	protected DocumentDescriptor documentDescriptor;
89
88
90
    /**
89
	/**
91
     * Whether a document descriptor must be generated.
90
	 * Whether a document descriptor must be generated.
92
     */
91
	 */
93
    protected boolean createDocumentDescriptor;
92
	protected boolean createDocumentDescriptor;
94
93
95
    /**
94
	/**
96
     * The current node.
95
	 * The current node.
97
     */
96
	 */
98
    protected Node currentNode;
97
	protected Node currentNode;
99
98
100
    /**
99
	/**
101
     * The locator.
100
	 * The locator.
102
     */
101
	 */
103
    protected Locator locator;
102
	protected Locator locator;
104
103
105
    /**
104
	/**
106
     * Contains collected string data.  May be Text, CDATA or Comment.
105
	 * Contains collected string data. May be Text, CDATA or Comment.
107
     */
106
	 */
108
    protected StringBuffer stringBuffer = new StringBuffer();
107
	protected StringBuffer stringBuffer = new StringBuffer();
109
    /**
110
     * Indicates if stringBuffer has content, needed in case of
111
     * zero sized "text" content.
112
     */
113
    protected boolean stringContent;
114
108
115
    /**
109
	/**
116
     * True if the parser is currently parsing a DTD.
110
	 * Indicates if stringBuffer has content, needed in case of zero sized
117
     */
111
	 * "text" content.
118
    protected boolean inDTD;
112
	 */
113
	protected boolean stringContent;
119
114
120
    /**
115
	/**
121
     * True if the parser is currently parsing a CDATA section.
116
	 * True if the parser is currently parsing a DTD.
122
     */
117
	 */
123
    protected boolean inCDATA;
118
	protected boolean inDTD;
124
119
125
    /**
120
	/**
126
     * Whether the parser still hasn't read the document element's
121
	 * True if the parser is currently parsing a CDATA section.
127
     * opening tag.
122
	 */
128
     */
123
	protected boolean inCDATA;
129
    protected boolean inProlog;
130
124
131
    /**
125
	/**
132
     * Whether the parser is in validating mode.
126
	 * Whether the parser still hasn't read the document element's opening tag.
133
     */
127
	 */
134
    protected boolean isValidating;
128
	protected boolean inProlog;
135
129
136
    /**
130
	/**
137
     * Whether the document just parsed was standalone.
131
	 * Whether the parser is in validating mode.
138
     */
132
	 */
139
    protected boolean isStandalone;
133
	protected boolean isValidating;
140
134
141
    /**
135
	/**
142
     * XML version of the document just parsed.
136
	 * Whether the document just parsed was standalone.
143
     */
137
	 */
144
    protected String xmlVersion;
138
	protected boolean isStandalone;
145
139
146
    /**
140
	/**
147
     * The stack used to store the namespace URIs.
141
	 * XML version of the document just parsed.
148
     */
142
	 */
149
    protected HashTableStack namespaces;
143
	protected String xmlVersion;
150
144
151
    /**
145
	/**
152
     * The error handler.
146
	 * The stack used to store the namespace URIs.
153
     */
147
	 */
154
    protected ErrorHandler errorHandler;
148
	protected HashTableStack namespaces;
155
149
156
    protected interface PreInfo {
150
	/**
157
        Node createNode(Document doc);
151
	 * The error handler.
158
    }
152
	 */
153
	protected ErrorHandler errorHandler;
159
154
160
    static class ProcessingInstructionInfo implements PreInfo {
155
	protected interface PreInfo {
161
        public String target, data;
156
		Node createNode(Document doc);
162
        public ProcessingInstructionInfo(String target, String data) {
157
	}
163
            this.target = target;
164
            this.data = data;
165
        }
166
        public Node createNode(Document doc) {
167
            return doc.createProcessingInstruction(target, data);
168
        }
169
    }
170
158
171
    static class CommentInfo implements PreInfo {
159
	static class ProcessingInstructionInfo implements PreInfo {
172
        public String comment;
160
		public String target, data;
173
        public CommentInfo(String comment) {
174
            this.comment = comment;
175
        }
176
        public Node createNode(Document doc) {
177
            return doc.createComment(comment);
178
        }
179
    }
180
161
181
    static class CDataInfo implements PreInfo {
162
		public ProcessingInstructionInfo(String target, String data) {
182
        public String cdata;
163
			this.target = target;
183
        public CDataInfo(String cdata) {
164
			this.data = data;
184
            this.cdata = cdata;
165
		}
185
        }
186
        public Node createNode(Document doc) {
187
            return doc.createCDATASection(cdata);
188
        }
189
    }
190
166
191
    static class TextInfo implements PreInfo {
167
		public Node createNode(Document doc) {
192
        public String text;
168
			return doc.createProcessingInstruction(target, data);
193
        public TextInfo(String text) {
169
		}
194
            this.text = text;
170
	}
195
        }
196
        public Node createNode(Document doc) {
197
            return doc.createTextNode(text);
198
        }
199
    }
200
171
201
    /**
172
	static class CommentInfo implements PreInfo {
202
     * Various elements encountered prior to real document root element.
173
		public String comment;
203
     * List of PreInfo objects.
204
     */
205
    protected List preInfo;
206
174
207
    /**
175
		public CommentInfo(String comment) {
208
     * Creates a new SAXDocumentFactory object.
176
			this.comment = comment;
209
     * No document descriptor will be created while generating a document.
177
		}
210
     * @param impl The DOM implementation to use for building the DOM tree.
211
     * @param parser The SAX2 parser classname.
212
     */
213
    public SAXDocumentFactory(DOMImplementation impl,
214
                              String parser) {
215
        implementation           = impl;
216
        parserClassName          = parser;
217
    }
218
178
219
    /**
179
		public Node createNode(Document doc) {
220
     * Creates a new SAXDocumentFactory object.
180
			return doc.createComment(comment);
221
     * @param impl The DOM implementation to use for building the DOM tree.
181
		}
222
     * @param parser The SAX2 parser classname.
182
	}
223
     * @param dd Whether a document descriptor must be generated.
224
     */
225
    public SAXDocumentFactory(DOMImplementation impl,
226
                              String parser,
227
                              boolean dd) {
228
        implementation           = impl;
229
        parserClassName          = parser;
230
        createDocumentDescriptor = dd;
231
    }
232
183
233
    /**
184
	static class CDataInfo implements PreInfo {
234
     * Creates a Document instance.
185
		public String cdata;
235
     * @param ns The namespace URI of the root element of the document.
236
     * @param root The name of the root element of the document.
237
     * @param uri The document URI.
238
     * @exception IOException if an error occured while reading the document.
239
     */
240
    public Document createDocument(String ns, String root, String uri)
241
        throws IOException {
242
        return createDocument(ns, root, uri, new InputSource(uri));
243
    }
244
186
245
    /**
187
		public CDataInfo(String cdata) {
246
     * Creates a Document instance.
188
			this.cdata = cdata;
247
     * @param uri The document URI.
189
		}
248
     * @exception IOException if an error occured while reading the document.
249
     */
250
    public Document createDocument(String uri)
251
        throws IOException {
252
        return createDocument(new InputSource(uri));
253
    }
254
190
255
    /**
191
		public Node createNode(Document doc) {
256
     * Creates a Document instance.
192
			return doc.createCDATASection(cdata);
257
     * @param ns The namespace URI of the root element of the document.
193
		}
258
     * @param root The name of the root element of the document.
194
	}
259
     * @param uri The document URI.
260
     * @param is The document input stream.
261
     * @exception IOException if an error occured while reading the document.
262
     */
263
    public Document createDocument(String ns, String root, String uri,
264
                                   InputStream is) throws IOException {
265
        InputSource inp = new InputSource(is);
266
        inp.setSystemId(uri);
267
        return createDocument(ns, root, uri, inp);
268
    }
269
195
270
    /**
196
	static class TextInfo implements PreInfo {
271
     * Creates a Document instance.
197
		public String text;
272
     * @param uri The document URI.
273
     * @param is The document input stream.
274
     * @exception IOException if an error occured while reading the document.
275
     */
276
    public Document createDocument(String uri, InputStream is)
277
        throws IOException {
278
        InputSource inp = new InputSource(is);
279
        inp.setSystemId(uri);
280
        return createDocument(inp);
281
    }
282
198
283
    /**
199
		public TextInfo(String text) {
284
     * Creates a Document instance.
200
			this.text = text;
285
     * @param ns The namespace URI of the root element of the document.
201
		}
286
     * @param root The name of the root element of the document.
287
     * @param uri The document URI.
288
     * @param r The document reader.
289
     * @exception IOException if an error occured while reading the document.
290
     */
291
    public Document createDocument(String ns, String root, String uri,
292
                                   Reader r) throws IOException {
293
        InputSource inp = new InputSource(r);
294
        inp.setSystemId(uri);
295
        return createDocument(ns, root, uri, inp);
296
    }
297
202
298
    /**
203
		public Node createNode(Document doc) {
299
     * Creates a Document instance.
204
			return doc.createTextNode(text);
300
     * @param ns The namespace URI of the root element of the document.
205
		}
301
     * @param root The name of the root element of the document.
206
	}
302
     * @param uri The document URI.
303
     * @param r an XMLReaderInstance
304
     * @exception IOException if an error occured while reading the document.
305
     */
306
    public Document createDocument(String ns, String root, String uri,
307
                                   XMLReader r) throws IOException {
308
        r.setContentHandler(this);
309
        r.setDTDHandler(this);
310
        r.setEntityResolver(this);
311
        try {
312
            r.parse(uri);
313
        } catch (SAXException e) {
314
            Exception ex = e.getException();
315
            if (ex != null && ex instanceof InterruptedIOException) {
316
                throw (InterruptedIOException) ex;
317
            }
318
            throw new SAXIOException(e);
319
        }
320
        currentNode = null;
321
        Document ret = document;
322
        document = null;
323
        return ret;
324
    }
325
207
326
    /**
208
	/**
327
     * Creates a Document instance.
209
	 * Various elements encountered prior to real document root element. List of
328
     * @param uri The document URI.
210
	 * PreInfo objects.
329
     * @param r The document reader.
211
	 */
330
     * @exception IOException if an error occured while reading the document.
212
	protected List preInfo;
331
     */
332
    public Document createDocument(String uri, Reader r) throws IOException {
333
        InputSource inp = new InputSource(r);
334
        inp.setSystemId(uri);
335
        return createDocument(inp);
336
    }
337
213
338
    /**
214
	/**
339
     * Creates a Document.
215
	 * Creates a new SAXDocumentFactory object. No document descriptor will be
340
     * @param ns The namespace URI of the root element.
216
	 * created while generating a document.
341
     * @param root The name of the root element.
217
	 * 
342
     * @param uri The document URI.
218
	 * @param impl
343
     * @param is  The document input source.
219
	 *            The DOM implementation to use for building the DOM tree.
344
     * @exception IOException if an error occured while reading the document.
220
	 * @param parser
345
     */
221
	 *            The SAX2 parser classname.
346
    protected Document createDocument(String ns, String root, String uri,
222
	 */
347
                                      InputSource is)
223
	public SAXDocumentFactory(DOMImplementation impl, String parser) {
348
        throws IOException {
224
		implementation = impl;
349
        Document ret = createDocument(is);
225
		parserClassName = parser;
350
        Element docElem = ret.getDocumentElement();
226
	}
351
227
352
        String lname = root;
228
	/**
353
        String nsURI = ns;
229
	 * Creates a new SAXDocumentFactory object.
354
        if (ns == null) {
230
	 * 
355
            int idx = lname.indexOf(':');
231
	 * @param impl
356
            String nsp = (idx == -1 || idx == lname.length()-1)
232
	 *            The DOM implementation to use for building the DOM tree.
357
                ? ""
233
	 * @param parser
358
                : lname.substring(0, idx);
234
	 *            The SAX2 parser classname.
359
            nsURI = namespaces.get(nsp);
235
	 * @param dd
360
            if (idx != -1 && idx != lname.length()-1) {
236
	 *            Whether a document descriptor must be generated.
361
                lname = lname.substring(idx+1);
237
	 */
362
            }
238
	public SAXDocumentFactory(DOMImplementation impl, String parser, boolean dd) {
363
        }
239
		implementation = impl;
240
		parserClassName = parser;
241
		createDocumentDescriptor = dd;
242
	}
364
243
244
	/**
245
	 * Creates a Document instance.
246
	 * 
247
	 * @param ns
248
	 *            The namespace URI of the root element of the document.
249
	 * @param root
250
	 *            The name of the root element of the document.
251
	 * @param uri
252
	 *            The document URI.
253
	 * @exception IOException
254
	 *                if an error occured while reading the document.
255
	 */
256
	public Document createDocument(String ns, String root, String uri)
257
			throws IOException {
258
		return createDocument(ns, root, uri, new InputSource(uri));
259
	}
365
260
366
        String docElemNS = docElem.getNamespaceURI();
261
	/**
367
        if ((docElemNS != nsURI) &&
262
	 * Creates a Document instance.
368
            ((docElemNS == null) || (!docElemNS.equals(nsURI))))
263
	 * 
369
            throw new IOException
264
	 * @param uri
370
                ("Root element namespace does not match that requested:\n" +
265
	 *            The document URI.
371
                 "Requested: " + nsURI + "\n" +
266
	 * @exception IOException
372
                 "Found: " + docElemNS);
267
	 *                if an error occured while reading the document.
268
	 */
269
	public Document createDocument(String uri) throws IOException {
270
		return createDocument(new InputSource(uri));
271
	}
373
272
374
        if (docElemNS != null) {
273
	/**
375
            if (!docElem.getLocalName().equals(lname))
274
	 * Creates a Document instance.
376
                throw new IOException
275
	 * 
377
                    ("Root element does not match that requested:\n" +
276
	 * @param ns
378
                     "Requested: " + lname + "\n" +
277
	 *            The namespace URI of the root element of the document.
379
                     "Found: " + docElem.getLocalName());
278
	 * @param root
380
        } else {
279
	 *            The name of the root element of the document.
381
            if (!docElem.getNodeName().equals(lname))
280
	 * @param uri
382
                throw new IOException
281
	 *            The document URI.
383
                    ("Root element does not match that requested:\n" +
282
	 * @param is
384
                     "Requested: " + lname + "\n" +
283
	 *            The document input stream.
385
                     "Found: " + docElem.getNodeName());
284
	 * @exception IOException
386
        }
285
	 *                if an error occured while reading the document.
286
	 */
287
	public Document createDocument(String ns, String root, String uri,
288
			InputStream is) throws IOException {
289
		InputSource inp = new InputSource(is);
290
		inp.setSystemId(uri);
291
		return createDocument(ns, root, uri, inp);
292
	}
387
293
388
        return ret;
294
	/**
389
    }
295
	 * Creates a Document instance.
296
	 * 
297
	 * @param uri
298
	 *            The document URI.
299
	 * @param is
300
	 *            The document input stream.
301
	 * @exception IOException
302
	 *                if an error occured while reading the document.
303
	 */
304
	public Document createDocument(String uri, InputStream is)
305
			throws IOException {
306
		InputSource inp = new InputSource(is);
307
		inp.setSystemId(uri);
308
		return createDocument(inp);
309
	}
390
310
391
    static SAXParserFactory saxFactory;
311
	/**
392
    static {
312
	 * Creates a Document instance.
393
        saxFactory = SAXParserFactory.newInstance();
313
	 * 
394
    }
314
	 * @param ns
315
	 *            The namespace URI of the root element of the document.
316
	 * @param root
317
	 *            The name of the root element of the document.
318
	 * @param uri
319
	 *            The document URI.
320
	 * @param r
321
	 *            The document reader.
322
	 * @exception IOException
323
	 *                if an error occured while reading the document.
324
	 */
325
	public Document createDocument(String ns, String root, String uri, Reader r)
326
			throws IOException {
327
		InputSource inp = new InputSource(r);
328
		inp.setSystemId(uri);
329
		return createDocument(ns, root, uri, inp);
330
	}
395
331
396
    /**
332
	/**
397
     * Creates a Document.
333
	 * Creates a Document instance.
398
     * @param is  The document input source.
334
	 * 
399
     * @exception IOException if an error occured while reading the document.
335
	 * @param ns
400
     */
336
	 *            The namespace URI of the root element of the document.
401
    protected Document createDocument(InputSource is)
337
	 * @param root
402
        throws IOException {
338
	 *            The name of the root element of the document.
403
        try {
339
	 * @param uri
404
            if (parserClassName != null) {
340
	 *            The document URI.
405
                parser = XMLReaderFactory.createXMLReader(parserClassName);
341
	 * @param r
406
            } else {
342
	 *            an XMLReaderInstance
407
                SAXParser saxParser;
343
	 * @exception IOException
408
                try {
344
	 *                if an error occured while reading the document.
409
                    saxParser = saxFactory.newSAXParser();
345
	 */
410
                } catch (ParserConfigurationException pce) {
346
	public Document createDocument(String ns, String root, String uri,
411
                    throw new IOException("Could not create SAXParser: "
347
			XMLReader r) throws IOException {
412
                            + pce.getMessage());
348
		r.setContentHandler(this);
413
                }
349
		r.setDTDHandler(this);
414
                parser = saxParser.getXMLReader();
350
		r.setEntityResolver(this);
415
            }
351
		try {
352
			r.parse(uri);
353
		} catch (SAXException e) {
354
			Exception ex = e.getException();
355
			if (ex != null && ex instanceof InterruptedIOException) {
356
				throw (InterruptedIOException) ex;
357
			}
358
			throw new SAXIOException(e);
359
		}
360
		currentNode = null;
361
		Document ret = document;
362
		document = null;
363
		return ret;
364
	}
416
365
417
            parser.setContentHandler(this);
366
	/**
418
            parser.setDTDHandler(this);
367
	 * Creates a Document instance.
419
            parser.setEntityResolver(this);
368
	 * 
420
            parser.setErrorHandler((errorHandler == null) ?
369
	 * @param uri
421
                                   this : errorHandler);
370
	 *            The document URI.
371
	 * @param r
372
	 *            The document reader.
373
	 * @exception IOException
374
	 *                if an error occured while reading the document.
375
	 */
376
	public Document createDocument(String uri, Reader r) throws IOException {
377
		InputSource inp = new InputSource(r);
378
		inp.setSystemId(uri);
379
		return createDocument(inp);
380
	}
422
381
423
            parser.setFeature("http://xml.org/sax/features/namespaces",
382
	/**
424
                              true);
383
	 * Creates a Document.
425
            parser.setFeature("http://xml.org/sax/features/namespace-prefixes",
384
	 * 
426
                              true);
385
	 * @param ns
427
            parser.setFeature("http://xml.org/sax/features/validation",
386
	 *            The namespace URI of the root element.
428
                              isValidating);
387
	 * @param root
429
            parser.setProperty("http://xml.org/sax/properties/lexical-handler",
388
	 *            The name of the root element.
430
                               this);
389
	 * @param uri
431
            parser.parse(is);
390
	 *            The document URI.
432
        } catch (SAXException e) {
391
	 * @param is
433
            Exception ex = e.getException();
392
	 *            The document input source.
434
            if (ex != null && ex instanceof InterruptedIOException) {
393
	 * @exception IOException
435
                throw (InterruptedIOException)ex;
394
	 *                if an error occured while reading the document.
436
            }
395
	 */
437
            throw new SAXIOException(e);
396
	protected Document createDocument(String ns, String root, String uri,
438
        }
397
			InputSource is) throws IOException {
398
		Document ret = createDocument(is);
399
		Element docElem = ret.getDocumentElement();
439
400
440
        currentNode  = null;
401
		String lname = root;
441
        Document ret = document;
402
		String nsURI = ns;
442
        document     = null;
403
		if (ns == null) {
443
        locator      = null;
404
			int idx = lname.indexOf(':');
444
        parser       = null;
405
			String nsp = (idx == -1 || idx == lname.length() - 1) ? "" : lname
445
        return ret;
406
					.substring(0, idx);
446
    }
407
			nsURI = namespaces.get(nsp);
408
			if (idx != -1 && idx != lname.length() - 1) {
409
				lname = lname.substring(idx + 1);
410
			}
411
		}
447
412
448
    /**
413
		String docElemNS = docElem.getNamespaceURI();
449
     * Returns the document descriptor associated with the latest created
414
		if ((docElemNS != nsURI)
450
     * document.
415
				&& ((docElemNS == null) || (!docElemNS.equals(nsURI))))
451
     * @return null if no document or descriptor was previously generated.
416
			throw new IOException(
452
     */
417
					"Root element namespace does not match that requested:\n"
453
    public DocumentDescriptor getDocumentDescriptor() {
418
							+ "Requested: " + nsURI + "\n" + "Found: "
454
        return documentDescriptor;
419
							+ docElemNS);
455
    }
456
420
457
    /**
421
		if (docElemNS != null) {
458
     * <b>SAX</b>: Implements {@link
422
			if (!docElem.getLocalName().equals(lname))
459
     * org.xml.sax.ContentHandler#setDocumentLocator(Locator)}.
423
				throw new IOException(
460
     */
424
						"Root element does not match that requested:\n"
461
    public void setDocumentLocator(Locator l) {
425
								+ "Requested: " + lname + "\n" + "Found: "
462
        locator = l;
426
								+ docElem.getLocalName());
463
    }
427
		} else {
428
			if (!docElem.getNodeName().equals(lname))
429
				throw new IOException(
430
						"Root element does not match that requested:\n"
431
								+ "Requested: " + lname + "\n" + "Found: "
432
								+ docElem.getNodeName());
433
		}
464
434
465
    /**
435
		return ret;
466
     * Sets whether or not the XML parser will validate the XML document
436
	}
467
     * depending on the specified parameter.
468
     *
469
     * @param isValidating indicates that the XML parser will validate the XML
470
     * document
471
     */
472
    public void setValidating(boolean isValidating) {
473
        this.isValidating = isValidating;
474
    }
475
437
476
    /**
438
	static SAXParserFactory saxFactory;
477
     * Returns true if the XML parser validates the XML stream, false
439
	static {
478
     * otherwise.
440
		saxFactory = SAXParserFactory.newInstance();
479
     */
441
	}
480
    public boolean isValidating() {
481
        return isValidating;
482
    }
483
442
484
    /**
443
	/**
485
     * Sets a custom error handler.
444
	 * Creates a Document.
486
     */
445
	 * 
487
    public void setErrorHandler(ErrorHandler eh) {
446
	 * @param is
488
        errorHandler = eh;
447
	 *            The document input source.
489
    }
448
	 * @exception IOException
449
	 *                if an error occured while reading the document.
450
	 */
451
	protected Document createDocument(InputSource is) throws IOException {
452
		try {
453
			if (parserClassName != null) {
454
				parser = XMLReaderFactory.createXMLReader(parserClassName);
455
			} else {
456
				SAXParser saxParser;
457
				try {
458
					saxParser = saxFactory.newSAXParser();
459
				} catch (ParserConfigurationException pce) {
460
					throw new IOException("Could not create SAXParser: "
461
							+ pce.getMessage());
462
				}
463
				parser = saxParser.getXMLReader();
464
			}
490
465
491
    public DOMImplementation getDOMImplementation(String ver) {
466
			parser.setContentHandler(this);
492
        return implementation;
467
			parser.setDTDHandler(this);
493
    }
468
			parser.setEntityResolver(this);
469
			parser
470
					.setErrorHandler((errorHandler == null) ? this
471
							: errorHandler);
494
472
495
    /**
473
			parser.setFeature("http://xml.org/sax/features/namespaces", true);
496
     * <b>SAX</b>: Implements {@link
474
			parser.setFeature("http://xml.org/sax/features/namespace-prefixes",
497
     * org.xml.sax.ErrorHandler#fatalError(SAXParseException)}.
475
					true);
498
     */
476
			parser.setFeature("http://xml.org/sax/features/validation",
499
    public void fatalError(SAXParseException ex) throws SAXException {
477
					isValidating);
500
        throw ex;
478
			parser.setProperty("http://xml.org/sax/properties/lexical-handler",
501
    }
479
					this);
480
			parser.parse(is);
481
		} catch (SAXException e) {
482
			Exception ex = e.getException();
483
			if (ex != null && ex instanceof InterruptedIOException) {
484
				throw (InterruptedIOException) ex;
485
			}
486
			throw new SAXIOException(e);
487
		}
502
488
503
    /**
489
		currentNode = null;
504
     * <b>SAX</b>: Implements {@link
490
		Document ret = document;
505
     * org.xml.sax.ErrorHandler#error(SAXParseException)}.
491
		document = null;
506
     */
492
		locator = null;
507
    public void error(SAXParseException ex) throws SAXException {
493
		parser = null;
508
        throw ex;
494
		return ret;
509
    }
495
	}
510
496
511
    /**
497
	/**
512
     * <b>SAX</b>: Implements {@link
498
	 * Returns the document descriptor associated with the latest created
513
     * org.xml.sax.ErrorHandler#warning(SAXParseException)}.
499
	 * document.
514
     */
500
	 * 
515
    public void warning(SAXParseException ex) throws SAXException {
501
	 * @return null if no document or descriptor was previously generated.
516
    }
502
	 */
503
	public DocumentDescriptor getDocumentDescriptor() {
504
		return documentDescriptor;
505
	}
517
506
518
    /**
507
	/**
519
     * <b>SAX</b>: Implements {@link
508
	 * <b>SAX</b>: Implements {@link
520
     * org.xml.sax.ContentHandler#startDocument()}.
509
	 * org.xml.sax.ContentHandler#setDocumentLocator(Locator)}.
521
     */
510
	 */
522
    public void startDocument() throws SAXException {
511
	public void setDocumentLocator(Locator l) {
523
        preInfo    = new LinkedList();
512
		locator = l;
524
        namespaces = new HashTableStack();
513
	}
525
        namespaces.put("xml", XMLSupport.XML_NAMESPACE_URI);
526
        namespaces.put("xmlns", XMLSupport.XMLNS_NAMESPACE_URI);
527
        namespaces.put("", null);
528
514
529
        inDTD        = false;
515
	/**
530
        inCDATA      = false;
516
	 * Sets whether or not the XML parser will validate the XML document
531
        inProlog     = true;
517
	 * depending on the specified parameter.
532
        currentNode  = null;
518
	 * 
533
        document     = null;
519
	 * @param isValidating
534
        isStandalone = false;
520
	 *            indicates that the XML parser will validate the XML document
535
        xmlVersion   = XMLConstants.XML_VERSION_10;
521
	 */
522
	public void setValidating(boolean isValidating) {
523
		this.isValidating = isValidating;
524
	}
536
525
537
        stringBuffer.setLength(0);
526
	/**
538
        stringContent = false;
527
	 * Returns true if the XML parser validates the XML stream, false otherwise.
528
	 */
529
	public boolean isValidating() {
530
		return isValidating;
531
	}
539
532
540
        if (createDocumentDescriptor) {
533
	/**
541
            documentDescriptor = new DocumentDescriptor();
534
	 * Sets a custom error handler.
542
        } else {
535
	 */
543
            documentDescriptor = null;
536
	public void setErrorHandler(ErrorHandler eh) {
544
        }
537
		errorHandler = eh;
545
    }
538
	}
546
539
547
    /**
540
	public DOMImplementation getDOMImplementation(String ver) {
548
     * <b>SAX</b>: Implements {@link
541
		return implementation;
549
     * org.xml.sax.ContentHandler#startElement(String,String,String,Attributes)}.
542
	}
550
     */
551
    public void startElement(String     uri,
552
                             String     localName,
553
                             String     rawName,
554
                             Attributes attributes) throws SAXException {
555
        // Check If we should halt early.
556
        if (HaltingThread.hasBeenHalted()) {
557
            throw new SAXException(new InterruptedIOException());
558
        }
559
543
560
        if (inProlog) {
544
	/**
561
            inProlog = false;
545
	 * <b>SAX</b>: Implements {@link
562
            try {
546
	 * org.xml.sax.ErrorHandler#fatalError(SAXParseException)}.
563
                isStandalone = parser.getFeature
547
	 */
564
                    ("http://xml.org/sax/features/is-standalone");
548
	public void fatalError(SAXParseException ex) throws SAXException {
565
            } catch (SAXNotRecognizedException ex) {
549
		throw ex;
566
            }
550
	}
567
            try {
568
                xmlVersion = (String) parser.getProperty
569
                    ("http://xml.org/sax/properties/document-xml-version");
570
            } catch (SAXNotRecognizedException ex) {
571
            }
572
        }
573
551
574
        // Namespaces resolution
552
	/**
575
        int len = attributes.getLength();
553
	 * <b>SAX</b>: Implements {@link
576
        namespaces.push();
554
	 * org.xml.sax.ErrorHandler#error(SAXParseException)}.
577
        String version = null;
555
	 */
578
        for (int i = 0; i < len; i++) {
556
	public void error(SAXParseException ex) throws SAXException {
579
            String aname = attributes.getQName(i);
557
		throw ex;
580
            int slen = aname.length();
558
	}
581
            if (slen < 5)
582
                continue;
583
            if (aname.equals("version")) {
584
                version = attributes.getValue(i);
585
                continue;
586
            }
587
            if (!aname.startsWith("xmlns"))
588
                continue;
589
            if (slen == 5) {
590
                String ns = attributes.getValue(i);
591
                if (ns.length() == 0)
592
                    ns = null;
593
                namespaces.put("", ns);
594
            } else if (aname.charAt(5) == ':') {
595
                String ns = attributes.getValue(i);
596
                if (ns.length() == 0) {
597
                    ns = null;
598
                }
599
                namespaces.put(aname.substring(6), ns);
600
            }
601
        }
602
559
603
        // Add any collected String Data before element.
560
	/**
604
        appendStringData();
561
	 * <b>SAX</b>: Implements {@link
562
	 * org.xml.sax.ErrorHandler#warning(SAXParseException)}.
563
	 */
564
	public void warning(SAXParseException ex) throws SAXException {
565
	}
605
566
606
        // Element creation
567
	/**
607
        Element e;
568
	 * <b>SAX</b>: Implements {@link
608
        int idx = rawName.indexOf(':');
569
	 * org.xml.sax.ContentHandler#startDocument()}.
609
        String nsp = (idx == -1 || idx == rawName.length()-1)
570
	 */
610
            ? ""
571
	public void startDocument() throws SAXException {
611
            : rawName.substring(0, idx);
572
		preInfo = new LinkedList();
612
        String nsURI = namespaces.get(nsp);
573
		namespaces = new HashTableStack();
613
        if (currentNode == null) {
574
		namespaces.put("xml", XMLSupport.XML_NAMESPACE_URI);
614
            implementation = getDOMImplementation(version);
575
		namespaces.put("xmlns", XMLSupport.XMLNS_NAMESPACE_URI);
615
            document = implementation.createDocument(nsURI, rawName, null);
576
		namespaces.put("", null);
616
            Iterator i = preInfo.iterator();
617
            currentNode = e = document.getDocumentElement();
618
            while (i.hasNext()) {
619
                PreInfo pi = (PreInfo)i.next();
620
                Node n = pi.createNode(document);
621
                document.insertBefore(n, e);
622
            }
623
            preInfo = null;
624
        } else {
625
            e = document.createElementNS(nsURI, rawName);
626
            currentNode.appendChild(e);
627
            currentNode = e;
628
        }
629
577
630
        // Storage of the line number.
578
		inDTD = false;
631
        if (createDocumentDescriptor && locator != null) {
579
		inCDATA = false;
632
            documentDescriptor.setLocation(e,
580
		inProlog = true;
633
                                           locator.getLineNumber(),
581
		currentNode = null;
634
                                           locator.getColumnNumber());
582
		document = null;
635
        }
583
		isStandalone = false;
584
		xmlVersion = XMLConstants.XML_VERSION_10;
636
585
637
        // Attributes creation
586
		stringBuffer = new StringBuffer();
638
        for (int i = 0; i < len; i++) {
587
		stringContent = false;
639
            String aname = attributes.getQName(i);
640
            if (aname.equals("xmlns")) {
641
                e.setAttributeNS(XMLSupport.XMLNS_NAMESPACE_URI,
642
                                 aname,
643
                                 attributes.getValue(i));
644
            } else {
645
                idx = aname.indexOf(':');
646
                nsURI = (idx == -1)
647
                    ? null
648
                    : namespaces.get(aname.substring(0, idx));
649
                e.setAttributeNS(nsURI, aname, attributes.getValue(i));
650
            }
651
        }
652
    }
653
588
654
    /**
589
		if (createDocumentDescriptor) {
655
     * <b>SAX</b>: Implements {@link
590
			documentDescriptor = new DocumentDescriptor();
656
     * org.xml.sax.ContentHandler#endElement(String,String,String)}.
591
		} else {
657
     */
592
			documentDescriptor = null;
658
    public void endElement(String uri, String localName, String rawName)
593
		}
659
        throws SAXException {
594
	}
660
        appendStringData(); // add string data if any.
661
595
662
        if (currentNode != null)
596
	/**
663
            currentNode = currentNode.getParentNode();
597
	 * <b>SAX</b>: Implements {@link
664
        namespaces.pop();
598
	 * org.xml.sax.ContentHandler#startElement(String,String,String,Attributes)}.
665
    }
599
	 */
600
	public void startElement(String uri, String localName, String rawName,
601
			Attributes attributes) throws SAXException {
602
		// Check If we should halt early.
603
		if (HaltingThread.hasBeenHalted()) {
604
			throw new SAXException(new InterruptedIOException());
605
		}
666
606
667
    public void appendStringData() {
607
		if (inProlog) {
668
        if (!stringContent) return;
608
			inProlog = false;
609
			try {
610
				isStandalone = parser
611
						.getFeature("http://xml.org/sax/features/is-standalone");
612
			} catch (SAXNotRecognizedException ex) {
613
			}
614
			try {
615
				xmlVersion = (String) parser
616
						.getProperty("http://xml.org/sax/properties/document-xml-version");
617
			} catch (SAXNotRecognizedException ex) {
618
			}
619
		}
669
620
670
        String str = stringBuffer.toString();
621
		// Namespaces resolution
671
        stringBuffer.setLength(0); // reuse buffer.
622
		int len = attributes.getLength();
672
        stringContent = false;
623
		namespaces.push();
673
        if (currentNode == null) {
624
		String version = null;
674
            if (inCDATA) preInfo.add(new CDataInfo(str));
625
		for (int i = 0; i < len; i++) {
675
            else         preInfo.add(new TextInfo(str));
626
			String aname = attributes.getQName(i);
676
        } else {
627
			int slen = aname.length();
677
            Node n;
628
			if (slen < 5)
678
            if (inCDATA) n = document.createCDATASection(str);
629
				continue;
679
            else         n = document.createTextNode(str);
630
			if (aname.equals("version")) {
680
            currentNode.appendChild(n);
631
				version = attributes.getValue(i);
681
        }
632
				continue;
682
    }
633
			}
634
			if (!aname.startsWith("xmlns"))
635
				continue;
636
			if (slen == 5) {
637
				String ns = attributes.getValue(i);
638
				if (ns.length() == 0)
639
					ns = null;
640
				namespaces.put("", ns);
641
			} else if (aname.charAt(5) == ':') {
642
				String ns = attributes.getValue(i);
643
				if (ns.length() == 0) {
644
					ns = null;
645
				}
646
				namespaces.put(aname.substring(6), ns);
647
			}
648
		}
683
649
684
    /**
650
		// Add any collected String Data before element.
685
     * <b>SAX</b>: Implements {@link
651
		appendStringData();
686
     * org.xml.sax.ContentHandler#characters(char[],int,int)}.
687
     */
688
    public void characters(char[] ch, int start, int length)
689
        throws SAXException {
690
        stringBuffer.append(ch, start, length);
691
        stringContent = true;
692
    }
693
652
653
		// Element creation
654
		Element e;
655
		int idx = rawName.indexOf(':');
656
		String nsp = (idx == -1 || idx == rawName.length() - 1) ? "" : rawName
657
				.substring(0, idx);
658
		String nsURI = namespaces.get(nsp);
659
		if (currentNode == null) {
660
			implementation = getDOMImplementation(version);
661
			document = implementation.createDocument(nsURI, rawName, null);
662
			Iterator i = preInfo.iterator();
663
			currentNode = e = document.getDocumentElement();
664
			while (i.hasNext()) {
665
				PreInfo pi = (PreInfo) i.next();
666
				Node n = pi.createNode(document);
667
				document.insertBefore(n, e);
668
			}
669
			preInfo = null;
670
		} else {
671
			e = document.createElementNS(nsURI, rawName);
672
			currentNode.appendChild(e);
673
			currentNode = e;
674
		}
694
675
695
    /**
676
		// Storage of the line number.
696
     * <b>SAX</b>: Implements {@link
677
		if (createDocumentDescriptor && locator != null) {
697
     * org.xml.sax.ContentHandler#ignorableWhitespace(char[],int,int)}.
678
			documentDescriptor.setLocation(e, locator.getLineNumber(), locator
698
     */
679
					.getColumnNumber());
699
    public void ignorableWhitespace(char[] ch,
680
		}
700
                                    int start,
701
                                    int length)
702
        throws SAXException {
703
        stringBuffer.append(ch, start, length);
704
        stringContent = true;
705
    }
706
681
707
    /**
682
		// Attributes creation
708
     * <b>SAX</b>: Implements {@link
683
		for (int i = 0; i < len; i++) {
709
     * org.xml.sax.ContentHandler#processingInstruction(String,String)}.
684
			String aname = attributes.getQName(i);
710
     */
685
			if (aname.equals("xmlns")) {
711
    public void processingInstruction(String target, String data)
686
				e.setAttributeNS(XMLSupport.XMLNS_NAMESPACE_URI, aname,
712
        throws SAXException {
687
						attributes.getValue(i));
713
        if (inDTD)
688
			} else {
714
            return;
689
				idx = aname.indexOf(':');
690
				nsURI = (idx == -1) ? null : namespaces.get(aname.substring(0,
691
						idx));
692
				e.setAttributeNS(nsURI, aname, attributes.getValue(i));
693
			}
694
		}
695
	}
715
696
716
        appendStringData(); // Add any collected String Data before PI
697
	/**
698
	 * <b>SAX</b>: Implements {@link
699
	 * org.xml.sax.ContentHandler#endElement(String,String,String)}.
700
	 */
701
	public void endElement(String uri, String localName, String rawName)
702
			throws SAXException {
703
		appendStringData(); // add string data if any.
717
704
718
        if (currentNode == null)
705
		if (currentNode != null)
719
            preInfo.add(new ProcessingInstructionInfo(target, data));
706
			currentNode = currentNode.getParentNode();
720
        else
707
		namespaces.pop();
721
            currentNode.appendChild
708
	}
722
                (document.createProcessingInstruction(target, data));
723
    }
724
709
725
    // LexicalHandler /////////////////////////////////////////////////////////
710
	public void appendStringData() {
711
		if (!stringContent)
712
			return;
726
713
727
    /**
714
		String str = stringBuffer.toString();
728
     * <b>SAX</b>: Implements {@link
715
		stringBuffer.setLength(0); // reuse buffer.
729
     * org.xml.sax.ext.LexicalHandler#startDTD(String,String,String)}.
716
		stringContent = false;
730
     */
717
		if (currentNode == null) {
731
    public void startDTD(String name, String publicId, String systemId)
718
			if (inCDATA)
732
        throws SAXException {
719
				preInfo.add(new CDataInfo(str));
733
        appendStringData(); // Add collected string data before entering DTD
720
			else
734
        inDTD = true;
721
				preInfo.add(new TextInfo(str));
735
    }
722
		} else {
723
			Node n;
724
			if (inCDATA)
725
				n = document.createCDATASection(str);
726
			else
727
				n = document.createTextNode(str);
728
			currentNode.appendChild(n);
729
		}
730
	}
736
731
737
    /**
732
	/**
738
     * <b>SAX</b>: Implements {@link org.xml.sax.ext.LexicalHandler#endDTD()}.
733
	 * <b>SAX</b>: Implements {@link
739
     */
734
	 * org.xml.sax.ContentHandler#characters(char[],int,int)}.
740
    public void endDTD() throws SAXException {
735
	 */
741
        inDTD = false;
736
	public void characters(char[] ch, int start, int length)
742
    }
737
			throws SAXException {
738
		stringBuffer.append(ch, start, length);
739
		stringContent = true;
740
	}
743
741
744
    /**
742
	/**
745
     * <b>SAX</b>: Implements
743
	 * <b>SAX</b>: Implements {@link
746
     * {@link org.xml.sax.ext.LexicalHandler#startEntity(String)}.
744
	 * org.xml.sax.ContentHandler#ignorableWhitespace(char[],int,int)}.
747
     */
745
	 */
748
    public void startEntity(String name) throws SAXException {
746
	public void ignorableWhitespace(char[] ch, int start, int length)
749
    }
747
			throws SAXException {
748
		stringBuffer.append(ch, start, length);
749
		stringContent = true;
750
	}
750
751
751
    /**
752
	/**
752
     * <b>SAX</b>: Implements
753
	 * <b>SAX</b>: Implements {@link
753
     * {@link org.xml.sax.ext.LexicalHandler#endEntity(String)}.
754
	 * org.xml.sax.ContentHandler#processingInstruction(String,String)}.
754
     */
755
	 */
755
    public void endEntity(String name) throws SAXException {
756
	public void processingInstruction(String target, String data)
756
    }
757
			throws SAXException {
758
		if (inDTD)
759
			return;
757
760
758
    /**
761
		appendStringData(); // Add any collected String Data before PI
759
     * <b>SAX</b>: Implements {@link
760
     * org.xml.sax.ext.LexicalHandler#startCDATA()}.
761
     */
762
    public void startCDATA() throws SAXException {
763
        appendStringData(); // Add any collected String Data before CData
764
        inCDATA       = true;
765
        stringContent = true; // always create CDATA even if empty.
766
    }
767
762
768
    /**
763
		if (currentNode == null)
769
     * <b>SAX</b>: Implements {@link
764
			preInfo.add(new ProcessingInstructionInfo(target, data));
770
     * org.xml.sax.ext.LexicalHandler#endCDATA()}.
765
		else
771
     */
766
			currentNode.appendChild(document.createProcessingInstruction(
772
    public void endCDATA() throws SAXException {
767
					target, data));
773
        appendStringData(); // Add the CDATA section
768
	}
774
        inCDATA = false;
775
    }
776
769
777
    /**
770
	// LexicalHandler /////////////////////////////////////////////////////////
778
     * <b>SAX</b>: Implements
779
     * {@link org.xml.sax.ext.LexicalHandler#comment(char[],int,int)}.
780
     */
781
    public void comment(char[] ch, int start, int length) throws SAXException {
782
        if (inDTD) return;
783
        appendStringData();
784
771
785
        String str = new String(ch, start, length);
772
	/**
786
        if (currentNode == null) {
773
	 * <b>SAX</b>: Implements {@link
787
            preInfo.add(new CommentInfo(str));
774
	 * org.xml.sax.ext.LexicalHandler#startDTD(String,String,String)}.
788
        } else {
775
	 */
789
            currentNode.appendChild(document.createComment(str));
776
	public void startDTD(String name, String publicId, String systemId)
790
        }
777
			throws SAXException {
791
    }
778
		appendStringData(); // Add collected string data before entering DTD
779
		inDTD = true;
780
	}
781
782
	/**
783
	 * <b>SAX</b>: Implements {@link org.xml.sax.ext.LexicalHandler#endDTD()}.
784
	 */
785
	public void endDTD() throws SAXException {
786
		inDTD = false;
787
	}
788
789
	/**
790
	 * <b>SAX</b>: Implements
791
	 * {@link org.xml.sax.ext.LexicalHandler#startEntity(String)}.
792
	 */
793
	public void startEntity(String name) throws SAXException {
794
	}
795
796
	/**
797
	 * <b>SAX</b>: Implements
798
	 * {@link org.xml.sax.ext.LexicalHandler#endEntity(String)}.
799
	 */
800
	public void endEntity(String name) throws SAXException {
801
	}
802
803
	/**
804
	 * <b>SAX</b>: Implements {@link
805
	 * org.xml.sax.ext.LexicalHandler#startCDATA()}.
806
	 */
807
	public void startCDATA() throws SAXException {
808
		appendStringData(); // Add any collected String Data before CData
809
		inCDATA = true;
810
		stringContent = true; // always create CDATA even if empty.
811
	}
812
813
	/**
814
	 * <b>SAX</b>: Implements {@link
815
	 * org.xml.sax.ext.LexicalHandler#endCDATA()}.
816
	 */
817
	public void endCDATA() throws SAXException {
818
		appendStringData(); // Add the CDATA section
819
		inCDATA = false;
820
	}
821
822
	/**
823
	 * <b>SAX</b>: Implements
824
	 * {@link org.xml.sax.ext.LexicalHandler#comment(char[],int,int)}.
825
	 */
826
	public void comment(char[] ch, int start, int length) throws SAXException {
827
		if (inDTD)
828
			return;
829
		appendStringData();
830
831
		String str = new String(ch, start, length);
832
		if (currentNode == null) {
833
			preInfo.add(new CommentInfo(str));
834
		} else {
835
			currentNode.appendChild(document.createComment(str));
836
		}
837
	}
792
}
838
}
(-)sources/org/apache/batik/swing/svg/SVGUserAgentGUIAdapter.java (-4 / +10 lines)
Lines 22-28 Link Here
22
import java.awt.Component;
22
import java.awt.Component;
23
import javax.swing.JDialog;
23
import javax.swing.JDialog;
24
import javax.swing.JOptionPane;
24
import javax.swing.JOptionPane;
25
26
import org.apache.batik.swing.JSVGCanvas;
27
import org.apache.batik.util.gui.ErrorConsole;
25
import org.apache.batik.util.gui.JErrorPane;
28
import org.apache.batik.util.gui.JErrorPane;
29
import org.apache.batik.util.gui.ErrorConsole.ErrorInfo;
26
30
27
/**
31
/**
28
 * One line Class Desc
32
 * One line Class Desc
Lines 53-62 Link Here
53
     * Displays an error resulting from the specified Exception.
57
     * Displays an error resulting from the specified Exception.
54
     */
58
     */
55
    public void displayError(Exception ex) {
59
    public void displayError(Exception ex) {
56
        JErrorPane pane = new JErrorPane(ex, JOptionPane.ERROR_MESSAGE);
60
//        JErrorPane pane = new JErrorPane(ex, JOptionPane.ERROR_MESSAGE);
57
        JDialog dialog = pane.createDialog(parentComponent, "ERROR");
61
    	ErrorConsole console = ErrorConsole.getInstance();
58
        dialog.setModal(false);
62
    	// <!FIX ME> Document is null for now, how to get access to it??
59
        dialog.setVisible(true);
63
    	ErrorInfo info = new ErrorInfo(ex, "Not available", ErrorConsole.ERROR);
64
    	console.add(info);
65
        ErrorConsole.showDialog(parentComponent);
60
    }
66
    }
61
67
62
    /**
68
    /**
(-)sources/org/apache/batik/swing/svg/SVGDocumentLoader.java (-2 / +2 lines)
Lines 73-79 Link Here
73
     */
73
     */
74
    public void run() {
74
    public void run() {
75
        SVGDocumentLoaderEvent evt;
75
        SVGDocumentLoaderEvent evt;
76
        evt = new SVGDocumentLoaderEvent(this, null);
76
        evt = new SVGDocumentLoaderEvent(this, null, null);
77
        try {
77
        try {
78
            fireEvent(startedDispatcher, evt);
78
            fireEvent(startedDispatcher, evt);
79
            if (isHalted()) {
79
            if (isHalted()) {
Lines 88-94 Link Here
88
                return;
88
                return;
89
            }
89
            }
90
90
91
            evt = new SVGDocumentLoaderEvent(this, svgDocument);
91
            evt = new SVGDocumentLoaderEvent(this, svgDocument, loader.getDocumentDescriptor(svgDocument));
92
            fireEvent(completedDispatcher, evt);
92
            fireEvent(completedDispatcher, evt);
93
        } catch (InterruptedIOException e) {
93
        } catch (InterruptedIOException e) {
94
            fireEvent(cancelledDispatcher, evt);
94
            fireEvent(cancelledDispatcher, evt);
(-)sources/org/apache/batik/swing/svg/SVGDocumentLoaderEvent.java (-1 / +16 lines)
Lines 20-25 Link Here
20
20
21
import java.util.EventObject;
21
import java.util.EventObject;
22
22
23
import org.apache.batik.dom.util.DocumentDescriptor;
23
import org.w3c.dom.svg.SVGDocument;
24
import org.w3c.dom.svg.SVGDocument;
24
25
25
/**
26
/**
Lines 37-50 Link Here
37
    protected SVGDocument svgDocument;
38
    protected SVGDocument svgDocument;
38
39
39
    /**
40
    /**
41
     * The document descriptor describing the document
42
     */
43
    protected DocumentDescriptor docDescriptor;
44
    
45
    /**
40
     * Creates a new SVGDocumentLoaderEvent.
46
     * Creates a new SVGDocumentLoaderEvent.
41
     * @param source the object that originated the event, ie. the
47
     * @param source the object that originated the event, ie. the
42
     *               SVGDocumentLoader.
48
     *               SVGDocumentLoader.
43
     * @param doc The associated document.
49
     * @param doc The associated document.
44
     */
50
     */
45
    public SVGDocumentLoaderEvent(Object source, SVGDocument doc) {
51
    public SVGDocumentLoaderEvent(Object source, SVGDocument doc, DocumentDescriptor desc) {
46
        super(source);
52
        super(source);
47
        svgDocument = doc;
53
        svgDocument = doc;
54
        docDescriptor = desc;
48
    }
55
    }
49
56
50
    /**
57
    /**
Lines 54-57 Link Here
54
    public SVGDocument getSVGDocument() {
61
    public SVGDocument getSVGDocument() {
55
        return svgDocument;
62
        return svgDocument;
56
    }
63
    }
64
    
65
    /**
66
     * Returns the document descriptor for this document, or null
67
     * if the document wasn't completely loaded
68
     */
69
    public DocumentDescriptor getDocumentDescriptor() {
70
    	return docDescriptor;
71
    }
57
}
72
}
(-)sources/org/apache/batik/swing/JSVGCanvas.java (-1022 / +1014 lines)
Lines 1-19 Link Here
1
/*
1
/*
2
2
3
   Licensed to the Apache Software Foundation (ASF) under one or more
3
 Licensed to the Apache Software Foundation (ASF) under one or more
4
   contributor license agreements.  See the NOTICE file distributed with
4
 contributor license agreements.  See the NOTICE file distributed with
5
   this work for additional information regarding copyright ownership.
5
 this work for additional information regarding copyright ownership.
6
   The ASF licenses this file to You under the Apache License, Version 2.0
6
 The ASF licenses this file to You under the Apache License, Version 2.0
7
   (the "License"); you may not use this file except in compliance with
7
 (the "License"); you may not use this file except in compliance with
8
   the License.  You may obtain a copy of the License at
8
 the License.  You may obtain a copy of the License at
9
9
10
       http://www.apache.org/licenses/LICENSE-2.0
10
 http://www.apache.org/licenses/LICENSE-2.0
11
11
12
   Unless required by applicable law or agreed to in writing, software
12
 Unless required by applicable law or agreed to in writing, software
13
   distributed under the License is distributed on an "AS IS" BASIS,
13
 distributed under the License is distributed on an "AS IS" BASIS,
14
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
   See the License for the specific language governing permissions and
15
 See the License for the specific language governing permissions and
16
   limitations under the License.
16
 limitations under the License.
17
17
18
 */
18
 */
19
package org.apache.batik.swing;
19
package org.apache.batik.swing;
Lines 57-64 Link Here
57
import org.apache.batik.swing.svg.SVGUserAgent;
57
import org.apache.batik.swing.svg.SVGUserAgent;
58
import org.apache.batik.util.SVGConstants;
58
import org.apache.batik.util.SVGConstants;
59
import org.apache.batik.util.XMLConstants;
59
import org.apache.batik.util.XMLConstants;
60
import org.apache.batik.util.gui.JErrorPane;
60
import org.apache.batik.util.gui.ErrorConsole;
61
61
import org.apache.batik.util.gui.ErrorConsole.ErrorInfo;
62
import org.w3c.dom.Element;
62
import org.w3c.dom.Element;
63
import org.w3c.dom.Node;
63
import org.w3c.dom.Node;
64
import org.w3c.dom.events.Event;
64
import org.w3c.dom.events.Event;
Lines 68-1232 Link Here
68
68
69
/**
69
/**
70
 * This class represents a general-purpose swing SVG component. The
70
 * This class represents a general-purpose swing SVG component. The
71
 * <tt>JSVGCanvas</tt> does not provided additional functionalities compared to
71
 * <tt>JSVGCanvas</tt> does not provided additional functionalities compared
72
 * the <tt>JSVGComponent</tt> but simply provides an API conformed to the
72
 * to the <tt>JSVGComponent</tt> but simply provides an API conformed to the
73
 * JavaBean specification. The only major change between the
73
 * JavaBean specification. The only major change between the
74
 * <tt>JSVGComponent</tt> and this component is that interactors and text
74
 * <tt>JSVGComponent</tt> and this component is that interactors and text
75
 * selection are activated by default.
75
 * selection are activated by default.
76
 *
76
 * 
77
 * @author <a href="mailto:tkormann@apache.org">Thierry Kormann</a>
77
 * @author <a href="mailto:tkormann@apache.org">Thierry Kormann</a>
78
 * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
78
 * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
79
 * @version $Id$
79
 * @version $Id$
80
 */
80
 */
81
public class JSVGCanvas extends JSVGComponent {
81
public class JSVGCanvas extends JSVGComponent {
82
82
83
    /**
83
	/**
84
     * The key for the Action to scroll right.
84
	 * The key for the Action to scroll right.
85
     */
85
	 */
86
    public static final String SCROLL_RIGHT_ACTION = "ScrollRight";
86
	public static final String SCROLL_RIGHT_ACTION = "ScrollRight";
87
87
88
    /**
88
	/**
89
     * The key for the Action to scroll left.
89
	 * The key for the Action to scroll left.
90
     */
90
	 */
91
    public static final String SCROLL_LEFT_ACTION = "ScrollLeft";
91
	public static final String SCROLL_LEFT_ACTION = "ScrollLeft";
92
92
93
    /**
93
	/**
94
     * The key for the Action to scroll up.
94
	 * The key for the Action to scroll up.
95
     */
95
	 */
96
    public static final String SCROLL_UP_ACTION = "ScrollUp";
96
	public static final String SCROLL_UP_ACTION = "ScrollUp";
97
97
98
    /**
98
	/**
99
     * The key for the Action to scroll down.
99
	 * The key for the Action to scroll down.
100
     */
100
	 */
101
    public static final String SCROLL_DOWN_ACTION = "ScrollDown";
101
	public static final String SCROLL_DOWN_ACTION = "ScrollDown";
102
102
103
    /**
103
	/**
104
     * The key for the Action to quickly scroll right.
104
	 * The key for the Action to quickly scroll right.
105
     */
105
	 */
106
    public static final String FAST_SCROLL_RIGHT_ACTION = "FastScrollRight";
106
	public static final String FAST_SCROLL_RIGHT_ACTION = "FastScrollRight";
107
107
108
    /**
108
	/**
109
     * The key for the Action to quickly scroll left.
109
	 * The key for the Action to quickly scroll left.
110
     */
110
	 */
111
    public static final String FAST_SCROLL_LEFT_ACTION = "FastScrollLeft";
111
	public static final String FAST_SCROLL_LEFT_ACTION = "FastScrollLeft";
112
112
113
    /**
113
	/**
114
     * The key for the Action to quickly scroll up.
114
	 * The key for the Action to quickly scroll up.
115
     */
115
	 */
116
    public static final String FAST_SCROLL_UP_ACTION = "FastScrollUp";
116
	public static final String FAST_SCROLL_UP_ACTION = "FastScrollUp";
117
117
118
    /**
118
	/**
119
     * The key for the Action to quickly scroll down.
119
	 * The key for the Action to quickly scroll down.
120
     */
120
	 */
121
    public static final String FAST_SCROLL_DOWN_ACTION = "FastScrollDown";
121
	public static final String FAST_SCROLL_DOWN_ACTION = "FastScrollDown";
122
122
123
    /**
123
	/**
124
     * The key for the Action to zoom in.
124
	 * The key for the Action to zoom in.
125
     */
125
	 */
126
    public static final String ZOOM_IN_ACTION = "ZoomIn";
126
	public static final String ZOOM_IN_ACTION = "ZoomIn";
127
127
128
    /**
128
	/**
129
     * The key for the Action to zoom out.
129
	 * The key for the Action to zoom out.
130
     */
130
	 */
131
    public static final String ZOOM_OUT_ACTION = "ZoomOut";
131
	public static final String ZOOM_OUT_ACTION = "ZoomOut";
132
132
133
    /**
133
	/**
134
     * The key for the Action to reset the transform.
134
	 * The key for the Action to reset the transform.
135
     */
135
	 */
136
    public static final String RESET_TRANSFORM_ACTION = "ResetTransform";
136
	public static final String RESET_TRANSFORM_ACTION = "ResetTransform";
137
137
138
    /**
138
	/**
139
     * This flag bit indicates whether or not the zoom interactor is
139
	 * This flag bit indicates whether or not the zoom interactor is enabled.
140
     * enabled. True means the zoom interactor is functional.
140
	 * True means the zoom interactor is functional.
141
     */
141
	 */
142
    private boolean isZoomInteractorEnabled = true;
142
	private boolean isZoomInteractorEnabled = true;
143
143
144
    /**
144
	/**
145
     * This flag bit indicates whether or not the image zoom interactor is
145
	 * This flag bit indicates whether or not the image zoom interactor is
146
     * enabled. True means the image zoom interactor is functional.
146
	 * enabled. True means the image zoom interactor is functional.
147
     */
147
	 */
148
    private boolean isImageZoomInteractorEnabled = true;
148
	private boolean isImageZoomInteractorEnabled = true;
149
149
150
    /**
150
	/**
151
     * This flag bit indicates whether or not the pan interactor is
151
	 * This flag bit indicates whether or not the pan interactor is enabled.
152
     * enabled. True means the pan interactor is functional.
152
	 * True means the pan interactor is functional.
153
     */
153
	 */
154
    private boolean isPanInteractorEnabled = true;
154
	private boolean isPanInteractorEnabled = true;
155
155
156
    /**
156
	/**
157
     * This flag bit indicates whether or not the rotate interactor is
157
	 * This flag bit indicates whether or not the rotate interactor is enabled.
158
     * enabled. True means the rotate interactor is functional.
158
	 * True means the rotate interactor is functional.
159
     */
159
	 */
160
    private boolean isRotateInteractorEnabled = true;
160
	private boolean isRotateInteractorEnabled = true;
161
161
162
    /**
162
	/**
163
     * This flag bit indicates whether or not the reset transform interactor is
163
	 * This flag bit indicates whether or not the reset transform interactor is
164
     * enabled. True means the reset transform interactor is functional.
164
	 * enabled. True means the reset transform interactor is functional.
165
     */
165
	 */
166
    private boolean isResetTransformInteractorEnabled = true;
166
	private boolean isResetTransformInteractorEnabled = true;
167
167
168
    /**
168
	/**
169
     * The <tt>PropertyChangeSupport</tt> used to fire
169
	 * The <tt>PropertyChangeSupport</tt> used to fire
170
     * <tt>PropertyChangeEvent</tt>.
170
	 * <tt>PropertyChangeEvent</tt>.
171
     */
171
	 */
172
    protected PropertyChangeSupport pcs = new PropertyChangeSupport(this);
172
	protected PropertyChangeSupport pcs = new PropertyChangeSupport(this);
173
173
174
    /**
174
	/**
175
     * The URI of the current document being displayed.
175
	 * The URI of the current document being displayed.
176
     */
176
	 */
177
    protected String uri;
177
	protected String uri;
178
178
179
    /**
179
	/**
180
     * Keeps track of the last known mouse position over the canvas.
180
	 * Keeps track of the last known mouse position over the canvas. This is
181
     * This is used for displaying tooltips at the right location.
181
	 * used for displaying tooltips at the right location.
182
     */
182
	 */
183
    protected LocationListener locationListener = new LocationListener();
183
	protected LocationListener locationListener = new LocationListener();
184
184
185
    /**
185
	/**
186
     * Mapping of elements to listeners so they can be removed,
186
	 * Mapping of elements to listeners so they can be removed, if the tooltip
187
     * if the tooltip is removed.
187
	 * is removed.
188
     */
188
	 */
189
    protected Map toolTipMap = null;
189
	protected Map toolTipMap = null;
190
    protected EventListener toolTipListener = new ToolTipModifier();
191
    protected EventTarget   lastTarget = null;
192
    protected Map toolTipDocs = null;
193
    /**
194
     * This is used as the value in the toolTipDocs WeakHashMap.
195
     * This way we can tell if a document has already been added.
196
     */
197
    protected static final Object MAP_TOKEN = new Object();
198
    /**
199
     * The time of the last tool tip event.
200
     */
201
    protected long lastToolTipEventTimeStamp;
202
190
203
    /**
191
	protected EventListener toolTipListener = new ToolTipModifier();
204
     * The target for which the last tool tip event was fired.
205
     */
206
    protected EventTarget lastToolTipEventTarget;
207
192
193
	protected EventTarget lastTarget = null;
208
194
195
	protected Map toolTipDocs = null;
209
196
210
    /**
197
	/**
211
     * Creates a new JSVGCanvas.
198
	 * This is used as the value in the toolTipDocs WeakHashMap. This way we can
212
     */
199
	 * tell if a document has already been added.
213
    public JSVGCanvas() {
200
	 */
214
        this(null, true, true);
201
	protected static final Object MAP_TOKEN = new Object();
215
        addMouseMotionListener(locationListener);
216
    }
217
202
218
    /**
203
	/**
219
     * Creates a new JSVGCanvas.
204
	 * The time of the last tool tip event.
220
     *
205
	 */
221
     * @param ua a SVGUserAgent instance or null.
206
	protected long lastToolTipEventTimeStamp;
222
     * @param eventsEnabled Whether the GVT tree should be reactive to mouse
223
     *                      and key events.
224
     * @param selectableText Whether the text should be selectable.
225
     */
226
    public JSVGCanvas(SVGUserAgent ua,
227
                      boolean eventsEnabled,
228
                      boolean selectableText) {
229
207
230
        super(ua, eventsEnabled, selectableText);
208
	/**
209
	 * The target for which the last tool tip event was fired.
210
	 */
211
	protected EventTarget lastToolTipEventTarget;
231
212
232
        setPreferredSize(new Dimension(200, 200));
213
	/**
233
        setMinimumSize(new Dimension(100, 100));
214
	 * Creates a new JSVGCanvas.
215
	 */
216
	public JSVGCanvas() {
217
		this(null, true, true);
218
		addMouseMotionListener(locationListener);
219
	}
234
220
235
        List intl = getInteractors();
221
	/**
236
        intl.add(zoomInteractor);
222
	 * Creates a new JSVGCanvas.
237
        intl.add(imageZoomInteractor);
223
	 * 
238
        intl.add(panInteractor);
224
	 * @param ua
239
        intl.add(rotateInteractor);
225
	 *            a SVGUserAgent instance or null.
240
        intl.add(resetTransformInteractor);
226
	 * @param eventsEnabled
227
	 *            Whether the GVT tree should be reactive to mouse and key
228
	 *            events.
229
	 * @param selectableText
230
	 *            Whether the text should be selectable.
231
	 */
232
	public JSVGCanvas(SVGUserAgent ua, boolean eventsEnabled,
233
			boolean selectableText) {
241
234
242
        installActions();
235
		super(ua, eventsEnabled, selectableText);
243
236
244
        if (eventsEnabled) {
237
		setPreferredSize(new Dimension(200, 200));
245
            addMouseListener(new MouseAdapter() {
238
		setMinimumSize(new Dimension(100, 100));
246
                public void mousePressed(MouseEvent evt) {
247
                    requestFocus();
248
                }
249
            });
250
239
251
            installKeyboardActions();
240
		List intl = getInteractors();
252
        }
241
		intl.add(zoomInteractor);
253
        addMouseMotionListener(locationListener);
242
		intl.add(imageZoomInteractor);
254
    }
243
		intl.add(panInteractor);
244
		intl.add(rotateInteractor);
245
		intl.add(resetTransformInteractor);
255
246
256
    /**
247
		installActions();
257
     * Builds the ActionMap of this canvas with a set of predefined
258
     * <tt>Action</tt>s.
259
     */
260
    protected void installActions() {
261
        ActionMap actionMap = getActionMap();
262
248
263
        actionMap.put(SCROLL_RIGHT_ACTION, new ScrollRightAction(10));
249
		if (eventsEnabled) {
264
        actionMap.put(SCROLL_LEFT_ACTION, new ScrollLeftAction(10));
250
			addMouseListener(new MouseAdapter() {
265
        actionMap.put(SCROLL_UP_ACTION, new ScrollUpAction(10));
251
				public void mousePressed(MouseEvent evt) {
266
        actionMap.put(SCROLL_DOWN_ACTION, new ScrollDownAction(10));
252
					requestFocus();
253
				}
254
			});
267
255
268
        actionMap.put(FAST_SCROLL_RIGHT_ACTION, new ScrollRightAction(30));
256
			installKeyboardActions();
269
        actionMap.put(FAST_SCROLL_LEFT_ACTION, new ScrollLeftAction(30));
257
		}
270
        actionMap.put(FAST_SCROLL_UP_ACTION, new ScrollUpAction(30));
258
		addMouseMotionListener(locationListener);
271
        actionMap.put(FAST_SCROLL_DOWN_ACTION, new ScrollDownAction(30));
259
	}
272
260
273
        actionMap.put(ZOOM_IN_ACTION, new ZoomInAction());
261
	/**
274
        actionMap.put(ZOOM_OUT_ACTION, new ZoomOutAction());
262
	 * Builds the ActionMap of this canvas with a set of predefined
263
	 * <tt>Action</tt>s.
264
	 */
265
	protected void installActions() {
266
		ActionMap actionMap = getActionMap();
275
267
276
        actionMap.put(RESET_TRANSFORM_ACTION, new ResetTransformAction());
268
		actionMap.put(SCROLL_RIGHT_ACTION, new ScrollRightAction(10));
277
    }
269
		actionMap.put(SCROLL_LEFT_ACTION, new ScrollLeftAction(10));
270
		actionMap.put(SCROLL_UP_ACTION, new ScrollUpAction(10));
271
		actionMap.put(SCROLL_DOWN_ACTION, new ScrollDownAction(10));
278
272
279
    public void setDisableInteractions(boolean b) {
273
		actionMap.put(FAST_SCROLL_RIGHT_ACTION, new ScrollRightAction(30));
280
        super.setDisableInteractions(b);
274
		actionMap.put(FAST_SCROLL_LEFT_ACTION, new ScrollLeftAction(30));
281
        ActionMap actionMap = getActionMap();
275
		actionMap.put(FAST_SCROLL_UP_ACTION, new ScrollUpAction(30));
276
		actionMap.put(FAST_SCROLL_DOWN_ACTION, new ScrollDownAction(30));
282
277
283
        actionMap.get(SCROLL_RIGHT_ACTION)     .setEnabled(!b);
278
		actionMap.put(ZOOM_IN_ACTION, new ZoomInAction());
284
        actionMap.get(SCROLL_LEFT_ACTION)      .setEnabled(!b);
279
		actionMap.put(ZOOM_OUT_ACTION, new ZoomOutAction());
285
        actionMap.get(SCROLL_UP_ACTION)        .setEnabled(!b);
286
        actionMap.get(SCROLL_DOWN_ACTION)      .setEnabled(!b);
287
280
288
        actionMap.get(FAST_SCROLL_RIGHT_ACTION).setEnabled(!b);
281
		actionMap.put(RESET_TRANSFORM_ACTION, new ResetTransformAction());
289
        actionMap.get(FAST_SCROLL_LEFT_ACTION) .setEnabled(!b);
282
	}
290
        actionMap.get(FAST_SCROLL_UP_ACTION)   .setEnabled(!b);
291
        actionMap.get(FAST_SCROLL_DOWN_ACTION) .setEnabled(!b);
292
283
293
        actionMap.get(ZOOM_IN_ACTION)          .setEnabled(!b);
284
	public void setDisableInteractions(boolean b) {
294
        actionMap.get(ZOOM_OUT_ACTION)         .setEnabled(!b);
285
		super.setDisableInteractions(b);
295
        actionMap.get(RESET_TRANSFORM_ACTION)  .setEnabled(!b);
286
		ActionMap actionMap = getActionMap();
296
    }
297
287
288
		actionMap.get(SCROLL_RIGHT_ACTION).setEnabled(!b);
289
		actionMap.get(SCROLL_LEFT_ACTION).setEnabled(!b);
290
		actionMap.get(SCROLL_UP_ACTION).setEnabled(!b);
291
		actionMap.get(SCROLL_DOWN_ACTION).setEnabled(!b);
298
292
299
        /**
293
		actionMap.get(FAST_SCROLL_RIGHT_ACTION).setEnabled(!b);
300
     * Builds the InputMap of this canvas with a set of predefined
294
		actionMap.get(FAST_SCROLL_LEFT_ACTION).setEnabled(!b);
301
     * <tt>Action</tt>s.
295
		actionMap.get(FAST_SCROLL_UP_ACTION).setEnabled(!b);
302
     */
296
		actionMap.get(FAST_SCROLL_DOWN_ACTION).setEnabled(!b);
303
    protected void installKeyboardActions() {
304
297
305
        InputMap inputMap = getInputMap(JComponent.WHEN_FOCUSED);
298
		actionMap.get(ZOOM_IN_ACTION).setEnabled(!b);
306
        KeyStroke key;
299
		actionMap.get(ZOOM_OUT_ACTION).setEnabled(!b);
300
		actionMap.get(RESET_TRANSFORM_ACTION).setEnabled(!b);
301
	}
307
302
308
        key = KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0);
303
	/**
309
        inputMap.put(key, SCROLL_RIGHT_ACTION);
304
	 * Builds the InputMap of this canvas with a set of predefined
305
	 * <tt>Action</tt>s.
306
	 */
307
	protected void installKeyboardActions() {
310
308
311
        key = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0);
309
		InputMap inputMap = getInputMap(JComponent.WHEN_FOCUSED);
312
        inputMap.put(key, SCROLL_LEFT_ACTION);
310
		KeyStroke key;
313
311
314
        key = KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0);
312
		key = KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0);
315
        inputMap.put(key, SCROLL_UP_ACTION);
313
		inputMap.put(key, SCROLL_RIGHT_ACTION);
316
314
317
        key = KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0);
315
		key = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0);
318
        inputMap.put(key, SCROLL_DOWN_ACTION);
316
		inputMap.put(key, SCROLL_LEFT_ACTION);
319
317
320
        key = KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, KeyEvent.SHIFT_MASK);
318
		key = KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0);
321
        inputMap.put(key, FAST_SCROLL_RIGHT_ACTION);
319
		inputMap.put(key, SCROLL_UP_ACTION);
322
320
323
        key = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, KeyEvent.SHIFT_MASK);
321
		key = KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0);
324
        inputMap.put(key, FAST_SCROLL_LEFT_ACTION);
322
		inputMap.put(key, SCROLL_DOWN_ACTION);
325
323
326
        key = KeyStroke.getKeyStroke(KeyEvent.VK_UP, KeyEvent.SHIFT_MASK);
324
		key = KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, KeyEvent.SHIFT_MASK);
327
        inputMap.put(key, FAST_SCROLL_UP_ACTION);
325
		inputMap.put(key, FAST_SCROLL_RIGHT_ACTION);
328
326
329
        key = KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, KeyEvent.SHIFT_MASK);
327
		key = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, KeyEvent.SHIFT_MASK);
330
        inputMap.put(key, FAST_SCROLL_DOWN_ACTION);
328
		inputMap.put(key, FAST_SCROLL_LEFT_ACTION);
331
329
332
        key = KeyStroke.getKeyStroke(KeyEvent.VK_I, KeyEvent.CTRL_MASK);
330
		key = KeyStroke.getKeyStroke(KeyEvent.VK_UP, KeyEvent.SHIFT_MASK);
333
        inputMap.put(key, ZOOM_IN_ACTION);
331
		inputMap.put(key, FAST_SCROLL_UP_ACTION);
334
332
335
        key = KeyStroke.getKeyStroke(KeyEvent.VK_O, KeyEvent.CTRL_MASK);
333
		key = KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, KeyEvent.SHIFT_MASK);
336
        inputMap.put(key, ZOOM_OUT_ACTION);
334
		inputMap.put(key, FAST_SCROLL_DOWN_ACTION);
337
335
338
        key = KeyStroke.getKeyStroke(KeyEvent.VK_T, KeyEvent.CTRL_MASK);
336
		key = KeyStroke.getKeyStroke(KeyEvent.VK_I, KeyEvent.CTRL_MASK);
339
        inputMap.put(key, RESET_TRANSFORM_ACTION);
337
		inputMap.put(key, ZOOM_IN_ACTION);
340
    }
341
338
342
    /**
339
		key = KeyStroke.getKeyStroke(KeyEvent.VK_O, KeyEvent.CTRL_MASK);
343
     * Adds the specified <tt>PropertyChangeListener</tt>.
340
		inputMap.put(key, ZOOM_OUT_ACTION);
344
     *
345
     * @param pcl the property change listener to add
346
     */
347
    public void addPropertyChangeListener(PropertyChangeListener pcl) {
348
        pcs.addPropertyChangeListener(pcl);
349
    }
350
341
351
    /**
342
		key = KeyStroke.getKeyStroke(KeyEvent.VK_T, KeyEvent.CTRL_MASK);
352
     * Removes the specified <tt>PropertyChangeListener</tt>.
343
		inputMap.put(key, RESET_TRANSFORM_ACTION);
353
     *
344
	}
354
     * @param pcl the property change listener to remove
355
     */
356
    public void removePropertyChangeListener(PropertyChangeListener pcl) {
357
        pcs.removePropertyChangeListener(pcl);
358
    }
359
345
360
    /**
346
	/**
361
     * Adds the specified <tt>PropertyChangeListener</tt> for the specified
347
	 * Adds the specified <tt>PropertyChangeListener</tt>.
362
     * property.
348
	 * 
363
     *
349
	 * @param pcl
364
     * @param propertyName the name of the property to listen on
350
	 *            the property change listener to add
365
     * @param pcl the property change listener to add
351
	 */
366
     */
352
	public void addPropertyChangeListener(PropertyChangeListener pcl) {
367
    public void addPropertyChangeListener(String propertyName,
353
		pcs.addPropertyChangeListener(pcl);
368
                                          PropertyChangeListener pcl) {
354
	}
369
        pcs.addPropertyChangeListener(propertyName, pcl);
370
    }
371
355
372
    /**
356
	/**
373
     * Removes the specified <tt>PropertyChangeListener</tt> for the specified
357
	 * Removes the specified <tt>PropertyChangeListener</tt>.
374
     * property.
358
	 * 
375
     *
359
	 * @param pcl
376
     * @param propertyName the name of the property that was listened on
360
	 *            the property change listener to remove
377
     * @param pcl the property change listener to remove
361
	 */
378
     */
362
	public void removePropertyChangeListener(PropertyChangeListener pcl) {
379
    public void removePropertyChangeListener(String propertyName,
363
		pcs.removePropertyChangeListener(pcl);
380
                                             PropertyChangeListener pcl) {
364
	}
381
        pcs.removePropertyChangeListener(propertyName, pcl);
382
    }
383
365
384
    /**
366
	/**
385
     * Determines whether the zoom interactor is enabled or not.
367
	 * Adds the specified <tt>PropertyChangeListener</tt> for the specified
386
     */
368
	 * property.
387
    public void setEnableZoomInteractor(boolean b) {
369
	 * 
388
        if (isZoomInteractorEnabled != b) {
370
	 * @param propertyName
389
            boolean oldValue = isZoomInteractorEnabled;
371
	 *            the name of the property to listen on
390
            isZoomInteractorEnabled = b;
372
	 * @param pcl
391
            if (isZoomInteractorEnabled) {
373
	 *            the property change listener to add
392
                getInteractors().add(zoomInteractor);
374
	 */
393
            } else {
375
	public void addPropertyChangeListener(String propertyName,
394
                getInteractors().remove(zoomInteractor);
376
			PropertyChangeListener pcl) {
395
            }
377
		pcs.addPropertyChangeListener(propertyName, pcl);
396
            pcs.firePropertyChange("enableZoomInteractor", oldValue, b);
378
	}
397
        }
398
    }
399
379
400
    /**
380
	/**
401
     * Returns true if the zoom interactor is enabled, false otherwise.
381
	 * Removes the specified <tt>PropertyChangeListener</tt> for the specified
402
     */
382
	 * property.
403
    public boolean getEnableZoomInteractor() {
383
	 * 
404
        return isZoomInteractorEnabled;
384
	 * @param propertyName
405
    }
385
	 *            the name of the property that was listened on
386
	 * @param pcl
387
	 *            the property change listener to remove
388
	 */
389
	public void removePropertyChangeListener(String propertyName,
390
			PropertyChangeListener pcl) {
391
		pcs.removePropertyChangeListener(propertyName, pcl);
392
	}
406
393
407
    /**
394
	/**
408
     * Determines whether the image zoom interactor is enabled or not.
395
	 * Determines whether the zoom interactor is enabled or not.
409
     */
396
	 */
410
    public void setEnableImageZoomInteractor(boolean b) {
397
	public void setEnableZoomInteractor(boolean b) {
411
        if (isImageZoomInteractorEnabled != b) {
398
		if (isZoomInteractorEnabled != b) {
412
            boolean oldValue = isImageZoomInteractorEnabled;
399
			boolean oldValue = isZoomInteractorEnabled;
413
            isImageZoomInteractorEnabled = b;
400
			isZoomInteractorEnabled = b;
414
            if (isImageZoomInteractorEnabled) {
401
			if (isZoomInteractorEnabled) {
415
                getInteractors().add(imageZoomInteractor);
402
				getInteractors().add(zoomInteractor);
416
            } else {
403
			} else {
417
                getInteractors().remove(imageZoomInteractor);
404
				getInteractors().remove(zoomInteractor);
418
            }
405
			}
419
            pcs.firePropertyChange("enableImageZoomInteractor", oldValue, b);
406
			pcs.firePropertyChange("enableZoomInteractor", oldValue, b);
420
        }
407
		}
421
    }
408
	}
422
409
423
    /**
410
	/**
424
     * Returns true if the image zoom interactor is enabled, false otherwise.
411
	 * Returns true if the zoom interactor is enabled, false otherwise.
425
     */
412
	 */
426
    public boolean getEnableImageZoomInteractor() {
413
	public boolean getEnableZoomInteractor() {
427
        return isImageZoomInteractorEnabled;
414
		return isZoomInteractorEnabled;
428
    }
415
	}
429
416
430
    /**
417
	/**
431
     * Determines whether the pan interactor is enabled or not.
418
	 * Determines whether the image zoom interactor is enabled or not.
432
     */
419
	 */
433
    public void setEnablePanInteractor(boolean b) {
420
	public void setEnableImageZoomInteractor(boolean b) {
434
        if (isPanInteractorEnabled != b) {
421
		if (isImageZoomInteractorEnabled != b) {
435
            boolean oldValue = isPanInteractorEnabled;
422
			boolean oldValue = isImageZoomInteractorEnabled;
436
            isPanInteractorEnabled = b;
423
			isImageZoomInteractorEnabled = b;
437
            if (isPanInteractorEnabled) {
424
			if (isImageZoomInteractorEnabled) {
438
                getInteractors().add(panInteractor);
425
				getInteractors().add(imageZoomInteractor);
439
            } else {
426
			} else {
440
                getInteractors().remove(panInteractor);
427
				getInteractors().remove(imageZoomInteractor);
441
            }
428
			}
442
            pcs.firePropertyChange("enablePanInteractor", oldValue, b);
429
			pcs.firePropertyChange("enableImageZoomInteractor", oldValue, b);
443
        }
430
		}
444
    }
431
	}
445
432
446
    /**
433
	/**
447
     * Returns true if the pan interactor is enabled, false otherwise.
434
	 * Returns true if the image zoom interactor is enabled, false otherwise.
448
     */
435
	 */
449
    public boolean getEnablePanInteractor() {
436
	public boolean getEnableImageZoomInteractor() {
450
        return isPanInteractorEnabled;
437
		return isImageZoomInteractorEnabled;
451
    }
438
	}
452
439
453
    /**
440
	/**
454
     * Determines whether the rotate interactor is enabled or not.
441
	 * Determines whether the pan interactor is enabled or not.
455
     */
442
	 */
456
    public void setEnableRotateInteractor(boolean b) {
443
	public void setEnablePanInteractor(boolean b) {
457
        if (isRotateInteractorEnabled != b) {
444
		if (isPanInteractorEnabled != b) {
458
            boolean oldValue = isRotateInteractorEnabled;
445
			boolean oldValue = isPanInteractorEnabled;
459
            isRotateInteractorEnabled = b;
446
			isPanInteractorEnabled = b;
460
            if (isRotateInteractorEnabled) {
447
			if (isPanInteractorEnabled) {
461
                getInteractors().add(rotateInteractor);
448
				getInteractors().add(panInteractor);
462
            } else {
449
			} else {
463
                getInteractors().remove(rotateInteractor);
450
				getInteractors().remove(panInteractor);
464
            }
451
			}
465
            pcs.firePropertyChange("enableRotateInteractor", oldValue, b);
452
			pcs.firePropertyChange("enablePanInteractor", oldValue, b);
466
        }
453
		}
467
    }
454
	}
468
455
469
    /**
456
	/**
470
     * Returns true if the rotate interactor is enabled, false otherwise.
457
	 * Returns true if the pan interactor is enabled, false otherwise.
471
     */
458
	 */
472
    public boolean getEnableRotateInteractor() {
459
	public boolean getEnablePanInteractor() {
473
        return isRotateInteractorEnabled;
460
		return isPanInteractorEnabled;
474
    }
461
	}
475
462
476
    /**
463
	/**
477
     * Determines whether the reset transform interactor is enabled or not.
464
	 * Determines whether the rotate interactor is enabled or not.
478
     */
465
	 */
479
    public void setEnableResetTransformInteractor(boolean b) {
466
	public void setEnableRotateInteractor(boolean b) {
480
        if (isResetTransformInteractorEnabled != b) {
467
		if (isRotateInteractorEnabled != b) {
481
            boolean oldValue = isResetTransformInteractorEnabled;
468
			boolean oldValue = isRotateInteractorEnabled;
482
            isResetTransformInteractorEnabled = b;
469
			isRotateInteractorEnabled = b;
483
            if (isResetTransformInteractorEnabled) {
470
			if (isRotateInteractorEnabled) {
484
                getInteractors().add(resetTransformInteractor);
471
				getInteractors().add(rotateInteractor);
485
            } else {
472
			} else {
486
                getInteractors().remove(resetTransformInteractor);
473
				getInteractors().remove(rotateInteractor);
487
            }
474
			}
488
            pcs.firePropertyChange("enableResetTransformInteractor",
475
			pcs.firePropertyChange("enableRotateInteractor", oldValue, b);
489
                                   oldValue,
476
		}
490
                                   b);
477
	}
491
        }
492
    }
493
478
494
    /**
479
	/**
495
     * Returns true if the reset transform interactor is enabled, false
480
	 * Returns true if the rotate interactor is enabled, false otherwise.
496
     * otherwise.
481
	 */
497
     */
482
	public boolean getEnableRotateInteractor() {
498
    public boolean getEnableResetTransformInteractor() {
483
		return isRotateInteractorEnabled;
499
        return isResetTransformInteractorEnabled;
484
	}
500
    }
501
485
502
    /**
486
	/**
503
     * Returns the URI of the current document.
487
	 * Determines whether the reset transform interactor is enabled or not.
504
     */
488
	 */
505
    public String getURI() {
489
	public void setEnableResetTransformInteractor(boolean b) {
506
        return uri;
490
		if (isResetTransformInteractorEnabled != b) {
507
    }
491
			boolean oldValue = isResetTransformInteractorEnabled;
492
			isResetTransformInteractorEnabled = b;
493
			if (isResetTransformInteractorEnabled) {
494
				getInteractors().add(resetTransformInteractor);
495
			} else {
496
				getInteractors().remove(resetTransformInteractor);
497
			}
498
			pcs.firePropertyChange("enableResetTransformInteractor", oldValue,
499
					b);
500
		}
501
	}
508
502
509
    /**
503
	/**
510
     * Sets the URI to the specified uri. If the input 'newURI'
504
	 * Returns true if the reset transform interactor is enabled, false
511
     * string is null, then the canvas will display an empty
505
	 * otherwise.
512
     * document.
506
	 */
513
     *
507
	public boolean getEnableResetTransformInteractor() {
514
     * @param newURI the new uri of the document to display
508
		return isResetTransformInteractorEnabled;
515
     */
509
	}
516
    public void setURI(String newURI) {
517
        String oldValue = uri;
518
        this.uri = newURI;
519
        if (uri != null) {
520
            loadSVGDocument(uri);
521
        } else {
522
            setSVGDocument(null);
523
        }
524
510
525
        pcs.firePropertyChange("URI", oldValue, uri);
511
	/**
526
    }
512
	 * Returns the URI of the current document.
513
	 */
514
	public String getURI() {
515
		return uri;
516
	}
527
517
528
    /**
518
	/**
529
     * Creates a UserAgent.
519
	 * Sets the URI to the specified uri. If the input 'newURI' string is null,
530
     */
520
	 * then the canvas will display an empty document.
531
    protected UserAgent createUserAgent() {
521
	 * 
532
        return new CanvasUserAgent();
522
	 * @param newURI
533
    }
523
	 *            the new uri of the document to display
524
	 */
525
	public void setURI(String newURI) {
526
		String oldValue = uri;
527
		this.uri = newURI;
528
		if (uri != null) {
529
			loadSVGDocument(uri);
530
		} else {
531
			setSVGDocument(null);
532
		}
534
533
535
    /**
534
		pcs.firePropertyChange("URI", oldValue, uri);
536
     * Creates an instance of Listener.
535
	}
537
     */
538
    protected Listener createListener() {
539
        return new CanvasSVGListener();
540
    }
541
536
542
    /**
537
	/**
543
     * To hide the listener methods. This class just reset the tooltip.
538
	 * Creates a UserAgent.
544
     */
539
	 */
545
    protected class CanvasSVGListener extends ExtendedSVGListener {
540
	protected UserAgent createUserAgent() {
541
		return new CanvasUserAgent();
542
	}
546
543
547
        /**
544
	/**
548
         * Called when the loading of a document was started.
545
	 * Creates an instance of Listener.
549
         */
546
	 */
550
        public void documentLoadingStarted(SVGDocumentLoaderEvent e) {
547
	protected Listener createListener() {
551
            super.documentLoadingStarted(e);
548
		return new CanvasSVGListener();
552
            JSVGCanvas.this.setToolTipText(null);
549
	}
553
        }
554
550
555
    }
551
	/**
552
	 * To hide the listener methods. This class just reset the tooltip.
553
	 */
554
	protected class CanvasSVGListener extends ExtendedSVGListener {
556
555
557
    protected void installSVGDocument(SVGDocument doc) {
556
		/**
558
        if (toolTipDocs != null) {
557
		 * Called when the loading of a document was started.
559
            Iterator i = toolTipDocs.keySet().iterator();
558
		 */
560
            while (i.hasNext()) {
559
		public void documentLoadingStarted(SVGDocumentLoaderEvent e) {
561
                SVGDocument ttdoc;
560
			super.documentLoadingStarted(e);
562
                ttdoc = (SVGDocument)i.next();
561
			JSVGCanvas.this.setToolTipText(null);
563
                if (ttdoc == null) continue;
562
		}
564
563
565
                NodeEventTarget root;
564
	}
566
                root = (NodeEventTarget)ttdoc.getRootElement();
567
                if (root == null) continue;
568
                root.removeEventListenerNS
569
                    (XMLConstants.XML_EVENTS_NAMESPACE_URI,
570
                     SVGConstants.SVG_EVENT_MOUSEOVER,
571
                     toolTipListener, false);
572
                root.removeEventListenerNS
573
                    (XMLConstants.XML_EVENTS_NAMESPACE_URI,
574
                     SVGConstants.SVG_EVENT_MOUSEOUT,
575
                     toolTipListener, false);
576
            }
577
            toolTipDocs = null;
578
        }
579
        lastTarget = null;
580
565
581
        if (toolTipMap != null) {
566
	protected void installSVGDocument(SVGDocument doc) {
582
            toolTipMap.clear();
567
		if (toolTipDocs != null) {
583
        }
568
			Iterator i = toolTipDocs.keySet().iterator();
569
			while (i.hasNext()) {
570
				SVGDocument ttdoc;
571
				ttdoc = (SVGDocument) i.next();
572
				if (ttdoc == null)
573
					continue;
584
574
585
        super.installSVGDocument(doc);
575
				NodeEventTarget root;
586
    }
576
				root = (NodeEventTarget) ttdoc.getRootElement();
577
				if (root == null)
578
					continue;
579
				root.removeEventListenerNS(
580
						XMLConstants.XML_EVENTS_NAMESPACE_URI,
581
						SVGConstants.SVG_EVENT_MOUSEOVER, toolTipListener,
582
						false);
583
				root
584
						.removeEventListenerNS(
585
								XMLConstants.XML_EVENTS_NAMESPACE_URI,
586
								SVGConstants.SVG_EVENT_MOUSEOUT,
587
								toolTipListener, false);
588
			}
589
			toolTipDocs = null;
590
		}
591
		lastTarget = null;
587
592
588
    // ----------------------------------------------------------------------
593
		if (toolTipMap != null) {
589
    // Actions
594
			toolTipMap.clear();
590
    // ----------------------------------------------------------------------
595
		}
591
596
592
    /**
597
		super.installSVGDocument(doc);
593
     * A swing action to reset the rendering transform of the canvas.
598
	}
594
     */
595
    public class ResetTransformAction extends AbstractAction {
596
        public void actionPerformed(ActionEvent evt) {
597
            fragmentIdentifier = null;
598
            resetRenderingTransform();
599
        }
600
    }
601
599
602
    /**
600
	// ----------------------------------------------------------------------
603
     * A swing action to append an affine transform to the current
601
	// Actions
604
     * rendering transform.  Before the rendering transform is
602
	// ----------------------------------------------------------------------
605
     * applied the method translates the center of the display to
606
     * 0,0 so scale and rotate occur around the middle of
607
     * the display.
608
     */
609
    public class AffineAction extends AbstractAction {
610
        AffineTransform at;
611
        public AffineAction(AffineTransform at) {
612
            this.at = at;
613
        }
614
603
615
        public void actionPerformed(ActionEvent evt) {
604
	/**
616
            if (gvtRoot == null) {
605
	 * A swing action to reset the rendering transform of the canvas.
617
                return;
606
	 */
618
            }
607
	public class ResetTransformAction extends AbstractAction {
619
            AffineTransform rat = getRenderingTransform();
608
		public void actionPerformed(ActionEvent evt) {
620
            if (at != null) {
609
			fragmentIdentifier = null;
621
                Dimension dim = getSize();
610
			resetRenderingTransform();
622
                int x = dim.width / 2;
611
		}
623
                int y = dim.height / 2;
612
	}
624
                AffineTransform t = AffineTransform.getTranslateInstance(x, y);
625
                t.concatenate(at);
626
                t.translate(-x, -y);
627
                t.concatenate(rat);
628
                setRenderingTransform(t);
629
            }
630
        }
631
    }
632
613
633
    /**
614
	/**
634
     * A swing action to apply a zoom factor to the canvas.
615
	 * A swing action to append an affine transform to the current rendering
635
     * This can be used to zoom in (scale > 1) and out (scale <1).
616
	 * transform. Before the rendering transform is applied the method
636
     */
617
	 * translates the center of the display to 0,0 so scale and rotate occur
637
    public class ZoomAction extends AffineAction {
618
	 * around the middle of the display.
638
        public ZoomAction(double scale) {
619
	 */
639
            super(AffineTransform.getScaleInstance(scale, scale));
620
	public class AffineAction extends AbstractAction {
640
        }
621
		AffineTransform at;
641
        public ZoomAction(double scaleX, double scaleY) {
642
            super(AffineTransform.getScaleInstance(scaleX, scaleY));
643
        }
644
    }
645
622
646
    /**
623
		public AffineAction(AffineTransform at) {
647
     * A swing action to zoom in the canvas.
624
			this.at = at;
648
     */
625
		}
649
    public class ZoomInAction extends ZoomAction {
650
        ZoomInAction() { super(2); }
651
    }
652
626
653
    /**
627
		public void actionPerformed(ActionEvent evt) {
654
     * A swing action to zoom out the canvas.
628
			if (gvtRoot == null) {
655
     */
629
				return;
656
    public class ZoomOutAction extends ZoomAction {
630
			}
657
        ZoomOutAction() { super(.5); }
631
			AffineTransform rat = getRenderingTransform();
658
    }
632
			if (at != null) {
633
				Dimension dim = getSize();
634
				int x = dim.width / 2;
635
				int y = dim.height / 2;
636
				AffineTransform t = AffineTransform.getTranslateInstance(x, y);
637
				t.concatenate(at);
638
				t.translate(-x, -y);
639
				t.concatenate(rat);
640
				setRenderingTransform(t);
641
			}
642
		}
643
	}
659
644
660
    /**
645
	/**
661
     * A swing action to Rotate the canvas.
646
	 * A swing action to apply a zoom factor to the canvas. This can be used to
662
     */
647
	 * zoom in (scale > 1) and out (scale <1).
663
    public class RotateAction extends AffineAction {
648
	 */
664
        public RotateAction(double theta) {
649
	public class ZoomAction extends AffineAction {
665
            super(AffineTransform.getRotateInstance(theta));
650
		public ZoomAction(double scale) {
666
        }
651
			super(AffineTransform.getScaleInstance(scale, scale));
667
    }
652
		}
668
653
669
    /**
654
		public ZoomAction(double scaleX, double scaleY) {
670
     * A swing action to Pan/scroll the canvas.
655
			super(AffineTransform.getScaleInstance(scaleX, scaleY));
671
     */
656
		}
672
    public class ScrollAction extends AffineAction {
657
	}
673
        public ScrollAction(double tx, double ty) {
674
            super(AffineTransform.getTranslateInstance(tx, ty));
675
        }
676
    }
677
658
678
    /**
659
	/**
679
     * A swing action to scroll the canvas to the right,
660
	 * A swing action to zoom in the canvas.
680
     * by a fixed amount
661
	 */
681
     */
662
	public class ZoomInAction extends ZoomAction {
682
    public class ScrollRightAction extends ScrollAction {
663
		ZoomInAction() {
683
        public ScrollRightAction(int inc) {
664
			super(2);
684
            super(-inc, 0);
665
		}
685
        }
666
	}
686
    }
687
667
688
    /**
668
	/**
689
     * A swing action to scroll the canvas to the left,
669
	 * A swing action to zoom out the canvas.
690
     * by a fixed amount
670
	 */
691
     */
671
	public class ZoomOutAction extends ZoomAction {
692
    public class ScrollLeftAction extends ScrollAction {
672
		ZoomOutAction() {
693
        public ScrollLeftAction(int inc) {
673
			super(.5);
694
            super(inc, 0);
674
		}
695
        }
675
	}
696
    }
697
676
698
    /**
677
	/**
699
     * A swing action to scroll the canvas up,
678
	 * A swing action to Rotate the canvas.
700
     * by a fixed amount
679
	 */
701
     */
680
	public class RotateAction extends AffineAction {
702
    public class ScrollUpAction extends ScrollAction {
681
		public RotateAction(double theta) {
703
        public ScrollUpAction(int inc) {
682
			super(AffineTransform.getRotateInstance(theta));
704
            super(0, inc);
683
		}
705
        }
684
	}
706
    }
707
685
708
    /**
686
	/**
709
     * A swing action to scroll the canvas down,
687
	 * A swing action to Pan/scroll the canvas.
710
     * by a fixed amount
688
	 */
711
     */
689
	public class ScrollAction extends AffineAction {
712
    public class ScrollDownAction extends ScrollAction {
690
		public ScrollAction(double tx, double ty) {
713
        public ScrollDownAction(int inc) {
691
			super(AffineTransform.getTranslateInstance(tx, ty));
714
            super(0, -inc);
692
		}
715
        }
693
	}
716
    }
717
694
718
    // ----------------------------------------------------------------------
695
	/**
719
    // Interactors
696
	 * A swing action to scroll the canvas to the right, by a fixed amount
720
    // ----------------------------------------------------------------------
697
	 */
698
	public class ScrollRightAction extends ScrollAction {
699
		public ScrollRightAction(int inc) {
700
			super(-inc, 0);
701
		}
702
	}
721
703
722
    /**
704
	/**
723
     * An interactor to perform a zoom.
705
	 * A swing action to scroll the canvas to the left, by a fixed amount
724
     * <p>Binding: BUTTON1 + CTRL Key</p>
706
	 */
725
     */
707
	public class ScrollLeftAction extends ScrollAction {
726
    protected Interactor zoomInteractor = new AbstractZoomInteractor() {
708
		public ScrollLeftAction(int inc) {
727
        public boolean startInteraction(InputEvent ie) {
709
			super(inc, 0);
728
            int mods = ie.getModifiers();
710
		}
729
            return
711
	}
730
                ie.getID() == MouseEvent.MOUSE_PRESSED &&
731
                (mods & InputEvent.BUTTON1_MASK) != 0 &&
732
                (mods & InputEvent.CTRL_MASK) != 0;
733
        }
734
    };
735
712
736
    /**
713
	/**
737
     * An interactor to perform a realtime zoom.
714
	 * A swing action to scroll the canvas up, by a fixed amount
738
     * <p>Binding: BUTTON3 + SHIFT Key</p>
715
	 */
739
     */
716
	public class ScrollUpAction extends ScrollAction {
740
    protected Interactor imageZoomInteractor
717
		public ScrollUpAction(int inc) {
741
        = new AbstractImageZoomInteractor() {
718
			super(0, inc);
742
        public boolean startInteraction(InputEvent ie) {
719
		}
743
            int mods = ie.getModifiers();
720
	}
744
            return
745
                ie.getID() == MouseEvent.MOUSE_PRESSED &&
746
                (mods & InputEvent.BUTTON3_MASK) != 0 &&
747
                (mods & InputEvent.SHIFT_MASK) != 0;
748
        }
749
    };
750
721
751
    /**
722
	/**
752
     * An interactor to perform a translation.
723
	 * A swing action to scroll the canvas down, by a fixed amount
753
     * <p>Binding: BUTTON1 + SHIFT Key</p>
724
	 */
754
     */
725
	public class ScrollDownAction extends ScrollAction {
755
    protected Interactor panInteractor = new AbstractPanInteractor() {
726
		public ScrollDownAction(int inc) {
756
        public boolean startInteraction(InputEvent ie) {
727
			super(0, -inc);
757
            int mods = ie.getModifiers();
728
		}
758
            return
729
	}
759
                ie.getID() == MouseEvent.MOUSE_PRESSED &&
760
                (mods & InputEvent.BUTTON1_MASK) != 0 &&
761
                (mods & InputEvent.SHIFT_MASK) != 0;
762
        }
763
    };
764
730
765
    /**
731
	// ----------------------------------------------------------------------
766
     * An interactor to perform a rotation.
732
	// Interactors
767
     * <p>Binding: BUTTON3 + CTRL Key</p>
733
	// ----------------------------------------------------------------------
768
     */
769
    protected Interactor rotateInteractor = new AbstractRotateInteractor() {
770
        public boolean startInteraction(InputEvent ie) {
771
            int mods = ie.getModifiers();
772
            return
773
                ie.getID() == MouseEvent.MOUSE_PRESSED &&
774
                (mods & InputEvent.BUTTON3_MASK) != 0 &&
775
                (mods & InputEvent.CTRL_MASK) != 0;
776
        }
777
    };
778
734
779
    /**
735
	/**
780
     * An interactor to reset the rendering transform.
736
	 * An interactor to perform a zoom.
781
     * <p>Binding: CTRL+SHIFT+BUTTON3</p>
737
	 * <p>
782
     */
738
	 * Binding: BUTTON1 + CTRL Key
783
    protected Interactor resetTransformInteractor =
739
	 * </p>
784
        new AbstractResetTransformInteractor() {
740
	 */
785
        public boolean startInteraction(InputEvent ie) {
741
	protected Interactor zoomInteractor = new AbstractZoomInteractor() {
786
            int mods = ie.getModifiers();
742
		public boolean startInteraction(InputEvent ie) {
787
            return
743
			int mods = ie.getModifiers();
788
                ie.getID() == MouseEvent.MOUSE_CLICKED &&
744
			return ie.getID() == MouseEvent.MOUSE_PRESSED
789
                (mods & InputEvent.BUTTON3_MASK) != 0 &&
745
					&& (mods & InputEvent.BUTTON1_MASK) != 0
790
                (mods & InputEvent.SHIFT_MASK) != 0 &&
746
					&& (mods & InputEvent.CTRL_MASK) != 0;
791
                (mods & InputEvent.CTRL_MASK) != 0;
747
		}
792
        }
748
	};
793
    };
794
749
795
    // ----------------------------------------------------------------------
750
	/**
796
    // User agent implementation
751
	 * An interactor to perform a realtime zoom.
797
    // ----------------------------------------------------------------------
752
	 * <p>
753
	 * Binding: BUTTON3 + SHIFT Key
754
	 * </p>
755
	 */
756
	protected Interactor imageZoomInteractor = new AbstractImageZoomInteractor() {
757
		public boolean startInteraction(InputEvent ie) {
758
			int mods = ie.getModifiers();
759
			return ie.getID() == MouseEvent.MOUSE_PRESSED
760
					&& (mods & InputEvent.BUTTON3_MASK) != 0
761
					&& (mods & InputEvent.SHIFT_MASK) != 0;
762
		}
763
	};
798
764
799
    /**
765
	/**
800
     * The <tt>CanvasUserAgent</tt> only adds tooltips to the behavior of the
766
	 * An interactor to perform a translation.
801
     * default <tt>BridgeUserAgent</tt>. A tooltip will be displayed
767
	 * <p>
802
     * wheneven the mouse lingers over an element which has a &lt;title&gt; or a
768
	 * Binding: BUTTON1 + SHIFT Key
803
     * &lt;desc&gt; child element.
769
	 * </p>
804
     */
770
	 */
805
    protected class CanvasUserAgent extends BridgeUserAgent
771
	protected Interactor panInteractor = new AbstractPanInteractor() {
772
		public boolean startInteraction(InputEvent ie) {
773
			int mods = ie.getModifiers();
774
			return ie.getID() == MouseEvent.MOUSE_PRESSED
775
					&& (mods & InputEvent.BUTTON1_MASK) != 0
776
					&& (mods & InputEvent.SHIFT_MASK) != 0;
777
		}
778
	};
806
779
807
        implements XMLConstants {
780
	/**
781
	 * An interactor to perform a rotation.
782
	 * <p>
783
	 * Binding: BUTTON3 + CTRL Key
784
	 * </p>
785
	 */
786
	protected Interactor rotateInteractor = new AbstractRotateInteractor() {
787
		public boolean startInteraction(InputEvent ie) {
788
			int mods = ie.getModifiers();
789
			return ie.getID() == MouseEvent.MOUSE_PRESSED
790
					&& (mods & InputEvent.BUTTON3_MASK) != 0
791
					&& (mods & InputEvent.CTRL_MASK) != 0;
792
		}
793
	};
808
794
809
        final String TOOLTIP_TITLE_ONLY
795
	/**
810
            = "JSVGCanvas.CanvasUserAgent.ToolTip.titleOnly";
796
	 * An interactor to reset the rendering transform.
811
        final String TOOLTIP_DESC_ONLY
797
	 * <p>
812
            = "JSVGCanvas.CanvasUserAgent.ToolTip.descOnly";
798
	 * Binding: CTRL+SHIFT+BUTTON3
813
        final String TOOLTIP_TITLE_AND_TEXT
799
	 * </p>
814
            = "JSVGCanvas.CanvasUserAgent.ToolTip.titleAndDesc";
800
	 */
801
	protected Interactor resetTransformInteractor = new AbstractResetTransformInteractor() {
802
		public boolean startInteraction(InputEvent ie) {
803
			int mods = ie.getModifiers();
804
			return ie.getID() == MouseEvent.MOUSE_CLICKED
805
					&& (mods & InputEvent.BUTTON3_MASK) != 0
806
					&& (mods & InputEvent.SHIFT_MASK) != 0
807
					&& (mods & InputEvent.CTRL_MASK) != 0;
808
		}
809
	};
815
810
816
        /**
811
	// ----------------------------------------------------------------------
817
         * The handleElement method builds a tool tip from the
812
	// User agent implementation
818
         * content of a &lt;title&gt; element, a &lt;desc&gt;
813
	// ----------------------------------------------------------------------
819
         * element or both. <br/>
820
         * Because these elements can appear in any order, here
821
         * is the algorithm used to build the tool tip:<br />
822
         * <ul>
823
         * <li>If a &lt;title&gt; is passed to <tt>handleElement</tt>
824
         *     the method checks if there is a &gt;desc&gt; peer. If
825
         *     there is one, nothing is done (because the desc will do
826
         *     it). If there in none, the tool tip is set to the value
827
         *     of the &lt;title&gt; element content.</li>
828
         * <li>If a &lt;desc&gt; is passed to <tt>handleElement</tt>
829
         *     the method checks if there is a &lt;title&gt; peer. If there
830
         *     is one, the content of that peer is pre-pended to the
831
         *     content of the &lt;desc&gt; element.</li>
832
         * </ul>
833
         */
834
        public void handleElement(Element elt, Object data){
835
            super.handleElement(elt, data);
836
814
837
            // Don't handle tool tips unless we are interactive.
815
	/**
838
            if (!isInteractive()) return;
816
	 * The <tt>CanvasUserAgent</tt> only adds tooltips to the behavior of the
817
	 * default <tt>BridgeUserAgent</tt>. A tooltip will be displayed wheneven
818
	 * the mouse lingers over an element which has a &lt;title&gt; or a
819
	 * &lt;desc&gt; child element.
820
	 */
821
	protected class CanvasUserAgent extends BridgeUserAgent
839
822
840
            if (!SVGConstants.SVG_NAMESPACE_URI.equals(elt.getNamespaceURI()))
823
	implements XMLConstants {
841
                return;
842
824
843
            // Don't handle tool tips for the root SVG element.
825
		final String TOOLTIP_TITLE_ONLY = "JSVGCanvas.CanvasUserAgent.ToolTip.titleOnly";
844
            if (elt.getParentNode() ==
845
                elt.getOwnerDocument().getDocumentElement()) {
846
                return;
847
            }
848
826
849
            Element parent;
827
		final String TOOLTIP_DESC_ONLY = "JSVGCanvas.CanvasUserAgent.ToolTip.descOnly";
850
            // When node is removed data is old parent node
851
            // since we can't get it otherwise.
852
            if (data instanceof Element) parent = (Element)data;
853
            else                         parent = (Element)elt.getParentNode();
854
828
855
            Element descPeer = null;
829
		final String TOOLTIP_TITLE_AND_TEXT = "JSVGCanvas.CanvasUserAgent.ToolTip.titleAndDesc";
856
            Element titlePeer = null;
857
            if (elt.getLocalName().equals(SVGConstants.SVG_TITLE_TAG)) {
858
                if (data == Boolean.TRUE)
859
                    titlePeer = elt;
860
                descPeer = getPeerWithTag(parent,
861
                                           SVGConstants.SVG_NAMESPACE_URI,
862
                                           SVGConstants.SVG_DESC_TAG);
863
            } else if (elt.getLocalName().equals(SVGConstants.SVG_DESC_TAG)) {
864
                if (data == Boolean.TRUE)
865
                    descPeer = elt;
866
                titlePeer = getPeerWithTag(parent,
867
                                           SVGConstants.SVG_NAMESPACE_URI,
868
                                           SVGConstants.SVG_TITLE_TAG);
869
            }
870
830
871
            String titleTip = null;
831
		/**
872
            if (titlePeer != null) {
832
		 * The handleElement method builds a tool tip from the content of a
873
                titlePeer.normalize();
833
		 * &lt;title&gt; element, a &lt;desc&gt; element or both. <br/> Because
874
                if (titlePeer.getFirstChild() != null)
834
		 * these elements can appear in any order, here is the algorithm used to
875
                    titleTip = titlePeer.getFirstChild().getNodeValue();
835
		 * build the tool tip:<br />
876
            }
836
		 * <ul>
837
		 * <li>If a &lt;title&gt; is passed to <tt>handleElement</tt> the
838
		 * method checks if there is a &gt;desc&gt; peer. If there is one,
839
		 * nothing is done (because the desc will do it). If there in none, the
840
		 * tool tip is set to the value of the &lt;title&gt; element content.</li>
841
		 * <li>If a &lt;desc&gt; is passed to <tt>handleElement</tt> the
842
		 * method checks if there is a &lt;title&gt; peer. If there is one, the
843
		 * content of that peer is pre-pended to the content of the &lt;desc&gt;
844
		 * element.</li>
845
		 * </ul>
846
		 */
847
		public void handleElement(Element elt, Object data) {
848
			super.handleElement(elt, data);
877
849
878
            String descTip = null;
850
			// Don't handle tool tips unless we are interactive.
879
            if (descPeer != null) {
851
			if (!isInteractive())
880
                descPeer.normalize();
852
				return;
881
                if (descPeer.getFirstChild() != null)
882
                    descTip = descPeer.getFirstChild().getNodeValue();
883
            }
884
853
885
            final String toolTip;
854
			if (!SVGConstants.SVG_NAMESPACE_URI.equals(elt.getNamespaceURI()))
886
            if ((titleTip != null) && (titleTip.length() != 0)) {
855
				return;
887
                if ((descTip != null) && (descTip.length() != 0)) {
888
                    toolTip = Messages.formatMessage
889
                        (TOOLTIP_TITLE_AND_TEXT,
890
                         new Object[] { toFormattedHTML(titleTip),
891
                                        toFormattedHTML(descTip)});
892
                } else {
893
                    toolTip = Messages.formatMessage
894
                        (TOOLTIP_TITLE_ONLY,
895
                         new Object[]{toFormattedHTML(titleTip)});
896
                }
897
            } else {
898
                if ((descTip != null) && (descTip.length() != 0)) {
899
                    toolTip = Messages.formatMessage
900
                        (TOOLTIP_DESC_ONLY,
901
                         new Object[]{toFormattedHTML(descTip)});
902
                } else {
903
                    toolTip = null;
904
                }
905
            }
906
856
907
            if (toolTip == null) {
857
			// Don't handle tool tips for the root SVG element.
908
                removeToolTip(parent);
858
			if (elt.getParentNode() == elt.getOwnerDocument()
909
                return;
859
					.getDocumentElement()) {
910
            }
860
				return;
861
			}
911
862
912
            if (lastTarget != parent) {
863
			Element parent;
913
                setToolTip(parent, toolTip);
864
			// When node is removed data is old parent node
914
            } else {
865
			// since we can't get it otherwise.
915
                // Already has focus check if it already has tip text.
866
			if (data instanceof Element)
916
                Object o = null;
867
				parent = (Element) data;
917
                if (toolTipMap != null) {
868
			else
918
                    o = toolTipMap.get(parent);
869
				parent = (Element) elt.getParentNode();
919
                    toolTipMap.put(parent, toolTip);
920
                }
921
870
922
                if (o != null) {
871
			Element descPeer = null;
923
                    // Update components tooltip text now.
872
			Element titlePeer = null;
924
                    EventQueue.invokeLater(new Runnable() {
873
			if (elt.getLocalName().equals(SVGConstants.SVG_TITLE_TAG)) {
925
                            public void run() {
874
				if (data == Boolean.TRUE)
926
                                setToolTipText(toolTip);
875
					titlePeer = elt;
927
                                MouseEvent e = new MouseEvent
876
				descPeer = getPeerWithTag(parent,
928
                                    (JSVGCanvas.this,
877
						SVGConstants.SVG_NAMESPACE_URI,
929
                                     MouseEvent.MOUSE_MOVED,
878
						SVGConstants.SVG_DESC_TAG);
930
                                     System.currentTimeMillis(),
879
			} else if (elt.getLocalName().equals(SVGConstants.SVG_DESC_TAG)) {
931
                                     0,
880
				if (data == Boolean.TRUE)
932
                                     locationListener.getLastX(),
881
					descPeer = elt;
933
                                     locationListener.getLastY(),
882
				titlePeer = getPeerWithTag(parent,
934
                                     0,
883
						SVGConstants.SVG_NAMESPACE_URI,
935
                                     false);
884
						SVGConstants.SVG_TITLE_TAG);
936
                                ToolTipManager.sharedInstance().mouseMoved(e);
885
			}
937
                            }
938
                        });
939
                } else {
940
                    EventQueue.invokeLater(new ToolTipRunnable(toolTip));
941
                }
942
            }
943
        }
944
886
945
        /**
887
			String titleTip = null;
946
         * Converts line breaks to HTML breaks and encodes special entities.
888
			if (titlePeer != null) {
947
         * Poor way of replacing '<', '>' and '&' in content.
889
				titlePeer.normalize();
948
         */
890
				if (titlePeer.getFirstChild() != null)
949
        public String toFormattedHTML(String str) {
891
					titleTip = titlePeer.getFirstChild().getNodeValue();
950
            StringBuffer sb = new StringBuffer(str);
892
			}
951
            replace(sb, XML_CHAR_AMP, XML_ENTITY_AMP);  // Must go first!
952
            replace(sb, XML_CHAR_LT, XML_ENTITY_LT);
953
            replace(sb, XML_CHAR_GT, XML_ENTITY_GT);
954
            replace(sb, XML_CHAR_QUOT, XML_ENTITY_QUOT);
955
            // Dont' quote "'" apostrphe since the display doesn't
956
            // seem to understand it.
957
            // replace(sb, XML_CHAR_APOS, XML_ENTITY_APOS);
958
            replace(sb, '\n', "<br>");
959
            return sb.toString();
960
        }
961
893
962
        protected void replace(StringBuffer sb, char c, String r) {
894
			String descTip = null;
963
            String v = sb.toString();
895
			if (descPeer != null) {
964
            int i = v.length();
896
				descPeer.normalize();
897
				if (descPeer.getFirstChild() != null)
898
					descTip = descPeer.getFirstChild().getNodeValue();
899
			}
965
900
966
            while( (i=v.lastIndexOf(c, i-1)) != -1 ) {
901
			final String toolTip;
967
                sb.deleteCharAt(i);
902
			if ((titleTip != null) && (titleTip.length() != 0)) {
968
                sb.insert(i, r);
903
				if ((descTip != null) && (descTip.length() != 0)) {
969
            }
904
					toolTip = Messages.formatMessage(TOOLTIP_TITLE_AND_TEXT,
970
        }
905
							new Object[] { toFormattedHTML(titleTip),
906
									toFormattedHTML(descTip) });
907
				} else {
908
					toolTip = Messages.formatMessage(TOOLTIP_TITLE_ONLY,
909
							new Object[] { toFormattedHTML(titleTip) });
910
				}
911
			} else {
912
				if ((descTip != null) && (descTip.length() != 0)) {
913
					toolTip = Messages.formatMessage(TOOLTIP_DESC_ONLY,
914
							new Object[] { toFormattedHTML(descTip) });
915
				} else {
916
					toolTip = null;
917
				}
918
			}
971
919
972
        /**
920
			if (toolTip == null) {
973
         * Checks if there is a peer element of a given type.  This returns the
921
				removeToolTip(parent);
974
         * first occurence of the given type or null if none is found.
922
				return;
975
         */
923
			}
976
        public Element getPeerWithTag(Element parent,
977
                                      String nameSpaceURI,
978
                                      String localName) {
979
924
980
            Element p = parent;
925
			if (lastTarget != parent) {
981
            if (p == null) {
926
				setToolTip(parent, toolTip);
982
                return null;
927
			} else {
983
            }
928
				// Already has focus check if it already has tip text.
929
				Object o = null;
930
				if (toolTipMap != null) {
931
					o = toolTipMap.get(parent);
932
					toolTipMap.put(parent, toolTip);
933
				}
984
934
985
            for (Node n=p.getFirstChild(); n!=null; n = n.getNextSibling()) {
935
				if (o != null) {
986
                if (!nameSpaceURI.equals(n.getNamespaceURI())){
936
					// Update components tooltip text now.
987
                    continue;
937
					EventQueue.invokeLater(new Runnable() {
988
                }
938
						public void run() {
989
                if (!localName.equals(n.getLocalName())){
939
							setToolTipText(toolTip);
990
                    continue;
940
							MouseEvent e = new MouseEvent(JSVGCanvas.this,
991
                }
941
									MouseEvent.MOUSE_MOVED, System
992
                if (n.getNodeType() == Node.ELEMENT_NODE) {
942
											.currentTimeMillis(), 0,
993
                    return (Element)n;
943
									locationListener.getLastX(),
994
                }
944
									locationListener.getLastY(), 0, false);
995
            }
945
							ToolTipManager.sharedInstance().mouseMoved(e);
996
            return null;
946
						}
997
        }
947
					});
948
				} else {
949
					EventQueue.invokeLater(new ToolTipRunnable(toolTip));
950
				}
951
			}
952
		}
998
953
999
        /**
954
		/**
1000
         * Returns a boolean defining whether or not there is a peer of
955
		 * Converts line breaks to HTML breaks and encodes special entities.
1001
         * <tt>elt</tt> with the given qualified tag.
956
		 * Poor way of replacing '<', '>' and '&' in content.
1002
         */
957
		 */
1003
        public boolean hasPeerWithTag(Element elt,
958
		public String toFormattedHTML(String str) {
1004
                                      String nameSpaceURI,
959
			StringBuffer sb = new StringBuffer(str);
1005
                                      String localName){
960
			replace(sb, XML_CHAR_AMP, XML_ENTITY_AMP); // Must go first!
961
			replace(sb, XML_CHAR_LT, XML_ENTITY_LT);
962
			replace(sb, XML_CHAR_GT, XML_ENTITY_GT);
963
			replace(sb, XML_CHAR_QUOT, XML_ENTITY_QUOT);
964
			// Dont' quote "'" apostrphe since the display doesn't
965
			// seem to understand it.
966
			// replace(sb, XML_CHAR_APOS, XML_ENTITY_APOS);
967
			replace(sb, '\n', "<br>");
968
			return sb.toString();
969
		}
1006
970
1007
            return !(getPeerWithTag(elt, nameSpaceURI, localName) == null);
971
		protected void replace(StringBuffer sb, char c, String r) {
1008
        }
972
			String v = sb.toString();
973
			int i = v.length();
1009
974
1010
        /**
975
			while ((i = v.lastIndexOf(c, i - 1)) != -1) {
1011
         * Sets the tool tip on the input element.
976
				sb.deleteCharAt(i);
1012
         */
977
				sb.insert(i, r);
1013
        public void setToolTip(Element elt, String toolTip){
978
			}
1014
            if (toolTipMap == null) {
979
		}
1015
                toolTipMap = new WeakHashMap();
1016
            }
1017
            if (toolTipDocs == null) {
1018
                toolTipDocs = new WeakHashMap();
1019
            }
1020
            SVGDocument doc = (SVGDocument)elt.getOwnerDocument();
1021
            if (toolTipDocs.put(doc, MAP_TOKEN) == null) {
1022
                NodeEventTarget root;
1023
                root = (NodeEventTarget)doc.getRootElement();
1024
                // On mouseover, it sets the tooltip to the given value
1025
                root.addEventListenerNS(XMLConstants.XML_EVENTS_NAMESPACE_URI,
1026
                                        SVGConstants.SVG_EVENT_MOUSEOVER,
1027
                                        toolTipListener,
1028
                                        false, null);
1029
                // On mouseout, it removes the tooltip
1030
                root.addEventListenerNS(XMLConstants.XML_EVENTS_NAMESPACE_URI,
1031
                                        SVGConstants.SVG_EVENT_MOUSEOUT,
1032
                                        toolTipListener,
1033
                                        false, null);
1034
            }
1035
980
1036
            toolTipMap.put(elt, toolTip);
981
		/**
982
		 * Checks if there is a peer element of a given type. This returns the
983
		 * first occurence of the given type or null if none is found.
984
		 */
985
		public Element getPeerWithTag(Element parent, String nameSpaceURI,
986
				String localName) {
1037
987
1038
            if (elt == lastTarget)
988
			Element p = parent;
1039
                EventQueue.invokeLater(new ToolTipRunnable(toolTip));
989
			if (p == null) {
1040
        }
990
				return null;
991
			}
1041
992
1042
        public void removeToolTip(Element elt) {
993
			for (Node n = p.getFirstChild(); n != null; n = n.getNextSibling()) {
1043
            if (toolTipMap != null)
994
				if (!nameSpaceURI.equals(n.getNamespaceURI())) {
1044
                toolTipMap.remove(elt);
995
					continue;
1045
            if (lastTarget == elt) { // clear ToolTip.
996
				}
1046
                EventQueue.invokeLater(new ToolTipRunnable(null));
997
				if (!localName.equals(n.getLocalName())) {
1047
            }
998
					continue;
1048
        }
999
				}
1000
				if (n.getNodeType() == Node.ELEMENT_NODE) {
1001
					return (Element) n;
1002
				}
1003
			}
1004
			return null;
1005
		}
1049
1006
1050
        /**
1007
		/**
1051
         * Displays an error message in the User Agent interface.
1008
		 * Returns a boolean defining whether or not there is a peer of
1052
         */
1009
		 * <tt>elt</tt> with the given qualified tag.
1053
        public void displayError(String message) {
1010
		 */
1054
            if (svgUserAgent != null) {
1011
		public boolean hasPeerWithTag(Element elt, String nameSpaceURI,
1055
                super.displayError(message);
1012
				String localName) {
1056
            } else {
1057
                JOptionPane pane =
1058
                    new JOptionPane(message, JOptionPane.ERROR_MESSAGE);
1059
                JDialog dialog =
1060
                    pane.createDialog(JSVGCanvas.this, "ERROR");
1061
                dialog.setModal(false);
1062
                dialog.setVisible(true); // Safe to be called from any thread
1063
            }
1064
        }
1065
1013
1066
        /**
1014
			return !(getPeerWithTag(elt, nameSpaceURI, localName) == null);
1067
         * Displays an error resulting from the specified Exception.
1015
		}
1068
         */
1069
        public void displayError(Exception ex) {
1070
            if (svgUserAgent != null) {
1071
                super.displayError(ex);
1072
            } else {
1073
                JErrorPane pane =
1074
                    new JErrorPane(ex, JOptionPane.ERROR_MESSAGE);
1075
                JDialog dialog = pane.createDialog(JSVGCanvas.this, "ERROR");
1076
                dialog.setModal(false);
1077
                dialog.setVisible(true); // Safe to be called from any thread
1078
            }
1079
        }
1080
    }
1081
1016
1082
    // ----------------------------------------------------------------------
1017
		/**
1083
    // Tooltip
1018
		 * Sets the tool tip on the input element.
1084
    // ----------------------------------------------------------------------
1019
		 */
1020
		public void setToolTip(Element elt, String toolTip) {
1021
			if (toolTipMap == null) {
1022
				toolTipMap = new WeakHashMap();
1023
			}
1024
			if (toolTipDocs == null) {
1025
				toolTipDocs = new WeakHashMap();
1026
			}
1027
			SVGDocument doc = (SVGDocument) elt.getOwnerDocument();
1028
			if (toolTipDocs.put(doc, MAP_TOKEN) == null) {
1029
				NodeEventTarget root;
1030
				root = (NodeEventTarget) doc.getRootElement();
1031
				// On mouseover, it sets the tooltip to the given value
1032
				root.addEventListenerNS(XMLConstants.XML_EVENTS_NAMESPACE_URI,
1033
						SVGConstants.SVG_EVENT_MOUSEOVER, toolTipListener,
1034
						false, null);
1035
				// On mouseout, it removes the tooltip
1036
				root.addEventListenerNS(XMLConstants.XML_EVENTS_NAMESPACE_URI,
1037
						SVGConstants.SVG_EVENT_MOUSEOUT, toolTipListener,
1038
						false, null);
1039
			}
1085
1040
1086
    /**
1041
			toolTipMap.put(elt, toolTip);
1087
     * Sets the time and element of the last tool tip event handled.
1088
     */
1089
    public void setLastToolTipEvent(long t, EventTarget et) {
1090
        lastToolTipEventTimeStamp = t;
1091
        lastToolTipEventTarget = et;
1092
    }
1093
1042
1094
    /**
1043
			if (elt == lastTarget)
1095
     * Checks if the specified event time and element are the same
1044
				EventQueue.invokeLater(new ToolTipRunnable(toolTip));
1096
     * as the last tool tip event.
1045
		}
1097
     */
1098
    public boolean matchLastToolTipEvent(long t, EventTarget et) {
1099
        return lastToolTipEventTimeStamp == t
1100
            && lastToolTipEventTarget == et;
1101
    }
1102
1046
1103
    /**
1047
		public void removeToolTip(Element elt) {
1104
     * Helper class. Simply keeps track of the last known mouse
1048
			if (toolTipMap != null)
1105
     * position over the canvas.
1049
				toolTipMap.remove(elt);
1106
     */
1050
			if (lastTarget == elt) { // clear ToolTip.
1107
    protected class LocationListener extends MouseMotionAdapter {
1051
				EventQueue.invokeLater(new ToolTipRunnable(null));
1052
			}
1053
		}
1108
1054
1109
        protected int lastX, lastY;
1055
		/**
1056
		 * Displays an error message in the User Agent interface.
1057
		 */
1058
		public void displayError(String message) {
1059
			if (svgUserAgent != null) {
1060
				super.displayError(message);
1061
			} else {
1062
				JOptionPane pane = new JOptionPane(message,
1063
						JOptionPane.ERROR_MESSAGE);
1064
				JDialog dialog = pane.createDialog(JSVGCanvas.this, "ERROR");
1065
				dialog.setModal(false);
1066
				dialog.setVisible(true); // Safe to be called from any thread
1067
			}
1068
		}
1110
1069
1111
        public LocationListener () {
1070
		/**
1112
            lastX = 0; lastY = 0;
1071
		 * Displays an error resulting from the specified Exception.
1113
        }
1072
		 */
1073
		public void displayError(Exception ex) {
1074
			if (svgUserAgent != null) {
1075
				super.displayError(ex);
1076
			} else {
1077
				// JErrorPane pane =
1078
				// new JErrorPane(ex, JOptionPane.ERROR_MESSAGE);
1079
				ErrorConsole console = ErrorConsole.getInstance();
1080
				ErrorInfo info = new ErrorInfo(ex, getURI(),
1081
						ErrorConsole.ERROR);
1082
				console.add(info);
1083
				ErrorConsole.showDialog(JSVGCanvas.this);
1084
			}
1085
		}
1086
	}
1114
1087
1115
        public void mouseMoved(MouseEvent evt) {
1088
	// ----------------------------------------------------------------------
1116
            lastX = evt.getX();
1089
	// Tooltip
1117
            lastY = evt.getY();
1090
	// ----------------------------------------------------------------------
1118
        }
1119
1091
1120
        public int getLastX() {
1092
	/**
1121
            return lastX;
1093
	 * Sets the time and element of the last tool tip event handled.
1122
        }
1094
	 */
1095
	public void setLastToolTipEvent(long t, EventTarget et) {
1096
		lastToolTipEventTimeStamp = t;
1097
		lastToolTipEventTarget = et;
1098
	}
1123
1099
1124
        public int getLastY() {
1100
	/**
1125
            return lastY;
1101
	 * Checks if the specified event time and element are the same as the last
1126
        }
1102
	 * tool tip event.
1127
    }
1103
	 */
1104
	public boolean matchLastToolTipEvent(long t, EventTarget et) {
1105
		return lastToolTipEventTimeStamp == t && lastToolTipEventTarget == et;
1106
	}
1128
1107
1129
    /**
1108
	/**
1130
     * Sets a specific tooltip on the JSVGCanvas when a given event occurs.
1109
	 * Helper class. Simply keeps track of the last known mouse position over
1131
     * This listener is used in the handleElement method to set, remove or
1110
	 * the canvas.
1132
     * modify the JSVGCanvas tooltip on mouseover and on mouseout.<br/>
1111
	 */
1133
     *
1112
	protected class LocationListener extends MouseMotionAdapter {
1134
     * Because we are on a single <tt>JComponent</tt> we trigger an artificial
1135
     * <tt>MouseEvent</tt> when the toolTip is set to a non-null value, so as
1136
     * to make sure it will show after the <tt>ToolTipManager</tt>'s default
1137
     * delay.
1138
     */
1139
    protected class ToolTipModifier implements EventListener {
1140
        /**
1141
         * The CanvasUserAgent used to track the last tool tip event.
1142
         */
1143
        protected CanvasUserAgent canvasUserAgent;
1144
1113
1145
        /**
1114
		protected int lastX, lastY;
1146
         * Creates a new ToolTipModifier object.
1147
         */
1148
        public ToolTipModifier() {
1149
        }
1150
1115
1151
        public void handleEvent(Event evt){
1116
		public LocationListener() {
1152
            // Don't set the tool tip if another ToolTipModifier
1117
			lastX = 0;
1153
            // has already handled this event (as it will have been
1118
			lastY = 0;
1154
            // a higher priority tool tip).
1119
		}
1155
            if (matchLastToolTipEvent(evt.getTimeStamp(), evt.getTarget())) {
1156
                return;
1157
            }
1158
            setLastToolTipEvent(evt.getTimeStamp(), evt.getTarget());
1159
            EventTarget prevLastTarget = lastTarget;
1160
            if (SVGConstants.SVG_EVENT_MOUSEOVER.equals(evt.getType())) {
1161
                lastTarget = evt.getTarget();
1162
            } else if (SVGConstants.SVG_EVENT_MOUSEOUT.equals(evt.getType())) {
1163
                // related target is one it is entering or null.
1164
                org.w3c.dom.events.MouseEvent mouseEvt;
1165
                mouseEvt = ((org.w3c.dom.events.MouseEvent)evt);
1166
                lastTarget = mouseEvt.getRelatedTarget();
1167
            }
1168
1120
1169
            if (toolTipMap != null) {
1121
		public void mouseMoved(MouseEvent evt) {
1170
                Element e = (Element)lastTarget;
1122
			lastX = evt.getX();
1171
                Object o = null;
1123
			lastY = evt.getY();
1172
                while (e != null) {
1124
		}
1173
                    // Search the parents of the current node for ToolTips.
1174
                    o = toolTipMap.get(e);
1175
                    if (o != null) {
1176
                        break;
1177
                    }
1178
                    e = CSSEngine.getParentCSSStylableElement(e);
1179
                }
1180
                final String theToolTip = (String)o;
1181
                if (prevLastTarget != lastTarget)
1182
                    EventQueue.invokeLater(new ToolTipRunnable(theToolTip));
1183
            }
1184
        }
1185
    }
1186
1125
1187
    protected class ToolTipRunnable implements Runnable {
1126
		public int getLastX() {
1188
        String theToolTip;
1127
			return lastX;
1189
        public ToolTipRunnable(String toolTip) {
1128
		}
1190
            this.theToolTip = toolTip;
1191
        }
1192
1129
1193
        public void run() {
1130
		public int getLastY() {
1194
            setToolTipText(theToolTip);
1131
			return lastY;
1132
		}
1133
	}
1195
1134
1196
            MouseEvent e;
1135
	/**
1197
            if (theToolTip != null) {
1136
	 * Sets a specific tooltip on the JSVGCanvas when a given event occurs. This
1198
                e = new MouseEvent
1137
	 * listener is used in the handleElement method to set, remove or modify the
1199
                    (JSVGCanvas.this,
1138
	 * JSVGCanvas tooltip on mouseover and on mouseout.<br/>
1200
                     MouseEvent.MOUSE_ENTERED,
1139
	 * 
1201
                     System.currentTimeMillis(),
1140
	 * Because we are on a single <tt>JComponent</tt> we trigger an artificial
1202
                     0,
1141
	 * <tt>MouseEvent</tt> when the toolTip is set to a non-null value, so as
1203
                     locationListener.getLastX(),
1142
	 * to make sure it will show after the <tt>ToolTipManager</tt>'s default
1204
                     locationListener.getLastY(),
1143
	 * delay.
1205
                     0,
1144
	 */
1206
                     false);
1145
	protected class ToolTipModifier implements EventListener {
1207
                ToolTipManager.sharedInstance().mouseEntered(e);
1146
		/**
1208
                e = new MouseEvent
1147
		 * The CanvasUserAgent used to track the last tool tip event.
1209
                    (JSVGCanvas.this,
1148
		 */
1210
                     MouseEvent.MOUSE_MOVED,
1149
		protected CanvasUserAgent canvasUserAgent;
1211
                     System.currentTimeMillis(),
1150
1212
                     0,
1151
		/**
1213
                     locationListener.getLastX(),
1152
		 * Creates a new ToolTipModifier object.
1214
                     locationListener.getLastY(),
1153
		 */
1215
                     0,
1154
		public ToolTipModifier() {
1216
                     false);
1155
		}
1217
                ToolTipManager.sharedInstance().mouseMoved(e);
1156
1218
            } else {
1157
		public void handleEvent(Event evt) {
1219
                e = new MouseEvent
1158
			// Don't set the tool tip if another ToolTipModifier
1220
                    (JSVGCanvas.this,
1159
			// has already handled this event (as it will have been
1221
                     MouseEvent.MOUSE_MOVED,
1160
			// a higher priority tool tip).
1222
                     System.currentTimeMillis(),
1161
			if (matchLastToolTipEvent(evt.getTimeStamp(), evt.getTarget())) {
1223
                     0,
1162
				return;
1224
                     locationListener.getLastX(),
1163
			}
1225
                     locationListener.getLastY(),
1164
			setLastToolTipEvent(evt.getTimeStamp(), evt.getTarget());
1226
                     0,
1165
			EventTarget prevLastTarget = lastTarget;
1227
                     false);
1166
			if (SVGConstants.SVG_EVENT_MOUSEOVER.equals(evt.getType())) {
1228
                ToolTipManager.sharedInstance().mouseMoved(e);
1167
				lastTarget = evt.getTarget();
1229
            }
1168
			} else if (SVGConstants.SVG_EVENT_MOUSEOUT.equals(evt.getType())) {
1230
        }
1169
				// related target is one it is entering or null.
1231
    }
1170
				org.w3c.dom.events.MouseEvent mouseEvt;
1171
				mouseEvt = ((org.w3c.dom.events.MouseEvent) evt);
1172
				lastTarget = mouseEvt.getRelatedTarget();
1173
			}
1174
1175
			if (toolTipMap != null) {
1176
				Element e = (Element) lastTarget;
1177
				Object o = null;
1178
				while (e != null) {
1179
					// Search the parents of the current node for ToolTips.
1180
					o = toolTipMap.get(e);
1181
					if (o != null) {
1182
						break;
1183
					}
1184
					e = CSSEngine.getParentCSSStylableElement(e);
1185
				}
1186
				final String theToolTip = (String) o;
1187
				if (prevLastTarget != lastTarget)
1188
					EventQueue.invokeLater(new ToolTipRunnable(theToolTip));
1189
			}
1190
		}
1191
	}
1192
1193
	protected class ToolTipRunnable implements Runnable {
1194
		String theToolTip;
1195
1196
		public ToolTipRunnable(String toolTip) {
1197
			this.theToolTip = toolTip;
1198
		}
1199
1200
		public void run() {
1201
			setToolTipText(theToolTip);
1202
1203
			MouseEvent e;
1204
			if (theToolTip != null) {
1205
				e = new MouseEvent(JSVGCanvas.this, MouseEvent.MOUSE_ENTERED,
1206
						System.currentTimeMillis(), 0, locationListener
1207
								.getLastX(), locationListener.getLastY(), 0,
1208
						false);
1209
				ToolTipManager.sharedInstance().mouseEntered(e);
1210
				e = new MouseEvent(JSVGCanvas.this, MouseEvent.MOUSE_MOVED,
1211
						System.currentTimeMillis(), 0, locationListener
1212
								.getLastX(), locationListener.getLastY(), 0,
1213
						false);
1214
				ToolTipManager.sharedInstance().mouseMoved(e);
1215
			} else {
1216
				e = new MouseEvent(JSVGCanvas.this, MouseEvent.MOUSE_MOVED,
1217
						System.currentTimeMillis(), 0, locationListener
1218
								.getLastX(), locationListener.getLastY(), 0,
1219
						false);
1220
				ToolTipManager.sharedInstance().mouseMoved(e);
1221
			}
1222
		}
1223
	}
1232
}
1224
}
(-)sources/org/apache/batik/bridge/SVGShapeElementBridge.java (+7 lines)
Lines 19-24 Link Here
19
package org.apache.batik.bridge;
19
package org.apache.batik.bridge;
20
20
21
import java.awt.RenderingHints;
21
import java.awt.RenderingHints;
22
import java.awt.Shape;
23
import java.awt.geom.Area;
22
24
23
import org.apache.batik.css.engine.CSSEngineEvent;
25
import org.apache.batik.css.engine.CSSEngineEvent;
24
import org.apache.batik.css.engine.SVGCSSEngine;
26
import org.apache.batik.css.engine.SVGCSSEngine;
Lines 35-40 Link Here
35
 */
37
 */
36
public abstract class SVGShapeElementBridge extends AbstractGraphicsNodeBridge {
38
public abstract class SVGShapeElementBridge extends AbstractGraphicsNodeBridge {
37
39
40
	/**
41
	 * 
42
	 */
43
	protected static Shape nullShape = new Area();
44
	
38
    /**
45
    /**
39
     * Constructs a new bridge for SVG shapes.
46
     * Constructs a new bridge for SVG shapes.
40
     */
47
     */
(-)sources/org/apache/batik/bridge/DocumentLoader.java (-3 / +20 lines)
Lines 18-32 Link Here
18
 */
18
 */
19
package org.apache.batik.bridge;
19
package org.apache.batik.bridge;
20
20
21
import java.io.IOException;
21
import java.io.InputStream;
22
import java.io.InputStream;
22
import java.io.IOException;
23
import java.util.HashMap;
23
import java.util.HashMap;
24
24
25
import org.apache.batik.dom.svg.SAXSVGDocumentFactory;
25
import org.apache.batik.dom.svg.SAXSVGDocumentFactory;
26
import org.apache.batik.dom.svg.SVGDocumentFactory;
26
import org.apache.batik.dom.svg.SVGDocumentFactory;
27
import org.apache.batik.dom.util.DocumentDescriptor;
27
import org.apache.batik.dom.util.DocumentDescriptor;
28
import org.apache.batik.util.CleanerThread;
28
import org.apache.batik.util.CleanerThread;
29
30
import org.w3c.dom.Document;
29
import org.w3c.dom.Document;
31
import org.w3c.dom.Element;
30
import org.w3c.dom.Element;
32
import org.w3c.dom.svg.SVGDocument;
31
import org.w3c.dom.svg.SVGDocument;
Lines 104-110 Link Here
104
            return ret;
103
            return ret;
105
104
106
        SVGDocument document = documentFactory.createSVGDocument(uri);
105
        SVGDocument document = documentFactory.createSVGDocument(uri);
107
108
        DocumentDescriptor desc = documentFactory.getDocumentDescriptor();
106
        DocumentDescriptor desc = documentFactory.getDocumentDescriptor();
109
        DocumentState state = new DocumentState(uri, document, desc);
107
        DocumentState state = new DocumentState(uri, document, desc);
110
        synchronized (cacheMap) {
108
        synchronized (cacheMap) {
Lines 176-181 Link Here
176
    }
174
    }
177
175
178
    /**
176
    /**
177
     * Returns the document descriptor of the last loaded document
178
     *
179
     * @return the document descriptor of the last loaded document, or
180
     * null if no document has been loaded.
181
     */
182
    public DocumentDescriptor getDocumentDescriptor(SVGDocument doc) {
183
        String uri = doc.getURL();
184
        DocumentState state;
185
        synchronized (cacheMap) {
186
            state = (DocumentState)cacheMap.get(uri);
187
        }
188
        if (state == null) {
189
            return null;
190
        } else {
191
            return state.desc;
192
        }
193
    }
194
195
    /**
179
     * A simple class that contains a Document and its number of nodes.
196
     * A simple class that contains a Document and its number of nodes.
180
     */
197
     */
181
    private class DocumentState extends CleanerThread.SoftReferenceCleared {
198
    private class DocumentState extends CleanerThread.SoftReferenceCleared {
(-)sources/org/apache/batik/bridge/SVGCircleElementBridge.java (-1 / +6 lines)
Lines 90-96 Link Here
90
            float w = r * 2;
90
            float w = r * 2;
91
            shapeNode.setShape(new Ellipse2D.Float(x, y, w, w));
91
            shapeNode.setShape(new Ellipse2D.Float(x, y, w, w));
92
        } catch (LiveAttributeException ex) {
92
        } catch (LiveAttributeException ex) {
93
            throw new BridgeException(ctx, ex);
93
        	if (strictParsing) {
94
	            throw new BridgeException(ctx, ex);
95
        	} else {
96
        		ctx.userAgent.displayError(ex);
97
        		shapeNode.setShape(nullShape);
98
        	}
94
        }
99
        }
95
    }
100
    }
96
101
(-)sources/org/apache/batik/bridge/SVGPolygonElementBridge.java (-1 / +7 lines)
Lines 20-25 Link Here
20
20
21
import java.awt.Shape;
21
import java.awt.Shape;
22
import java.awt.geom.GeneralPath;
22
import java.awt.geom.GeneralPath;
23
import java.awt.geom.Rectangle2D;
23
24
24
import org.apache.batik.css.engine.SVGCSSEngine;
25
import org.apache.batik.css.engine.SVGCSSEngine;
25
import org.apache.batik.dom.svg.AnimatedLiveAttributeValue;
26
import org.apache.batik.dom.svg.AnimatedLiveAttributeValue;
Lines 98-104 Link Here
98
                shapeNode.setShape(app.getShape());
99
                shapeNode.setShape(app.getShape());
99
            }
100
            }
100
        } catch (LiveAttributeException ex) {
101
        } catch (LiveAttributeException ex) {
101
            throw new BridgeException(ctx, ex);
102
        	if (strictParsing) {
103
	            throw new BridgeException(ctx, ex);
104
        	} else {
105
        		ctx.userAgent.displayError(ex);
106
        		shapeNode.setShape(nullShape);
107
        	}
102
        }
108
        }
103
    }
109
    }
104
110
(-)sources/org/apache/batik/bridge/SVGEllipseElementBridge.java (-1 / +6 lines)
Lines 93-99 Link Here
93
            shapeNode.setShape(new Ellipse2D.Float(cx - rx, cy - ry,
93
            shapeNode.setShape(new Ellipse2D.Float(cx - rx, cy - ry,
94
                                                   rx * 2, ry * 2));
94
                                                   rx * 2, ry * 2));
95
        } catch (LiveAttributeException ex) {
95
        } catch (LiveAttributeException ex) {
96
            throw new BridgeException(ctx, ex);
96
        	if (strictParsing) {
97
	            throw new BridgeException(ctx, ex);
98
        	} else {
99
        		ctx.userAgent.displayError(ex);
100
        		shapeNode.setShape(nullShape);
101
        	}
97
        }
102
        }
98
    }
103
    }
99
104
(-)sources/org/apache/batik/bridge/SVGRectElementBridge.java (-2 / +6 lines)
Lines 28-34 Link Here
28
import org.apache.batik.dom.svg.SVGOMRectElement;
28
import org.apache.batik.dom.svg.SVGOMRectElement;
29
import org.apache.batik.gvt.ShapeNode;
29
import org.apache.batik.gvt.ShapeNode;
30
import org.apache.batik.gvt.ShapePainter;
30
import org.apache.batik.gvt.ShapePainter;
31
32
import org.w3c.dom.Element;
31
import org.w3c.dom.Element;
33
32
34
/**
33
/**
Lines 116-122 Link Here
116
            }
115
            }
117
            shapeNode.setShape(shape);
116
            shapeNode.setShape(shape);
118
        } catch (LiveAttributeException ex) {
117
        } catch (LiveAttributeException ex) {
119
            throw new BridgeException(ctx, ex);
118
        	if (strictParsing) {
119
	            throw new BridgeException(ctx, ex);
120
        	} else {
121
        		ctx.userAgent.displayError(ex);
122
        		shapeNode.setShape(nullShape);
123
        	}
120
        }
124
        }
121
    }
125
    }
122
126
(-)sources/org/apache/batik/apps/svgbrowser/srcview/TextAreaPainter.java (+693 lines)
Line 0 Link Here
1
/*
2
 * TextAreaPainter.java - Paints the text area
3
 * Copyright (C) 1999 Slava Pestov
4
 *
5
 * You may use and modify this package for any purpose. Redistribution is
6
 * permitted, in both source and binary form, provided that this notice
7
 * remains intact in all source distributions of this package.
8
 */
9
package org.apache.batik.apps.svgbrowser.srcview;
10
11
import javax.swing.ToolTipManager;
12
import javax.swing.text.*;
13
import javax.swing.JComponent;
14
import java.awt.event.MouseEvent;
15
import java.awt.*;
16
17
/**
18
 * The text area repaint manager. It performs double buffering and paints
19
 * lines of text.
20
 * @author Slava Pestov
21
 * @version $Id: TextAreaPainter.java,v 1.24 1999/12/13 03:40:30 sp Exp $
22
 */
23
public class TextAreaPainter extends JComponent implements TabExpander
24
{
25
	/**
26
	 * Creates a new repaint manager. This should be not be called
27
	 * directly.
28
	 */
29
	public TextAreaPainter(JEditTextArea textArea, TextAreaDefaults defaults)
30
	{
31
		this.textArea = textArea;
32
33
		setAutoscrolls(true);
34
		setDoubleBuffered(true);
35
		setOpaque(true);
36
37
		ToolTipManager.sharedInstance().registerComponent(this);
38
39
		currentLine = new Segment();
40
		currentLineIndex = -1;
41
42
		setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
43
44
		setFont(new Font("Monospaced",Font.PLAIN,14));
45
		setForeground(Color.black);
46
		setBackground(Color.white);
47
48
		blockCaret = defaults.blockCaret;
49
		styles = defaults.styles;
50
		cols = defaults.cols;
51
		rows = defaults.rows;
52
		caretColor = defaults.caretColor;
53
		selectionColor = defaults.selectionColor;
54
		lineHighlightColor = defaults.lineHighlightColor;
55
		lineHighlight = defaults.lineHighlight;
56
		bracketHighlightColor = defaults.bracketHighlightColor;
57
		bracketHighlight = defaults.bracketHighlight;
58
		paintInvalid = defaults.paintInvalid;
59
		eolMarkerColor = defaults.eolMarkerColor;
60
		eolMarkers = defaults.eolMarkers;
61
	}
62
63
	/**
64
	 * Returns if this component can be traversed by pressing the
65
	 * Tab key. This returns false.
66
	 */
67
	public final boolean isManagingFocus()
68
	{
69
		return false;
70
	}
71
72
	/**
73
	 * Returns the syntax styles used to paint colorized text. Entry <i>n</i>
74
	 * will be used to paint tokens with id = <i>n</i>.
75
	 * @see org.gjt.sp.jedit.syntax.Token
76
	 */
77
	public final SyntaxStyle[] getStyles()
78
	{
79
		return styles;
80
	}
81
82
	/**
83
	 * Sets the syntax styles used to paint colorized text. Entry <i>n</i>
84
	 * will be used to paint tokens with id = <i>n</i>.
85
	 * @param styles The syntax styles
86
	 * @see org.gjt.sp.jedit.syntax.Token
87
	 */
88
	public final void setStyles(SyntaxStyle[] styles)
89
	{
90
		this.styles = styles;
91
		repaint();
92
	}
93
94
	/**
95
	 * Returns the caret color.
96
	 */
97
	public final Color getCaretColor()
98
	{
99
		return caretColor;
100
	}
101
102
	/**
103
	 * Sets the caret color.
104
	 * @param caretColor The caret color
105
	 */
106
	public final void setCaretColor(Color caretColor)
107
	{
108
		this.caretColor = caretColor;
109
		invalidateSelectedLines();
110
	}
111
112
	/**
113
	 * Returns the selection color.
114
	 */
115
	public final Color getSelectionColor()
116
	{
117
		return selectionColor;
118
	}
119
120
	/**
121
	 * Sets the selection color.
122
	 * @param selectionColor The selection color
123
	 */
124
	public final void setSelectionColor(Color selectionColor)
125
	{
126
		this.selectionColor = selectionColor;
127
		invalidateSelectedLines();
128
	}
129
130
	/**
131
	 * Returns the line highlight color.
132
	 */
133
	public final Color getLineHighlightColor()
134
	{
135
		return lineHighlightColor;
136
	}
137
138
	/**
139
	 * Sets the line highlight color.
140
	 * @param lineHighlightColor The line highlight color
141
	 */
142
	public final void setLineHighlightColor(Color lineHighlightColor)
143
	{
144
		this.lineHighlightColor = lineHighlightColor;
145
		invalidateSelectedLines();
146
	}
147
148
	/**
149
	 * Returns true if line highlight is enabled, false otherwise.
150
	 */
151
	public final boolean isLineHighlightEnabled()
152
	{
153
		return lineHighlight;
154
	}
155
156
	/**
157
	 * Enables or disables current line highlighting.
158
	 * @param lineHighlight True if current line highlight should be enabled,
159
	 * false otherwise
160
	 */
161
	public final void setLineHighlightEnabled(boolean lineHighlight)
162
	{
163
		this.lineHighlight = lineHighlight;
164
		invalidateSelectedLines();
165
	}
166
167
	/**
168
	 * Returns the bracket highlight color.
169
	 */
170
	public final Color getBracketHighlightColor()
171
	{
172
		return bracketHighlightColor;
173
	}
174
175
	/**
176
	 * Sets the bracket highlight color.
177
	 * @param bracketHighlightColor The bracket highlight color
178
	 */
179
	public final void setBracketHighlightColor(Color bracketHighlightColor)
180
	{
181
		this.bracketHighlightColor = bracketHighlightColor;
182
		invalidateLine(textArea.getBracketLine());
183
	}
184
185
	/**
186
	 * Returns true if bracket highlighting is enabled, false otherwise.
187
	 * When bracket highlighting is enabled, the bracket matching the
188
	 * one before the caret (if any) is highlighted.
189
	 */
190
	public final boolean isBracketHighlightEnabled()
191
	{
192
		return bracketHighlight;
193
	}
194
195
	/**
196
	 * Enables or disables bracket highlighting.
197
	 * When bracket highlighting is enabled, the bracket matching the
198
	 * one before the caret (if any) is highlighted.
199
	 * @param bracketHighlight True if bracket highlighting should be
200
	 * enabled, false otherwise
201
	 */
202
	public final void setBracketHighlightEnabled(boolean bracketHighlight)
203
	{
204
		this.bracketHighlight = bracketHighlight;
205
		invalidateLine(textArea.getBracketLine());
206
	}
207
208
	/**
209
	 * Returns true if the caret should be drawn as a block, false otherwise.
210
	 */
211
	public final boolean isBlockCaretEnabled()
212
	{
213
		return blockCaret;
214
	}
215
216
	/**
217
	 * Sets if the caret should be drawn as a block, false otherwise.
218
	 * @param blockCaret True if the caret should be drawn as a block,
219
	 * false otherwise.
220
	 */
221
	public final void setBlockCaretEnabled(boolean blockCaret)
222
	{
223
		this.blockCaret = blockCaret;
224
		invalidateSelectedLines();
225
	}
226
227
	/**
228
	 * Returns the EOL marker color.
229
	 */
230
	public final Color getEOLMarkerColor()
231
	{
232
		return eolMarkerColor;
233
	}
234
235
	/**
236
	 * Sets the EOL marker color.
237
	 * @param eolMarkerColor The EOL marker color
238
	 */
239
	public final void setEOLMarkerColor(Color eolMarkerColor)
240
	{
241
		this.eolMarkerColor = eolMarkerColor;
242
		repaint();
243
	}
244
245
	/**
246
	 * Returns true if EOL markers are drawn, false otherwise.
247
	 */
248
	public final boolean getEOLMarkersPainted()
249
	{
250
		return eolMarkers;
251
	}
252
253
	/**
254
	 * Sets if EOL markers are to be drawn.
255
	 * @param eolMarkers True if EOL markers should be drawn, false otherwise
256
	 */
257
	public final void setEOLMarkersPainted(boolean eolMarkers)
258
	{
259
		this.eolMarkers = eolMarkers;
260
		repaint();
261
	}
262
263
	/**
264
	 * Returns true if invalid lines are painted as red tildes (~),
265
	 * false otherwise.
266
	 */
267
	public boolean getInvalidLinesPainted()
268
	{
269
		return paintInvalid;
270
	}
271
272
	/**
273
	 * Sets if invalid lines are to be painted as red tildes.
274
	 * @param paintInvalid True if invalid lines should be drawn, false otherwise
275
	 */
276
	public void setInvalidLinesPainted(boolean paintInvalid)
277
	{
278
		this.paintInvalid = paintInvalid;
279
	}
280
281
	/**
282
	 * Adds a custom highlight painter.
283
	 * @param highlight The highlight
284
	 */
285
	public void addCustomHighlight(Highlight highlight)
286
	{
287
		highlight.init(textArea,highlights);
288
		highlights = highlight;
289
	}
290
291
	/**
292
	 * Highlight interface.
293
	 */
294
	public interface Highlight
295
	{
296
		/**
297
		 * Called after the highlight painter has been added.
298
		 * @param textArea The text area
299
		 * @param next The painter this one should delegate to
300
		 */
301
		void init(JEditTextArea textArea, Highlight next);
302
303
		/**
304
		 * This should paint the highlight and delgate to the
305
		 * next highlight painter.
306
		 * @param gfx The graphics context
307
		 * @param line The line number
308
		 * @param y The y co-ordinate of the line
309
		 */
310
		void paintHighlight(Graphics gfx, int line, int y);
311
312
		/**
313
		 * Returns the tool tip to display at the specified
314
		 * location. If this highlighter doesn't know what to
315
		 * display, it should delegate to the next highlight
316
		 * painter.
317
		 * @param evt The mouse event
318
		 */
319
		String getToolTipText(MouseEvent evt);
320
	}
321
322
	/**
323
	 * Returns the tool tip to display at the specified location.
324
	 * @param evt The mouse event
325
	 */
326
	public String getToolTipText(MouseEvent evt)
327
	{
328
		if(highlights != null)
329
			return highlights.getToolTipText(evt);
330
		else
331
			return null;
332
	}
333
334
	/**
335
	 * Returns the font metrics used by this component.
336
	 */
337
	public FontMetrics getFontMetrics()
338
	{
339
		return fm;
340
	}
341
342
	/**
343
	 * Sets the font for this component. This is overridden to update the
344
	 * cached font metrics and to recalculate which lines are visible.
345
	 * @param font The font
346
	 */
347
	public void setFont(Font font)
348
	{
349
		super.setFont(font);
350
		fm = Toolkit.getDefaultToolkit().getFontMetrics(font);
351
		textArea.recalculateVisibleLines();
352
	}
353
354
	/**
355
	 * Repaints the text.
356
	 * @param g The graphics context
357
	 */
358
	public void paint(Graphics gfx)
359
	{
360
		tabSize = fm.charWidth(' ') * ((Integer)textArea
361
			.getDocument().getProperty(
362
			PlainDocument.tabSizeAttribute)).intValue();
363
364
		Rectangle clipRect = gfx.getClipBounds();
365
366
		gfx.setColor(getBackground());
367
		gfx.fillRect(clipRect.x,clipRect.y,clipRect.width,clipRect.height);
368
369
		// We don't use yToLine() here because that method doesn't
370
		// return lines past the end of the document
371
		int height = fm.getHeight();
372
		int firstLine = textArea.getFirstLine();
373
		int firstInvalid = firstLine + clipRect.y / height;
374
		// Because the clipRect's height is usually an even multiple
375
		// of the font height, we subtract 1 from it, otherwise one
376
		// too many lines will always be painted.
377
		int lastInvalid = firstLine + (clipRect.y + clipRect.height - 1) / height;
378
379
		try
380
		{
381
			TokenMarker tokenMarker = textArea.getDocument()
382
				.getTokenMarker();
383
			int x = textArea.getHorizontalOffset();
384
385
			for(int line = firstInvalid; line <= lastInvalid; line++)
386
			{
387
				paintLine(gfx,tokenMarker,line,x);
388
			}
389
390
			if(tokenMarker != null && tokenMarker.isNextLineRequested())
391
			{
392
				int h = clipRect.y + clipRect.height;
393
				repaint(0,h,getWidth(),getHeight() - h);
394
			}
395
		}
396
		catch(Exception e)
397
		{
398
			System.err.println("Error repainting line"
399
				+ " range {" + firstInvalid + ","
400
				+ lastInvalid + "}:");
401
			e.printStackTrace();
402
		}
403
	}
404
405
	/**
406
	 * Marks a line as needing a repaint.
407
	 * @param line The line to invalidate
408
	 */
409
	public final void invalidateLine(int line)
410
	{
411
		repaint(0,textArea.lineToY(line) + fm.getMaxDescent() + fm.getLeading(),
412
			getWidth(),fm.getHeight());
413
	}
414
415
	/**
416
	 * Marks a range of lines as needing a repaint.
417
	 * @param firstLine The first line to invalidate
418
	 * @param lastLine The last line to invalidate
419
	 */
420
	public final void invalidateLineRange(int firstLine, int lastLine)
421
	{
422
		repaint(0,textArea.lineToY(firstLine) + fm.getMaxDescent() + fm.getLeading(),
423
			getWidth(),(lastLine - firstLine + 1) * fm.getHeight());
424
	}
425
426
	/**
427
	 * Repaints the lines containing the selection.
428
	 */
429
	public final void invalidateSelectedLines()
430
	{
431
		invalidateLineRange(textArea.getSelectionStartLine(),
432
			textArea.getSelectionEndLine());
433
	}
434
435
	/**
436
	 * Implementation of TabExpander interface. Returns next tab stop after
437
	 * a specified point.
438
	 * @param x The x co-ordinate
439
	 * @param tabOffset Ignored
440
	 * @return The next tab stop after <i>x</i>
441
	 */
442
	public float nextTabStop(float x, int tabOffset)
443
	{
444
		int offset = textArea.getHorizontalOffset();
445
		int ntabs = ((int)x - offset) / tabSize;
446
		return (ntabs + 1) * tabSize + offset;
447
	}
448
449
	/**
450
	 * Returns the painter's preferred size.
451
	 */
452
	public Dimension getPreferredSize()
453
	{
454
		Dimension dim = new Dimension();
455
		dim.width = fm.charWidth('w') * cols;
456
		dim.height = fm.getHeight() * rows;
457
		return dim;
458
	}
459
460
461
	/**
462
	 * Returns the painter's minimum size.
463
	 */
464
	public Dimension getMinimumSize()
465
	{
466
		return getPreferredSize();
467
	}
468
469
	// package-private members
470
	int currentLineIndex;
471
	Token currentLineTokens;
472
	Segment currentLine;
473
474
	// protected members
475
	protected JEditTextArea textArea;
476
	
477
	protected SyntaxStyle[] styles;
478
	protected Color caretColor;
479
	protected Color selectionColor;
480
	protected Color lineHighlightColor;
481
	protected Color bracketHighlightColor;
482
	protected Color eolMarkerColor;
483
484
	protected boolean blockCaret;
485
	protected boolean lineHighlight;
486
	protected boolean bracketHighlight;
487
	protected boolean paintInvalid;
488
	protected boolean eolMarkers;
489
	protected int cols;
490
	protected int rows;
491
	
492
	protected int tabSize;
493
	protected FontMetrics fm;
494
495
	protected Highlight highlights;
496
497
	protected void paintLine(Graphics gfx, TokenMarker tokenMarker,
498
		int line, int x)
499
	{
500
		Font defaultFont = getFont();
501
		Color defaultColor = getForeground();
502
503
		currentLineIndex = line;
504
		int y = textArea.lineToY(line);
505
506
		if(line < 0 || line >= textArea.getLineCount())
507
		{
508
			if(paintInvalid)
509
			{
510
				paintHighlight(gfx,line,y);
511
				styles[Token.INVALID].setGraphicsFlags(gfx,defaultFont);
512
				gfx.drawString("~",0,y + fm.getHeight());
513
			}
514
		}
515
		else if(tokenMarker == null)
516
		{
517
			paintPlainLine(gfx,line,defaultFont,defaultColor,x,y);
518
		}
519
		else
520
		{
521
			paintSyntaxLine(gfx,tokenMarker,line,defaultFont,
522
				defaultColor,x,y);
523
		}
524
	}
525
526
	protected void paintPlainLine(Graphics gfx, int line, Font defaultFont,
527
		Color defaultColor, int x, int y)
528
	{
529
		paintHighlight(gfx,line,y);
530
		textArea.getLineText(line,currentLine);
531
532
		gfx.setFont(defaultFont);
533
		gfx.setColor(defaultColor);
534
535
		y += fm.getHeight();
536
		x = Utilities.drawTabbedText(currentLine,x,y,gfx,this,0);
537
538
		if(eolMarkers)
539
		{
540
			gfx.setColor(eolMarkerColor);
541
			gfx.drawString(".",x,y);
542
		}
543
	}
544
545
	protected void paintSyntaxLine(Graphics gfx, TokenMarker tokenMarker,
546
		int line, Font defaultFont, Color defaultColor, int x, int y)
547
	{
548
		textArea.getLineText(currentLineIndex,currentLine);
549
		currentLineTokens = tokenMarker.markTokens(currentLine,
550
			currentLineIndex);
551
552
		paintHighlight(gfx,line,y);
553
554
		gfx.setFont(defaultFont);
555
		gfx.setColor(defaultColor);
556
		y += fm.getHeight();
557
		x = SyntaxUtilities.paintSyntaxLine(currentLine,
558
			currentLineTokens,styles,this,gfx,x,y);
559
560
		if(eolMarkers)
561
		{
562
			gfx.setColor(eolMarkerColor);
563
			gfx.drawString(".",x,y);
564
		}
565
	}
566
567
	protected void paintHighlight(Graphics gfx, int line, int y)
568
	{
569
		if(line >= textArea.getSelectionStartLine()
570
			&& line <= textArea.getSelectionEndLine())
571
			paintLineHighlight(gfx,line,y);
572
573
		if(highlights != null)
574
			highlights.paintHighlight(gfx,line,y);
575
576
		if(bracketHighlight && line == textArea.getBracketLine())
577
			paintBracketHighlight(gfx,line,y);
578
579
		if(line == textArea.getCaretLine())
580
			paintCaret(gfx,line,y);
581
	}
582
583
	protected void paintLineHighlight(Graphics gfx, int line, int y)
584
	{
585
		int height = fm.getHeight();
586
		y += fm.getLeading() + fm.getMaxDescent();
587
588
		int selectionStart = textArea.getSelectionStart();
589
		int selectionEnd = textArea.getSelectionEnd();
590
591
		if(selectionStart == selectionEnd)
592
		{
593
			if(lineHighlight)
594
			{
595
				gfx.setColor(lineHighlightColor);
596
				gfx.fillRect(0,y,getWidth(),height);
597
			}
598
		}
599
		else
600
		{
601
			gfx.setColor(selectionColor);
602
603
			int selectionStartLine = textArea.getSelectionStartLine();
604
			int selectionEndLine = textArea.getSelectionEndLine();
605
			int lineStart = textArea.getLineStartOffset(line);
606
607
			int x1, x2;
608
			if(textArea.isSelectionRectangular())
609
			{
610
				int lineLen = textArea.getLineLength(line);
611
				x1 = textArea._offsetToX(line,Math.min(lineLen,
612
					selectionStart - textArea.getLineStartOffset(
613
					selectionStartLine)));
614
				x2 = textArea._offsetToX(line,Math.min(lineLen,
615
					selectionEnd - textArea.getLineStartOffset(
616
					selectionEndLine)));
617
				if(x1 == x2)
618
					x2++;
619
			}
620
			else if(selectionStartLine == selectionEndLine)
621
			{
622
				x1 = textArea._offsetToX(line,
623
					selectionStart - lineStart);
624
				x2 = textArea._offsetToX(line,
625
					selectionEnd - lineStart);
626
			}
627
			else if(line == selectionStartLine)
628
			{
629
				x1 = textArea._offsetToX(line,
630
					selectionStart - lineStart);
631
				x2 = getWidth();
632
			}
633
			else if(line == selectionEndLine)
634
			{
635
				x1 = 0;
636
				x2 = textArea._offsetToX(line,
637
					selectionEnd - lineStart);
638
			}
639
			else
640
			{
641
				x1 = 0;
642
				x2 = getWidth();
643
			}
644
645
			// "inlined" min/max()
646
			gfx.fillRect(x1 > x2 ? x2 : x1,y,x1 > x2 ?
647
				(x1 - x2) : (x2 - x1),height);
648
		}
649
650
	}
651
652
	protected void paintBracketHighlight(Graphics gfx, int line, int y)
653
	{
654
		int position = textArea.getBracketPosition();
655
		if(position == -1)
656
			return;
657
		y += fm.getLeading() + fm.getMaxDescent();
658
		int x = textArea._offsetToX(line,position);
659
		gfx.setColor(bracketHighlightColor);
660
		// Hack!!! Since there is no fast way to get the character
661
		// from the bracket matching routine, we use ( since all
662
		// brackets probably have the same width anyway
663
		gfx.drawRect(x,y,fm.charWidth('(') - 1,
664
			fm.getHeight() - 1);
665
	}
666
667
	protected void paintCaret(Graphics gfx, int line, int y)
668
	{
669
		if(textArea.isCaretVisible())
670
		{
671
			int offset = textArea.getCaretPosition() 
672
				- textArea.getLineStartOffset(line);
673
			int caretX = textArea._offsetToX(line,offset);
674
			int caretWidth = ((blockCaret ||
675
				textArea.isOverwriteEnabled()) ?
676
				fm.charWidth('w') : 1);
677
			y += fm.getLeading() + fm.getMaxDescent();
678
			int height = fm.getHeight();
679
			
680
			gfx.setColor(caretColor);
681
682
			if(textArea.isOverwriteEnabled())
683
			{
684
				gfx.fillRect(caretX,y + height - 1,
685
					caretWidth,1);
686
			}
687
			else
688
			{
689
				gfx.drawRect(caretX,y,caretWidth - 1,height - 1);
690
			}
691
		}
692
	}
693
}
(-)sources/org/apache/batik/apps/svgbrowser/srcview/DefaultInputHandler.java (+347 lines)
Line 0 Link Here
1
/*
2
 * DefaultInputHandler.java - Default implementation of an input handler
3
 * Copyright (C) 1999 Slava Pestov
4
 *
5
 * You may use and modify this package for any purpose. Redistribution is
6
 * permitted, in both source and binary form, provided that this notice
7
 * remains intact in all source distributions of this package.
8
 */
9
package org.apache.batik.apps.svgbrowser.srcview;
10
11
import javax.swing.KeyStroke;
12
import java.awt.event.*;
13
import java.awt.Toolkit;
14
import java.util.Hashtable;
15
import java.util.StringTokenizer;
16
17
/**
18
 * The default input handler. It maps sequences of keystrokes into actions
19
 * and inserts key typed events into the text area.
20
 * @author Slava Pestov
21
 * @version $Id: DefaultInputHandler.java,v 1.18 1999/12/13 03:40:30 sp Exp $
22
 */
23
public class DefaultInputHandler extends InputHandler
24
{
25
	/**
26
	 * Creates a new input handler with no key bindings defined.
27
	 */
28
	public DefaultInputHandler()
29
	{
30
		bindings = currentBindings = new Hashtable();
31
	}
32
33
	/**
34
	 * Sets up the default key bindings.
35
	 */
36
	public void addDefaultKeyBindings()
37
	{
38
		addKeyBinding("BACK_SPACE",BACKSPACE);
39
		addKeyBinding("C+BACK_SPACE",BACKSPACE_WORD);
40
		addKeyBinding("DELETE",DELETE);
41
		addKeyBinding("C+DELETE",DELETE_WORD);
42
43
		addKeyBinding("ENTER",INSERT_BREAK);
44
		addKeyBinding("TAB",INSERT_TAB);
45
46
		addKeyBinding("INSERT",OVERWRITE);
47
		addKeyBinding("C+\\",TOGGLE_RECT);
48
49
		addKeyBinding("HOME",HOME);
50
		addKeyBinding("END",END);
51
		addKeyBinding("S+HOME",SELECT_HOME);
52
		addKeyBinding("S+END",SELECT_END);
53
		addKeyBinding("C+HOME",DOCUMENT_HOME);
54
		addKeyBinding("C+END",DOCUMENT_END);
55
		addKeyBinding("CS+HOME",SELECT_DOC_HOME);
56
		addKeyBinding("CS+END",SELECT_DOC_END);
57
58
		addKeyBinding("PAGE_UP",PREV_PAGE);
59
		addKeyBinding("PAGE_DOWN",NEXT_PAGE);
60
		addKeyBinding("S+PAGE_UP",SELECT_PREV_PAGE);
61
		addKeyBinding("S+PAGE_DOWN",SELECT_NEXT_PAGE);
62
63
		addKeyBinding("LEFT",PREV_CHAR);
64
		addKeyBinding("S+LEFT",SELECT_PREV_CHAR);
65
		addKeyBinding("C+LEFT",PREV_WORD);
66
		addKeyBinding("CS+LEFT",SELECT_PREV_WORD);
67
		addKeyBinding("RIGHT",NEXT_CHAR);
68
		addKeyBinding("S+RIGHT",SELECT_NEXT_CHAR);
69
		addKeyBinding("C+RIGHT",NEXT_WORD);
70
		addKeyBinding("CS+RIGHT",SELECT_NEXT_WORD);
71
		addKeyBinding("UP",PREV_LINE);
72
		addKeyBinding("S+UP",SELECT_PREV_LINE);
73
		addKeyBinding("DOWN",NEXT_LINE);
74
		addKeyBinding("S+DOWN",SELECT_NEXT_LINE);
75
76
		addKeyBinding("C+ENTER",REPEAT);
77
	}
78
79
	/**
80
	 * Adds a key binding to this input handler. The key binding is
81
	 * a list of white space separated key strokes of the form
82
	 * <i>[modifiers+]key</i> where modifier is C for Control, A for Alt,
83
	 * or S for Shift, and key is either a character (a-z) or a field
84
	 * name in the KeyEvent class prefixed with VK_ (e.g., BACK_SPACE)
85
	 * @param keyBinding The key binding
86
	 * @param action The action
87
	 */
88
	public void addKeyBinding(String keyBinding, ActionListener action)
89
	{
90
	        Hashtable current = bindings;
91
92
		StringTokenizer st = new StringTokenizer(keyBinding);
93
		while(st.hasMoreTokens())
94
		{
95
			KeyStroke keyStroke = parseKeyStroke(st.nextToken());
96
			if(keyStroke == null)
97
				return;
98
99
			if(st.hasMoreTokens())
100
			{
101
				Object o = current.get(keyStroke);
102
				if(o instanceof Hashtable)
103
					current = (Hashtable)o;
104
				else
105
				{
106
					o = new Hashtable();
107
					current.put(keyStroke,o);
108
					current = (Hashtable)o;
109
				}
110
			}
111
			else
112
				current.put(keyStroke,action);
113
		}
114
	}
115
116
	/**
117
	 * Removes a key binding from this input handler. This is not yet
118
	 * implemented.
119
	 * @param keyBinding The key binding
120
	 */
121
	public void removeKeyBinding(String keyBinding)
122
	{
123
		throw new InternalError("Not yet implemented");
124
	}
125
126
	/**
127
	 * Removes all key bindings from this input handler.
128
	 */
129
	public void removeAllKeyBindings()
130
	{
131
		bindings.clear();
132
	}
133
134
	/**
135
	 * Returns a copy of this input handler that shares the same
136
	 * key bindings. Setting key bindings in the copy will also
137
	 * set them in the original.
138
	 */
139
	public InputHandler copy()
140
	{
141
		return new DefaultInputHandler(this);
142
	}
143
144
	/**
145
	 * Handle a key pressed event. This will look up the binding for
146
	 * the key stroke and execute it.
147
	 */
148
	public void keyPressed(KeyEvent evt)
149
	{
150
		int keyCode = evt.getKeyCode();
151
		int modifiers = evt.getModifiers();
152
153
		if(keyCode == KeyEvent.VK_CONTROL ||
154
			keyCode == KeyEvent.VK_SHIFT ||
155
			keyCode == KeyEvent.VK_ALT ||
156
			keyCode == KeyEvent.VK_META)
157
			return;
158
159
		if((modifiers & ~KeyEvent.SHIFT_MASK) != 0
160
			|| evt.isActionKey()
161
			|| keyCode == KeyEvent.VK_BACK_SPACE
162
			|| keyCode == KeyEvent.VK_DELETE
163
			|| keyCode == KeyEvent.VK_ENTER
164
			|| keyCode == KeyEvent.VK_TAB
165
			|| keyCode == KeyEvent.VK_ESCAPE)
166
		{
167
			if(grabAction != null)
168
			{
169
				handleGrabAction(evt);
170
				return;
171
			}
172
173
			KeyStroke keyStroke = KeyStroke.getKeyStroke(keyCode,
174
				modifiers);
175
			Object o = currentBindings.get(keyStroke);
176
			if(o == null)
177
			{
178
				// Don't beep if the user presses some
179
				// key we don't know about unless a
180
				// prefix is active. Otherwise it will
181
				// beep when caps lock is pressed, etc.
182
				if(currentBindings != bindings)
183
				{
184
					Toolkit.getDefaultToolkit().beep();
185
					// F10 should be passed on, but C+e F10
186
					// shouldn't
187
					repeatCount = 0;
188
					repeat = false;
189
					evt.consume();
190
				}
191
				currentBindings = bindings;
192
				return;
193
			}
194
			else if(o instanceof ActionListener)
195
			{
196
				currentBindings = bindings;
197
198
				executeAction(((ActionListener)o),
199
					evt.getSource(),null);
200
201
				evt.consume();
202
				return;
203
			}
204
			else if(o instanceof Hashtable)
205
			{
206
				currentBindings = (Hashtable)o;
207
				evt.consume();
208
				return;
209
			}
210
		}
211
	}
212
213
	/**
214
	 * Handle a key typed event. This inserts the key into the text area.
215
	 */
216
	public void keyTyped(KeyEvent evt)
217
	{
218
		int modifiers = evt.getModifiers();
219
		char c = evt.getKeyChar();
220
		if(c != KeyEvent.CHAR_UNDEFINED &&
221
			(modifiers & KeyEvent.ALT_MASK) == 0)
222
		{
223
			if(c >= 0x20 && c != 0x7f)
224
			{
225
				KeyStroke keyStroke = KeyStroke.getKeyStroke(
226
					Character.toUpperCase(c));
227
				Object o = currentBindings.get(keyStroke);
228
229
				if(o instanceof Hashtable)
230
				{
231
					currentBindings = (Hashtable)o;
232
					return;
233
				}
234
				else if(o instanceof ActionListener)
235
				{
236
					currentBindings = bindings;
237
					executeAction((ActionListener)o,
238
						evt.getSource(),
239
						String.valueOf(c));
240
					return;
241
				}
242
243
				currentBindings = bindings;
244
245
				if(grabAction != null)
246
				{
247
					handleGrabAction(evt);
248
					return;
249
				}
250
251
				// 0-9 adds another 'digit' to the repeat number
252
				if(repeat && Character.isDigit(c))
253
				{
254
					repeatCount *= 10;
255
					repeatCount += (c - '0');
256
					return;
257
				}
258
259
				executeAction(INSERT_CHAR,evt.getSource(),
260
					String.valueOf(evt.getKeyChar()));
261
262
				repeatCount = 0;
263
				repeat = false;
264
			}
265
		}
266
	}
267
268
	/**
269
	 * Converts a string to a keystroke. The string should be of the
270
	 * form <i>modifiers</i>+<i>shortcut</i> where <i>modifiers</i>
271
	 * is any combination of A for Alt, C for Control, S for Shift
272
	 * or M for Meta, and <i>shortcut</i> is either a single character,
273
	 * or a keycode name from the <code>KeyEvent</code> class, without
274
	 * the <code>VK_</code> prefix.
275
	 * @param keyStroke A string description of the key stroke
276
	 */
277
	public static KeyStroke parseKeyStroke(String keyStroke)
278
	{
279
		if(keyStroke == null)
280
			return null;
281
		int modifiers = 0;
282
		int index = keyStroke.indexOf('+');
283
		if(index != -1)
284
		{
285
			for(int i = 0; i < index; i++)
286
			{
287
				switch(Character.toUpperCase(keyStroke
288
					.charAt(i)))
289
				{
290
				case 'A':
291
					modifiers |= InputEvent.ALT_MASK;
292
					break;
293
				case 'C':
294
					modifiers |= InputEvent.CTRL_MASK;
295
					break;
296
				case 'M':
297
					modifiers |= InputEvent.META_MASK;
298
					break;
299
				case 'S':
300
					modifiers |= InputEvent.SHIFT_MASK;
301
					break;
302
				}
303
			}
304
		}
305
		String key = keyStroke.substring(index + 1);
306
		if(key.length() == 1)
307
		{
308
			char ch = Character.toUpperCase(key.charAt(0));
309
			if(modifiers == 0)
310
				return KeyStroke.getKeyStroke(ch);
311
			else
312
				return KeyStroke.getKeyStroke(ch,modifiers);
313
		}
314
		else if(key.length() == 0)
315
		{
316
			System.err.println("Invalid key stroke: " + keyStroke);
317
			return null;
318
		}
319
		else
320
		{
321
			int ch;
322
323
			try
324
			{
325
				ch = KeyEvent.class.getField("VK_".concat(key))
326
					.getInt(null);
327
			}
328
			catch(Exception e)
329
			{
330
				System.err.println("Invalid key stroke: "
331
					+ keyStroke);
332
				return null;
333
			}
334
335
			return KeyStroke.getKeyStroke(ch,modifiers);
336
		}
337
	}
338
339
	// private members
340
	private Hashtable bindings;
341
	private Hashtable currentBindings;
342
343
	private DefaultInputHandler(DefaultInputHandler copy)
344
	{
345
		bindings = currentBindings = copy.bindings;
346
	}
347
}
(-)sources/org/apache/batik/apps/svgbrowser/srcview/XMLTokenMarker.java (+190 lines)
Line 0 Link Here
1
/*
2
 * XMLTokenMarker.java - XML token marker
3
 * Copyright (C) 1998, 1999 Slava Pestov
4
 * Copyright (C) 2001 Tom Bradford
5
 *
6
 * You may use and modify this package for any purpose. Redistribution is
7
 * permitted, in both source and binary form, provided that this notice
8
 * remains intact in all source distributions of this package.
9
 */
10
package org.apache.batik.apps.svgbrowser.srcview;
11
12
import javax.swing.text.Segment;
13
14
/**
15
 * XML Token Marker Rewrite
16
 *
17
 * @author Tom Bradford
18
 * @version $Id: XMLTokenMarker.java,v 1.5 2001/07/29 20:45:43 tom Exp $
19
 */
20
public class XMLTokenMarker extends TokenMarker {
21
   public XMLTokenMarker() {
22
   }
23
   
24
   public byte markTokensImpl(byte token, Segment line, int lineIndex) {
25
      char[] array = line.array;
26
      int offset = line.offset;
27
      int lastOffset = offset;
28
      int length = line.count + offset;
29
      
30
      // Ugly hack to handle multi-line tags
31
      boolean sk1 = token == Token.KEYWORD1;
32
      
33
      for ( int i = offset; i < length; i++ ) {
34
         int ip1 = i+1;
35
         char c = array[i];
36
         switch ( token ) {
37
            case Token.NULL: // text
38
               switch ( c ) {
39
                  case '<':
40
                     addToken(i-lastOffset, token);
41
                     lastOffset = i;
42
                     if ( SyntaxUtilities.regionMatches(false, line, ip1, "!--") ) {
43
                        i += 3;
44
                        token = Token.COMMENT1;
45
                     }
46
                     else if ( array[ip1] == '!' ) {
47
                        i += 1;
48
                        token = Token.COMMENT2;
49
                     }
50
                     else if ( array[ip1] == '?' ) {
51
                        i += 1;
52
                        token = Token.KEYWORD3;
53
                     }
54
                     else
55
                        token = Token.KEYWORD1;
56
                     break;
57
                     
58
                  case '&':
59
                     addToken(i - lastOffset, token);
60
                     lastOffset = i;
61
                     token = Token.LABEL;
62
                     break;
63
               }
64
               break;
65
               
66
            case Token.KEYWORD1: // tag
67
               switch ( c ) {
68
                  case '>':
69
                     addToken(ip1-lastOffset, token);
70
                     lastOffset = ip1;
71
                     token = Token.NULL;
72
                     sk1 = false;
73
                     break;
74
                     
75
                  case ' ':
76
                  case '\t':
77
                     addToken(i-lastOffset, token);
78
                     lastOffset = i;
79
                     token = Token.KEYWORD2;
80
                     sk1 = false;
81
                     break;
82
                     
83
                  default:
84
                     if ( sk1 ) {
85
                        token = Token.KEYWORD2;
86
                        sk1 = false;
87
                     }
88
                     break;
89
               }
90
               break;
91
92
            case Token.KEYWORD2: // attribute
93
               switch ( c ) {
94
                   case '>':
95
                     addToken(ip1-lastOffset, token);
96
                     lastOffset = ip1;
97
                     token = Token.NULL;
98
                     break;
99
                    
100
                  case '/':
101
                     addToken(i-lastOffset, token);
102
                     lastOffset = i;
103
                     token = Token.KEYWORD1;
104
                     break;
105
                     
106
                  case '=':
107
                     addToken(i-lastOffset, token);
108
                     lastOffset = i;
109
                     token = Token.OPERATOR;
110
               }
111
               break;
112
               
113
            case Token.OPERATOR: // equal for attribute
114
               switch ( c ) {
115
                  case '\"':
116
                  case '\'':
117
                     addToken(i-lastOffset, token);
118
                     lastOffset = i;
119
                     if ( c == '\"' )
120
                        token = Token.LITERAL1;
121
                     else
122
                        token = Token.LITERAL2;
123
                     break;
124
               }
125
               break;
126
               
127
            case Token.LITERAL1:
128
            case Token.LITERAL2: // strings
129
               if ( ( token == Token.LITERAL1 && c == '\"' )
130
                 || ( token == Token.LITERAL2 && c == '\'' ) ) {
131
                  addToken(ip1-lastOffset, token);
132
                  lastOffset = ip1;
133
                  token = Token.KEYWORD1;
134
               }
135
               break;
136
            
137
            case Token.LABEL: // entity
138
               if ( c == ';' ) {
139
                  addToken(ip1-lastOffset, token);
140
                  lastOffset = ip1;
141
                  token = Token.NULL;
142
                  break;
143
               }
144
               break;
145
               
146
            case Token.COMMENT1: // Inside a comment
147
               if ( SyntaxUtilities.regionMatches(false, line, i, "-->") ) {
148
                  addToken((i+3)-lastOffset, token);
149
                  lastOffset = i+3;
150
                  token = Token.NULL;
151
               }
152
               break;
153
154
            case Token.COMMENT2: // Inside a declaration
155
               if ( SyntaxUtilities.regionMatches(false, line, i, ">") ) {
156
                  addToken(ip1-lastOffset, token);
157
                  lastOffset = ip1;
158
                  token = Token.NULL;
159
               }
160
               break;
161
162
            case Token.KEYWORD3: // Inside a processor instruction
163
               if ( SyntaxUtilities.regionMatches(false, line, i, "?>") ) {
164
                  addToken((i+2)-lastOffset, token);
165
                  lastOffset = i+2;
166
                  token = Token.NULL;
167
               }
168
               break;
169
               
170
            default:
171
               throw new InternalError("Invalid state: " + token);
172
         }
173
      }
174
      
175
      switch ( token ) {
176
         case Token.LABEL:
177
            addToken(length-lastOffset, Token.INVALID);
178
            token = Token.NULL;
179
            break;
180
            
181
         default:
182
            addToken(length-lastOffset, token);
183
            break;
184
      }
185
      
186
      return token;
187
   }
188
}
189
190
(-)sources/org/apache/batik/apps/svgbrowser/srcview/TextAreaDefaults.java (+83 lines)
Line 0 Link Here
1
/*
2
 * TextAreaDefaults.java - Encapsulates default values for various settings
3
 * Copyright (C) 1999 Slava Pestov
4
 *
5
 * You may use and modify this package for any purpose. Redistribution is
6
 * permitted, in both source and binary form, provided that this notice
7
 * remains intact in all source distributions of this package.
8
 */
9
package org.apache.batik.apps.svgbrowser.srcview;
10
11
import javax.swing.JPopupMenu;
12
import java.awt.Color;
13
14
/**
15
 * Encapsulates default settings for a text area. This can be passed
16
 * to the constructor once the necessary fields have been filled out.
17
 * The advantage of doing this over calling lots of set() methods after
18
 * creating the text area is that this method is faster.
19
 */
20
public class TextAreaDefaults
21
{
22
	private static TextAreaDefaults DEFAULTS;
23
24
	public InputHandler inputHandler;
25
	public SyntaxDocument document;
26
	public boolean editable;
27
28
	public boolean caretVisible;
29
	public boolean caretBlinks;
30
	public boolean blockCaret;
31
	public int electricScroll;
32
33
	public int cols;
34
	public int rows;
35
	public SyntaxStyle[] styles;
36
	public Color caretColor;
37
	public Color selectionColor;
38
	public Color lineHighlightColor;
39
	public boolean lineHighlight;
40
	public Color bracketHighlightColor;
41
	public boolean bracketHighlight;
42
	public Color eolMarkerColor;
43
	public boolean eolMarkers;
44
	public boolean paintInvalid;
45
46
	public JPopupMenu popup;
47
48
	/**
49
	 * Returns a new TextAreaDefaults object with the default values filled
50
	 * in.
51
	 */
52
	public static TextAreaDefaults getDefaults()
53
	{
54
		if(DEFAULTS == null)
55
		{
56
			DEFAULTS = new TextAreaDefaults();
57
58
			DEFAULTS.inputHandler = new DefaultInputHandler();
59
			DEFAULTS.inputHandler.addDefaultKeyBindings();
60
			DEFAULTS.document = new SyntaxDocument();
61
			DEFAULTS.editable = true;
62
63
			DEFAULTS.caretVisible = true;
64
			DEFAULTS.caretBlinks = true;
65
			DEFAULTS.electricScroll = 3;
66
67
			DEFAULTS.cols = 80;
68
			DEFAULTS.rows = 25;
69
			DEFAULTS.styles = SyntaxUtilities.getDefaultSyntaxStyles();
70
			DEFAULTS.caretColor = Color.red;
71
			DEFAULTS.selectionColor = new Color(0xccccff);
72
			DEFAULTS.lineHighlightColor = new Color(0xe0e0e0);
73
			DEFAULTS.lineHighlight = true;
74
			DEFAULTS.bracketHighlightColor = Color.black;
75
			DEFAULTS.bracketHighlight = true;
76
			DEFAULTS.eolMarkerColor = new Color(0x009999);
77
			DEFAULTS.eolMarkers = true;
78
			DEFAULTS.paintInvalid = true;
79
		}
80
81
		return DEFAULTS;
82
	}
83
}
(-)sources/org/apache/batik/apps/svgbrowser/srcview/SourceViewFrame.java (+867 lines)
Line 0 Link Here
1
package org.apache.batik.apps.svgbrowser.srcview;
2
3
import java.awt.BorderLayout;
4
import java.awt.Color;
5
import java.awt.DefaultFocusTraversalPolicy;
6
import java.awt.Dimension;
7
import java.awt.FocusTraversalPolicy;
8
import java.awt.Font;
9
import java.awt.event.ActionEvent;
10
import java.awt.event.ActionListener;
11
import java.io.BufferedOutputStream;
12
import java.io.File;
13
import java.io.FileOutputStream;
14
import java.io.OutputStream;
15
import java.io.OutputStreamWriter;
16
import java.util.HashMap;
17
import java.util.Locale;
18
import java.util.Map;
19
import java.util.MissingResourceException;
20
import java.util.ResourceBundle;
21
22
import javax.swing.AbstractAction;
23
import javax.swing.Action;
24
import javax.swing.BorderFactory;
25
import javax.swing.Box;
26
import javax.swing.BoxLayout;
27
import javax.swing.ImageIcon;
28
import javax.swing.JButton;
29
import javax.swing.JCheckBox;
30
import javax.swing.JDialog;
31
import javax.swing.JFileChooser;
32
import javax.swing.JFrame;
33
import javax.swing.JLabel;
34
import javax.swing.JMenuBar;
35
import javax.swing.JPanel;
36
import javax.swing.JTextField;
37
import javax.swing.JToggleButton;
38
import javax.swing.JToolBar;
39
import javax.swing.SwingUtilities;
40
import javax.swing.UIManager;
41
import javax.swing.event.CaretEvent;
42
import javax.swing.event.CaretListener;
43
import javax.swing.event.DocumentEvent;
44
import javax.swing.event.DocumentListener;
45
import javax.swing.filechooser.FileFilter;
46
47
import org.apache.batik.apps.svgbrowser.AboutDialog;
48
import org.apache.batik.apps.svgbrowser.Application;
49
import org.apache.batik.swing.svg.SVGUserAgent;
50
import org.apache.batik.util.gui.ErrorConsole;
51
import org.apache.batik.util.gui.resource.ActionMap;
52
import org.apache.batik.util.gui.resource.ButtonFactory;
53
import org.apache.batik.util.gui.resource.MenuFactory;
54
import org.apache.batik.util.gui.resource.MissingListenerException;
55
import org.apache.batik.util.gui.resource.ResourceManager;
56
57
public class SourceViewFrame extends JFrame implements ActionMap {
58
59
	public static final String RESOURCES = "org.apache.batik.apps.svgbrowser.srcview.resources.SourceViewFrame";
60
61
	// The action names
62
	public static final String SAVE_AS_ACTION = "SaveAsAction";
63
64
	public static final String CLOSE_ACTION = "CloseAction";
65
66
	public static final String UNDO_ACTION = "UndoAction";
67
68
	public static final String REDO_ACTION = "RedoAction";
69
70
	public static final String CUT_ACTION = "CutAction";
71
72
	public static final String COPY_ACTION = "CopyAction";
73
74
	public static final String PASTE_ACTION = "PasteAction";
75
76
	public static final String DELETE_ACTION = "DeleteAction";
77
78
	public static final String SELECT_ALL_ACTION = "SelectAllAction";
79
80
	public static final String FIND_ACTION = "FindAction";
81
82
	public static final String FIND_CLOSE_ACTION = "FindCloseAction";
83
84
	public static final String FIND_AGAIN_ACTION = "FindAgainAction";
85
86
	public static final String FIND_PREVIOUS_ACTION = "FindPreviousAction";
87
88
	public static final String HIGHLIGHT_ALL_ACTION = "HighlightAllAction";
89
90
	public static final String GOTO_LINE_ACTION = "GotoLineAction";
91
92
	public static final String TEXT_SIZE_INCREASE_ACTION = "TextSizeIncreaseAction";
93
94
	public static final String TEXT_SIZE_DECREASE_ACTION = "TextSizeDecreaseAction";
95
96
	public static final String TEXT_SIZE_NORMAL_ACTION = "TextSizeNormalAction";
97
98
	public static final String SYNTAX_HIGHLIGHTING_ACTION = "SyntaxHighlightingAction";
99
100
	public static final String ABOUT_ACTION = "AboutAction";
101
102
	protected static final float[] FONT_SIZES = { 6, 8, 10, 11, 12, 14, 18, 28,
103
			36, 72 };
104
105
	/**
106
	 * The resource bundle
107
	 */
108
	protected static ResourceBundle bundle;
109
110
	/**
111
	 * The resource manager
112
	 */
113
	protected static ResourceManager resources;
114
	static {
115
		bundle = ResourceBundle.getBundle(RESOURCES, Locale.getDefault());
116
		resources = new ResourceManager(bundle);
117
	}
118
119
	/**
120
	 * The SVG user agent.
121
	 */
122
	protected SVGUserAgent userAgent;
123
124
	/**
125
	 * The current application.
126
	 */
127
	protected Application application;
128
129
	/**
130
	 * The syntax highlighted text area
131
	 */
132
	protected JEditTextArea textArea;
133
134
	/**
135
	 * TokenMarker used by syntax highlighted text area to tokenize text
136
	 */
137
	protected TokenMarker tokenMarker;
138
139
	/**
140
	 * The current save path.
141
	 */
142
	protected File currentSavePath = new File("");
143
144
	/**
145
	 * The find bar.
146
	 */
147
	protected JToolBar findbar;
148
149
	/**
150
	 * Label to display status messages in the find bar
151
	 */
152
	protected FindBarMessage findbarMessage;
153
154
	/**
155
	 * The status bar.
156
	 */
157
	protected StatusBar statusBar;
158
159
	/**
160
	 * The current font size index (into the array FONT_SIZES)
161
	 */
162
	protected int fontSizeIndex;
163
164
	/**
165
	 * The default font size index (into the array FONT_SIZES)
166
	 */
167
	protected final int defaultFontSizeIndex = 4;
168
169
	/**
170
	 * Creates a new source viewer frame.
171
	 */
172
	public SourceViewFrame(Application app, SVGUserAgent agt)
173
			throws MissingResourceException {
174
		application = app;
175
		userAgent = agt;
176
177
		listeners.put(SAVE_AS_ACTION, new SaveAsAction());
178
		listeners.put(CLOSE_ACTION, new CloseAction());
179
		listeners.put(UNDO_ACTION, new UndoAction());
180
		listeners.put(REDO_ACTION, new RedoAction());
181
		listeners.put(CUT_ACTION, new CutAction());
182
		listeners.put(COPY_ACTION, new CopyAction());
183
		listeners.put(PASTE_ACTION, new PasteAction());
184
		listeners.put(DELETE_ACTION, new DeleteAction());
185
		listeners.put(SELECT_ALL_ACTION, new SelectAllAction());
186
		listeners.put(FIND_ACTION, new FindAction());
187
		listeners.put(FIND_CLOSE_ACTION, new FindCloseAction());
188
		listeners.put(FIND_AGAIN_ACTION, new FindAgainAction());
189
		listeners.put(FIND_PREVIOUS_ACTION, new FindPreviousAction());
190
		listeners.put(HIGHLIGHT_ALL_ACTION, new HighlightAllAction());
191
		listeners.put(GOTO_LINE_ACTION, new GotoLineAction());
192
		listeners.put(TEXT_SIZE_INCREASE_ACTION, new TextSizeIncreaseAction());
193
		listeners.put(TEXT_SIZE_DECREASE_ACTION, new TextSizeDecreaseAction());
194
		listeners.put(TEXT_SIZE_NORMAL_ACTION, new TextSizeNormalAction());
195
		listeners.put(SYNTAX_HIGHLIGHTING_ACTION,
196
				new SyntaxHighlightingAction());
197
		listeners.put(ABOUT_ACTION, new AboutAction());
198
199
		// Create the menu
200
		MenuFactory mf = new MenuFactory(bundle, this);
201
202
		// TODO:Remove this and use specialized version (commented out below)
203
		JMenuBar mb = mf.createJMenuBar("MenuBar");
204
		// JMenuBar mb = mf.createJMenuBar("MenuBar", application
205
		// .getUISpecialization());
206
		setJMenuBar(mb);
207
208
		// Create the central panel
209
		JPanel center = new JPanel(new BorderLayout());
210
		getContentPane().add(center, BorderLayout.CENTER);
211
212
		// Create syntax-highlighted text area
213
		textArea = new JEditTextArea();
214
		tokenMarker = new XMLTokenMarker();
215
		textArea.setTokenMarker(tokenMarker);
216
		fontSizeIndex = defaultFontSizeIndex;
217
		TextAreaPainter painter = textArea.getPainter();
218
		painter.setFont(new Font("Monospaced", Font.PLAIN,
219
				(int) (FONT_SIZES[fontSizeIndex])));
220
		textArea.addCaretListener(new CaretListener() {
221
			public void caretUpdate(CaretEvent e) {
222
				JEditTextArea a = (JEditTextArea) e.getSource();
223
				int row = a.getCaretLine() + 1;
224
				int col = a.getCaretPosition() - a.getLineStartOffset(row - 1)
225
						+ 1;
226
				statusBar.setPosition(row, col);
227
			}
228
		});
229
		center.add(textArea);
230
231
		// Create find bar (initially invisible)
232
		ButtonFactory bf = new ButtonFactory(bundle, this);
233
		findbar = new JToolBar();
234
		findbar.setVisible(false);
235
		findbar.setFloatable(false);
236
		findbar.add(bf.createJToolbarButton("FindBarClose"));
237
		findbar
238
				.add(new JLabel(resources.getString("FindBar.label.find")
239
						+ ": "));
240
		final JTextField findText = new JTextField(20);
241
		JPanel p = new JPanel();
242
		p.setOpaque(false);
243
		p.add(findText);
244
		p.setMinimumSize(p.getPreferredSize());
245
		p.setMaximumSize(p.getPreferredSize());
246
		findbar.add(p);
247
		final JButton next = bf.createJToolbarButton("FindBarNext");
248
		next.setEnabled(false);
249
		findbar.add(next);
250
		final JButton previous = bf.createJToolbarButton("FindBarPrevious");
251
		previous.setEnabled(false);
252
		findbar.add(previous);
253
		final JToggleButton highlightAll = bf
254
				.createJToolbarToggleButton("FindBarHighlightAll");
255
		highlightAll.setEnabled(false);
256
		findbar.add(highlightAll);
257
		JCheckBox matchCase = bf.createJCheckBox("FindBarMatchCase");
258
		matchCase.setOpaque(false);
259
		findbar.add(matchCase);
260
		findbarMessage = new FindBarMessage();
261
		findbar.add(findbarMessage);
262
		findText.getDocument().addDocumentListener(new DocumentListener() {
263
			private final Color NOT_FOUND_BACKGROUND = new Color(255, 128, 128);
264
265
			private final Color DEFAULT_BACKGROUND = findText.getBackground();
266
267
			public void changedUpdate(DocumentEvent e) {
268
				update();
269
			}
270
271
			public void insertUpdate(DocumentEvent e) {
272
				update();
273
			}
274
275
			public void removeUpdate(DocumentEvent e) {
276
				update();
277
			}
278
279
			private void update() {
280
				String str = findText.getText();
281
				boolean enabled = !str.equals("");
282
				next.setEnabled(enabled);
283
				previous.setEnabled(enabled);
284
				highlightAll.setEnabled(enabled);
285
				if (enabled) {
286
					if (find(str, DIRECTION_DOWN, false)) {
287
						findText.setBackground(DEFAULT_BACKGROUND);
288
					} else {
289
						findText.setBackground(NOT_FOUND_BACKGROUND);
290
					}
291
				} else {
292
					findbarMessage.setMessage(FindBarMessage.NONE);
293
					findText.setBackground(UIManager
294
							.getColor("TextField.background"));
295
				}
296
			}
297
		});
298
		center.add(findbar, BorderLayout.SOUTH);
299
300
		// Create status bar
301
		statusBar = new StatusBar();
302
		getContentPane().add(statusBar, BorderLayout.SOUTH);
303
	}
304
305
	public void setVisible(boolean visible) {
306
		super.setVisible(visible);
307
308
		if (visible) {
309
			// Set focus on the text area
310
			textArea.requestFocus();
311
		}
312
	}
313
314
	public void setText(String text) {
315
		textArea.setText(text);
316
	}
317
318
	public String getText() {
319
		return textArea.getText();
320
	}
321
322
	public void select(int start, int end) {
323
		textArea.select(start, end);
324
	}
325
326
	protected static ImageIcon notFoundIcon, continueFromTopIcon, continueFromBottomIcon;
327
328
	protected static String notFoundStr, continueFromTopStr, continueFromBottomStr;
329
330
	static {
331
		notFoundStr = resources.getString("FindBarNotFound.text");
332
		notFoundIcon = new ImageIcon(SourceViewFrame.class
333
				.getResource(resources.getString("FindBarNotFound.icon")));
334
		continueFromTopStr = resources.getString("FindBarContinueFromTop.text");
335
		continueFromTopIcon = new ImageIcon(
336
				SourceViewFrame.class.getResource(resources
337
						.getString("FindBarContinueFromTop.icon")));
338
		continueFromBottomStr = resources.getString("FindBarContinueFromBottom.text");
339
		continueFromBottomIcon = new ImageIcon(
340
				SourceViewFrame.class.getResource(resources
341
						.getString("FindBarContinueFromBottom.icon")));
342
	}
343
344
	protected class FindBarMessage extends JLabel {
345
		public static final int NONE = 0, NOT_FOUND = 1, CONTINUE_FROM_TOP = 2,
346
				CONTINUE_FROM_BOTTOM = 3;
347
348
		public void setMessage(int type) {
349
			switch (type) {
350
			case NOT_FOUND:
351
				setIcon(notFoundIcon);
352
				setText(notFoundStr);
353
				break;
354
			case CONTINUE_FROM_TOP:
355
				setIcon(continueFromTopIcon);
356
				setText(continueFromTopStr);
357
				break;
358
			case NONE:
359
			default:
360
				setIcon(null);
361
				setText("");
362
				break;
363
			}
364
		}
365
	}
366
367
	/**
368
	 * Save the document as a different file
369
	 */
370
	public class SaveAsAction extends AbstractAction {
371
		public void actionPerformed(ActionEvent e) {
372
			JFileChooser fileChooser;
373
			fileChooser = new JFileChooser(
374
					currentSavePath.isAbsolute() ? currentSavePath
375
							: currentSavePath.getAbsoluteFile());
376
			fileChooser.setDialogTitle(resources.getString("SaveAs.title"));
377
			fileChooser.setFileHidingEnabled(false);
378
			fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
379
			fileChooser.addChoosableFileFilter(new FileFilter() {
380
				public boolean accept(File f) {
381
					if (f == null) {
382
						return false;
383
					}
384
					if (f.isDirectory()) {
385
						return true;
386
					}
387
					String fileName = f.getName().toLowerCase();
388
					return fileName.endsWith(".svg");
389
				}
390
391
				public String getDescription() {
392
					return "SVG Document";
393
				}
394
			});
395
396
			int choice = fileChooser.showSaveDialog(SourceViewFrame.this);
397
			if (choice != JFileChooser.APPROVE_OPTION)
398
				return;
399
400
			final File f = fileChooser.getSelectedFile();
401
402
			statusBar.setMessage(resources.getString("Message.saveAs"));
403
			currentSavePath = f;
404
			OutputStreamWriter w = null;
405
			try {
406
				OutputStream tos = null;
407
				tos = new FileOutputStream(f);
408
				tos = new BufferedOutputStream(tos);
409
				w = new OutputStreamWriter(tos, "utf-8");
410
			} catch (Exception ex) {
411
				userAgent.displayError(ex);
412
				return;
413
			}
414
415
			final OutputStreamWriter writer = w;
416
417
			final Runnable doneRun = new Runnable() {
418
				public void run() {
419
					String doneStr = resources.getString("Message.done");
420
					statusBar.setMessage(doneStr);
421
				}
422
			};
423
424
			try {
425
				writer.write(textArea.getText());
426
				writer.close();
427
428
				SwingUtilities.invokeLater(doneRun);
429
			} catch (Exception ex) {
430
				userAgent.displayError(ex);
431
			}
432
		}
433
	}
434
435
	/**
436
	 * Closes the source viewer
437
	 */
438
	public class CloseAction extends AbstractAction {
439
		public void actionPerformed(ActionEvent e) {
440
			dispose();
441
		}
442
	}
443
444
	/**
445
	 * Undo last action
446
	 */
447
	public class UndoAction extends AbstractAction {
448
		public void actionPerformed(ActionEvent e) {
449
450
		}
451
	}
452
453
	/**
454
	 * Redo last undone action
455
	 */
456
	public class RedoAction extends AbstractAction {
457
		public void actionPerformed(ActionEvent e) {
458
459
		}
460
	}
461
462
	/**
463
	 * Cut selected text
464
	 */
465
	public class CutAction extends AbstractAction {
466
		public void actionPerformed(ActionEvent e) {
467
			textArea.cut();
468
		}
469
	}
470
471
	/**
472
	 * Copy selected text
473
	 */
474
	public class CopyAction extends AbstractAction {
475
		public void actionPerformed(ActionEvent e) {
476
			textArea.copy();
477
		}
478
	}
479
480
	/**
481
	 * Paste copied text
482
	 */
483
	public class PasteAction extends AbstractAction {
484
		public void actionPerformed(ActionEvent e) {
485
			textArea.paste();
486
		}
487
	}
488
489
	/**
490
	 * Delete selected text
491
	 */
492
	public class DeleteAction extends AbstractAction {
493
		public void actionPerformed(ActionEvent e) {
494
		}
495
	}
496
497
	/**
498
	 * Select all text
499
	 */
500
	public class SelectAllAction extends AbstractAction {
501
		public void actionPerformed(ActionEvent e) {
502
			textArea.selectAll();
503
		}
504
	}
505
506
	/**
507
	 * Displays the find bar if not already visible
508
	 */
509
	public class FindAction extends AbstractAction {
510
		public void actionPerformed(ActionEvent e) {
511
			if (!findbar.isVisible()) {
512
				findbar.setVisible(true);
513
			}
514
		}
515
	}
516
517
	/**
518
	 * Closes the find bar if visible
519
	 */
520
	public class FindCloseAction extends AbstractAction {
521
		public void actionPerformed(ActionEvent e) {
522
			if (findbar.isVisible()) {
523
				findbar.setVisible(false);
524
			}
525
		}
526
	}
527
528
	/**
529
	 * Find the string in the text specified using the Find action
530
	 */
531
	public class FindAgainAction extends AbstractAction {
532
		public void actionPerformed(ActionEvent e) {
533
			if (!findbar.isVisible()) {
534
				findbar.setVisible(true);
535
			} else {
536
				find(currentPhrase, DIRECTION_DOWN, true);
537
			}
538
		}
539
	}
540
541
	/**
542
	 * Find the string in the text specified using the Find action
543
	 */
544
	public class FindPreviousAction extends AbstractAction {
545
		public void actionPerformed(ActionEvent e) {
546
			if (!findbar.isVisible()) {
547
				findbar.setVisible(true);
548
			} else {
549
				find(currentPhrase, DIRECTION_UP, true);
550
			}
551
		}
552
	}
553
554
	/**
555
	 * Highlight all occurrences of the search phrase in the text
556
	 */
557
	public class HighlightAllAction extends AbstractAction {
558
		public void actionPerformed(ActionEvent e) {
559
		}
560
	}
561
562
	private String currentPhrase;
563
564
	private int currentOffset = -1;
565
566
	private static final int DIRECTION_UP = -1, DIRECTION_DOWN = 1;
567
568
	/**
569
	 * Helper function to search for a phrase in the text
570
	 * 
571
	 * @param currentPhrase
572
	 *            search string
573
	 * @param direction
574
	 *            whether to search downward or upward
575
	 * @return true is search string found, false otherwise
576
	 */
577
	private boolean find(String phrase, int direction, boolean next) {
578
		currentPhrase = phrase;
579
		boolean found = false;
580
		boolean wrap = false;
581
582
		String text = textArea.getText();
583
584
		int offset;
585
		switch (direction) {
586
		case DIRECTION_UP:
587
			offset = text.lastIndexOf(currentPhrase, currentOffset
588
					- (next ? 1 : 0));
589
			break;
590
		case DIRECTION_DOWN:
591
		default:
592
			offset = text
593
					.indexOf(currentPhrase, currentOffset + (next ? 1 : 0));
594
			break;
595
		}
596
		if (offset < 0) { // Not found, wrap around and search again
597
			wrap = true;
598
			switch (direction) {
599
			case DIRECTION_UP:
600
				offset = text.lastIndexOf(currentPhrase, text.length());
601
				break;
602
			case DIRECTION_DOWN:
603
			default:
604
				offset = text.indexOf(currentPhrase, 0);
605
				break;
606
			}
607
		}
608
		found = offset >= 0;
609
610
		if (found) {
611
			currentOffset = offset;
612
			textArea.select(currentOffset, currentOffset
613
					+ currentPhrase.length());
614
		}
615
616
		if (!found) {
617
			findbarMessage.setMessage(FindBarMessage.NOT_FOUND);
618
		} else if (wrap) {
619
			switch (direction) {
620
			case DIRECTION_UP:
621
				findbarMessage.setMessage(FindBarMessage.CONTINUE_FROM_BOTTOM);
622
				break;
623
			case DIRECTION_DOWN:
624
			default:
625
				findbarMessage.setMessage(FindBarMessage.CONTINUE_FROM_TOP);
626
				break;
627
			}
628
		} else {
629
			findbarMessage.setMessage(FindBarMessage.NONE);
630
		}
631
		return found;
632
	}
633
634
	/**
635
	 * Goto a particular line
636
	 */
637
	public class GotoLineAction extends AbstractAction {
638
		public void actionPerformed(ActionEvent e) {
639
			SwingUtilities.invokeLater(new Runnable() {
640
				public void run() {
641
					GotoLineDialog gld = new GotoLineDialog(
642
							SourceViewFrame.this, textArea.getLineCount());
643
					gld.setVisible(true);
644
					int n = gld.getLineNumber();
645
					if (n > 0) {
646
						gotoLine(n);
647
					}
648
				}
649
			});
650
		}
651
	}
652
653
	/**
654
	 * Helper function to adjust caret position and scroll viewport
655
	 * 
656
	 * @param n
657
	 *            line number of the new caret position
658
	 */
659
	private void gotoLine(int n) {
660
		textArea.setCaretPosition(textArea.getLineStartOffset(n - 1));
661
		textArea.scrollToCaret();
662
	}
663
664
	/**
665
	 * Increase text size
666
	 */
667
	public class TextSizeIncreaseAction extends AbstractAction {
668
		public void actionPerformed(ActionEvent e) {
669
			if (fontSizeIndex < FONT_SIZES.length - 1) {
670
				TextAreaPainter painter = textArea.getPainter();
671
				painter.setFont(painter.getFont().deriveFont(
672
						FONT_SIZES[++fontSizeIndex]));
673
			}
674
		}
675
	}
676
677
	/**
678
	 * Decrease text size
679
	 */
680
	public class TextSizeDecreaseAction extends AbstractAction {
681
		public void actionPerformed(ActionEvent e) {
682
			if (fontSizeIndex > 0) {
683
				TextAreaPainter painter = textArea.getPainter();
684
				painter.setFont(painter.getFont().deriveFont(
685
						FONT_SIZES[--fontSizeIndex]));
686
			}
687
		}
688
	}
689
690
	/**
691
	 * Set text size to default value
692
	 */
693
	public class TextSizeNormalAction extends AbstractAction {
694
		public void actionPerformed(ActionEvent e) {
695
			TextAreaPainter painter = textArea.getPainter();
696
			painter.setFont(painter.getFont().deriveFont(
697
					FONT_SIZES[fontSizeIndex = defaultFontSizeIndex]));
698
		}
699
	}
700
701
	/**
702
	 * Toggle syntax highlighting
703
	 */
704
	public class SyntaxHighlightingAction extends AbstractAction {
705
		public void actionPerformed(ActionEvent e) {
706
			textArea
707
					.setTokenMarker(textArea.getTokenMarker() == null ? tokenMarker
708
							: null);
709
			textArea.repaint();
710
		}
711
	}
712
713
	/**
714
	 * To show the about dialog
715
	 */
716
	public class AboutAction extends AbstractAction {
717
		public void actionPerformed(ActionEvent e) {
718
			AboutDialog dlg = new AboutDialog(SourceViewFrame.this);
719
			// Work around pack() bug on some platforms
720
			dlg.setSize(dlg.getPreferredSize());
721
			dlg.setLocationRelativeTo(SourceViewFrame.this);
722
			dlg.setVisible(true);
723
			dlg.toFront();
724
		}
725
	}
726
727
	/**
728
	 * The map that contains the action listeners
729
	 */
730
	protected Map listeners = new HashMap();
731
732
	/**
733
	 * Returns the action associated with the given string or null on error
734
	 * 
735
	 * @param key
736
	 *            the key mapped with the action to get
737
	 * @throws MissingListenerException
738
	 *             if the action is not found
739
	 */
740
	public Action getAction(String key) throws MissingListenerException {
741
		Action result = (Action) listeners.get(key);
742
		if (result == null) {
743
			throw new MissingListenerException("Can't find action.", RESOURCES,
744
					key);
745
		}
746
		return result;
747
	}
748
749
	private class GotoLineDialog extends JDialog implements ActionListener,
750
			DocumentListener {
751
752
		private JTextField textField;
753
754
		private JButton okButton, cancelButton;
755
756
		private JLabel errorMessage;
757
758
		private int totalLines;
759
760
		private int lineNumber = -1;
761
762
		public GotoLineDialog(JFrame owner, int totalLines) {
763
			super(owner, resources.getString("GotoLine.title"), true);
764
			this.totalLines = totalLines;
765
766
			JPanel content = new JPanel(new BorderLayout());
767
			content.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
768
			content.setPreferredSize(new Dimension(300, 120));
769
			getContentPane().add(content);
770
771
			Box input = new Box(BoxLayout.Y_AXIS);
772
			content.add(input, BorderLayout.NORTH);
773
774
			String str = resources.getString("GotoLine.label.enterLineNumber");
775
			str = str.replace("{0}", "" + totalLines);
776
			JLabel label = new JLabel(str);
777
			input.add(label);
778
779
			textField = new JTextField(120);
780
			textField.getDocument().addDocumentListener(this);
781
			input.add(textField);
782
783
			errorMessage = new JLabel();
784
			input.add(errorMessage);
785
786
			Box buttons = new Box(BoxLayout.X_AXIS);
787
			content.add(buttons, BorderLayout.SOUTH);
788
789
			buttons.add(Box.createHorizontalGlue());
790
791
			okButton = new JButton(resources.getString("GotoLine.button.ok"));
792
			okButton.setEnabled(false);
793
			okButton.addActionListener(this);
794
			buttons.add(okButton);
795
796
			buttons.add(Box.createHorizontalStrut(5));
797
798
			cancelButton = new JButton(resources
799
					.getString("GotoLine.button.cancel"));
800
			cancelButton.addActionListener(this);
801
			buttons.add(cancelButton);
802
803
			pack();
804
			setLocationRelativeTo(getParent());
805
		}
806
807
		public int getLineNumber() {
808
			return lineNumber;
809
		}
810
811
		public void actionPerformed(ActionEvent e) {
812
			if (e.getSource() == okButton) {
813
				lineNumber = Integer.parseInt(textField.getText());
814
				dispose();
815
			} else if (e.getSource() == cancelButton) {
816
				dispose();
817
			}
818
		}
819
820
		public void changedUpdate(DocumentEvent e) {
821
			check();
822
		}
823
824
		public void insertUpdate(DocumentEvent e) {
825
			check();
826
		}
827
828
		public void removeUpdate(DocumentEvent e) {
829
			check();
830
		}
831
832
		private void check() {
833
			boolean disabled = false;
834
			String error = "";
835
			try {
836
				String text = textField.getText();
837
				if (text == null || text.trim().equals("")) {
838
					disabled = true;
839
				} else {
840
					int n = Integer.parseInt(text);
841
					if (n < 1 || n > totalLines) {
842
						disabled = true;
843
						error = "Number out of range";
844
					}
845
				}
846
			} catch (NumberFormatException e) {
847
				disabled = true;
848
				error = "Not a number";
849
			}
850
			okButton.setEnabled(!disabled);
851
			errorMessage.setText(error);
852
		}
853
	}
854
855
	public static void main(String[] args) {
856
		// try {
857
		// UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
858
		// } catch (Exception e) {
859
		// e.printStackTrace();
860
		// }
861
862
		SourceViewFrame svf = new SourceViewFrame(null, null);
863
		svf.setSize(700, 500);
864
		svf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
865
		svf.setVisible(true);
866
	}
867
}
(-)sources/org/apache/batik/apps/svgbrowser/srcview/SyntaxStyle.java (+136 lines)
Line 0 Link Here
1
/*
2
 * SyntaxStyle.java - A simple text style class
3
 * Copyright (C) 1999 Slava Pestov
4
 *
5
 * You may use and modify this package for any purpose. Redistribution is
6
 * permitted, in both source and binary form, provided that this notice
7
 * remains intact in all source distributions of this package.
8
 */
9
package org.apache.batik.apps.svgbrowser.srcview;
10
11
import java.awt.*;
12
import java.util.StringTokenizer;
13
14
/**
15
 * A simple text style class. It can specify the color, italic flag,
16
 * and bold flag of a run of text.
17
 * @author Slava Pestov
18
 * @version $Id: SyntaxStyle.java,v 1.6 1999/12/13 03:40:30 sp Exp $
19
 */
20
public class SyntaxStyle
21
{
22
	/**
23
	 * Creates a new SyntaxStyle.
24
	 * @param color The text color
25
	 * @param italic True if the text should be italics
26
	 * @param bold True if the text should be bold
27
	 */
28
	public SyntaxStyle(Color color, boolean italic, boolean bold)
29
	{
30
		this.color = color;
31
		this.italic = italic;
32
		this.bold = bold;
33
	}
34
35
	/**
36
	 * Returns the color specified in this style.
37
	 */
38
	public Color getColor()
39
	{
40
		return color;
41
	}
42
43
	/**
44
	 * Returns true if no font styles are enabled.
45
	 */
46
	public boolean isPlain()
47
	{
48
		return !(bold || italic);
49
	}
50
51
	/**
52
	 * Returns true if italics is enabled for this style.
53
	 */
54
	public boolean isItalic()
55
	{
56
		return italic;
57
	}
58
59
	/**
60
	 * Returns true if boldface is enabled for this style.
61
	 */
62
	public boolean isBold()
63
	{
64
		return bold;
65
	}
66
67
	/**
68
	 * Returns the specified font, but with the style's bold and
69
	 * italic flags applied.
70
	 */
71
	public Font getStyledFont(Font font)
72
	{
73
		if(font == null)
74
			throw new NullPointerException("font param must not"
75
				+ " be null");
76
		if(font.equals(lastFont))
77
			return lastStyledFont;
78
		lastFont = font;
79
		lastStyledFont = new Font(font.getFamily(),
80
			(bold ? Font.BOLD : 0)
81
			| (italic ? Font.ITALIC : 0),
82
			font.getSize());
83
		return lastStyledFont;
84
	}
85
86
	/**
87
	 * Returns the font metrics for the styled font.
88
	 */
89
	public FontMetrics getFontMetrics(Font font)
90
	{
91
		if(font == null)
92
			throw new NullPointerException("font param must not"
93
				+ " be null");
94
		if(font.equals(lastFont) && fontMetrics != null)
95
			return fontMetrics;
96
		lastFont = font;
97
		lastStyledFont = new Font(font.getFamily(),
98
			(bold ? Font.BOLD : 0)
99
			| (italic ? Font.ITALIC : 0),
100
			font.getSize());
101
		fontMetrics = Toolkit.getDefaultToolkit().getFontMetrics(
102
			lastStyledFont);
103
		return fontMetrics;
104
	}
105
106
	/**
107
	 * Sets the foreground color and font of the specified graphics
108
	 * context to that specified in this style.
109
	 * @param gfx The graphics context
110
	 * @param font The font to add the styles to
111
	 */
112
	public void setGraphicsFlags(Graphics gfx, Font font)
113
	{
114
		Font _font = getStyledFont(font);
115
		gfx.setFont(_font);
116
		gfx.setColor(color);
117
	}
118
119
	/**
120
	 * Returns a string representation of this object.
121
	 */
122
	public String toString()
123
	{
124
		return getClass().getName() + "[color=" + color +
125
			(italic ? ",italic" : "") +
126
			(bold ? ",bold" : "") + "]";
127
	}
128
129
	// private members
130
	private Color color;
131
	private boolean italic;
132
	private boolean bold;
133
	private Font lastFont;
134
	private Font lastStyledFont;
135
	private FontMetrics fontMetrics;
136
}
(-)sources/org/apache/batik/apps/svgbrowser/srcview/StatusBar.java (+147 lines)
Line 0 Link Here
1
/*
2
3
   Licensed to the Apache Software Foundation (ASF) under one or more
4
   contributor license agreements.  See the NOTICE file distributed with
5
   this work for additional information regarding copyright ownership.
6
   The ASF licenses this file to You under the Apache License, Version 2.0
7
   (the "License"); you may not use this file except in compliance with
8
   the License.  You may obtain a copy of the License at
9
10
       http://www.apache.org/licenses/LICENSE-2.0
11
12
   Unless required by applicable law or agreed to in writing, software
13
   distributed under the License is distributed on an "AS IS" BASIS,
14
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
   See the License for the specific language governing permissions and
16
   limitations under the License.
17
18
 */
19
package org.apache.batik.apps.svgbrowser.srcview;
20
21
import java.awt.Dimension;
22
import java.util.Locale;
23
import java.util.MissingResourceException;
24
import java.util.ResourceBundle;
25
26
import javax.swing.BorderFactory;
27
import javax.swing.Box;
28
import javax.swing.BoxLayout;
29
import javax.swing.JLabel;
30
import javax.swing.JPanel;
31
import javax.swing.border.BevelBorder;
32
33
import org.apache.batik.util.gui.resource.ResourceManager;
34
35
/**
36
 * This class represents a viewer status bar.
37
 *
38
 */
39
public class StatusBar extends JPanel {
40
41
    /**
42
     * The gui resources file name
43
     */
44
    protected static final String RESOURCES =
45
        "org.apache.batik.apps.svgbrowser.srcview.resources.StatusBarMessages";
46
47
    /**
48
     * The resource bundle
49
     */
50
    protected static ResourceBundle bundle;
51
52
    /**
53
     * The resource manager
54
     */
55
    protected static ResourceManager rManager;
56
57
    /**
58
     * The string to be used for "Row"
59
     */
60
    private static String rowStr;
61
    
62
    /**
63
     * The string to be used for "Column"
64
     */
65
    private static String colStr;
66
    
67
    static {
68
        bundle = ResourceBundle.getBundle(RESOURCES, Locale.getDefault());
69
        rManager = new ResourceManager(bundle);
70
    	rowStr = rManager.getString("Position.row");
71
    	colStr = rManager.getString("Position.column");
72
    }
73
74
    /**
75
     * The row value
76
     */
77
    protected int row;
78
    
79
    /**
80
     * The column value
81
     */
82
    protected int column;
83
    
84
    /**
85
     * The position label.
86
     */
87
    protected JLabel position;
88
89
    /**
90
     * The message label
91
     */
92
    protected JLabel message;
93
94
    /**
95
     * Creates a new status bar.
96
     */
97
    public StatusBar() throws MissingResourceException {
98
        setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
99
        setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
100
101
    	position = new JLabel();
102
        position.setPreferredSize(new Dimension(110, 16));
103
        add(position);
104
105
        message = new JLabel();
106
        add(message);
107
        
108
        add(Box.createHorizontalGlue());
109
    }
110
111
    /**
112
     * Sets the row.
113
     */
114
    public void setRow(int row) {
115
    	this.row = row;
116
    	updatePosition();
117
    }
118
119
    /**
120
     * Sets the column.
121
     */
122
    public void setColumn(int column) {
123
    	this.column = column;
124
    	updatePosition();
125
    }
126
    
127
    /**
128
     * Sets the row and column together
129
     */
130
    public void setPosition(int row, int column) {
131
    	this.row = row;
132
    	this.column = column;
133
    	updatePosition();
134
    }
135
    
136
    private void updatePosition() {
137
    	position.setText(rowStr + " " + row + ", " + colStr + " " + column);
138
    }
139
140
    /**
141
     * Sets the message
142
     * @param s the message
143
     */
144
    public void setMessage(String s) {
145
        message.setText(s);
146
    }
147
}
(-)sources/org/apache/batik/apps/svgbrowser/srcview/Token.java (+149 lines)
Line 0 Link Here
1
/*
2
 * Token.java - Generic token
3
 * Copyright (C) 1998, 1999 Slava Pestov
4
 *
5
 * You may use and modify this package for any purpose. Redistribution is
6
 * permitted, in both source and binary form, provided that this notice
7
 * remains intact in all source distributions of this package.
8
 */
9
10
package org.apache.batik.apps.svgbrowser.srcview;
11
12
/**
13
 * A linked list of tokens. Each token has three fields - a token
14
 * identifier, which is a byte value that can be looked up in the
15
 * array returned by <code>SyntaxDocument.getColors()</code>
16
 * to get a color value, a length value which is the length of the
17
 * token in the text, and a pointer to the next token in the list.
18
 *
19
 * @author Slava Pestov
20
 * @version $Id: Token.java,v 1.12 1999/12/13 03:40:30 sp Exp $
21
 */
22
public class Token
23
{
24
	/**
25
	 * Normal text token id. This should be used to mark
26
	 * normal text.
27
	 */
28
	public static final byte NULL = 0;
29
30
	/**
31
	 * Comment 1 token id. This can be used to mark a comment.
32
	 */
33
	public static final byte COMMENT1 = 1;
34
35
	/**
36
	 * Comment 2 token id. This can be used to mark a comment.
37
	 */
38
	public static final byte COMMENT2 = 2;
39
40
	
41
	/**
42
	 * Literal 1 token id. This can be used to mark a string
43
	 * literal (eg, C mode uses this to mark "..." literals)
44
	 */
45
	public static final byte LITERAL1 = 3;
46
47
	/**
48
	 * Literal 2 token id. This can be used to mark an object
49
	 * literal (eg, Java mode uses this to mark true, false, etc)
50
	 */
51
	public static final byte LITERAL2 = 4;
52
53
	/**
54
	 * Label token id. This can be used to mark labels
55
	 * (eg, C mode uses this to mark ...: sequences)
56
	 */
57
	public static final byte LABEL = 5;
58
59
	/**
60
	 * Keyword 1 token id. This can be used to mark a
61
	 * keyword. This should be used for general language
62
	 * constructs.
63
	 */
64
	public static final byte KEYWORD1 = 6;
65
66
	/**
67
	 * Keyword 2 token id. This can be used to mark a
68
	 * keyword. This should be used for preprocessor
69
	 * commands, or variables.
70
	 */
71
	public static final byte KEYWORD2 = 7;
72
73
	/**
74
	 * Keyword 3 token id. This can be used to mark a
75
	 * keyword. This should be used for data types.
76
	 */
77
	public static final byte KEYWORD3 = 8;
78
79
	/**
80
	 * Operator token id. This can be used to mark an
81
	 * operator. (eg, SQL mode marks +, -, etc with this
82
	 * token type)
83
	 */
84
	public static final byte OPERATOR = 9;
85
86
	/**
87
	 * Invalid token id. This can be used to mark invalid
88
	 * or incomplete tokens, so the user can easily spot
89
	 * syntax errors.
90
	 */
91
	public static final byte INVALID = 10;
92
93
	/**
94
	 * The total number of defined token ids.
95
	 */
96
	public static final byte ID_COUNT = 11;
97
98
	/**
99
	 * The first id that can be used for internal state
100
	 * in a token marker.
101
	 */
102
	public static final byte INTERNAL_FIRST = 100;
103
104
	/**
105
	 * The last id that can be used for internal state
106
	 * in a token marker.
107
	 */
108
	public static final byte INTERNAL_LAST = 126;
109
110
	/**
111
	 * The token type, that along with a length of 0
112
	 * marks the end of the token list.
113
	 */
114
	public static final byte END = 127;
115
116
	/**
117
	 * The length of this token.
118
	 */
119
	public int length;
120
121
	/**
122
	 * The id of this token.
123
	 */
124
	public byte id;
125
126
	/**
127
	 * The next token in the linked list.
128
	 */
129
	public Token next;
130
131
	/**
132
	 * Creates a new token.
133
	 * @param length The length of the token
134
	 * @param id The id of the token
135
	 */
136
	public Token(int length, byte id)
137
	{
138
		this.length = length;
139
		this.id = id;
140
	}
141
142
	/**
143
	 * Returns a string representation of this token.
144
	 */
145
	public String toString()
146
	{
147
		return "[id=" + id + ",length=" + length + "]";
148
	}
149
}
(-)sources/org/apache/batik/apps/svgbrowser/srcview/TextUtilities.java (+183 lines)
Line 0 Link Here
1
/*
2
 * TextUtilities.java - Utility functions used by the text area classes
3
 * Copyright (C) 1999 Slava Pestov
4
 *
5
 * You may use and modify this package for any purpose. Redistribution is
6
 * permitted, in both source and binary form, provided that this notice
7
 * remains intact in all source distributions of this package.
8
 */
9
package org.apache.batik.apps.svgbrowser.srcview;
10
11
import javax.swing.text.*;
12
13
/**
14
 * Class with several utility functions used by the text area component.
15
 * @author Slava Pestov
16
 * @version $Id: TextUtilities.java,v 1.4 1999/12/13 03:40:30 sp Exp $
17
 */
18
public class TextUtilities
19
{
20
	/**
21
	 * Returns the offset of the bracket matching the one at the
22
	 * specified offset of the document, or -1 if the bracket is
23
	 * unmatched (or if the character is not a bracket).
24
	 * @param doc The document
25
	 * @param offset The offset
26
	 * @exception BadLocationException If an out-of-bounds access
27
	 * was attempted on the document text
28
	 */
29
	public static int findMatchingBracket(Document doc, int offset)
30
		throws BadLocationException
31
	{
32
		if(doc.getLength() == 0)
33
			return -1;
34
		char c = doc.getText(offset,1).charAt(0);
35
		char cprime; // c` - corresponding character
36
		boolean direction; // true = back, false = forward
37
38
		switch(c)
39
		{
40
		case '(': cprime = ')'; direction = false; break;
41
		case ')': cprime = '('; direction = true; break;
42
		case '[': cprime = ']'; direction = false; break;
43
		case ']': cprime = '['; direction = true; break;
44
		case '{': cprime = '}'; direction = false; break;
45
		case '}': cprime = '{'; direction = true; break;
46
		default: return -1;
47
		}
48
49
		int count;
50
51
		// How to merge these two cases is left as an exercise
52
		// for the reader.
53
54
		// Go back or forward
55
		if(direction)
56
		{
57
			// Count is 1 initially because we have already
58
			// `found' one closing bracket
59
			count = 1;
60
61
			// Get text[0,offset-1];
62
			String text = doc.getText(0,offset);
63
64
			// Scan backwards
65
			for(int i = offset - 1; i >= 0; i--)
66
			{
67
				// If text[i] == c, we have found another
68
				// closing bracket, therefore we will need
69
				// two opening brackets to complete the
70
				// match.
71
				char x = text.charAt(i);
72
				if(x == c)
73
					count++;
74
75
				// If text[i] == cprime, we have found a
76
				// opening bracket, so we return i if
77
				// --count == 0
78
				else if(x == cprime)
79
				{
80
					if(--count == 0)
81
						return i;
82
				}
83
			}
84
		}
85
		else
86
		{
87
			// Count is 1 initially because we have already
88
			// `found' one opening bracket
89
			count = 1;
90
91
			// So we don't have to + 1 in every loop
92
			offset++;
93
94
			// Number of characters to check
95
			int len = doc.getLength() - offset;
96
97
			// Get text[offset+1,len];
98
			String text = doc.getText(offset,len);
99
100
			// Scan forwards
101
			for(int i = 0; i < len; i++)
102
			{
103
				// If text[i] == c, we have found another
104
				// opening bracket, therefore we will need
105
				// two closing brackets to complete the
106
				// match.
107
				char x = text.charAt(i);
108
109
				if(x == c)
110
					count++;
111
112
				// If text[i] == cprime, we have found an
113
				// closing bracket, so we return i if
114
				// --count == 0
115
				else if(x == cprime)
116
				{
117
					if(--count == 0)
118
						return i + offset;
119
				}
120
			}
121
		}
122
123
		// Nothing found
124
		return -1;
125
	}
126
127
	/**
128
	 * Locates the start of the word at the specified position.
129
	 * @param line The text
130
	 * @param pos The position
131
	 */
132
	public static int findWordStart(String line, int pos, String noWordSep)
133
	{
134
		char ch = line.charAt(pos - 1);
135
136
		if(noWordSep == null)
137
			noWordSep = "";
138
		boolean selectNoLetter = (!Character.isLetterOrDigit(ch)
139
			&& noWordSep.indexOf(ch) == -1);
140
141
		int wordStart = 0;
142
		for(int i = pos - 1; i >= 0; i--)
143
		{
144
			ch = line.charAt(i);
145
			if(selectNoLetter ^ (!Character.isLetterOrDigit(ch) &&
146
				noWordSep.indexOf(ch) == -1))
147
			{
148
				wordStart = i + 1;
149
				break;
150
			}
151
		}
152
153
		return wordStart;
154
	}
155
156
	/**
157
	 * Locates the end of the word at the specified position.
158
	 * @param line The text
159
	 * @param pos The position
160
	 */
161
	public static int findWordEnd(String line, int pos, String noWordSep)
162
	{
163
		char ch = line.charAt(pos);
164
165
		if(noWordSep == null)
166
			noWordSep = "";
167
		boolean selectNoLetter = (!Character.isLetterOrDigit(ch)
168
			&& noWordSep.indexOf(ch) == -1);
169
170
		int wordEnd = line.length();
171
		for(int i = pos; i < line.length(); i++)
172
		{
173
			ch = line.charAt(i);
174
			if(selectNoLetter ^ (!Character.isLetterOrDigit(ch) &&
175
				noWordSep.indexOf(ch) == -1))
176
			{
177
				wordEnd = i;
178
				break;
179
			}
180
		}
181
		return wordEnd;
182
	}
183
}
(-)sources/org/apache/batik/apps/svgbrowser/srcview/KeywordMap.java (+139 lines)
Line 0 Link Here
1
/*
2
 * KeywordMap.java - Fast keyword->id map
3
 * Copyright (C) 1998, 1999 Slava Pestov
4
 * Copyright (C) 1999 Mike Dillon
5
 *
6
 * You may use and modify this package for any purpose. Redistribution is
7
 * permitted, in both source and binary form, provided that this notice
8
 * remains intact in all source distributions of this package.
9
 */
10
package org.apache.batik.apps.svgbrowser.srcview;
11
12
import javax.swing.text.Segment;
13
14
/**
15
 * A <code>KeywordMap</code> is similar to a hashtable in that it maps keys
16
 * to values. However, the `keys' are Swing segments. This allows lookups of
17
 * text substrings without the overhead of creating a new string object.
18
 * <p>
19
 * This class is used by <code>CTokenMarker</code> to map keywords to ids.
20
 *
21
 * @author Slava Pestov, Mike Dillon
22
 * @version $Id: KeywordMap.java,v 1.16 1999/12/13 03:40:30 sp Exp $
23
 */
24
public class KeywordMap
25
{
26
	/**
27
	 * Creates a new <code>KeywordMap</code>.
28
	 * @param ignoreCase True if keys are case insensitive
29
	 */
30
	public KeywordMap(boolean ignoreCase)
31
	{
32
		this(ignoreCase, 52);
33
		this.ignoreCase = ignoreCase;
34
	}
35
36
	/**
37
	 * Creates a new <code>KeywordMap</code>.
38
	 * @param ignoreCase True if the keys are case insensitive
39
	 * @param mapLength The number of `buckets' to create.
40
	 * A value of 52 will give good performance for most maps.
41
	 */
42
	public KeywordMap(boolean ignoreCase, int mapLength)
43
	{
44
		this.mapLength = mapLength;
45
		this.ignoreCase = ignoreCase;
46
		map = new Keyword[mapLength];
47
	}
48
49
	/**
50
	 * Looks up a key.
51
	 * @param text The text segment
52
	 * @param offset The offset of the substring within the text segment
53
	 * @param length The length of the substring
54
	 */
55
	public byte lookup(Segment text, int offset, int length)
56
	{
57
		if(length == 0)
58
			return Token.NULL;
59
		Keyword k = map[getSegmentMapKey(text, offset, length)];
60
		while(k != null)
61
		{
62
			if(length != k.keyword.length)
63
			{
64
				k = k.next;
65
				continue;
66
			}
67
			if(SyntaxUtilities.regionMatches(ignoreCase,text,offset,
68
				k.keyword))
69
				return k.id;
70
			k = k.next;
71
		}
72
		return Token.NULL;
73
	}
74
75
	/**
76
	 * Adds a key-value mapping.
77
	 * @param keyword The key
78
	 * @Param id The value
79
	 */
80
	public void add(String keyword, byte id)
81
	{
82
		int key = getStringMapKey(keyword);
83
		map[key] = new Keyword(keyword.toCharArray(),id,map[key]);
84
	}
85
86
	/**
87
	 * Returns true if the keyword map is set to be case insensitive,
88
	 * false otherwise.
89
	 */
90
	public boolean getIgnoreCase()
91
	{
92
		return ignoreCase;
93
	}
94
95
	/**
96
	 * Sets if the keyword map should be case insensitive.
97
	 * @param ignoreCase True if the keyword map should be case
98
	 * insensitive, false otherwise
99
	 */
100
	public void setIgnoreCase(boolean ignoreCase)
101
	{
102
		this.ignoreCase = ignoreCase;
103
	}
104
105
	// protected members
106
	protected int mapLength;
107
108
	protected int getStringMapKey(String s)
109
	{
110
		return (Character.toUpperCase(s.charAt(0)) +
111
				Character.toUpperCase(s.charAt(s.length()-1)))
112
				% mapLength;
113
	}
114
115
	protected int getSegmentMapKey(Segment s, int off, int len)
116
	{
117
		return (Character.toUpperCase(s.array[off]) +
118
				Character.toUpperCase(s.array[off + len - 1]))
119
				% mapLength;
120
	}
121
122
	// private members
123
	class Keyword
124
	{
125
		public Keyword(char[] keyword, byte id, Keyword next)
126
		{
127
			this.keyword = keyword;
128
			this.id = id;
129
			this.next = next;
130
		}
131
132
		public char[] keyword;
133
		public byte id;
134
		public Keyword next;
135
	}
136
137
	private Keyword[] map;
138
	private boolean ignoreCase;
139
}
(-)sources/org/apache/batik/apps/svgbrowser/srcview/SyntaxUtilities.java (+157 lines)
Line 0 Link Here
1
/*
2
 * SyntaxUtilities.java - Utility functions used by syntax colorizing
3
 * Copyright (C) 1999 Slava Pestov
4
 *
5
 * You may use and modify this package for any purpose. Redistribution is
6
 * permitted, in both source and binary form, provided that this notice
7
 * remains intact in all source distributions of this package.
8
 */
9
package org.apache.batik.apps.svgbrowser.srcview;
10
11
import javax.swing.text.*;
12
import java.awt.*;
13
14
/**
15
 * Class with several utility functions used by jEdit's syntax colorizing
16
 * subsystem.
17
 *
18
 * @author Slava Pestov
19
 * @version $Id: SyntaxUtilities.java,v 1.9 1999/12/13 03:40:30 sp Exp $
20
 */
21
public class SyntaxUtilities
22
{
23
	/**
24
	 * Checks if a subregion of a <code>Segment</code> is equal to a
25
	 * string.
26
	 * @param ignoreCase True if case should be ignored, false otherwise
27
	 * @param text The segment
28
	 * @param offset The offset into the segment
29
	 * @param match The string to match
30
	 */
31
	public static boolean regionMatches(boolean ignoreCase, Segment text,
32
					    int offset, String match)
33
	{
34
		int length = offset + match.length();
35
		char[] textArray = text.array;
36
		if(length > text.offset + text.count)
37
			return false;
38
		for(int i = offset, j = 0; i < length; i++, j++)
39
		{
40
			char c1 = textArray[i];
41
			char c2 = match.charAt(j);
42
			if(ignoreCase)
43
			{
44
				c1 = Character.toUpperCase(c1);
45
				c2 = Character.toUpperCase(c2);
46
			}
47
			if(c1 != c2)
48
				return false;
49
		}
50
		return true;
51
	}
52
	
53
	/**
54
	 * Checks if a subregion of a <code>Segment</code> is equal to a
55
	 * character array.
56
	 * @param ignoreCase True if case should be ignored, false otherwise
57
	 * @param text The segment
58
	 * @param offset The offset into the segment
59
	 * @param match The character array to match
60
	 */
61
	public static boolean regionMatches(boolean ignoreCase, Segment text,
62
					    int offset, char[] match)
63
	{
64
		int length = offset + match.length;
65
		char[] textArray = text.array;
66
		if(length > text.offset + text.count)
67
			return false;
68
		for(int i = offset, j = 0; i < length; i++, j++)
69
		{
70
			char c1 = textArray[i];
71
			char c2 = match[j];
72
			if(ignoreCase)
73
			{
74
				c1 = Character.toUpperCase(c1);
75
				c2 = Character.toUpperCase(c2);
76
			}
77
			if(c1 != c2)
78
				return false;
79
		}
80
		return true;
81
	}
82
83
	/**
84
	 * Returns the default style table. This can be passed to the
85
	 * <code>setStyles()</code> method of <code>SyntaxDocument</code>
86
	 * to use the default syntax styles.
87
	 */
88
	public static SyntaxStyle[] getDefaultSyntaxStyles()
89
	{
90
		SyntaxStyle[] styles = new SyntaxStyle[Token.ID_COUNT];
91
92
		styles[Token.COMMENT1] = new SyntaxStyle(Color.black,true,true);
93
		styles[Token.COMMENT2] = new SyntaxStyle(new Color(0x990033),true,true);
94
		styles[Token.KEYWORD1] = new SyntaxStyle(Color.black,false,true);
95
		styles[Token.KEYWORD2] = new SyntaxStyle(Color.magenta,false,true);
96
		styles[Token.KEYWORD3] = new SyntaxStyle(new Color(0x009600),false,false);
97
		styles[Token.LITERAL1] = new SyntaxStyle(new Color(0x650099),false,false);
98
		styles[Token.LITERAL2] = new SyntaxStyle(new Color(0x650099),false,true);
99
		styles[Token.LABEL] = new SyntaxStyle(new Color(0x990033),false,true);
100
		styles[Token.OPERATOR] = new SyntaxStyle(Color.black,false,true);
101
		styles[Token.INVALID] = new SyntaxStyle(Color.red,false,true);
102
103
		return styles;
104
	}
105
106
	/**
107
	 * Paints the specified line onto the graphics context. Note that this
108
	 * method munges the offset and count values of the segment.
109
	 * @param line The line segment
110
	 * @param tokens The token list for the line
111
	 * @param styles The syntax style list
112
	 * @param expander The tab expander used to determine tab stops. May
113
	 * be null
114
	 * @param gfx The graphics context
115
	 * @param x The x co-ordinate
116
	 * @param y The y co-ordinate
117
	 * @return The x co-ordinate, plus the width of the painted string
118
	 */
119
	public static int paintSyntaxLine(Segment line, Token tokens,
120
		SyntaxStyle[] styles, TabExpander expander, Graphics gfx,
121
		int x, int y)
122
	{
123
		Font defaultFont = gfx.getFont();
124
		Color defaultColor = gfx.getColor();
125
126
		int offset = 0;
127
		for(;;)
128
		{
129
			byte id = tokens.id;
130
			if(id == Token.END)
131
				break;
132
133
			int length = tokens.length;
134
			if(id == Token.NULL)
135
			{
136
				if(!defaultColor.equals(gfx.getColor()))
137
					gfx.setColor(defaultColor);
138
				if(!defaultFont.equals(gfx.getFont()))
139
					gfx.setFont(defaultFont);
140
			}
141
			else
142
				styles[id].setGraphicsFlags(gfx,defaultFont);
143
144
			line.count = length;
145
			x = Utilities.drawTabbedText(line,x,y,gfx,expander,0);
146
			line.offset += length;
147
			offset += length;
148
149
			tokens = tokens.next;
150
		}
151
152
		return x;
153
	}
154
155
	// private members
156
	private SyntaxUtilities() {}
157
}
(-)sources/org/apache/batik/apps/svgbrowser/srcview/TokenMarker.java (+344 lines)
Line 0 Link Here
1
/*
2
 * TokenMarker.java - Generic token marker
3
 * Copyright (C) 1998, 1999 Slava Pestov
4
 *
5
 * You may use and modify this package for any purpose. Redistribution is
6
 * permitted, in both source and binary form, provided that this notice
7
 * remains intact in all source distributions of this package.
8
 */
9
package org.apache.batik.apps.svgbrowser.srcview;
10
11
import javax.swing.text.Segment;
12
import java.util.*;
13
14
/**
15
 * A token marker that splits lines of text into tokens. Each token carries
16
 * a length field and an indentification tag that can be mapped to a color
17
 * for painting that token.<p>
18
 *
19
 * For performance reasons, the linked list of tokens is reused after each
20
 * line is tokenized. Therefore, the return value of <code>markTokens</code>
21
 * should only be used for immediate painting. Notably, it cannot be
22
 * cached.
23
 *
24
 * @author Slava Pestov
25
 * @version $Id: TokenMarker.java,v 1.32 1999/12/13 03:40:30 sp Exp $
26
 *
27
 * @see org.gjt.sp.jedit.syntax.Token
28
 */
29
public abstract class TokenMarker
30
{
31
	/**
32
	 * A wrapper for the lower-level <code>markTokensImpl</code> method
33
	 * that is called to split a line up into tokens.
34
	 * @param line The line
35
	 * @param lineIndex The line number
36
	 */
37
	public Token markTokens(Segment line, int lineIndex)
38
	{
39
		if(lineIndex >= length)
40
		{
41
			throw new IllegalArgumentException("Tokenizing invalid line: "
42
				+ lineIndex);
43
		}
44
45
		lastToken = null;
46
47
		LineInfo info = lineInfo[lineIndex];
48
		LineInfo prev;
49
		if(lineIndex == 0)
50
			prev = null;
51
		else
52
			prev = lineInfo[lineIndex - 1];
53
54
		byte oldToken = info.token;
55
		byte token = markTokensImpl(prev == null ?
56
			Token.NULL : prev.token,line,lineIndex);
57
58
		info.token = token;
59
60
		/*
61
		 * This is a foul hack. It stops nextLineRequested
62
		 * from being cleared if the same line is marked twice.
63
		 *
64
		 * Why is this necessary? It's all JEditTextArea's fault.
65
		 * When something is inserted into the text, firing a
66
		 * document event, the insertUpdate() method shifts the
67
		 * caret (if necessary) by the amount inserted.
68
		 *
69
		 * All caret movement is handled by the select() method,
70
		 * which eventually pipes the new position to scrollTo()
71
		 * and calls repaint().
72
		 *
73
		 * Note that at this point in time, the new line hasn't
74
		 * yet been painted; the caret is moved first.
75
		 *
76
		 * scrollTo() calls offsetToX(), which tokenizes the line
77
		 * unless it is being called on the last line painted
78
		 * (in which case it uses the text area's painter cached
79
		 * token list). What scrollTo() does next is irrelevant.
80
		 *
81
		 * After scrollTo() has done it's job, repaint() is
82
		 * called, and eventually we end up in paintLine(), whose
83
		 * job is to paint the changed line. It, too, calls
84
		 * markTokens().
85
		 *
86
		 * The problem was that if the line started a multiline
87
		 * token, the first markTokens() (done in offsetToX())
88
		 * would set nextLineRequested (because the line end
89
		 * token had changed) but the second would clear it
90
		 * (because the line was the same that time) and therefore
91
		 * paintLine() would never know that it needed to repaint
92
		 * subsequent lines.
93
		 *
94
		 * This bug took me ages to track down, that's why I wrote
95
		 * all the relevant info down so that others wouldn't
96
		 * duplicate it.
97
		 */
98
		 if(!(lastLine == lineIndex && nextLineRequested))
99
			nextLineRequested = (oldToken != token);
100
101
		lastLine = lineIndex;
102
103
		addToken(0,Token.END);
104
105
		return firstToken;
106
	}
107
108
	/**
109
	 * An abstract method that splits a line up into tokens. It
110
	 * should parse the line, and call <code>addToken()</code> to
111
	 * add syntax tokens to the token list. Then, it should return
112
	 * the initial token type for the next line.<p>
113
	 *
114
	 * For example if the current line contains the start of a 
115
	 * multiline comment that doesn't end on that line, this method
116
	 * should return the comment token type so that it continues on
117
	 * the next line.
118
	 *
119
	 * @param token The initial token type for this line
120
	 * @param line The line to be tokenized
121
	 * @param lineIndex The index of the line in the document,
122
	 * starting at 0
123
	 * @return The initial token type for the next line
124
	 */
125
	protected abstract byte markTokensImpl(byte token, Segment line,
126
		int lineIndex);
127
128
	/**
129
	 * Returns if the token marker supports tokens that span multiple
130
	 * lines. If this is true, the object using this token marker is
131
	 * required to pass all lines in the document to the
132
	 * <code>markTokens()</code> method (in turn).<p>
133
	 *
134
	 * The default implementation returns true; it should be overridden
135
	 * to return false on simpler token markers for increased speed.
136
	 */
137
	public boolean supportsMultilineTokens()
138
	{
139
		return true;
140
	}
141
142
	/**
143
	 * Informs the token marker that lines have been inserted into
144
	 * the document. This inserts a gap in the <code>lineInfo</code>
145
	 * array.
146
	 * @param index The first line number
147
	 * @param lines The number of lines 
148
	 */
149
	public void insertLines(int index, int lines)
150
	{
151
		if(lines <= 0)
152
			return;
153
		length += lines;
154
		ensureCapacity(length);
155
		int len = index + lines;
156
		System.arraycopy(lineInfo,index,lineInfo,len,
157
			lineInfo.length - len);
158
159
		for(int i = index + lines - 1; i >= index; i--)
160
		{
161
			lineInfo[i] = new LineInfo();
162
		}
163
	}
164
	
165
	/**
166
	 * Informs the token marker that line have been deleted from
167
	 * the document. This removes the lines in question from the
168
	 * <code>lineInfo</code> array.
169
	 * @param index The first line number
170
	 * @param lines The number of lines
171
	 */
172
	public void deleteLines(int index, int lines)
173
	{
174
		if (lines <= 0)
175
			return;
176
		int len = index + lines;
177
		length -= lines;
178
		System.arraycopy(lineInfo,len,lineInfo,
179
			index,lineInfo.length - len);
180
	}
181
182
	/**
183
	 * Returns the number of lines in this token marker.
184
	 */
185
	public int getLineCount()
186
	{
187
		return length;
188
	}
189
190
	/**
191
	 * Returns true if the next line should be repainted. This
192
	 * will return true after a line has been tokenized that starts
193
	 * a multiline token that continues onto the next line.
194
	 */
195
	public boolean isNextLineRequested()
196
	{
197
		return nextLineRequested;
198
	}
199
200
	// protected members
201
202
	/**
203
	 * The first token in the list. This should be used as the return
204
	 * value from <code>markTokens()</code>.
205
	 */
206
	protected Token firstToken;
207
208
	/**
209
	 * The last token in the list. New tokens are added here.
210
	 * This should be set to null before a new line is to be tokenized.
211
	 */
212
	protected Token lastToken;
213
214
	/**
215
	 * An array for storing information about lines. It is enlarged and
216
	 * shrunk automatically by the <code>insertLines()</code> and
217
	 * <code>deleteLines()</code> methods.
218
	 */
219
	protected LineInfo[] lineInfo;
220
221
	/**
222
	 * The number of lines in the model being tokenized. This can be
223
	 * less than the length of the <code>lineInfo</code> array.
224
	 */
225
	protected int length;
226
227
	/**
228
	 * The last tokenized line.
229
	 */
230
	protected int lastLine;
231
232
	/**
233
	 * True if the next line should be painted.
234
	 */
235
	protected boolean nextLineRequested;
236
237
	/**
238
	 * Creates a new <code>TokenMarker</code>. This DOES NOT create
239
	 * a lineInfo array; an initial call to <code>insertLines()</code>
240
	 * does that.
241
	 */
242
	protected TokenMarker()
243
	{
244
		lastLine = -1;
245
	}
246
247
	/**
248
	 * Ensures that the <code>lineInfo</code> array can contain the
249
	 * specified index. This enlarges it if necessary. No action is
250
	 * taken if the array is large enough already.<p>
251
	 *
252
	 * It should be unnecessary to call this under normal
253
	 * circumstances; <code>insertLine()</code> should take care of
254
	 * enlarging the line info array automatically.
255
	 *
256
	 * @param index The array index
257
	 */
258
	protected void ensureCapacity(int index)
259
	{
260
		if(lineInfo == null)
261
			lineInfo = new LineInfo[index + 1];
262
		else if(lineInfo.length <= index)
263
		{
264
			LineInfo[] lineInfoN = new LineInfo[(index + 1) * 2];
265
			System.arraycopy(lineInfo,0,lineInfoN,0,
266
					 lineInfo.length);
267
			lineInfo = lineInfoN;
268
		}
269
	}
270
271
	/**
272
	 * Adds a token to the token list.
273
	 * @param length The length of the token
274
	 * @param id The id of the token
275
	 */
276
	protected void addToken(int length, byte id)
277
	{
278
		if(id >= Token.INTERNAL_FIRST && id <= Token.INTERNAL_LAST)
279
			throw new InternalError("Invalid id: " + id);
280
281
		if(length == 0 && id != Token.END)
282
			return;
283
284
		if(firstToken == null)
285
		{
286
			firstToken = new Token(length,id);
287
			lastToken = firstToken;
288
		}
289
		else if(lastToken == null)
290
		{
291
			lastToken = firstToken;
292
			firstToken.length = length;
293
			firstToken.id = id;
294
		}
295
		else if(lastToken.next == null)
296
		{
297
			lastToken.next = new Token(length,id);
298
			lastToken = lastToken.next;
299
		}
300
		else
301
		{
302
			lastToken = lastToken.next;
303
			lastToken.length = length;
304
			lastToken.id = id;
305
		}
306
	}
307
308
	/**
309
	 * Inner class for storing information about tokenized lines.
310
	 */
311
	public class LineInfo
312
	{
313
		/**
314
		 * Creates a new LineInfo object with token = Token.NULL
315
		 * and obj = null.
316
		 */
317
		public LineInfo()
318
		{
319
		}
320
321
		/**
322
		 * Creates a new LineInfo object with the specified
323
		 * parameters.
324
		 */
325
		public LineInfo(byte token, Object obj)
326
		{
327
			this.token = token;
328
			this.obj = obj;
329
		}
330
331
		/**
332
		 * The id of the last token of the line.
333
		 */
334
		public byte token;
335
336
		/**
337
		 * This is for use by the token marker implementations
338
		 * themselves. It can be used to store anything that
339
		 * is an object and that needs to exist on a per-line
340
		 * basis.
341
		 */
342
		public Object obj;
343
	}
344
}
(-)sources/org/apache/batik/apps/svgbrowser/srcview/SyntaxDocument.java (+165 lines)
Line 0 Link Here
1
/*
2
 * SyntaxDocument.java - Document that can be tokenized
3
 * Copyright (C) 1999 Slava Pestov
4
 *
5
 * You may use and modify this package for any purpose. Redistribution is
6
 * permitted, in both source and binary form, provided that this notice
7
 * remains intact in all source distributions of this package.
8
 */
9
package org.apache.batik.apps.svgbrowser.srcview;
10
11
import javax.swing.event.*;
12
import javax.swing.text.*;
13
import javax.swing.undo.UndoableEdit;
14
15
/**
16
 * A document implementation that can be tokenized by the syntax highlighting
17
 * system.
18
 *
19
 * @author Slava Pestov
20
 * @version $Id: SyntaxDocument.java,v 1.14 1999/12/13 03:40:30 sp Exp $
21
 */
22
public class SyntaxDocument extends PlainDocument
23
{
24
	/**
25
	 * Returns the token marker that is to be used to split lines
26
	 * of this document up into tokens. May return null if this
27
	 * document is not to be colorized.
28
	 */
29
	public TokenMarker getTokenMarker()
30
	{
31
		return tokenMarker;
32
	}
33
34
	/**
35
	 * Sets the token marker that is to be used to split lines of
36
	 * this document up into tokens. May throw an exception if
37
	 * this is not supported for this type of document.
38
	 * @param tm The new token marker
39
	 */
40
	public void setTokenMarker(TokenMarker tm)
41
	{
42
		tokenMarker = tm;
43
		if(tm == null)
44
			return;
45
		tokenMarker.insertLines(0,getDefaultRootElement()
46
			.getElementCount());
47
		tokenizeLines();
48
	}
49
50
	/**
51
	 * Reparses the document, by passing all lines to the token
52
	 * marker. This should be called after the document is first
53
	 * loaded.
54
	 */
55
	public void tokenizeLines()
56
	{
57
		tokenizeLines(0,getDefaultRootElement().getElementCount());
58
	}
59
60
	/**
61
	 * Reparses the document, by passing the specified lines to the
62
	 * token marker. This should be called after a large quantity of
63
	 * text is first inserted.
64
	 * @param start The first line to parse
65
	 * @param len The number of lines, after the first one to parse
66
	 */
67
	public void tokenizeLines(int start, int len)
68
	{
69
		if(tokenMarker == null || !tokenMarker.supportsMultilineTokens())
70
			return;
71
72
		Segment lineSegment = new Segment();
73
		Element map = getDefaultRootElement();
74
75
		len += start;
76
77
		try
78
		{
79
			for(int i = start; i < len; i++)
80
			{
81
				Element lineElement = map.getElement(i);
82
				int lineStart = lineElement.getStartOffset();
83
				getText(lineStart,lineElement.getEndOffset()
84
					- lineStart - 1,lineSegment);
85
				tokenMarker.markTokens(lineSegment,i);
86
			}
87
		}
88
		catch(BadLocationException bl)
89
		{
90
			bl.printStackTrace();
91
		}
92
	}
93
94
	/**
95
	 * Starts a compound edit that can be undone in one operation.
96
	 * Subclasses that implement undo should override this method;
97
	 * this class has no undo functionality so this method is
98
	 * empty.
99
	 */
100
	public void beginCompoundEdit() {}
101
102
	/**
103
	 * Ends a compound edit that can be undone in one operation.
104
	 * Subclasses that implement undo should override this method;
105
	 * this class has no undo functionality so this method is
106
	 * empty.
107
	 */
108
	public void endCompoundEdit() {}
109
110
	/**
111
	 * Adds an undoable edit to this document's undo list. The edit
112
	 * should be ignored if something is currently being undone.
113
	 * @param edit The undoable edit
114
	 *
115
	 * @since jEdit 2.2pre1
116
	 */
117
	public void addUndoableEdit(UndoableEdit edit) {}
118
119
	// protected members
120
	protected TokenMarker tokenMarker;
121
122
	/**
123
	 * We overwrite this method to update the token marker
124
	 * state immediately so that any event listeners get a
125
	 * consistent token marker.
126
	 */
127
	protected void fireInsertUpdate(DocumentEvent evt)
128
	{
129
		if(tokenMarker != null)
130
		{
131
			DocumentEvent.ElementChange ch = evt.getChange(
132
				getDefaultRootElement());
133
			if(ch != null)
134
			{
135
				tokenMarker.insertLines(ch.getIndex() + 1,
136
					ch.getChildrenAdded().length -
137
					ch.getChildrenRemoved().length);
138
			}
139
		}
140
141
		super.fireInsertUpdate(evt);
142
	}
143
	
144
	/**
145
	 * We overwrite this method to update the token marker
146
	 * state immediately so that any event listeners get a
147
	 * consistent token marker.
148
	 */
149
	protected void fireRemoveUpdate(DocumentEvent evt)
150
	{
151
		if(tokenMarker != null)
152
		{
153
			DocumentEvent.ElementChange ch = evt.getChange(
154
				getDefaultRootElement());
155
			if(ch != null)
156
			{
157
				tokenMarker.deleteLines(ch.getIndex() + 1,
158
					ch.getChildrenRemoved().length -
159
					ch.getChildrenAdded().length);
160
			}
161
		}
162
163
		super.fireRemoveUpdate(evt);
164
	}
165
}
(-)sources/org/apache/batik/apps/svgbrowser/srcview/JEditTextArea.java (+2128 lines)
Line 0 Link Here
1
/*
2
 * JEditTextArea.java - jEdit's text component
3
 * Copyright (C) 1999 Slava Pestov
4
 *
5
 * You may use and modify this package for any purpose. Redistribution is
6
 * permitted, in both source and binary form, provided that this notice
7
 * remains intact in all source distributions of this package.
8
 */
9
package org.apache.batik.apps.svgbrowser.srcview;
10
11
import javax.swing.event.*;
12
import javax.swing.text.*;
13
import javax.swing.undo.*;
14
import javax.swing.*;
15
import java.awt.datatransfer.*;
16
import java.awt.event.*;
17
import java.awt.*;
18
import java.util.Enumeration;
19
import java.util.Vector;
20
21
/**
22
 * jEdit's text area component. It is more suited for editing program
23
 * source code than JEditorPane, because it drops the unnecessary features
24
 * (images, variable-width lines, and so on) and adds a whole bunch of
25
 * useful goodies such as:
26
 * <ul>
27
 * <li>More flexible key binding scheme
28
 * <li>Supports macro recorders
29
 * <li>Rectangular selection
30
 * <li>Bracket highlighting
31
 * <li>Syntax highlighting
32
 * <li>Command repetition
33
 * <li>Block caret can be enabled
34
 * </ul>
35
 * It is also faster and doesn't have as many problems. It can be used
36
 * in other applications; the only other part of jEdit it depends on is
37
 * the syntax package.<p>
38
 *
39
 * To use it in your app, treat it like any other component, for example:
40
 * <pre>JEditTextArea ta = new JEditTextArea();
41
 * ta.setTokenMarker(new JavaTokenMarker());
42
 * ta.setText("public class Test {\n"
43
 *     + "    public static void main(String[] args) {\n"
44
 *     + "        System.out.println(\"Hello World\");\n"
45
 *     + "    }\n"
46
 *     + "}");</pre>
47
 *
48
 * @author Slava Pestov
49
 * @version $Id: JEditTextArea.java,v 1.36 1999/12/13 03:40:30 sp Exp $
50
 */
51
public class JEditTextArea extends JComponent
52
{
53
	/**
54
	 * Adding components with this name to the text area will place
55
	 * them left of the horizontal scroll bar. In jEdit, the status
56
	 * bar is added this way.
57
	 */
58
	public static String LEFT_OF_SCROLLBAR = "los";
59
60
	/**
61
	 * Creates a new JEditTextArea with the default settings.
62
	 */
63
	public JEditTextArea()
64
	{
65
		this(TextAreaDefaults.getDefaults());
66
	}
67
68
	/**
69
	 * Creates a new JEditTextArea with the specified settings.
70
	 * @param defaults The default settings
71
	 */
72
	public JEditTextArea(TextAreaDefaults defaults)
73
	{
74
		// Enable the necessary events
75
		enableEvents(AWTEvent.KEY_EVENT_MASK);
76
77
		// Initialize some misc. stuff
78
		painter = new TextAreaPainter(this,defaults);
79
		documentHandler = new DocumentHandler();
80
		listenerList = new EventListenerList();
81
		caretEvent = new MutableCaretEvent();
82
		lineSegment = new Segment();
83
		bracketLine = bracketPosition = -1;
84
		blink = true;
85
86
		// Initialize the GUI
87
		setLayout(new ScrollLayout());
88
		add(CENTER,painter);
89
		add(RIGHT,vertical = new JScrollBar(JScrollBar.VERTICAL));
90
		add(BOTTOM,horizontal = new JScrollBar(JScrollBar.HORIZONTAL));
91
92
		// Add some event listeners
93
		vertical.addAdjustmentListener(new AdjustHandler());
94
		horizontal.addAdjustmentListener(new AdjustHandler());
95
		painter.addComponentListener(new ComponentHandler());
96
		painter.addMouseListener(new MouseHandler());
97
		painter.addMouseMotionListener(new DragHandler());
98
		addFocusListener(new FocusHandler());
99
100
		// Load the defaults
101
		setInputHandler(defaults.inputHandler);
102
		setDocument(defaults.document);
103
		editable = defaults.editable;
104
		caretVisible = defaults.caretVisible;
105
		caretBlinks = defaults.caretBlinks;
106
		electricScroll = defaults.electricScroll;
107
108
		popup = defaults.popup;
109
110
		// We don't seem to get the initial focus event?
111
		focusedComponent = this;
112
	}
113
114
	/**
115
	 * Returns if this component can be traversed by pressing
116
	 * the Tab key. This returns false.
117
	 */
118
	public final boolean isManagingFocus()
119
	{
120
		return true;
121
	}
122
123
	/**
124
	 * Returns the object responsible for painting this text area.
125
	 */
126
	public final TextAreaPainter getPainter()
127
	{
128
		return painter;
129
	}
130
131
	/**
132
	 * Returns the input handler.
133
	 */
134
	public final InputHandler getInputHandler()
135
	{
136
		return inputHandler;
137
	}
138
139
	/**
140
	 * Sets the input handler.
141
	 * @param inputHandler The new input handler
142
	 */
143
	public void setInputHandler(InputHandler inputHandler)
144
	{
145
		this.inputHandler = inputHandler;
146
	}
147
148
	/**
149
	 * Returns true if the caret is blinking, false otherwise.
150
	 */
151
	public final boolean isCaretBlinkEnabled()
152
	{
153
		return caretBlinks;
154
	}
155
156
	/**
157
	 * Toggles caret blinking.
158
	 * @param caretBlinks True if the caret should blink, false otherwise
159
	 */
160
	public void setCaretBlinkEnabled(boolean caretBlinks)
161
	{
162
		this.caretBlinks = caretBlinks;
163
		if(!caretBlinks)
164
			blink = false;
165
166
		painter.invalidateSelectedLines();
167
	}
168
169
	/**
170
	 * Returns true if the caret is visible, false otherwise.
171
	 */
172
	public final boolean isCaretVisible()
173
	{
174
		return (!caretBlinks || blink) && caretVisible;
175
	}
176
177
	/**
178
	 * Sets if the caret should be visible.
179
	 * @param caretVisible True if the caret should be visible, false
180
	 * otherwise
181
	 */
182
	public void setCaretVisible(boolean caretVisible)
183
	{
184
		this.caretVisible = caretVisible;
185
		blink = true;
186
187
		painter.invalidateSelectedLines();
188
	}
189
190
	/**
191
	 * Blinks the caret.
192
	 */
193
	public final void blinkCaret()
194
	{
195
		if(caretBlinks)
196
		{
197
			blink = !blink;
198
			painter.invalidateSelectedLines();
199
		}
200
		else
201
			blink = true;
202
	}
203
204
	/**
205
	 * Returns the number of lines from the top and button of the
206
	 * text area that are always visible.
207
	 */
208
	public final int getElectricScroll()
209
	{
210
		return electricScroll;
211
	}
212
213
	/**
214
	 * Sets the number of lines from the top and bottom of the text
215
	 * area that are always visible
216
	 * @param electricScroll The number of lines always visible from
217
	 * the top or bottom
218
	 */
219
	public final void setElectricScroll(int electricScroll)
220
	{
221
		this.electricScroll = electricScroll;
222
	}
223
224
	/**
225
	 * Updates the state of the scroll bars. This should be called
226
	 * if the number of lines in the document changes, or when the
227
	 * size of the text are changes.
228
	 */
229
	public void updateScrollBars()
230
	{
231
		if(vertical != null && visibleLines != 0)
232
		{
233
			vertical.setValues(firstLine,visibleLines,0,getLineCount());
234
			vertical.setUnitIncrement(2);
235
			vertical.setBlockIncrement(visibleLines);
236
		}
237
238
		int width = painter.getWidth();
239
		if(horizontal != null && width != 0)
240
		{
241
			horizontal.setValues(-horizontalOffset,width,0,width * 5);
242
			horizontal.setUnitIncrement(painter.getFontMetrics()
243
				.charWidth('w'));
244
			horizontal.setBlockIncrement(width / 2);
245
		}
246
	}
247
248
	/**
249
	 * Returns the line displayed at the text area's origin.
250
	 */
251
	public final int getFirstLine()
252
	{
253
		return firstLine;
254
	}
255
256
	/**
257
	 * Sets the line displayed at the text area's origin without
258
	 * updating the scroll bars.
259
	 */
260
	public void setFirstLine(int firstLine)
261
	{
262
		if(firstLine == this.firstLine)
263
			return;
264
		int oldFirstLine = this.firstLine;
265
		this.firstLine = firstLine;
266
		if(firstLine != vertical.getValue())
267
			updateScrollBars();
268
		painter.repaint();
269
	}
270
271
	/**
272
	 * Returns the number of lines visible in this text area.
273
	 */
274
	public final int getVisibleLines()
275
	{
276
		return visibleLines;
277
	}
278
279
	/**
280
	 * Recalculates the number of visible lines. This should not
281
	 * be called directly.
282
	 */
283
	public final void recalculateVisibleLines()
284
	{
285
		if(painter == null)
286
			return;
287
		int height = painter.getHeight();
288
		int lineHeight = painter.getFontMetrics().getHeight();
289
		int oldVisibleLines = visibleLines;
290
		visibleLines = height / lineHeight;
291
		updateScrollBars();
292
	}
293
294
	/**
295
	 * Returns the horizontal offset of drawn lines.
296
	 */
297
	public final int getHorizontalOffset()
298
	{
299
		return horizontalOffset;
300
	}
301
302
	/**
303
	 * Sets the horizontal offset of drawn lines. This can be used to
304
	 * implement horizontal scrolling.
305
	 * @param horizontalOffset offset The new horizontal offset
306
	 */
307
	public void setHorizontalOffset(int horizontalOffset)
308
	{
309
		if(horizontalOffset == this.horizontalOffset)
310
			return;
311
		this.horizontalOffset = horizontalOffset;
312
		if(horizontalOffset != horizontal.getValue())
313
			updateScrollBars();
314
		painter.repaint();
315
	}
316
317
	/**
318
	 * A fast way of changing both the first line and horizontal
319
	 * offset.
320
	 * @param firstLine The new first line
321
	 * @param horizontalOffset The new horizontal offset
322
	 * @return True if any of the values were changed, false otherwise
323
	 */
324
	public boolean setOrigin(int firstLine, int horizontalOffset)
325
	{
326
		boolean changed = false;
327
		int oldFirstLine = this.firstLine;
328
329
		if(horizontalOffset != this.horizontalOffset)
330
		{
331
			this.horizontalOffset = horizontalOffset;
332
			changed = true;
333
		}
334
335
		if(firstLine != this.firstLine)
336
		{
337
			this.firstLine = firstLine;
338
			changed = true;
339
		}
340
341
		if(changed)
342
		{
343
			updateScrollBars();
344
			painter.repaint();
345
		}
346
347
		return changed;
348
	}
349
350
	/**
351
	 * Ensures that the caret is visible by scrolling the text area if
352
	 * necessary.
353
	 * @return True if scrolling was actually performed, false if the
354
	 * caret was already visible
355
	 */
356
	public boolean scrollToCaret()
357
	{
358
		int line = getCaretLine();
359
		int lineStart = getLineStartOffset(line);
360
		int offset = Math.max(0,Math.min(getLineLength(line) - 1,
361
			getCaretPosition() - lineStart));
362
363
		return scrollTo(line,offset);
364
	}
365
366
	/**
367
	 * Ensures that the specified line and offset is visible by scrolling
368
	 * the text area if necessary.
369
	 * @param line The line to scroll to
370
	 * @param offset The offset in the line to scroll to
371
	 * @return True if scrolling was actually performed, false if the
372
	 * line and offset was already visible
373
	 */
374
	public boolean scrollTo(int line, int offset)
375
	{
376
		// visibleLines == 0 before the component is realized
377
		// we can't do any proper scrolling then, so we have
378
		// this hack...
379
		if(visibleLines == 0)
380
		{
381
			setFirstLine(Math.max(0,line - electricScroll));
382
			return true;
383
		}
384
385
		int newFirstLine = firstLine;
386
		int newHorizontalOffset = horizontalOffset;
387
388
		if(line < firstLine + electricScroll)
389
		{
390
			newFirstLine = Math.max(0,line - electricScroll);
391
		}
392
		else if(line + electricScroll >= firstLine + visibleLines)
393
		{
394
			newFirstLine = (line - visibleLines) + electricScroll + 1;
395
			if(newFirstLine + visibleLines >= getLineCount())
396
				newFirstLine = getLineCount() - visibleLines;
397
			if(newFirstLine < 0)
398
				newFirstLine = 0;
399
		}
400
401
		int x = _offsetToX(line,offset);
402
		int width = painter.getFontMetrics().charWidth('w');
403
404
		if(x < 0)
405
		{
406
			newHorizontalOffset = Math.min(0,horizontalOffset
407
				- x + width + 5);
408
		}
409
		else if(x + width >= painter.getWidth())
410
		{
411
			newHorizontalOffset = horizontalOffset +
412
				(painter.getWidth() - x) - width - 5;
413
		}
414
415
		return setOrigin(newFirstLine,newHorizontalOffset);
416
	}
417
418
	/**
419
	 * Converts a line index to a y co-ordinate.
420
	 * @param line The line
421
	 */
422
	public int lineToY(int line)
423
	{
424
		FontMetrics fm = painter.getFontMetrics();
425
		return (line - firstLine) * fm.getHeight()
426
			- (fm.getLeading() + fm.getMaxDescent());
427
	}
428
429
	/**
430
	 * Converts a y co-ordinate to a line index.
431
	 * @param y The y co-ordinate
432
	 */
433
	public int yToLine(int y)
434
	{
435
		FontMetrics fm = painter.getFontMetrics();
436
		int height = fm.getHeight();
437
		return Math.max(0,Math.min(getLineCount() - 1,
438
			y / height + firstLine));
439
	}
440
441
	/**
442
	 * Converts an offset in a line into an x co-ordinate. This is a
443
	 * slow version that can be used any time.
444
	 * @param line The line
445
	 * @param offset The offset, from the start of the line
446
	 */
447
	public final int offsetToX(int line, int offset)
448
	{
449
		// don't use cached tokens
450
		painter.currentLineTokens = null;
451
		return _offsetToX(line,offset);
452
	}
453
454
	/**
455
	 * Converts an offset in a line into an x co-ordinate. This is a
456
	 * fast version that should only be used if no changes were made
457
	 * to the text since the last repaint.
458
	 * @param line The line
459
	 * @param offset The offset, from the start of the line
460
	 */
461
	public int _offsetToX(int line, int offset)
462
	{
463
		TokenMarker tokenMarker = getTokenMarker();
464
465
		/* Use painter's cached info for speed */
466
		FontMetrics fm = painter.getFontMetrics();
467
468
		getLineText(line,lineSegment);
469
470
		int segmentOffset = lineSegment.offset;
471
		int x = horizontalOffset;
472
473
		/* If syntax coloring is disabled, do simple translation */
474
		if(tokenMarker == null)
475
		{
476
			lineSegment.count = offset;
477
			return x + Utilities.getTabbedTextWidth(lineSegment,
478
				fm,x,painter,0);
479
		}
480
		/* If syntax coloring is enabled, we have to do this because
481
		 * tokens can vary in width */
482
		else
483
		{
484
			Token tokens;
485
			if(painter.currentLineIndex == line
486
				&& painter.currentLineTokens != null)
487
				tokens = painter.currentLineTokens;
488
			else
489
			{
490
				painter.currentLineIndex = line;
491
				tokens = painter.currentLineTokens
492
					= tokenMarker.markTokens(lineSegment,line);
493
			}
494
495
			Toolkit toolkit = painter.getToolkit();
496
			Font defaultFont = painter.getFont();
497
			SyntaxStyle[] styles = painter.getStyles();
498
499
			for(;;)
500
			{
501
				byte id = tokens.id;
502
				if(id == Token.END)
503
				{
504
					return x;
505
				}
506
507
				if(id == Token.NULL)
508
					fm = painter.getFontMetrics();
509
				else
510
					fm = styles[id].getFontMetrics(defaultFont);
511
512
				int length = tokens.length;
513
514
				if(offset + segmentOffset < lineSegment.offset + length)
515
				{
516
					lineSegment.count = offset - (lineSegment.offset - segmentOffset);
517
					return x + Utilities.getTabbedTextWidth(
518
						lineSegment,fm,x,painter,0);
519
				}
520
				else
521
				{
522
					lineSegment.count = length;
523
					x += Utilities.getTabbedTextWidth(
524
						lineSegment,fm,x,painter,0);
525
					lineSegment.offset += length;
526
				}
527
				tokens = tokens.next;
528
			}
529
		}
530
	}
531
532
	/**
533
	 * Converts an x co-ordinate to an offset within a line.
534
	 * @param line The line
535
	 * @param x The x co-ordinate
536
	 */
537
	public int xToOffset(int line, int x)
538
	{
539
		TokenMarker tokenMarker = getTokenMarker();
540
541
		/* Use painter's cached info for speed */
542
		FontMetrics fm = painter.getFontMetrics();
543
544
		getLineText(line,lineSegment);
545
546
		char[] segmentArray = lineSegment.array;
547
		int segmentOffset = lineSegment.offset;
548
		int segmentCount = lineSegment.count;
549
550
		int width = horizontalOffset;
551
552
		if(tokenMarker == null)
553
		{
554
			for(int i = 0; i < segmentCount; i++)
555
			{
556
				char c = segmentArray[i + segmentOffset];
557
				int charWidth;
558
				if(c == '\t')
559
					charWidth = (int)painter.nextTabStop(width,i)
560
						- width;
561
				else
562
					charWidth = fm.charWidth(c);
563
564
				if(painter.isBlockCaretEnabled())
565
				{
566
					if(x - charWidth <= width)
567
						return i;
568
				}
569
				else
570
				{
571
					if(x - charWidth / 2 <= width)
572
						return i;
573
				}
574
575
				width += charWidth;
576
			}
577
578
			return segmentCount;
579
		}
580
		else
581
		{
582
			Token tokens;
583
			if(painter.currentLineIndex == line && painter
584
				.currentLineTokens != null)
585
				tokens = painter.currentLineTokens;
586
			else
587
			{
588
				painter.currentLineIndex = line;
589
				tokens = painter.currentLineTokens
590
					= tokenMarker.markTokens(lineSegment,line);
591
			}
592
593
			int offset = 0;
594
			Toolkit toolkit = painter.getToolkit();
595
			Font defaultFont = painter.getFont();
596
			SyntaxStyle[] styles = painter.getStyles();
597
598
			for(;;)
599
			{
600
				byte id = tokens.id;
601
				if(id == Token.END)
602
					return offset;
603
604
				if(id == Token.NULL)
605
					fm = painter.getFontMetrics();
606
				else
607
					fm = styles[id].getFontMetrics(defaultFont);
608
609
				int length = tokens.length;
610
611
				for(int i = 0; i < length; i++)
612
				{
613
					char c = segmentArray[segmentOffset + offset + i];
614
					int charWidth;
615
					if(c == '\t')
616
						charWidth = (int)painter.nextTabStop(width,offset + i)
617
							- width;
618
					else
619
						charWidth = fm.charWidth(c);
620
621
					if(painter.isBlockCaretEnabled())
622
					{
623
						if(x - charWidth <= width)
624
							return offset + i;
625
					}
626
					else
627
					{
628
						if(x - charWidth / 2 <= width)
629
							return offset + i;
630
					}
631
632
					width += charWidth;
633
				}
634
635
				offset += length;
636
				tokens = tokens.next;
637
			}
638
		}
639
	}
640
641
	/**
642
	 * Converts a point to an offset, from the start of the text.
643
	 * @param x The x co-ordinate of the point
644
	 * @param y The y co-ordinate of the point
645
	 */
646
	public int xyToOffset(int x, int y)
647
	{
648
		int line = yToLine(y);
649
		int start = getLineStartOffset(line);
650
		return start + xToOffset(line,x);
651
	}
652
653
	/**
654
	 * Returns the document this text area is editing.
655
	 */
656
	public final SyntaxDocument getDocument()
657
	{
658
		return document;
659
	}
660
661
	/**
662
	 * Sets the document this text area is editing.
663
	 * @param document The document
664
	 */
665
	public void setDocument(SyntaxDocument document)
666
	{
667
		if(this.document == document)
668
			return;
669
		if(this.document != null)
670
			this.document.removeDocumentListener(documentHandler);
671
		this.document = document;
672
673
		document.addDocumentListener(documentHandler);
674
675
		select(0,0);
676
		updateScrollBars();
677
		painter.repaint();
678
	}
679
680
	/**
681
	 * Returns the document's token marker. Equivalent to calling
682
	 * <code>getDocument().getTokenMarker()</code>.
683
	 */
684
	public final TokenMarker getTokenMarker()
685
	{
686
		return document.getTokenMarker();
687
	}
688
689
	/**
690
	 * Sets the document's token marker. Equivalent to caling
691
	 * <code>getDocument().setTokenMarker()</code>.
692
	 * @param tokenMarker The token marker
693
	 */
694
	public final void setTokenMarker(TokenMarker tokenMarker)
695
	{
696
		document.setTokenMarker(tokenMarker);
697
	}
698
699
	/**
700
	 * Returns the length of the document. Equivalent to calling
701
	 * <code>getDocument().getLength()</code>.
702
	 */
703
	public final int getDocumentLength()
704
	{
705
		return document.getLength();
706
	}
707
708
	/**
709
	 * Returns the number of lines in the document.
710
	 */
711
	public final int getLineCount()
712
	{
713
		return document.getDefaultRootElement().getElementCount();
714
	}
715
716
	/**
717
	 * Returns the line containing the specified offset.
718
	 * @param offset The offset
719
	 */
720
	public final int getLineOfOffset(int offset)
721
	{
722
		return document.getDefaultRootElement().getElementIndex(offset);
723
	}
724
725
	/**
726
	 * Returns the start offset of the specified line.
727
	 * @param line The line
728
	 * @return The start offset of the specified line, or -1 if the line is
729
	 * invalid
730
	 */
731
	public int getLineStartOffset(int line)
732
	{
733
		Element lineElement = document.getDefaultRootElement()
734
			.getElement(line);
735
		if(lineElement == null)
736
			return -1;
737
		else
738
			return lineElement.getStartOffset();
739
	}
740
741
	/**
742
	 * Returns the end offset of the specified line.
743
	 * @param line The line
744
	 * @return The end offset of the specified line, or -1 if the line is
745
	 * invalid.
746
	 */
747
	public int getLineEndOffset(int line)
748
	{
749
		Element lineElement = document.getDefaultRootElement()
750
			.getElement(line);
751
		if(lineElement == null)
752
			return -1;
753
		else
754
			return lineElement.getEndOffset();
755
	}
756
757
	/**
758
	 * Returns the length of the specified line.
759
	 * @param line The line
760
	 */
761
	public int getLineLength(int line)
762
	{
763
		Element lineElement = document.getDefaultRootElement()
764
			.getElement(line);
765
		if(lineElement == null)
766
			return -1;
767
		else
768
			return lineElement.getEndOffset()
769
				- lineElement.getStartOffset() - 1;
770
	}
771
772
	/**
773
	 * Returns the entire text of this text area.
774
	 */
775
	public String getText()
776
	{
777
		try
778
		{
779
			return document.getText(0,document.getLength());
780
		}
781
		catch(BadLocationException bl)
782
		{
783
			bl.printStackTrace();
784
			return null;
785
		}
786
	}
787
788
	/**
789
	 * Sets the entire text of this text area.
790
	 */
791
	public void setText(String text)
792
	{
793
		try
794
		{
795
			document.beginCompoundEdit();
796
			document.remove(0,document.getLength());
797
			document.insertString(0,text,null);
798
		}
799
		catch(BadLocationException bl)
800
		{
801
			bl.printStackTrace();
802
		}
803
		finally
804
		{
805
			document.endCompoundEdit();
806
		}
807
	}
808
809
	/**
810
	 * Returns the specified substring of the document.
811
	 * @param start The start offset
812
	 * @param len The length of the substring
813
	 * @return The substring, or null if the offsets are invalid
814
	 */
815
	public final String getText(int start, int len)
816
	{
817
		try
818
		{
819
			return document.getText(start,len);
820
		}
821
		catch(BadLocationException bl)
822
		{
823
			bl.printStackTrace();
824
			return null;
825
		}
826
	}
827
828
	/**
829
	 * Copies the specified substring of the document into a segment.
830
	 * If the offsets are invalid, the segment will contain a null string.
831
	 * @param start The start offset
832
	 * @param len The length of the substring
833
	 * @param segment The segment
834
	 */
835
	public final void getText(int start, int len, Segment segment)
836
	{
837
		try
838
		{
839
			document.getText(start,len,segment);
840
		}
841
		catch(BadLocationException bl)
842
		{
843
			bl.printStackTrace();
844
			segment.offset = segment.count = 0;
845
		}
846
	}
847
848
	/**
849
	 * Returns the text on the specified line.
850
	 * @param lineIndex The line
851
	 * @return The text, or null if the line is invalid
852
	 */
853
	public final String getLineText(int lineIndex)
854
	{
855
		int start = getLineStartOffset(lineIndex);
856
		return getText(start,getLineEndOffset(lineIndex) - start - 1);
857
	}
858
859
	/**
860
	 * Copies the text on the specified line into a segment. If the line
861
	 * is invalid, the segment will contain a null string.
862
	 * @param lineIndex The line
863
	 */
864
	public final void getLineText(int lineIndex, Segment segment)
865
	{
866
		int start = getLineStartOffset(lineIndex);
867
		getText(start,getLineEndOffset(lineIndex) - start - 1,segment);
868
	}
869
870
	/**
871
	 * Returns the selection start offset.
872
	 */
873
	public final int getSelectionStart()
874
	{
875
		return selectionStart;
876
	}
877
878
	/**
879
	 * Returns the offset where the selection starts on the specified
880
	 * line.
881
	 */
882
	public int getSelectionStart(int line)
883
	{
884
		if(line == selectionStartLine)
885
			return selectionStart;
886
		else if(rectSelect)
887
		{
888
			Element map = document.getDefaultRootElement();
889
			int start = selectionStart - map.getElement(selectionStartLine)
890
				.getStartOffset();
891
892
			Element lineElement = map.getElement(line);
893
			int lineStart = lineElement.getStartOffset();
894
			int lineEnd = lineElement.getEndOffset() - 1;
895
			return Math.min(lineEnd,lineStart + start);
896
		}
897
		else
898
			return getLineStartOffset(line);
899
	}
900
901
	/**
902
	 * Returns the selection start line.
903
	 */
904
	public final int getSelectionStartLine()
905
	{
906
		return selectionStartLine;
907
	}
908
909
	/**
910
	 * Sets the selection start. The new selection will be the new
911
	 * selection start and the old selection end.
912
	 * @param selectionStart The selection start
913
	 * @see #select(int,int)
914
	 */
915
	public final void setSelectionStart(int selectionStart)
916
	{
917
		select(selectionStart,selectionEnd);
918
	}
919
920
	/**
921
	 * Returns the selection end offset.
922
	 */
923
	public final int getSelectionEnd()
924
	{
925
		return selectionEnd;
926
	}
927
928
	/**
929
	 * Returns the offset where the selection ends on the specified
930
	 * line.
931
	 */
932
	public int getSelectionEnd(int line)
933
	{
934
		if(line == selectionEndLine)
935
			return selectionEnd;
936
		else if(rectSelect)
937
		{
938
			Element map = document.getDefaultRootElement();
939
			int end = selectionEnd - map.getElement(selectionEndLine)
940
				.getStartOffset();
941
942
			Element lineElement = map.getElement(line);
943
			int lineStart = lineElement.getStartOffset();
944
			int lineEnd = lineElement.getEndOffset() - 1;
945
			return Math.min(lineEnd,lineStart + end);
946
		}
947
		else
948
			return getLineEndOffset(line) - 1;
949
	}
950
951
	/**
952
	 * Returns the selection end line.
953
	 */
954
	public final int getSelectionEndLine()
955
	{
956
		return selectionEndLine;
957
	}
958
959
	/**
960
	 * Sets the selection end. The new selection will be the old
961
	 * selection start and the bew selection end.
962
	 * @param selectionEnd The selection end
963
	 * @see #select(int,int)
964
	 */
965
	public final void setSelectionEnd(int selectionEnd)
966
	{
967
		select(selectionStart,selectionEnd);
968
	}
969
970
	/**
971
	 * Returns the caret position. This will either be the selection
972
	 * start or the selection end, depending on which direction the
973
	 * selection was made in.
974
	 */
975
	public final int getCaretPosition()
976
	{
977
		return (biasLeft ? selectionStart : selectionEnd);
978
	}
979
980
	/**
981
	 * Returns the caret line.
982
	 */
983
	public final int getCaretLine()
984
	{
985
		return (biasLeft ? selectionStartLine : selectionEndLine);
986
	}
987
988
	/**
989
	 * Returns the mark position. This will be the opposite selection
990
	 * bound to the caret position.
991
	 * @see #getCaretPosition()
992
	 */
993
	public final int getMarkPosition()
994
	{
995
		return (biasLeft ? selectionEnd : selectionStart);
996
	}
997
998
	/**
999
	 * Returns the mark line.
1000
	 */
1001
	public final int getMarkLine()
1002
	{
1003
		return (biasLeft ? selectionEndLine : selectionStartLine);
1004
	}
1005
1006
	/**
1007
	 * Sets the caret position. The new selection will consist of the
1008
	 * caret position only (hence no text will be selected)
1009
	 * @param caret The caret position
1010
	 * @see #select(int,int)
1011
	 */
1012
	public final void setCaretPosition(int caret)
1013
	{
1014
		select(caret,caret);
1015
	}
1016
1017
	/**
1018
	 * Selects all text in the document.
1019
	 */
1020
	public final void selectAll()
1021
	{
1022
		select(0,getDocumentLength());
1023
	}
1024
1025
	/**
1026
	 * Moves the mark to the caret position.
1027
	 */
1028
	public final void selectNone()
1029
	{
1030
		select(getCaretPosition(),getCaretPosition());
1031
	}
1032
1033
	/**
1034
	 * Selects from the start offset to the end offset. This is the
1035
	 * general selection method used by all other selecting methods.
1036
	 * The caret position will be start if start &lt; end, and end
1037
	 * if end &gt; start.
1038
	 * @param start The start offset
1039
	 * @param end The end offset
1040
	 */
1041
	public void select(int start, int end)
1042
	{
1043
		int newStart, newEnd;
1044
		boolean newBias;
1045
		if(start <= end)
1046
		{
1047
			newStart = start;
1048
			newEnd = end;
1049
			newBias = false;
1050
		}
1051
		else
1052
		{
1053
			newStart = end;
1054
			newEnd = start;
1055
			newBias = true;
1056
		}
1057
1058
		if(newStart < 0 || newEnd > getDocumentLength())
1059
		{
1060
			throw new IllegalArgumentException("Bounds out of"
1061
				+ " range: " + newStart + "," +
1062
				newEnd);
1063
		}
1064
1065
		// If the new position is the same as the old, we don't
1066
		// do all this crap, however we still do the stuff at
1067
		// the end (clearing magic position, scrolling)
1068
		if(newStart != selectionStart || newEnd != selectionEnd
1069
			|| newBias != biasLeft)
1070
		{
1071
			int newStartLine = getLineOfOffset(newStart);
1072
			int newEndLine = getLineOfOffset(newEnd);
1073
1074
			if(painter.isBracketHighlightEnabled())
1075
			{
1076
				if(bracketLine != -1)
1077
					painter.invalidateLine(bracketLine);
1078
				updateBracketHighlight(end);
1079
				if(bracketLine != -1)
1080
					painter.invalidateLine(bracketLine);
1081
			}
1082
1083
			painter.invalidateLineRange(selectionStartLine,selectionEndLine);
1084
			painter.invalidateLineRange(newStartLine,newEndLine);
1085
1086
			document.addUndoableEdit(new CaretUndo(
1087
				selectionStart,selectionEnd));
1088
1089
			selectionStart = newStart;
1090
			selectionEnd = newEnd;
1091
			selectionStartLine = newStartLine;
1092
			selectionEndLine = newEndLine;
1093
			biasLeft = newBias;
1094
1095
			fireCaretEvent();
1096
		}
1097
1098
		// When the user is typing, etc, we don't want the caret
1099
		// to blink
1100
		blink = true;
1101
		caretTimer.restart();
1102
1103
		// Disable rectangle select if selection start = selection end
1104
		if(selectionStart == selectionEnd)
1105
			rectSelect = false;
1106
1107
		// Clear the `magic' caret position used by up/down
1108
		magicCaret = -1;
1109
1110
		scrollToCaret();
1111
	}
1112
1113
	/**
1114
	 * Returns the selected text, or null if no selection is active.
1115
	 */
1116
	public final String getSelectedText()
1117
	{
1118
		if(selectionStart == selectionEnd)
1119
			return null;
1120
1121
		if(rectSelect)
1122
		{
1123
			// Return each row of the selection on a new line
1124
1125
			Element map = document.getDefaultRootElement();
1126
1127
			int start = selectionStart - map.getElement(selectionStartLine)
1128
				.getStartOffset();
1129
			int end = selectionEnd - map.getElement(selectionEndLine)
1130
				.getStartOffset();
1131
1132
			// Certain rectangles satisfy this condition...
1133
			if(end < start)
1134
			{
1135
				int tmp = end;
1136
				end = start;
1137
				start = tmp;
1138
			}
1139
1140
			StringBuffer buf = new StringBuffer();
1141
			Segment seg = new Segment();
1142
1143
			for(int i = selectionStartLine; i <= selectionEndLine; i++)
1144
			{
1145
				Element lineElement = map.getElement(i);
1146
				int lineStart = lineElement.getStartOffset();
1147
				int lineEnd = lineElement.getEndOffset() - 1;
1148
				int lineLen = lineEnd - lineStart;
1149
1150
				lineStart = Math.min(lineStart + start,lineEnd);
1151
				lineLen = Math.min(end - start,lineEnd - lineStart);
1152
1153
				getText(lineStart,lineLen,seg);
1154
				buf.append(seg.array,seg.offset,seg.count);
1155
1156
				if(i != selectionEndLine)
1157
					buf.append('\n');
1158
			}
1159
1160
			return buf.toString();
1161
		}
1162
		else
1163
		{
1164
			return getText(selectionStart,
1165
				selectionEnd - selectionStart);
1166
		}
1167
	}
1168
1169
	/**
1170
	 * Replaces the selection with the specified text.
1171
	 * @param selectedText The replacement text for the selection
1172
	 */
1173
	public void setSelectedText(String selectedText)
1174
	{
1175
		if(!editable)
1176
		{
1177
			throw new InternalError("Text component"
1178
				+ " read only");
1179
		}
1180
1181
		document.beginCompoundEdit();
1182
1183
		try
1184
		{
1185
			if(rectSelect)
1186
			{
1187
				Element map = document.getDefaultRootElement();
1188
1189
				int start = selectionStart - map.getElement(selectionStartLine)
1190
					.getStartOffset();
1191
				int end = selectionEnd - map.getElement(selectionEndLine)
1192
					.getStartOffset();
1193
1194
				// Certain rectangles satisfy this condition...
1195
				if(end < start)
1196
				{
1197
					int tmp = end;
1198
					end = start;
1199
					start = tmp;
1200
				}
1201
1202
				int lastNewline = 0;
1203
				int currNewline = 0;
1204
1205
				for(int i = selectionStartLine; i <= selectionEndLine; i++)
1206
				{
1207
					Element lineElement = map.getElement(i);
1208
					int lineStart = lineElement.getStartOffset();
1209
					int lineEnd = lineElement.getEndOffset() - 1;
1210
					int rectStart = Math.min(lineEnd,lineStart + start);
1211
1212
					document.remove(rectStart,Math.min(lineEnd - rectStart,
1213
						end - start));
1214
1215
					if(selectedText == null)
1216
						continue;
1217
1218
					currNewline = selectedText.indexOf('\n',lastNewline);
1219
					if(currNewline == -1)
1220
						currNewline = selectedText.length();
1221
1222
					document.insertString(rectStart,selectedText
1223
						.substring(lastNewline,currNewline),null);
1224
1225
					lastNewline = Math.min(selectedText.length(),
1226
						currNewline + 1);
1227
				}
1228
1229
				if(selectedText != null &&
1230
					currNewline != selectedText.length())
1231
				{
1232
					int offset = map.getElement(selectionEndLine)
1233
						.getEndOffset() - 1;
1234
					document.insertString(offset,"\n",null);
1235
					document.insertString(offset + 1,selectedText
1236
						.substring(currNewline + 1),null);
1237
				}
1238
			}
1239
			else
1240
			{
1241
				document.remove(selectionStart,
1242
					selectionEnd - selectionStart);
1243
				if(selectedText != null)
1244
				{
1245
					document.insertString(selectionStart,
1246
						selectedText,null);
1247
				}
1248
			}
1249
		}
1250
		catch(BadLocationException bl)
1251
		{
1252
			bl.printStackTrace();
1253
			throw new InternalError("Cannot replace"
1254
				+ " selection");
1255
		}
1256
		// No matter what happends... stops us from leaving document
1257
		// in a bad state
1258
		finally
1259
		{
1260
			document.endCompoundEdit();
1261
		}
1262
1263
		setCaretPosition(selectionEnd);
1264
	}
1265
1266
	/**
1267
	 * Returns true if this text area is editable, false otherwise.
1268
	 */
1269
	public final boolean isEditable()
1270
	{
1271
		return editable;
1272
	}
1273
1274
	/**
1275
	 * Sets if this component is editable.
1276
	 * @param editable True if this text area should be editable,
1277
	 * false otherwise
1278
	 */
1279
	public final void setEditable(boolean editable)
1280
	{
1281
		this.editable = editable;
1282
	}
1283
1284
	/**
1285
	 * Returns the right click popup menu.
1286
	 */
1287
	public final JPopupMenu getRightClickPopup()
1288
	{
1289
		return popup;
1290
	}
1291
1292
	/**
1293
	 * Sets the right click popup menu.
1294
	 * @param popup The popup
1295
	 */
1296
	public final void setRightClickPopup(JPopupMenu popup)
1297
	{
1298
		this.popup = popup;
1299
	}
1300
1301
	/**
1302
	 * Returns the `magic' caret position. This can be used to preserve
1303
	 * the column position when moving up and down lines.
1304
	 */
1305
	public final int getMagicCaretPosition()
1306
	{
1307
		return magicCaret;
1308
	}
1309
1310
	/**
1311
	 * Sets the `magic' caret position. This can be used to preserve
1312
	 * the column position when moving up and down lines.
1313
	 * @param magicCaret The magic caret position
1314
	 */
1315
	public final void setMagicCaretPosition(int magicCaret)
1316
	{
1317
		this.magicCaret = magicCaret;
1318
	}
1319
1320
	/**
1321
	 * Similar to <code>setSelectedText()</code>, but overstrikes the
1322
	 * appropriate number of characters if overwrite mode is enabled.
1323
	 * @param str The string
1324
	 * @see #setSelectedText(String)
1325
	 * @see #isOverwriteEnabled()
1326
	 */
1327
	public void overwriteSetSelectedText(String str)
1328
	{
1329
		// Don't overstrike if there is a selection
1330
		if(!overwrite || selectionStart != selectionEnd)
1331
		{
1332
			setSelectedText(str);
1333
			return;
1334
		}
1335
1336
		// Don't overstrike if we're on the end of
1337
		// the line
1338
		int caret = getCaretPosition();
1339
		int caretLineEnd = getLineEndOffset(getCaretLine());
1340
		if(caretLineEnd - caret <= str.length())
1341
		{
1342
			setSelectedText(str);
1343
			return;
1344
		}
1345
1346
		document.beginCompoundEdit();
1347
1348
		try
1349
		{
1350
			document.remove(caret,str.length());
1351
			document.insertString(caret,str,null);
1352
		}
1353
		catch(BadLocationException bl)
1354
		{
1355
			bl.printStackTrace();
1356
		}
1357
		finally
1358
		{
1359
			document.endCompoundEdit();
1360
		}
1361
	}
1362
1363
	/**
1364
	 * Returns true if overwrite mode is enabled, false otherwise.
1365
	 */
1366
	public final boolean isOverwriteEnabled()
1367
	{
1368
		return overwrite;
1369
	}
1370
1371
	/**
1372
	 * Sets if overwrite mode should be enabled.
1373
	 * @param overwrite True if overwrite mode should be enabled,
1374
	 * false otherwise.
1375
	 */
1376
	public final void setOverwriteEnabled(boolean overwrite)
1377
	{
1378
		this.overwrite = overwrite;
1379
		painter.invalidateSelectedLines();
1380
	}
1381
1382
	/**
1383
	 * Returns true if the selection is rectangular, false otherwise.
1384
	 */
1385
	public final boolean isSelectionRectangular()
1386
	{
1387
		return rectSelect;
1388
	}
1389
1390
	/**
1391
	 * Sets if the selection should be rectangular.
1392
	 * @param overwrite True if the selection should be rectangular,
1393
	 * false otherwise.
1394
	 */
1395
	public final void setSelectionRectangular(boolean rectSelect)
1396
	{
1397
		this.rectSelect = rectSelect;
1398
		painter.invalidateSelectedLines();
1399
	}
1400
1401
	/**
1402
	 * Returns the position of the highlighted bracket (the bracket
1403
	 * matching the one before the caret)
1404
	 */
1405
	public final int getBracketPosition()
1406
	{
1407
		return bracketPosition;
1408
	}
1409
1410
	/**
1411
	 * Returns the line of the highlighted bracket (the bracket
1412
	 * matching the one before the caret)
1413
	 */
1414
	public final int getBracketLine()
1415
	{
1416
		return bracketLine;
1417
	}
1418
1419
	/**
1420
	 * Adds a caret change listener to this text area.
1421
	 * @param listener The listener
1422
	 */
1423
	public final void addCaretListener(CaretListener listener)
1424
	{
1425
		listenerList.add(CaretListener.class,listener);
1426
	}
1427
1428
	/**
1429
	 * Removes a caret change listener from this text area.
1430
	 * @param listener The listener
1431
	 */
1432
	public final void removeCaretListener(CaretListener listener)
1433
	{
1434
		listenerList.remove(CaretListener.class,listener);
1435
	}
1436
1437
	/**
1438
	 * Deletes the selected text from the text area and places it
1439
	 * into the clipboard.
1440
	 */
1441
	public void cut()
1442
	{
1443
		if(editable)
1444
		{
1445
			copy();
1446
			setSelectedText("");
1447
		}
1448
	}
1449
1450
	/**
1451
	 * Places the selected text into the clipboard.
1452
	 */
1453
	public void copy()
1454
	{
1455
		if(selectionStart != selectionEnd)
1456
		{
1457
			Clipboard clipboard = getToolkit().getSystemClipboard();
1458
1459
			String selection = getSelectedText();
1460
1461
			int repeatCount = inputHandler.getRepeatCount();
1462
			StringBuffer buf = new StringBuffer();
1463
			for(int i = 0; i < repeatCount; i++)
1464
				buf.append(selection);
1465
1466
			clipboard.setContents(new StringSelection(buf.toString()),null);
1467
		}
1468
	}
1469
1470
	/**
1471
	 * Inserts the clipboard contents into the text.
1472
	 */
1473
	public void paste()
1474
	{
1475
		if(editable)
1476
		{
1477
			Clipboard clipboard = getToolkit().getSystemClipboard();
1478
			try
1479
			{
1480
				// The MacOS MRJ doesn't convert \r to \n,
1481
				// so do it here
1482
				String selection = ((String)clipboard
1483
					.getContents(this).getTransferData(
1484
					DataFlavor.stringFlavor))
1485
					.replace('\r','\n');
1486
1487
				int repeatCount = inputHandler.getRepeatCount();
1488
				StringBuffer buf = new StringBuffer();
1489
				for(int i = 0; i < repeatCount; i++)
1490
					buf.append(selection);
1491
				selection = buf.toString();
1492
				setSelectedText(selection);
1493
			}
1494
			catch(Exception e)
1495
			{
1496
				getToolkit().beep();
1497
				System.err.println("Clipboard does not"
1498
					+ " contain a string");
1499
			}
1500
		}
1501
	}
1502
1503
	/**
1504
	 * Called by the AWT when this component is removed from it's parent.
1505
	 * This stops clears the currently focused component.
1506
	 */
1507
	public void removeNotify()
1508
	{
1509
		super.removeNotify();
1510
		if(focusedComponent == this)
1511
			focusedComponent = null;
1512
	}
1513
1514
	/**
1515
	 * Forwards key events directly to the input handler.
1516
	 * This is slightly faster than using a KeyListener
1517
	 * because some Swing overhead is avoided.
1518
	 */
1519
	public void processKeyEvent(KeyEvent evt)
1520
	{
1521
		if(inputHandler == null)
1522
			return;
1523
		switch(evt.getID())
1524
		{
1525
		case KeyEvent.KEY_TYPED:
1526
			inputHandler.keyTyped(evt);
1527
			break;
1528
		case KeyEvent.KEY_PRESSED:
1529
			inputHandler.keyPressed(evt);
1530
			break;
1531
		case KeyEvent.KEY_RELEASED:
1532
			inputHandler.keyReleased(evt);
1533
			break;
1534
		}
1535
	}
1536
1537
	// protected members
1538
	protected static String CENTER = "center";
1539
	protected static String RIGHT = "right";
1540
	protected static String BOTTOM = "bottom";
1541
1542
	protected static JEditTextArea focusedComponent;
1543
	protected static Timer caretTimer;
1544
	
1545
	protected TextAreaPainter painter;
1546
1547
	protected JPopupMenu popup;
1548
1549
	protected EventListenerList listenerList;
1550
	protected MutableCaretEvent caretEvent;
1551
1552
	protected boolean caretBlinks;
1553
	protected boolean caretVisible;
1554
	protected boolean blink;
1555
1556
	protected boolean editable;
1557
1558
	protected int firstLine;
1559
	protected int visibleLines;
1560
	protected int electricScroll;
1561
1562
	protected int horizontalOffset;
1563
	
1564
	protected JScrollBar vertical;
1565
	protected JScrollBar horizontal;
1566
	protected boolean scrollBarsInitialized;
1567
1568
	protected InputHandler inputHandler;
1569
	protected SyntaxDocument document;
1570
	protected DocumentHandler documentHandler;
1571
1572
	protected Segment lineSegment;
1573
1574
	protected int selectionStart;
1575
	protected int selectionStartLine;
1576
	protected int selectionEnd;
1577
	protected int selectionEndLine;
1578
	protected boolean biasLeft;
1579
1580
	protected int bracketPosition;
1581
	protected int bracketLine;
1582
1583
	protected int magicCaret;
1584
	protected boolean overwrite;
1585
	protected boolean rectSelect;
1586
1587
	protected void fireCaretEvent()
1588
	{
1589
		Object[] listeners = listenerList.getListenerList();
1590
		for(int i = listeners.length - 2; i >= 0; i--)
1591
		{
1592
			if(listeners[i] == CaretListener.class)
1593
			{
1594
				((CaretListener)listeners[i+1]).caretUpdate(caretEvent);
1595
			}
1596
		}
1597
	}
1598
1599
	protected void updateBracketHighlight(int newCaretPosition)
1600
	{
1601
		if(newCaretPosition == 0)
1602
		{
1603
			bracketPosition = bracketLine = -1;
1604
			return;
1605
		}
1606
1607
		try
1608
		{
1609
			int offset = TextUtilities.findMatchingBracket(
1610
				document,newCaretPosition - 1);
1611
			if(offset != -1)
1612
			{
1613
				bracketLine = getLineOfOffset(offset);
1614
				bracketPosition = offset - getLineStartOffset(bracketLine);
1615
				return;
1616
			}
1617
		}
1618
		catch(BadLocationException bl)
1619
		{
1620
			bl.printStackTrace();
1621
		}
1622
1623
		bracketLine = bracketPosition = -1;
1624
	}
1625
1626
	protected void documentChanged(DocumentEvent evt)
1627
	{
1628
		DocumentEvent.ElementChange ch = evt.getChange(
1629
			document.getDefaultRootElement());
1630
1631
		int count;
1632
		if(ch == null)
1633
			count = 0;
1634
		else
1635
			count = ch.getChildrenAdded().length -
1636
				ch.getChildrenRemoved().length;
1637
1638
		int line = getLineOfOffset(evt.getOffset());
1639
		if(count == 0)
1640
		{
1641
			painter.invalidateLine(line);
1642
		}
1643
		// do magic stuff
1644
		else if(line < firstLine)
1645
		{
1646
			setFirstLine(firstLine + count);
1647
		}
1648
		// end of magic stuff
1649
		else
1650
		{
1651
			painter.invalidateLineRange(line,firstLine + visibleLines);
1652
			updateScrollBars();
1653
		}
1654
	}
1655
1656
	class ScrollLayout implements LayoutManager
1657
	{
1658
		public void addLayoutComponent(String name, Component comp)
1659
		{
1660
			if(name.equals(CENTER))
1661
				center = comp;
1662
			else if(name.equals(RIGHT))
1663
				right = comp;
1664
			else if(name.equals(BOTTOM))
1665
				bottom = comp;
1666
			else if(name.equals(LEFT_OF_SCROLLBAR))
1667
				leftOfScrollBar.addElement(comp);
1668
		}
1669
1670
		public void removeLayoutComponent(Component comp)
1671
		{
1672
			if(center == comp)
1673
				center = null;
1674
			if(right == comp)
1675
				right = null;
1676
			if(bottom == comp)
1677
				bottom = null;
1678
			else
1679
				leftOfScrollBar.removeElement(comp);
1680
		}
1681
1682
		public Dimension preferredLayoutSize(Container parent)
1683
		{
1684
			Dimension dim = new Dimension();
1685
			Insets insets = getInsets();
1686
			dim.width = insets.left + insets.right;
1687
			dim.height = insets.top + insets.bottom;
1688
1689
			Dimension centerPref = center.getPreferredSize();
1690
			dim.width += centerPref.width;
1691
			dim.height += centerPref.height;
1692
			Dimension rightPref = right.getPreferredSize();
1693
			dim.width += rightPref.width;
1694
			Dimension bottomPref = bottom.getPreferredSize();
1695
			dim.height += bottomPref.height;
1696
1697
			return dim;
1698
		}
1699
1700
		public Dimension minimumLayoutSize(Container parent)
1701
		{
1702
			Dimension dim = new Dimension();
1703
			Insets insets = getInsets();
1704
			dim.width = insets.left + insets.right;
1705
			dim.height = insets.top + insets.bottom;
1706
1707
			Dimension centerPref = center.getMinimumSize();
1708
			dim.width += centerPref.width; 
1709
			dim.height += centerPref.height;
1710
			Dimension rightPref = right.getMinimumSize();
1711
			dim.width += rightPref.width;
1712
			Dimension bottomPref = bottom.getMinimumSize();
1713
			dim.height += bottomPref.height;
1714
1715
			return dim;
1716
		}
1717
1718
		public void layoutContainer(Container parent)
1719
		{
1720
			Dimension size = parent.getSize();
1721
			Insets insets = parent.getInsets();
1722
			int itop = insets.top;
1723
			int ileft = insets.left;
1724
			int ibottom = insets.bottom;
1725
			int iright = insets.right;
1726
1727
			int rightWidth = right.getPreferredSize().width;
1728
			int bottomHeight = bottom.getPreferredSize().height;
1729
			int centerWidth = size.width - rightWidth - ileft - iright;
1730
			int centerHeight = size.height - bottomHeight - itop - ibottom;
1731
1732
			center.setBounds(
1733
				ileft,
1734
				itop,
1735
				centerWidth,
1736
				centerHeight);
1737
1738
			right.setBounds(
1739
				ileft + centerWidth,
1740
				itop,
1741
				rightWidth,
1742
				centerHeight);
1743
1744
			// Lay out all status components, in order
1745
			Enumeration status = leftOfScrollBar.elements();
1746
			while(status.hasMoreElements())
1747
			{
1748
				Component comp = (Component)status.nextElement();
1749
				Dimension dim = comp.getPreferredSize();
1750
				comp.setBounds(ileft,
1751
					itop + centerHeight,
1752
					dim.width,
1753
					bottomHeight);
1754
				ileft += dim.width;
1755
			}
1756
1757
			bottom.setBounds(
1758
				ileft,
1759
				itop + centerHeight,
1760
				size.width - rightWidth - ileft - iright,
1761
				bottomHeight);
1762
		}
1763
1764
		// private members
1765
		private Component center;
1766
		private Component right;
1767
		private Component bottom;
1768
		private Vector leftOfScrollBar = new Vector();
1769
	}
1770
1771
	static class CaretBlinker implements ActionListener
1772
	{
1773
		public void actionPerformed(ActionEvent evt)
1774
		{
1775
			if(focusedComponent != null
1776
				&& focusedComponent.hasFocus())
1777
				focusedComponent.blinkCaret();
1778
		}
1779
	}
1780
1781
	class MutableCaretEvent extends CaretEvent
1782
	{
1783
		MutableCaretEvent()
1784
		{
1785
			super(JEditTextArea.this);
1786
		}
1787
1788
		public int getDot()
1789
		{
1790
			return getCaretPosition();
1791
		}
1792
1793
		public int getMark()
1794
		{
1795
			return getMarkPosition();
1796
		}
1797
	}
1798
1799
	class AdjustHandler implements AdjustmentListener
1800
	{
1801
		public void adjustmentValueChanged(final AdjustmentEvent evt)
1802
		{
1803
			if(!scrollBarsInitialized)
1804
				return;
1805
1806
			// If this is not done, mousePressed events accumilate
1807
			// and the result is that scrolling doesn't stop after
1808
			// the mouse is released
1809
			SwingUtilities.invokeLater(new Runnable() {
1810
				public void run()
1811
				{
1812
					if(evt.getAdjustable() == vertical)
1813
						setFirstLine(vertical.getValue());
1814
					else
1815
						setHorizontalOffset(-horizontal.getValue());
1816
				}
1817
			});
1818
		}
1819
	}
1820
1821
	class ComponentHandler extends ComponentAdapter
1822
	{
1823
		public void componentResized(ComponentEvent evt)
1824
		{
1825
			recalculateVisibleLines();
1826
			scrollBarsInitialized = true;
1827
		}
1828
	}
1829
1830
	class DocumentHandler implements DocumentListener
1831
	{
1832
		public void insertUpdate(DocumentEvent evt)
1833
		{
1834
			documentChanged(evt);
1835
1836
			int offset = evt.getOffset();
1837
			int length = evt.getLength();
1838
1839
			int newStart;
1840
			int newEnd;
1841
1842
			if(selectionStart > offset || (selectionStart 
1843
				== selectionEnd && selectionStart == offset))
1844
				newStart = selectionStart + length;
1845
			else
1846
				newStart = selectionStart;
1847
1848
			if(selectionEnd >= offset)
1849
				newEnd = selectionEnd + length;
1850
			else
1851
				newEnd = selectionEnd;
1852
1853
			select(newStart,newEnd);
1854
		}
1855
	
1856
		public void removeUpdate(DocumentEvent evt)
1857
		{
1858
			documentChanged(evt);
1859
1860
			int offset = evt.getOffset();
1861
			int length = evt.getLength();
1862
1863
			int newStart;
1864
			int newEnd;
1865
1866
			if(selectionStart > offset)
1867
			{
1868
				if(selectionStart > offset + length)
1869
					newStart = selectionStart - length;
1870
				else
1871
					newStart = offset;
1872
			}
1873
			else
1874
				newStart = selectionStart;
1875
1876
			if(selectionEnd > offset)
1877
			{
1878
				if(selectionEnd > offset + length)
1879
					newEnd = selectionEnd - length;
1880
				else
1881
					newEnd = offset;
1882
			}
1883
			else
1884
				newEnd = selectionEnd;
1885
1886
			select(newStart,newEnd);
1887
		}
1888
1889
		public void changedUpdate(DocumentEvent evt)
1890
		{
1891
		}
1892
	}
1893
1894
	class DragHandler implements MouseMotionListener
1895
	{
1896
		public void mouseDragged(MouseEvent evt)
1897
		{
1898
			if(popup != null && popup.isVisible())
1899
				return;
1900
1901
			setSelectionRectangular((evt.getModifiers()
1902
				& InputEvent.CTRL_MASK) != 0);
1903
			select(getMarkPosition(),xyToOffset(evt.getX(),evt.getY()));
1904
		}
1905
1906
		public void mouseMoved(MouseEvent evt) {}
1907
	}
1908
1909
	class FocusHandler implements FocusListener
1910
	{
1911
		public void focusGained(FocusEvent evt)
1912
		{
1913
			setCaretVisible(true);
1914
			focusedComponent = JEditTextArea.this;
1915
		}
1916
1917
		public void focusLost(FocusEvent evt)
1918
		{
1919
			setCaretVisible(false);
1920
			focusedComponent = null;
1921
		}
1922
	}
1923
1924
	class MouseHandler extends MouseAdapter
1925
	{
1926
		public void mousePressed(MouseEvent evt)
1927
		{
1928
			requestFocus();
1929
1930
			// Focus events not fired sometimes?
1931
			setCaretVisible(true);
1932
			focusedComponent = JEditTextArea.this;
1933
1934
			if((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0
1935
				&& popup != null)
1936
			{
1937
				popup.show(painter,evt.getX(),evt.getY());
1938
				return;
1939
			}
1940
1941
			int line = yToLine(evt.getY());
1942
			int offset = xToOffset(line,evt.getX());
1943
			int dot = getLineStartOffset(line) + offset;
1944
1945
			switch(evt.getClickCount())
1946
			{
1947
			case 1:
1948
				doSingleClick(evt,line,offset,dot);
1949
				break;
1950
			case 2:
1951
				// It uses the bracket matching stuff, so
1952
				// it can throw a BLE
1953
				try
1954
				{
1955
					doDoubleClick(evt,line,offset,dot);
1956
				}
1957
				catch(BadLocationException bl)
1958
				{
1959
					bl.printStackTrace();
1960
				}
1961
				break;
1962
			case 3:
1963
				doTripleClick(evt,line,offset,dot);
1964
				break;
1965
			}
1966
		}
1967
1968
		private void doSingleClick(MouseEvent evt, int line, 
1969
			int offset, int dot)
1970
		{
1971
			if((evt.getModifiers() & InputEvent.SHIFT_MASK) != 0)
1972
			{
1973
				rectSelect = (evt.getModifiers() & InputEvent.CTRL_MASK) != 0;
1974
				select(getMarkPosition(),dot);
1975
			}
1976
			else
1977
				setCaretPosition(dot);
1978
		}
1979
1980
		private void doDoubleClick(MouseEvent evt, int line,
1981
			int offset, int dot) throws BadLocationException
1982
		{
1983
			// Ignore empty lines
1984
			if(getLineLength(line) == 0)
1985
				return;
1986
1987
			try
1988
			{
1989
				int bracket = TextUtilities.findMatchingBracket(
1990
					document,Math.max(0,dot - 1));
1991
				if(bracket != -1)
1992
				{
1993
					int mark = getMarkPosition();
1994
					// Hack
1995
					if(bracket > mark)
1996
					{
1997
						bracket++;
1998
						mark--;
1999
					}
2000
					select(mark,bracket);
2001
					return;
2002
				}
2003
			}
2004
			catch(BadLocationException bl)
2005
			{
2006
				bl.printStackTrace();
2007
			}
2008
2009
			// Ok, it's not a bracket... select the word
2010
			String lineText = getLineText(line);
2011
			char ch = lineText.charAt(Math.max(0,offset - 1));
2012
2013
			String noWordSep = (String)document.getProperty("noWordSep");
2014
			if(noWordSep == null)
2015
				noWordSep = "";
2016
2017
			// If the user clicked on a non-letter char,
2018
			// we select the surrounding non-letters
2019
			boolean selectNoLetter = (!Character
2020
				.isLetterOrDigit(ch)
2021
				&& noWordSep.indexOf(ch) == -1);
2022
2023
			int wordStart = 0;
2024
2025
			for(int i = offset - 1; i >= 0; i--)
2026
			{
2027
				ch = lineText.charAt(i);
2028
				if(selectNoLetter ^ (!Character
2029
					.isLetterOrDigit(ch) &&
2030
					noWordSep.indexOf(ch) == -1))
2031
				{
2032
					wordStart = i + 1;
2033
					break;
2034
				}
2035
			}
2036
2037
			int wordEnd = lineText.length();
2038
			for(int i = offset; i < lineText.length(); i++)
2039
			{
2040
				ch = lineText.charAt(i);
2041
				if(selectNoLetter ^ (!Character
2042
					.isLetterOrDigit(ch) &&
2043
					noWordSep.indexOf(ch) == -1))
2044
				{
2045
					wordEnd = i;
2046
					break;
2047
				}
2048
			}
2049
2050
			int lineStart = getLineStartOffset(line);
2051
			select(lineStart + wordStart,lineStart + wordEnd);
2052
2053
			/*
2054
			String lineText = getLineText(line);
2055
			String noWordSep = (String)document.getProperty("noWordSep");
2056
			int wordStart = TextUtilities.findWordStart(lineText,offset,noWordSep);
2057
			int wordEnd = TextUtilities.findWordEnd(lineText,offset,noWordSep);
2058
2059
			int lineStart = getLineStartOffset(line);
2060
			select(lineStart + wordStart,lineStart + wordEnd);
2061
			*/
2062
		}
2063
2064
		private void doTripleClick(MouseEvent evt, int line,
2065
			int offset, int dot)
2066
		{
2067
			select(getLineStartOffset(line),getLineEndOffset(line)-1);
2068
		}
2069
	}
2070
2071
	class CaretUndo extends AbstractUndoableEdit
2072
	{
2073
		private int start;
2074
		private int end;
2075
2076
		CaretUndo(int start, int end)
2077
		{
2078
			this.start = start;
2079
			this.end = end;
2080
		}
2081
2082
		public boolean isSignificant()
2083
		{
2084
			return false;
2085
		}
2086
2087
		public String getPresentationName()
2088
		{
2089
			return "caret move";
2090
		}
2091
2092
		public void undo() throws CannotUndoException
2093
		{
2094
			super.undo();
2095
2096
			select(start,end);
2097
		}
2098
2099
		public void redo() throws CannotRedoException
2100
		{
2101
			super.redo();
2102
2103
			select(start,end);
2104
		}
2105
2106
		public boolean addEdit(UndoableEdit edit)
2107
		{
2108
			if(edit instanceof CaretUndo)
2109
			{
2110
				CaretUndo cedit = (CaretUndo)edit;
2111
				start = cedit.start;
2112
				end = cedit.end;
2113
				cedit.die();
2114
2115
				return true;
2116
			}
2117
			else
2118
				return false;
2119
		}
2120
	}
2121
2122
	static
2123
	{
2124
		caretTimer = new Timer(500,new CaretBlinker());
2125
		caretTimer.setInitialDelay(500);
2126
		caretTimer.start();
2127
	}
2128
}
(-)sources/org/apache/batik/apps/svgbrowser/srcview/InputHandler.java (+1070 lines)
Line 0 Link Here
1
/*
2
 * InputHandler.java - Manages key bindings and executes actions
3
 * Copyright (C) 1999 Slava Pestov
4
 *
5
 * You may use and modify this package for any purpose. Redistribution is
6
 * permitted, in both source and binary form, provided that this notice
7
 * remains intact in all source distributions of this package.
8
 */
9
package org.apache.batik.apps.svgbrowser.srcview;
10
11
import javax.swing.text.*;
12
import javax.swing.JPopupMenu;
13
import java.awt.event.*;
14
import java.awt.Component;
15
import java.util.*;
16
17
/**
18
 * An input handler converts the user's key strokes into concrete actions.
19
 * It also takes care of macro recording and action repetition.<p>
20
 *
21
 * This class provides all the necessary support code for an input
22
 * handler, but doesn't actually do any key binding logic. It is up
23
 * to the implementations of this class to do so.
24
 *
25
 * @author Slava Pestov
26
 * @version $Id: InputHandler.java,v 1.14 1999/12/13 03:40:30 sp Exp $
27
 * @see org.gjt.sp.jedit.textarea.DefaultInputHandler
28
 */
29
public abstract class InputHandler extends KeyAdapter
30
{
31
	/**
32
	 * If this client property is set to Boolean.TRUE on the text area,
33
	 * the home/end keys will support 'smart' BRIEF-like behaviour
34
	 * (one press = start/end of line, two presses = start/end of
35
	 * viewscreen, three presses = start/end of document). By default,
36
	 * this property is not set.
37
	 */
38
	public static final String SMART_HOME_END_PROPERTY = "InputHandler.homeEnd";
39
40
	public static final ActionListener BACKSPACE = new backspace();
41
	public static final ActionListener BACKSPACE_WORD = new backspace_word();
42
	public static final ActionListener DELETE = new delete();
43
	public static final ActionListener DELETE_WORD = new delete_word();
44
	public static final ActionListener END = new end(false);
45
	public static final ActionListener DOCUMENT_END = new document_end(false);
46
	public static final ActionListener SELECT_END = new end(true);
47
	public static final ActionListener SELECT_DOC_END = new document_end(true);
48
	public static final ActionListener INSERT_BREAK = new insert_break();
49
	public static final ActionListener INSERT_TAB = new insert_tab();
50
	public static final ActionListener HOME = new home(false);
51
	public static final ActionListener DOCUMENT_HOME = new document_home(false);
52
	public static final ActionListener SELECT_HOME = new home(true);
53
	public static final ActionListener SELECT_DOC_HOME = new document_home(true);
54
	public static final ActionListener NEXT_CHAR = new next_char(false);
55
	public static final ActionListener NEXT_LINE = new next_line(false);
56
	public static final ActionListener NEXT_PAGE = new next_page(false);
57
	public static final ActionListener NEXT_WORD = new next_word(false);
58
	public static final ActionListener SELECT_NEXT_CHAR = new next_char(true);
59
	public static final ActionListener SELECT_NEXT_LINE = new next_line(true);
60
	public static final ActionListener SELECT_NEXT_PAGE = new next_page(true);
61
	public static final ActionListener SELECT_NEXT_WORD = new next_word(true);
62
	public static final ActionListener OVERWRITE = new overwrite();
63
	public static final ActionListener PREV_CHAR = new prev_char(false);
64
	public static final ActionListener PREV_LINE = new prev_line(false);
65
	public static final ActionListener PREV_PAGE = new prev_page(false);
66
	public static final ActionListener PREV_WORD = new prev_word(false);
67
	public static final ActionListener SELECT_PREV_CHAR = new prev_char(true);
68
	public static final ActionListener SELECT_PREV_LINE = new prev_line(true);
69
	public static final ActionListener SELECT_PREV_PAGE = new prev_page(true);
70
	public static final ActionListener SELECT_PREV_WORD = new prev_word(true);
71
	public static final ActionListener REPEAT = new repeat();
72
	public static final ActionListener TOGGLE_RECT = new toggle_rect();
73
74
	// Default action
75
	public static final ActionListener INSERT_CHAR = new insert_char();
76
77
	private static Hashtable actions;
78
79
	static
80
	{
81
		actions = new Hashtable();
82
		actions.put("backspace",BACKSPACE);
83
		actions.put("backspace-word",BACKSPACE_WORD);
84
		actions.put("delete",DELETE);
85
		actions.put("delete-word",DELETE_WORD);
86
		actions.put("end",END);
87
		actions.put("select-end",SELECT_END);
88
		actions.put("document-end",DOCUMENT_END);
89
		actions.put("select-doc-end",SELECT_DOC_END);
90
		actions.put("insert-break",INSERT_BREAK);
91
		actions.put("insert-tab",INSERT_TAB);
92
		actions.put("home",HOME);
93
		actions.put("select-home",SELECT_HOME);
94
		actions.put("document-home",DOCUMENT_HOME);
95
		actions.put("select-doc-home",SELECT_DOC_HOME);
96
		actions.put("next-char",NEXT_CHAR);
97
		actions.put("next-line",NEXT_LINE);
98
		actions.put("next-page",NEXT_PAGE);
99
		actions.put("next-word",NEXT_WORD);
100
		actions.put("select-next-char",SELECT_NEXT_CHAR);
101
		actions.put("select-next-line",SELECT_NEXT_LINE);
102
		actions.put("select-next-page",SELECT_NEXT_PAGE);
103
		actions.put("select-next-word",SELECT_NEXT_WORD);
104
		actions.put("overwrite",OVERWRITE);
105
		actions.put("prev-char",PREV_CHAR);
106
		actions.put("prev-line",PREV_LINE);
107
		actions.put("prev-page",PREV_PAGE);
108
		actions.put("prev-word",PREV_WORD);
109
		actions.put("select-prev-char",SELECT_PREV_CHAR);
110
		actions.put("select-prev-line",SELECT_PREV_LINE);
111
		actions.put("select-prev-page",SELECT_PREV_PAGE);
112
		actions.put("select-prev-word",SELECT_PREV_WORD);
113
		actions.put("repeat",REPEAT);
114
		actions.put("toggle-rect",TOGGLE_RECT);
115
		actions.put("insert-char",INSERT_CHAR);
116
	}
117
118
	/**
119
	 * Returns a named text area action.
120
	 * @param name The action name
121
	 */
122
	public static ActionListener getAction(String name)
123
	{
124
		return (ActionListener)actions.get(name);
125
	}
126
127
	/**
128
	 * Returns the name of the specified text area action.
129
	 * @param listener The action
130
	 */
131
	public static String getActionName(ActionListener listener)
132
	{
133
		Enumeration e = getActions();
134
		while(e.hasMoreElements())
135
		{
136
			String name = (String)e.nextElement();
137
			ActionListener _listener = getAction(name);
138
			if(_listener == listener)
139
				return name;
140
		}
141
		return null;
142
	}
143
144
	/**
145
	 * Returns an enumeration of all available actions.
146
	 */
147
	public static Enumeration getActions()
148
	{
149
		return actions.keys();
150
	}
151
152
	/**
153
	 * Adds the default key bindings to this input handler.
154
	 * This should not be called in the constructor of this
155
	 * input handler, because applications might load the
156
	 * key bindings from a file, etc.
157
	 */
158
	public abstract void addDefaultKeyBindings();
159
160
	/**
161
	 * Adds a key binding to this input handler.
162
	 * @param keyBinding The key binding (the format of this is
163
	 * input-handler specific)
164
	 * @param action The action
165
	 */
166
	public abstract void addKeyBinding(String keyBinding, ActionListener action);
167
168
	/**
169
	 * Removes a key binding from this input handler.
170
	 * @param keyBinding The key binding
171
	 */
172
	public abstract void removeKeyBinding(String keyBinding);
173
174
	/**
175
	 * Removes all key bindings from this input handler.
176
	 */
177
	public abstract void removeAllKeyBindings();
178
179
	/**
180
	 * Grabs the next key typed event and invokes the specified
181
	 * action with the key as a the action command.
182
	 * @param action The action
183
	 */
184
	public void grabNextKeyStroke(ActionListener listener)
185
	{
186
		grabAction = listener;
187
	}
188
189
	/**
190
	 * Returns if repeating is enabled. When repeating is enabled,
191
	 * actions will be executed multiple times. This is usually
192
	 * invoked with a special key stroke in the input handler.
193
	 */
194
	public boolean isRepeatEnabled()
195
	{
196
		return repeat;
197
	}
198
199
	/**
200
	 * Enables repeating. When repeating is enabled, actions will be
201
	 * executed multiple times. Once repeating is enabled, the input
202
	 * handler should read a number from the keyboard.
203
	 */
204
	public void setRepeatEnabled(boolean repeat)
205
	{
206
		this.repeat = repeat;
207
	}
208
209
	/**
210
	 * Returns the number of times the next action will be repeated.
211
	 */
212
	public int getRepeatCount()
213
	{
214
		return (repeat ? Math.max(1,repeatCount) : 1);
215
	}
216
217
	/**
218
	 * Sets the number of times the next action will be repeated.
219
	 * @param repeatCount The repeat count
220
	 */
221
	public void setRepeatCount(int repeatCount)
222
	{
223
		this.repeatCount = repeatCount;
224
	}
225
226
	/**
227
	 * Returns the macro recorder. If this is non-null, all executed
228
	 * actions should be forwarded to the recorder.
229
	 */
230
	public InputHandler.MacroRecorder getMacroRecorder()
231
	{
232
		return recorder;
233
	}
234
235
	/**
236
	 * Sets the macro recorder. If this is non-null, all executed
237
	 * actions should be forwarded to the recorder.
238
	 * @param recorder The macro recorder
239
	 */
240
	public void setMacroRecorder(InputHandler.MacroRecorder recorder)
241
	{
242
		this.recorder = recorder;
243
	}
244
245
	/**
246
	 * Returns a copy of this input handler that shares the same
247
	 * key bindings. Setting key bindings in the copy will also
248
	 * set them in the original.
249
	 */
250
	public abstract InputHandler copy();
251
252
	/**
253
	 * Executes the specified action, repeating and recording it as
254
	 * necessary.
255
	 * @param listener The action listener
256
	 * @param source The event source
257
	 * @param actionCommand The action command
258
	 */
259
	public void executeAction(ActionListener listener, Object source,
260
		String actionCommand)
261
	{
262
		// create event
263
		ActionEvent evt = new ActionEvent(source,
264
			ActionEvent.ACTION_PERFORMED,
265
			actionCommand);
266
267
		// don't do anything if the action is a wrapper
268
		// (like EditAction.Wrapper)
269
		if(listener instanceof Wrapper)
270
		{
271
			listener.actionPerformed(evt);
272
			return;
273
		}
274
275
		// remember old values, in case action changes them
276
		boolean _repeat = repeat;
277
		int _repeatCount = getRepeatCount();
278
279
		// execute the action
280
		if(listener instanceof InputHandler.NonRepeatable)
281
			listener.actionPerformed(evt);
282
		else
283
		{
284
			for(int i = 0; i < Math.max(1,repeatCount); i++)
285
				listener.actionPerformed(evt);
286
		}
287
288
		// do recording. Notice that we do no recording whatsoever
289
		// for actions that grab keys
290
		if(grabAction == null)
291
		{
292
			if(recorder != null)
293
			{
294
				if(!(listener instanceof InputHandler.NonRecordable))
295
				{
296
					if(_repeatCount != 1)
297
						recorder.actionPerformed(REPEAT,String.valueOf(_repeatCount));
298
299
					recorder.actionPerformed(listener,actionCommand);
300
				}
301
			}
302
303
			// If repeat was true originally, clear it
304
			// Otherwise it might have been set by the action, etc
305
			if(_repeat)
306
			{
307
				repeat = false;
308
				repeatCount = 0;
309
			}
310
		}
311
	}
312
313
	/**
314
	 * Returns the text area that fired the specified event.
315
	 * @param evt The event
316
	 */
317
	public static JEditTextArea getTextArea(EventObject evt)
318
	{
319
		if(evt != null)
320
		{
321
			Object o = evt.getSource();
322
			if(o instanceof Component)
323
			{
324
				// find the parent text area
325
				Component c = (Component)o;
326
				for(;;)
327
				{
328
					if(c instanceof JEditTextArea)
329
						return (JEditTextArea)c;
330
					else if(c == null)
331
						break;
332
					if(c instanceof JPopupMenu)
333
						c = ((JPopupMenu)c)
334
							.getInvoker();
335
					else
336
						c = c.getParent();
337
				}
338
			}
339
		}
340
341
		// this shouldn't happen
342
		System.err.println("BUG: getTextArea() returning null");
343
		System.err.println("Report this to Slava Pestov <sp@gjt.org>");
344
		return null;
345
	}
346
347
	// protected members
348
349
	/**
350
	 * If a key is being grabbed, this method should be called with
351
	 * the appropriate key event. It executes the grab action with
352
	 * the typed character as the parameter.
353
	 */
354
	protected void handleGrabAction(KeyEvent evt)
355
	{
356
		// Clear it *before* it is executed so that executeAction()
357
		// resets the repeat count
358
		ActionListener _grabAction = grabAction;
359
		grabAction = null;
360
		executeAction(_grabAction,evt.getSource(),
361
			String.valueOf(evt.getKeyChar()));
362
	}
363
364
	// protected members
365
	protected ActionListener grabAction;
366
	protected boolean repeat;
367
	protected int repeatCount;
368
	protected InputHandler.MacroRecorder recorder;
369
370
	/**
371
	 * If an action implements this interface, it should not be repeated.
372
	 * Instead, it will handle the repetition itself.
373
	 */
374
	public interface NonRepeatable {}
375
376
	/**
377
	 * If an action implements this interface, it should not be recorded
378
	 * by the macro recorder. Instead, it will do its own recording.
379
	 */
380
	public interface NonRecordable {}
381
382
	/**
383
	 * For use by EditAction.Wrapper only.
384
	 * @since jEdit 2.2final
385
	 */
386
	public interface Wrapper {}
387
388
	/**
389
	 * Macro recorder.
390
	 */
391
	public interface MacroRecorder
392
	{
393
		void actionPerformed(ActionListener listener,
394
			String actionCommand);
395
	}
396
397
	public static class backspace implements ActionListener
398
	{
399
		public void actionPerformed(ActionEvent evt)
400
		{
401
			JEditTextArea textArea = getTextArea(evt);
402
403
			if(!textArea.isEditable())
404
			{
405
				textArea.getToolkit().beep();
406
				return;
407
			}
408
409
			if(textArea.getSelectionStart()
410
			   != textArea.getSelectionEnd())
411
			{
412
				textArea.setSelectedText("");
413
			}
414
			else
415
			{
416
				int caret = textArea.getCaretPosition();
417
				if(caret == 0)
418
				{
419
					textArea.getToolkit().beep();
420
					return;
421
				}
422
				try
423
				{
424
					textArea.getDocument().remove(caret - 1,1);
425
				}
426
				catch(BadLocationException bl)
427
				{
428
					bl.printStackTrace();
429
				}
430
			}
431
		}
432
	}
433
434
	public static class backspace_word implements ActionListener
435
	{
436
		public void actionPerformed(ActionEvent evt)
437
		{
438
			JEditTextArea textArea = getTextArea(evt);
439
			int start = textArea.getSelectionStart();
440
			if(start != textArea.getSelectionEnd())
441
			{
442
				textArea.setSelectedText("");
443
			}
444
445
			int line = textArea.getCaretLine();
446
			int lineStart = textArea.getLineStartOffset(line);
447
			int caret = start - lineStart;
448
449
			String lineText = textArea.getLineText(textArea
450
				.getCaretLine());
451
452
			if(caret == 0)
453
			{
454
				if(lineStart == 0)
455
				{
456
					textArea.getToolkit().beep();
457
					return;
458
				}
459
				caret--;
460
			}
461
			else
462
			{
463
				String noWordSep = (String)textArea.getDocument().getProperty("noWordSep");
464
				caret = TextUtilities.findWordStart(lineText,caret,noWordSep);
465
			}
466
467
			try
468
			{
469
				textArea.getDocument().remove(
470
						caret + lineStart,
471
						start - (caret + lineStart));
472
			}
473
			catch(BadLocationException bl)
474
			{
475
				bl.printStackTrace();
476
			}
477
		}
478
	}
479
480
	public static class delete implements ActionListener
481
	{
482
		public void actionPerformed(ActionEvent evt)
483
		{
484
			JEditTextArea textArea = getTextArea(evt);
485
486
			if(!textArea.isEditable())
487
			{
488
				textArea.getToolkit().beep();
489
				return;
490
			}
491
492
			if(textArea.getSelectionStart()
493
			   != textArea.getSelectionEnd())
494
			{
495
				textArea.setSelectedText("");
496
			}
497
			else
498
			{
499
				int caret = textArea.getCaretPosition();
500
				if(caret == textArea.getDocumentLength())
501
				{
502
					textArea.getToolkit().beep();
503
					return;
504
				}
505
				try
506
				{
507
					textArea.getDocument().remove(caret,1);
508
				}
509
				catch(BadLocationException bl)
510
				{
511
					bl.printStackTrace();
512
				}
513
			}
514
		}
515
	}
516
517
	public static class delete_word implements ActionListener
518
	{
519
		public void actionPerformed(ActionEvent evt)
520
		{
521
			JEditTextArea textArea = getTextArea(evt);
522
			int start = textArea.getSelectionStart();
523
			if(start != textArea.getSelectionEnd())
524
			{
525
				textArea.setSelectedText("");
526
			}
527
528
			int line = textArea.getCaretLine();
529
			int lineStart = textArea.getLineStartOffset(line);
530
			int caret = start - lineStart;
531
532
			String lineText = textArea.getLineText(textArea
533
				.getCaretLine());
534
535
			if(caret == lineText.length())
536
			{
537
				if(lineStart + caret == textArea.getDocumentLength())
538
				{
539
					textArea.getToolkit().beep();
540
					return;
541
				}
542
				caret++;
543
			}
544
			else
545
			{
546
				String noWordSep = (String)textArea.getDocument().getProperty("noWordSep");
547
				caret = TextUtilities.findWordEnd(lineText,caret,noWordSep);
548
			}
549
550
			try
551
			{
552
				textArea.getDocument().remove(start,
553
					(caret + lineStart) - start);
554
			}
555
			catch(BadLocationException bl)
556
			{
557
				bl.printStackTrace();
558
			}
559
		}
560
	}
561
562
	public static class end implements ActionListener
563
	{
564
		private boolean select;
565
566
		public end(boolean select)
567
		{
568
			this.select = select;
569
		}
570
571
		public void actionPerformed(ActionEvent evt)
572
		{
573
			JEditTextArea textArea = getTextArea(evt);
574
575
			int caret = textArea.getCaretPosition();
576
577
			int lastOfLine = textArea.getLineEndOffset(
578
				textArea.getCaretLine()) - 1;
579
			int lastVisibleLine = textArea.getFirstLine()
580
				+ textArea.getVisibleLines();
581
			if(lastVisibleLine >= textArea.getLineCount())
582
			{
583
				lastVisibleLine = Math.min(textArea.getLineCount() - 1,
584
					lastVisibleLine);
585
			}
586
			else
587
				lastVisibleLine -= (textArea.getElectricScroll() + 1);
588
589
			int lastVisible = textArea.getLineEndOffset(lastVisibleLine) - 1;
590
			int lastDocument = textArea.getDocumentLength();
591
592
			if(caret == lastDocument)
593
			{
594
				textArea.getToolkit().beep();
595
				return;
596
			}
597
			else if(!Boolean.TRUE.equals(textArea.getClientProperty(
598
				SMART_HOME_END_PROPERTY)))
599
				caret = lastOfLine;
600
			else if(caret == lastVisible)
601
				caret = lastDocument;
602
			else if(caret == lastOfLine)
603
				caret = lastVisible;
604
			else
605
				caret = lastOfLine;
606
607
			if(select)
608
				textArea.select(textArea.getMarkPosition(),caret);
609
			else
610
				textArea.setCaretPosition(caret);
611
		}
612
	}
613
614
	public static class document_end implements ActionListener
615
	{
616
		private boolean select;
617
618
		public document_end(boolean select)
619
		{
620
			this.select = select;
621
		}
622
623
		public void actionPerformed(ActionEvent evt)
624
		{
625
			JEditTextArea textArea = getTextArea(evt);
626
			if(select)
627
				textArea.select(textArea.getMarkPosition(),
628
					textArea.getDocumentLength());
629
			else
630
				textArea.setCaretPosition(textArea
631
					.getDocumentLength());
632
		}
633
	}
634
635
	public static class home implements ActionListener
636
	{
637
		private boolean select;
638
639
		public home(boolean select)
640
		{
641
			this.select = select;
642
		}
643
644
		public void actionPerformed(ActionEvent evt)
645
		{
646
			JEditTextArea textArea = getTextArea(evt);
647
648
			int caret = textArea.getCaretPosition();
649
650
			int firstLine = textArea.getFirstLine();
651
652
			int firstOfLine = textArea.getLineStartOffset(
653
				textArea.getCaretLine());
654
			int firstVisibleLine = (firstLine == 0 ? 0 :
655
				firstLine + textArea.getElectricScroll());
656
			int firstVisible = textArea.getLineStartOffset(
657
				firstVisibleLine);
658
659
			if(caret == 0)
660
			{
661
				textArea.getToolkit().beep();
662
				return;
663
			}
664
			else if(!Boolean.TRUE.equals(textArea.getClientProperty(
665
				SMART_HOME_END_PROPERTY)))
666
				caret = firstOfLine;
667
			else if(caret == firstVisible)
668
				caret = 0;
669
			else if(caret == firstOfLine)
670
				caret = firstVisible;
671
			else
672
				caret = firstOfLine;
673
674
			if(select)
675
				textArea.select(textArea.getMarkPosition(),caret);
676
			else
677
				textArea.setCaretPosition(caret);
678
		}
679
	}
680
681
	public static class document_home implements ActionListener
682
	{
683
		private boolean select;
684
685
		public document_home(boolean select)
686
		{
687
			this.select = select;
688
		}
689
690
		public void actionPerformed(ActionEvent evt)
691
		{
692
			JEditTextArea textArea = getTextArea(evt);
693
			if(select)
694
				textArea.select(textArea.getMarkPosition(),0);
695
			else
696
				textArea.setCaretPosition(0);
697
		}
698
	}
699
700
	public static class insert_break implements ActionListener
701
	{
702
		public void actionPerformed(ActionEvent evt)
703
		{
704
			JEditTextArea textArea = getTextArea(evt);
705
706
			if(!textArea.isEditable())
707
			{
708
				textArea.getToolkit().beep();
709
				return;
710
			}
711
712
			textArea.setSelectedText("\n");
713
		}
714
	}
715
716
	public static class insert_tab implements ActionListener
717
	{
718
		public void actionPerformed(ActionEvent evt)
719
		{
720
			JEditTextArea textArea = getTextArea(evt);
721
722
			if(!textArea.isEditable())
723
			{
724
				textArea.getToolkit().beep();
725
				return;
726
			}
727
728
			textArea.overwriteSetSelectedText("\t");
729
		}
730
	}
731
732
	public static class next_char implements ActionListener
733
	{
734
		private boolean select;
735
736
		public next_char(boolean select)
737
		{
738
			this.select = select;
739
		}
740
741
		public void actionPerformed(ActionEvent evt)
742
		{
743
			JEditTextArea textArea = getTextArea(evt);
744
			int caret = textArea.getCaretPosition();
745
			if(caret == textArea.getDocumentLength())
746
			{
747
				textArea.getToolkit().beep();
748
				return;
749
			}
750
751
			if(select)
752
				textArea.select(textArea.getMarkPosition(),
753
					caret + 1);
754
			else
755
				textArea.setCaretPosition(caret + 1);
756
		}
757
	}
758
759
	public static class next_line implements ActionListener
760
	{
761
		private boolean select;
762
763
		public next_line(boolean select)
764
		{
765
			this.select = select;
766
		}
767
768
		public void actionPerformed(ActionEvent evt)
769
		{
770
			JEditTextArea textArea = getTextArea(evt);
771
			int caret = textArea.getCaretPosition();
772
			int line = textArea.getCaretLine();
773
774
			if(line == textArea.getLineCount() - 1)
775
			{
776
				textArea.getToolkit().beep();
777
				return;
778
			}
779
780
			int magic = textArea.getMagicCaretPosition();
781
			if(magic == -1)
782
			{
783
				magic = textArea.offsetToX(line,
784
					caret - textArea.getLineStartOffset(line));
785
			}
786
787
			caret = textArea.getLineStartOffset(line + 1)
788
				+ textArea.xToOffset(line + 1,magic);
789
			if(select)
790
				textArea.select(textArea.getMarkPosition(),caret);
791
			else
792
				textArea.setCaretPosition(caret);
793
			textArea.setMagicCaretPosition(magic);
794
		}
795
	}
796
797
	public static class next_page implements ActionListener
798
	{
799
		private boolean select;
800
801
		public next_page(boolean select)
802
		{
803
			this.select = select;
804
		}
805
806
		public void actionPerformed(ActionEvent evt)
807
		{
808
			JEditTextArea textArea = getTextArea(evt);
809
			int lineCount = textArea.getLineCount();
810
			int firstLine = textArea.getFirstLine();
811
			int visibleLines = textArea.getVisibleLines();
812
			int line = textArea.getCaretLine();
813
814
			firstLine += visibleLines;
815
816
			if(firstLine + visibleLines >= lineCount - 1)
817
				firstLine = lineCount - visibleLines;
818
819
			textArea.setFirstLine(firstLine);
820
821
			int caret = textArea.getLineStartOffset(
822
				Math.min(textArea.getLineCount() - 1,
823
				line + visibleLines));
824
			if(select)
825
				textArea.select(textArea.getMarkPosition(),caret);
826
			else
827
				textArea.setCaretPosition(caret);
828
		}
829
	}
830
831
	public static class next_word implements ActionListener
832
	{
833
		private boolean select;
834
835
		public next_word(boolean select)
836
		{
837
			this.select = select;
838
		}
839
840
		public void actionPerformed(ActionEvent evt)
841
		{
842
			JEditTextArea textArea = getTextArea(evt);
843
			int caret = textArea.getCaretPosition();
844
			int line = textArea.getCaretLine();
845
			int lineStart = textArea.getLineStartOffset(line);
846
			caret -= lineStart;
847
848
			String lineText = textArea.getLineText(textArea
849
				.getCaretLine());
850
851
			if(caret == lineText.length())
852
			{
853
				if(lineStart + caret == textArea.getDocumentLength())
854
				{
855
					textArea.getToolkit().beep();
856
					return;
857
				}
858
				caret++;
859
			}
860
			else
861
			{
862
				String noWordSep = (String)textArea.getDocument().getProperty("noWordSep");
863
				caret = TextUtilities.findWordEnd(lineText,caret,noWordSep);
864
			}
865
866
			if(select)
867
				textArea.select(textArea.getMarkPosition(),
868
					lineStart + caret);
869
			else
870
				textArea.setCaretPosition(lineStart + caret);
871
		}
872
	}
873
874
	public static class overwrite implements ActionListener
875
	{
876
		public void actionPerformed(ActionEvent evt)
877
		{
878
			JEditTextArea textArea = getTextArea(evt);
879
			textArea.setOverwriteEnabled(
880
				!textArea.isOverwriteEnabled());
881
		}
882
	}
883
884
	public static class prev_char implements ActionListener
885
	{
886
		private boolean select;
887
888
		public prev_char(boolean select)
889
		{
890
			this.select = select;
891
		}
892
893
		public void actionPerformed(ActionEvent evt)
894
		{
895
			JEditTextArea textArea = getTextArea(evt);
896
			int caret = textArea.getCaretPosition();
897
			if(caret == 0)
898
			{
899
				textArea.getToolkit().beep();
900
				return;
901
			}
902
903
			if(select)
904
				textArea.select(textArea.getMarkPosition(),
905
					caret - 1);
906
			else
907
				textArea.setCaretPosition(caret - 1);
908
		}
909
	}
910
911
	public static class prev_line implements ActionListener
912
	{
913
		private boolean select;
914
915
		public prev_line(boolean select)
916
		{
917
			this.select = select;
918
		}
919
920
		public void actionPerformed(ActionEvent evt)
921
		{
922
			JEditTextArea textArea = getTextArea(evt);
923
			int caret = textArea.getCaretPosition();
924
			int line = textArea.getCaretLine();
925
926
			if(line == 0)
927
			{
928
				textArea.getToolkit().beep();
929
				return;
930
			}
931
932
			int magic = textArea.getMagicCaretPosition();
933
			if(magic == -1)
934
			{
935
				magic = textArea.offsetToX(line,
936
					caret - textArea.getLineStartOffset(line));
937
			}
938
939
			caret = textArea.getLineStartOffset(line - 1)
940
				+ textArea.xToOffset(line - 1,magic);
941
			if(select)
942
				textArea.select(textArea.getMarkPosition(),caret);
943
			else
944
				textArea.setCaretPosition(caret);
945
			textArea.setMagicCaretPosition(magic);
946
		}
947
	}
948
949
	public static class prev_page implements ActionListener
950
	{
951
		private boolean select;
952
953
		public prev_page(boolean select)
954
		{
955
			this.select = select;
956
		}
957
958
		public void actionPerformed(ActionEvent evt)
959
		{
960
			JEditTextArea textArea = getTextArea(evt);
961
			int firstLine = textArea.getFirstLine();
962
			int visibleLines = textArea.getVisibleLines();
963
			int line = textArea.getCaretLine();
964
965
			if(firstLine < visibleLines)
966
				firstLine = visibleLines;
967
968
			textArea.setFirstLine(firstLine - visibleLines);
969
970
			int caret = textArea.getLineStartOffset(
971
				Math.max(0,line - visibleLines));
972
			if(select)
973
				textArea.select(textArea.getMarkPosition(),caret);
974
			else
975
				textArea.setCaretPosition(caret);
976
		}
977
	}
978
979
	public static class prev_word implements ActionListener
980
	{
981
		private boolean select;
982
983
		public prev_word(boolean select)
984
		{
985
			this.select = select;
986
		}
987
988
		public void actionPerformed(ActionEvent evt)
989
		{
990
			JEditTextArea textArea = getTextArea(evt);
991
			int caret = textArea.getCaretPosition();
992
			int line = textArea.getCaretLine();
993
			int lineStart = textArea.getLineStartOffset(line);
994
			caret -= lineStart;
995
996
			String lineText = textArea.getLineText(textArea
997
				.getCaretLine());
998
999
			if(caret == 0)
1000
			{
1001
				if(lineStart == 0)
1002
				{
1003
					textArea.getToolkit().beep();
1004
					return;
1005
				}
1006
				caret--;
1007
			}
1008
			else
1009
			{
1010
				String noWordSep = (String)textArea.getDocument().getProperty("noWordSep");
1011
				caret = TextUtilities.findWordStart(lineText,caret,noWordSep);
1012
			}
1013
1014
			if(select)
1015
				textArea.select(textArea.getMarkPosition(),
1016
					lineStart + caret);
1017
			else
1018
				textArea.setCaretPosition(lineStart + caret);
1019
		}
1020
	}
1021
1022
	public static class repeat implements ActionListener,
1023
		InputHandler.NonRecordable
1024
	{
1025
		public void actionPerformed(ActionEvent evt)
1026
		{
1027
			JEditTextArea textArea = getTextArea(evt);
1028
			textArea.getInputHandler().setRepeatEnabled(true);
1029
			String actionCommand = evt.getActionCommand();
1030
			if(actionCommand != null)
1031
			{
1032
				textArea.getInputHandler().setRepeatCount(
1033
					Integer.parseInt(actionCommand));
1034
			}
1035
		}
1036
	}
1037
1038
	public static class toggle_rect implements ActionListener
1039
	{
1040
		public void actionPerformed(ActionEvent evt)
1041
		{
1042
			JEditTextArea textArea = getTextArea(evt);
1043
			textArea.setSelectionRectangular(
1044
				!textArea.isSelectionRectangular());
1045
		}
1046
	}
1047
1048
	public static class insert_char implements ActionListener,
1049
		InputHandler.NonRepeatable
1050
	{
1051
		public void actionPerformed(ActionEvent evt)
1052
		{
1053
			JEditTextArea textArea = getTextArea(evt);
1054
			String str = evt.getActionCommand();
1055
			int repeatCount = textArea.getInputHandler().getRepeatCount();
1056
1057
			if(textArea.isEditable())
1058
			{
1059
				StringBuffer buf = new StringBuffer();
1060
				for(int i = 0; i < repeatCount; i++)
1061
					buf.append(str);
1062
				textArea.overwriteSetSelectedText(buf.toString());
1063
			}
1064
			else
1065
			{
1066
				textArea.getToolkit().beep();
1067
			}
1068
		}
1069
	}
1070
}
(-)sources/org/apache/batik/apps/svgbrowser/JSVGViewerFrame.java (-2626 / +2821 lines)
Lines 1-19 Link Here
1
/*
1
/*
2
2
3
   Licensed to the Apache Software Foundation (ASF) under one or more
3
 Licensed to the Apache Software Foundation (ASF) under one or more
4
   contributor license agreements.  See the NOTICE file distributed with
4
 contributor license agreements.  See the NOTICE file distributed with
5
   this work for additional information regarding copyright ownership.
5
 this work for additional information regarding copyright ownership.
6
   The ASF licenses this file to You under the Apache License, Version 2.0
6
 The ASF licenses this file to You under the Apache License, Version 2.0
7
   (the "License"); you may not use this file except in compliance with
7
 (the "License"); you may not use this file except in compliance with
8
   the License.  You may obtain a copy of the License at
8
 the License.  You may obtain a copy of the License at
9
9
10
       http://www.apache.org/licenses/LICENSE-2.0
10
 http://www.apache.org/licenses/LICENSE-2.0
11
11
12
   Unless required by applicable law or agreed to in writing, software
12
 Unless required by applicable law or agreed to in writing, software
13
   distributed under the License is distributed on an "AS IS" BASIS,
13
 distributed under the License is distributed on an "AS IS" BASIS,
14
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
   See the License for the specific language governing permissions and
15
 See the License for the specific language governing permissions and
16
   limitations under the License.
16
 limitations under the License.
17
17
18
 */
18
 */
19
package org.apache.batik.apps.svgbrowser;
19
package org.apache.batik.apps.svgbrowser;
Lines 25-31 Link Here
25
import java.awt.Event;
25
import java.awt.Event;
26
import java.awt.EventQueue;
26
import java.awt.EventQueue;
27
import java.awt.FileDialog;
27
import java.awt.FileDialog;
28
import java.awt.Font;
29
import java.awt.Graphics2D;
28
import java.awt.Graphics2D;
30
import java.awt.Rectangle;
29
import java.awt.Rectangle;
31
import java.awt.Toolkit;
30
import java.awt.Toolkit;
Lines 44-54 Link Here
44
import java.awt.image.BufferedImage;
43
import java.awt.image.BufferedImage;
45
import java.awt.print.PrinterException;
44
import java.awt.print.PrinterException;
46
import java.io.BufferedOutputStream;
45
import java.io.BufferedOutputStream;
46
import java.io.BufferedReader;
47
import java.io.File;
47
import java.io.File;
48
import java.io.FileOutputStream;
48
import java.io.FilenameFilter;
49
import java.io.FilenameFilter;
49
import java.io.FileOutputStream;
50
import java.io.IOException;
50
import java.io.IOException;
51
import java.io.InputStream;
51
import java.io.InputStream;
52
import java.io.InputStreamReader;
52
import java.io.OutputStream;
53
import java.io.OutputStream;
53
import java.io.OutputStreamWriter;
54
import java.io.OutputStreamWriter;
54
import java.io.Reader;
55
import java.io.Reader;
Lines 70-75 Link Here
70
import javax.swing.Action;
71
import javax.swing.Action;
71
import javax.swing.BorderFactory;
72
import javax.swing.BorderFactory;
72
import javax.swing.ButtonGroup;
73
import javax.swing.ButtonGroup;
74
import javax.swing.ImageIcon;
73
import javax.swing.JComponent;
75
import javax.swing.JComponent;
74
import javax.swing.JDialog;
76
import javax.swing.JDialog;
75
import javax.swing.JFileChooser;
77
import javax.swing.JFileChooser;
Lines 79-93 Link Here
79
import javax.swing.JOptionPane;
81
import javax.swing.JOptionPane;
80
import javax.swing.JPanel;
82
import javax.swing.JPanel;
81
import javax.swing.JRadioButtonMenuItem;
83
import javax.swing.JRadioButtonMenuItem;
82
import javax.swing.JScrollPane;
83
import javax.swing.JTextArea;
84
import javax.swing.JToolBar;
84
import javax.swing.JToolBar;
85
import javax.swing.JWindow;
85
import javax.swing.JWindow;
86
import javax.swing.KeyStroke;
86
import javax.swing.KeyStroke;
87
import javax.swing.filechooser.FileFilter;
87
import javax.swing.filechooser.FileFilter;
88
import javax.swing.text.Document;
89
import javax.swing.text.PlainDocument;
90
88
89
import org.apache.batik.apps.svgbrowser.srcview.SourceViewFrame;
91
import org.apache.batik.bridge.DefaultExternalResourceSecurity;
90
import org.apache.batik.bridge.DefaultExternalResourceSecurity;
92
import org.apache.batik.bridge.DefaultScriptSecurity;
91
import org.apache.batik.bridge.DefaultScriptSecurity;
93
import org.apache.batik.bridge.EmbededExternalResourceSecurity;
92
import org.apache.batik.bridge.EmbededExternalResourceSecurity;
Lines 102-110 Link Here
102
import org.apache.batik.bridge.UpdateManagerEvent;
101
import org.apache.batik.bridge.UpdateManagerEvent;
103
import org.apache.batik.bridge.UpdateManagerListener;
102
import org.apache.batik.bridge.UpdateManagerListener;
104
import org.apache.batik.dom.StyleSheetProcessingInstruction;
103
import org.apache.batik.dom.StyleSheetProcessingInstruction;
104
import org.apache.batik.dom.svg.LiveAttributeException;
105
import org.apache.batik.dom.svg.SVGOMDocument;
105
import org.apache.batik.dom.svg.SVGOMDocument;
106
import org.apache.batik.dom.util.DOMUtilities;
107
import org.apache.batik.dom.util.DocumentDescriptor;
106
import org.apache.batik.dom.util.HashTable;
108
import org.apache.batik.dom.util.HashTable;
107
import org.apache.batik.dom.util.DOMUtilities;
108
import org.apache.batik.ext.swing.JAffineTransformChooser;
109
import org.apache.batik.ext.swing.JAffineTransformChooser;
109
import org.apache.batik.swing.JSVGCanvas;
110
import org.apache.batik.swing.JSVGCanvas;
110
import org.apache.batik.swing.gvt.GVTTreeRendererEvent;
111
import org.apache.batik.swing.gvt.GVTTreeRendererEvent;
Lines 129-142 Link Here
129
import org.apache.batik.transcoder.svg2svg.SVGTranscoder;
130
import org.apache.batik.transcoder.svg2svg.SVGTranscoder;
130
import org.apache.batik.util.ParsedURL;
131
import org.apache.batik.util.ParsedURL;
131
import org.apache.batik.util.Platform;
132
import org.apache.batik.util.Platform;
133
import org.apache.batik.util.SVGConstants;
132
import org.apache.batik.util.Service;
134
import org.apache.batik.util.Service;
133
import org.apache.batik.util.SVGConstants;
134
import org.apache.batik.util.XMLConstants;
135
import org.apache.batik.util.XMLConstants;
135
import org.apache.batik.util.gui.DOMViewer;
136
import org.apache.batik.util.gui.DOMViewer;
136
import org.apache.batik.util.gui.JErrorPane;
137
import org.apache.batik.util.gui.ErrorConsole;
137
import org.apache.batik.util.gui.LocationBar;
138
import org.apache.batik.util.gui.LocationBar;
138
import org.apache.batik.util.gui.MemoryMonitor;
139
import org.apache.batik.util.gui.MemoryMonitor;
140
import org.apache.batik.util.gui.TimelineViewer;
139
import org.apache.batik.util.gui.URIChooser;
141
import org.apache.batik.util.gui.URIChooser;
142
import org.apache.batik.util.gui.ErrorConsole.ErrorInfo;
143
import org.apache.batik.util.gui.ErrorConsole.AttributeErrorInfo;
140
import org.apache.batik.util.gui.resource.ActionMap;
144
import org.apache.batik.util.gui.resource.ActionMap;
141
import org.apache.batik.util.gui.resource.JComponentModifier;
145
import org.apache.batik.util.gui.resource.JComponentModifier;
142
import org.apache.batik.util.gui.resource.MenuFactory;
146
import org.apache.batik.util.gui.resource.MenuFactory;
Lines 151-3086 Link Here
151
155
152
/**
156
/**
153
 * This class represents a SVG viewer swing frame.
157
 * This class represents a SVG viewer swing frame.
154
 *
158
 * 
155
 * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
159
 * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
156
 * @version $Id$
160
 * @version $Id$
157
 */
161
 */
158
public class JSVGViewerFrame
162
public class JSVGViewerFrame extends JFrame implements ActionMap,
159
    extends    JFrame
163
		SVGDocumentLoaderListener, GVTTreeBuilderListener,
160
    implements ActionMap,
164
		SVGLoadEventDispatcherListener, GVTTreeRendererListener,
161
               SVGDocumentLoaderListener,
165
		LinkActivationListener, UpdateManagerListener {
162
               GVTTreeBuilderListener,
163
               SVGLoadEventDispatcherListener,
164
               GVTTreeRendererListener,
165
               LinkActivationListener,
166
               UpdateManagerListener {
167
166
168
    private static String EOL;
167
	private static String EOL;
169
    static {
168
	static {
170
        try {
169
		try {
171
            EOL = System.getProperty("line.separator", "\n");
170
			EOL = System.getProperty("line.separator", "\n");
172
        } catch (SecurityException e) {
171
		} catch (SecurityException e) {
173
            EOL = "\n";
172
			EOL = "\n";
174
        }
173
		}
175
    }
174
	}
176
175
177
    /**
176
	/**
178
     * Kind of ugly, but we need to know if we are running before
177
	 * Kind of ugly, but we need to know if we are running before or after
179
     * or after 1.4...
178
	 * 1.4...
180
     */
179
	 */
181
    protected static boolean priorJDK1_4 = true;
180
	protected static boolean priorJDK1_4 = true;
182
181
183
    /**
182
	/**
184
     * If the following class can be found (it appeared in JDK 1.4),
183
	 * If the following class can be found (it appeared in JDK 1.4), then we
185
     * then we know we are post JDK 1.4.
184
	 * know we are post JDK 1.4.
186
     */
185
	 */
187
    protected static final String JDK_1_4_PRESENCE_TEST_CLASS
186
	protected static final String JDK_1_4_PRESENCE_TEST_CLASS = "java.util.logging.LoggingPermission";
188
        = "java.util.logging.LoggingPermission";
189
187
190
    static {
188
	static {
191
        try {
189
		try {
192
            Class.forName(JDK_1_4_PRESENCE_TEST_CLASS);
190
			Class.forName(JDK_1_4_PRESENCE_TEST_CLASS);
193
            priorJDK1_4 = false;
191
			priorJDK1_4 = false;
194
        } catch (ClassNotFoundException e) {
192
		} catch (ClassNotFoundException e) {
195
        }
193
		}
196
    }
194
	}
197
195
198
    /**
196
	/**
199
     * The gui resources file name
197
	 * The gui resources file name
200
     */
198
	 */
201
    public static final String RESOURCES =
199
	public static final String RESOURCES = "org.apache.batik.apps.svgbrowser.resources.GUI";
202
        "org.apache.batik.apps.svgbrowser.resources.GUI";
203
200
204
    // The actions names.
201
	// The actions names.
205
    public static final String ABOUT_ACTION = "AboutAction";
202
	public static final String ABOUT_ACTION = "AboutAction";
206
    public static final String OPEN_ACTION = "OpenAction";
207
    public static final String OPEN_LOCATION_ACTION = "OpenLocationAction";
208
    public static final String NEW_WINDOW_ACTION = "NewWindowAction";
209
    public static final String RELOAD_ACTION = "ReloadAction";
210
    public static final String SAVE_AS_ACTION = "SaveAsAction";
211
    public static final String BACK_ACTION = "BackAction";
212
    public static final String FORWARD_ACTION = "ForwardAction";
213
    public static final String FULL_SCREEN_ACTION = "FullScreenAction";
214
    public static final String PRINT_ACTION = "PrintAction";
215
    public static final String EXPORT_AS_JPG_ACTION = "ExportAsJPGAction";
216
    public static final String EXPORT_AS_PNG_ACTION = "ExportAsPNGAction";
217
    public static final String EXPORT_AS_TIFF_ACTION = "ExportAsTIFFAction";
218
    public static final String PREFERENCES_ACTION = "PreferencesAction";
219
    public static final String CLOSE_ACTION = "CloseAction";
220
    public static final String VIEW_SOURCE_ACTION = "ViewSourceAction";
221
    public static final String EXIT_ACTION = "ExitAction";
222
    public static final String RESET_TRANSFORM_ACTION = "ResetTransformAction";
223
    public static final String ZOOM_IN_ACTION = "ZoomInAction";
224
    public static final String ZOOM_OUT_ACTION = "ZoomOutAction";
225
    public static final String PREVIOUS_TRANSFORM_ACTION = "PreviousTransformAction";
226
    public static final String NEXT_TRANSFORM_ACTION = "NextTransformAction";
227
    public static final String USE_STYLESHEET_ACTION = "UseStylesheetAction";
228
    public static final String PLAY_ACTION = "PlayAction";
229
    public static final String PAUSE_ACTION = "PauseAction";
230
    public static final String STOP_ACTION = "StopAction";
231
    public static final String MONITOR_ACTION = "MonitorAction";
232
    public static final String DOM_VIEWER_ACTION = "DOMViewerAction";
233
    public static final String SET_TRANSFORM_ACTION = "SetTransformAction";
234
    public static final String FIND_DIALOG_ACTION = "FindDialogAction";
235
    public static final String THUMBNAIL_DIALOG_ACTION = "ThumbnailDialogAction";
236
    public static final String FLUSH_ACTION = "FlushAction";
237
    public static final String TOGGLE_DEBUGGER_ACTION = "ToggleDebuggerAction";
238
203
239
    /**
204
	public static final String OPEN_ACTION = "OpenAction";
240
     * The cursor indicating that an operation is pending.
241
     */
242
    public static final Cursor WAIT_CURSOR =
243
        new Cursor(Cursor.WAIT_CURSOR);
244
205
245
    /**
206
	public static final String OPEN_LOCATION_ACTION = "OpenLocationAction";
246
     * The default cursor.
247
     */
248
    public static final Cursor DEFAULT_CURSOR =
249
        new Cursor(Cursor.DEFAULT_CURSOR);
250
207
251
    /**
208
	public static final String NEW_WINDOW_ACTION = "NewWindowAction";
252
     * Name for the os-name property
253
     */
254
    public static final String PROPERTY_OS_NAME
255
        = Resources.getString("JSVGViewerFrame.property.os.name");
256
209
257
    /**
210
	public static final String RELOAD_ACTION = "ReloadAction";
258
     * Name for the os.name default
259
     */
260
    public static final String PROPERTY_OS_NAME_DEFAULT
261
        = Resources.getString("JSVGViewerFrame.property.os.name.default");
262
211
263
    /**
212
	public static final String SAVE_AS_ACTION = "SaveAsAction";
264
     * Name for the os.name property prefix we are looking
265
     * for in OpenAction to work around JFileChooser bug
266
     */
267
    public static final String PROPERTY_OS_WINDOWS_PREFIX
268
        = Resources.getString("JSVGViewerFrame.property.os.windows.prefix");
269
213
270
    /**
214
	public static final String BACK_ACTION = "BackAction";
271
     * Resource string name for the Open dialog.
272
     */
273
    protected static final String OPEN_TITLE = "Open.title";
274
215
275
    /**
216
	public static final String FORWARD_ACTION = "ForwardAction";
276
     * The input handlers
277
     */
278
    protected static Vector handlers;
279
217
280
    /**
218
	public static final String FULL_SCREEN_ACTION = "FullScreenAction";
281
     * The default input handler
282
     */
283
    protected static SquiggleInputHandler defaultHandler = new SVGInputHandler();
284
219
285
    /**
220
	public static final String PRINT_ACTION = "PrintAction";
286
     * The resource bundle
287
     */
288
    protected static ResourceBundle bundle;
289
221
290
    /**
222
	public static final String EXPORT_AS_JPG_ACTION = "ExportAsJPGAction";
291
     * The resource manager
292
     */
293
    protected static ResourceManager resources;
294
    static {
295
        bundle = ResourceBundle.getBundle(RESOURCES, Locale.getDefault());
296
        resources = new ResourceManager(bundle);
297
    }
298
223
299
    /**
224
	public static final String EXPORT_AS_PNG_ACTION = "ExportAsPNGAction";
300
     * The current application.
301
     */
302
    protected Application application;
303
225
304
    /**
226
	public static final String EXPORT_AS_TIFF_ACTION = "ExportAsTIFFAction";
305
     * The JSVGCanvas.
306
     */
307
    protected Canvas svgCanvas;
308
227
309
    /**
228
	public static final String PREFERENCES_ACTION = "PreferencesAction";
310
     * An extension of JSVGCanvas that exposes the Rhino interpreter.
311
     */
312
    protected static class Canvas extends JSVGCanvas {
313
229
314
        /**
230
	public static final String CLOSE_ACTION = "CloseAction";
315
         * Creates a new Canvas.
316
         */
317
        public Canvas(SVGUserAgent ua, boolean eventsEnabled,
318
                      boolean selectableText) {
319
            super(ua, eventsEnabled, selectableText);
320
        }
321
231
322
        /**
232
	public static final String VIEW_SOURCE_ACTION = "ViewSourceAction";
323
         * Returns the Rhino interpreter for this canvas.
324
         */
325
        public Object getRhinoInterpreter() {
326
            if (bridgeContext == null) {
327
                return null;
328
            }
329
            return bridgeContext.getInterpreter("text/ecmascript");
330
        }
331
    }
332
233
333
    /**
234
	public static final String EXIT_ACTION = "ExitAction";
334
     * The panel where the svgCanvas is displayed
335
     */
336
    protected JPanel svgCanvasPanel;
337
235
338
    /**
236
	public static final String RESET_TRANSFORM_ACTION = "ResetTransformAction";
339
     * A window used for full screen display
340
     */
341
    protected JWindow window;
342
237
343
    /**
238
	public static final String ZOOM_IN_ACTION = "ZoomInAction";
344
     * The memory monitor frame.
345
     */
346
    protected static JFrame memoryMonitorFrame;
347
239
348
    /**
240
	public static final String ZOOM_OUT_ACTION = "ZoomOutAction";
349
     * The current path.
350
     */
351
    protected File currentPath = new File("");
352
241
353
    /**
242
	public static final String PREVIOUS_TRANSFORM_ACTION = "PreviousTransformAction";
354
     * The current export path.
355
     */
356
    protected File currentSavePath = new File("");
357
243
358
    /**
244
	public static final String NEXT_TRANSFORM_ACTION = "NextTransformAction";
359
     * The back action
360
     */
361
    protected BackAction backAction = new BackAction();
362
245
363
    /**
246
	public static final String USE_STYLESHEET_ACTION = "UseStylesheetAction";
364
     * The forward action
365
     */
366
    protected ForwardAction forwardAction = new ForwardAction();
367
247
368
    /**
248
	public static final String PLAY_ACTION = "PlayAction";
369
     * The play action
370
     */
371
    protected PlayAction playAction = new PlayAction();
372
249
373
    /**
250
	public static final String PAUSE_ACTION = "PauseAction";
374
     * The pause action
375
     */
376
    protected PauseAction pauseAction = new PauseAction();
377
251
378
    /**
252
	public static final String STOP_ACTION = "StopAction";
379
     * The stop action
380
     */
381
    protected StopAction stopAction = new StopAction();
382
253
383
    /**
254
	public static final String MONITOR_ACTION = "MonitorAction";
384
     * The previous transform action
385
     */
386
    protected PreviousTransformAction previousTransformAction =
387
        new PreviousTransformAction();
388
255
389
    /**
256
	public static final String DOM_VIEWER_ACTION = "DOMViewerAction";
390
     * The next transform action
391
     */
392
    protected NextTransformAction nextTransformAction =
393
        new NextTransformAction();
394
257
395
    /**
258
	public static final String TIMELINE_VIEWER_ACTION = "TimelineViewerAction";
396
     * The use (author) stylesheet action
397
     */
398
    protected UseStylesheetAction useStylesheetAction =
399
        new UseStylesheetAction();
400
259
401
    /**
260
	public static final String SET_TRANSFORM_ACTION = "SetTransformAction";
402
     * The debug flag.
403
     */
404
    protected boolean debug;
405
261
406
    /**
262
	public static final String FIND_DIALOG_ACTION = "FindDialogAction";
407
     * The auto adjust flag.
408
     */
409
    protected boolean autoAdjust = true;
410
263
411
    /**
264
	public static final String THUMBNAIL_DIALOG_ACTION = "ThumbnailDialogAction";
412
     * Whether the update manager was stopped.
413
     */
414
    protected boolean managerStopped;
415
265
416
    /**
266
	public static final String FLUSH_ACTION = "FlushAction";
417
     * The SVG user agent.
418
     */
419
    protected SVGUserAgent userAgent = new UserAgent();
420
267
421
    /**
268
	public static final String TOGGLE_DEBUGGER_ACTION = "ToggleDebuggerAction";
422
     * The current document.
423
     */
424
    protected SVGDocument svgDocument;
425
269
426
    /**
270
	/**
427
     * The URI chooser.
271
	 * The cursor indicating that an operation is pending.
428
     */
272
	 */
429
    protected URIChooser uriChooser;
273
	public static final Cursor WAIT_CURSOR = new Cursor(Cursor.WAIT_CURSOR);
430
274
431
    /**
275
	/**
432
     * The DOM viewer.
276
	 * The default cursor.
433
     */
277
	 */
434
    protected DOMViewer domViewer;
278
	public static final Cursor DEFAULT_CURSOR = new Cursor(
279
			Cursor.DEFAULT_CURSOR);
435
280
436
    /**
281
	/**
437
     * The Find dialog.
282
	 * Name for the os-name property
438
     */
283
	 */
439
    protected FindDialog findDialog;
284
	public static final String PROPERTY_OS_NAME = Resources
285
			.getString("JSVGViewerFrame.property.os.name");
440
286
441
    /**
287
	/**
442
     * The Find dialog.
288
	 * Name for the os.name default
443
     */
289
	 */
444
    protected ThumbnailDialog thumbnailDialog;
290
	public static final String PROPERTY_OS_NAME_DEFAULT = Resources
291
			.getString("JSVGViewerFrame.property.os.name.default");
445
292
446
    /**
293
	/**
447
     * The transform dialog
294
	 * Name for the os.name property prefix we are looking for in OpenAction to
448
     */
295
	 * work around JFileChooser bug
449
    protected JAffineTransformChooser.Dialog transformDialog;
296
	 */
297
	public static final String PROPERTY_OS_WINDOWS_PREFIX = Resources
298
			.getString("JSVGViewerFrame.property.os.windows.prefix");
450
299
451
    /**
300
	/**
452
     * The location bar.
301
	 * Resource string name for the Open dialog.
453
     */
302
	 */
454
    protected LocationBar locationBar;
303
	protected static final String OPEN_TITLE = "Open.title";
455
304
456
    /**
305
	/**
457
     * The status bar.
306
	 * The input handlers
458
     */
307
	 */
459
    protected StatusBar statusBar;
308
	protected static Vector handlers;
460
309
461
    /**
310
	/**
462
     * The initial frame title.
311
	 * The default input handler
463
     */
312
	 */
464
    protected String title;
313
	protected static SquiggleInputHandler defaultHandler = new SVGInputHandler();
465
314
466
    /**
315
	/**
467
     * The local history.
316
	 * The resource bundle
468
     */
317
	 */
469
    protected LocalHistory localHistory;
318
	protected static ResourceBundle bundle;
470
319
471
    /**
320
	/**
472
     * The transform history.
321
	 * The resource manager
473
     */
322
	 */
474
    protected TransformHistory transformHistory = new TransformHistory();
323
	protected static ResourceManager resources;
324
	static {
325
		bundle = ResourceBundle.getBundle(RESOURCES, Locale.getDefault());
326
		resources = new ResourceManager(bundle);
327
	}
475
328
476
    /**
329
	/**
477
     * The alternate style-sheet title.
330
	 * The current application.
478
     */
331
	 */
479
    protected String alternateStyleSheet;
332
	protected Application application;
480
333
481
    /**
334
	/**
482
     * The debugger object.
335
	 * The JSVGCanvas.
483
     */
336
	 */
484
    protected Debugger debugger;
337
	protected Canvas svgCanvas;
485
338
486
    /**
339
	/**
487
     * Creates a new SVG viewer frame.
340
	 * An extension of JSVGCanvas that exposes the Rhino interpreter.
488
     */
341
	 */
489
    public JSVGViewerFrame(Application app) {
342
	protected static class Canvas extends JSVGCanvas {
490
        application = app;
491
343
492
        addWindowListener(new WindowAdapter() {
344
		/**
493
            public void windowClosing(WindowEvent e) {
345
		 * Creates a new Canvas.
494
                application.closeJSVGViewerFrame(JSVGViewerFrame.this);
346
		 */
495
            }
347
		public Canvas(SVGUserAgent ua, boolean eventsEnabled,
496
        });
348
				boolean selectableText) {
349
			super(ua, eventsEnabled, selectableText);
350
		}
497
351
498
        //
352
		/**
499
        // Set the frame's maximum size so that content
353
		 * Returns the Rhino interpreter for this canvas.
500
        // bigger than the screen does not cause the creation
354
		 */
501
        // of unnecessary large images.
355
		public Object getRhinoInterpreter() {
502
        //
356
			if (bridgeContext == null) {
503
        svgCanvas = new Canvas(userAgent, true, true) {
357
				return null;
504
                Dimension screenSize;
358
			}
359
			return bridgeContext.getInterpreter("text/ecmascript");
360
		}
361
	}
505
362
506
                {
363
	/**
507
                    screenSize = Toolkit.getDefaultToolkit().getScreenSize();
364
	 * The panel where the svgCanvas is displayed
508
                    setMaximumSize(screenSize);
365
	 */
509
                }
366
	protected JPanel svgCanvasPanel;
510
367
511
                public Dimension getPreferredSize(){
368
	/**
512
                    Dimension s = super.getPreferredSize();
369
	 * A window used for full screen display
513
                    if (s.width > screenSize.width) s.width =screenSize.width;
370
	 */
514
                    if (s.height > screenSize.height) s.height = screenSize.height;
371
	protected JWindow window;
515
                    return s;
516
                }
517
372
373
	/**
374
	 * The memory monitor frame.
375
	 */
376
	protected static JFrame memoryMonitorFrame;
518
377
519
                /**
378
	/**
520
                 * This method is called when the component knows the desired
379
	 * The current path.
521
                 * size of the window (based on width/height of outermost SVG
380
	 */
522
                 * element). We override it to immediately pack this frame.
381
	protected File currentPath = new File("");
523
                 */
524
                public void setMySize(Dimension d) {
525
                    setPreferredSize(d);
526
                    invalidate();
527
                    if (JSVGViewerFrame.this.autoAdjust) {
528
                        Platform.unmaximize(JSVGViewerFrame.this);
529
                        JSVGViewerFrame.this.pack();
530
                    }
531
                }
532
382
533
                public void setDisableInteractions(boolean b) {
383
	/**
534
                    super.setDisableInteractions(b);
384
	 * The current export path.
385
	 */
386
	protected File currentSavePath = new File("");
535
387
536
                    // Disable/Enable all our different ways to adjust the
388
	/**
537
                    // rendering transform (menus, toolbar, thumbnail, keyboard).
389
	 * The back action
390
	 */
391
	protected BackAction backAction = new BackAction();
538
392
539
                    ((Action)listeners.get(SET_TRANSFORM_ACTION)) .setEnabled(!b);
393
	/**
394
	 * The forward action
395
	 */
396
	protected ForwardAction forwardAction = new ForwardAction();
540
397
541
                    if (thumbnailDialog != null)
398
	/**
542
                        thumbnailDialog.setInteractionEnabled(!b);
399
	 * The play action
543
                }
400
	 */
544
            };
401
	protected PlayAction playAction = new PlayAction();
545
402
546
        javax.swing.ActionMap map = svgCanvas.getActionMap();
403
	/**
547
        map.put(FULL_SCREEN_ACTION, new FullScreenAction());
404
	 * The pause action
548
        javax.swing.InputMap imap = svgCanvas.getInputMap(JComponent.WHEN_FOCUSED);
405
	 */
549
        KeyStroke key = KeyStroke.getKeyStroke(KeyEvent.VK_F11, 0);
406
	protected PauseAction pauseAction = new PauseAction();
550
        imap.put(key, FULL_SCREEN_ACTION);
551
407
552
        svgCanvas.setDoubleBufferedRendering(true);
408
	/**
409
	 * The stop action
410
	 */
411
	protected StopAction stopAction = new StopAction();
553
412
554
        listeners.put(ABOUT_ACTION, new AboutAction());
413
	/**
555
        listeners.put(OPEN_ACTION, new OpenAction());
414
	 * The previous transform action
556
        listeners.put(OPEN_LOCATION_ACTION, new OpenLocationAction());
415
	 */
557
        listeners.put(NEW_WINDOW_ACTION, new NewWindowAction());
416
	protected PreviousTransformAction previousTransformAction = new PreviousTransformAction();
558
        listeners.put(RELOAD_ACTION, new ReloadAction());
559
        listeners.put(SAVE_AS_ACTION, new SaveAsAction());
560
        listeners.put(BACK_ACTION, backAction);
561
        listeners.put(FORWARD_ACTION, forwardAction);
562
        listeners.put(PRINT_ACTION, new PrintAction());
563
        listeners.put(EXPORT_AS_JPG_ACTION, new ExportAsJPGAction());
564
        listeners.put(EXPORT_AS_PNG_ACTION, new ExportAsPNGAction());
565
        listeners.put(EXPORT_AS_TIFF_ACTION, new ExportAsTIFFAction());
566
        listeners.put(PREFERENCES_ACTION, new PreferencesAction());
567
        listeners.put(CLOSE_ACTION, new CloseAction());
568
        listeners.put(EXIT_ACTION, application.createExitAction(this));
569
        listeners.put(VIEW_SOURCE_ACTION, new ViewSourceAction());
570
417
571
        javax.swing.ActionMap cMap = svgCanvas.getActionMap();
418
	/**
572
        listeners.put(RESET_TRANSFORM_ACTION,
419
	 * The next transform action
573
                      cMap.get(JSVGCanvas.RESET_TRANSFORM_ACTION));
420
	 */
574
        listeners.put(ZOOM_IN_ACTION,
421
	protected NextTransformAction nextTransformAction = new NextTransformAction();
575
                      cMap.get(JSVGCanvas.ZOOM_IN_ACTION));
576
        listeners.put(ZOOM_OUT_ACTION,
577
                      cMap.get(JSVGCanvas.ZOOM_OUT_ACTION));
578
422
579
        listeners.put(PREVIOUS_TRANSFORM_ACTION, previousTransformAction);
423
	/**
580
        key = KeyStroke.getKeyStroke(KeyEvent.VK_K, KeyEvent.CTRL_MASK);
424
	 * The use (author) stylesheet action
581
        imap.put(key, previousTransformAction);
425
	 */
426
	protected UseStylesheetAction useStylesheetAction = new UseStylesheetAction();
582
427
583
        listeners.put(NEXT_TRANSFORM_ACTION, nextTransformAction);
428
	/**
584
        key = KeyStroke.getKeyStroke(KeyEvent.VK_L, KeyEvent.CTRL_MASK);
429
	 * The debug flag.
585
        imap.put(key, nextTransformAction);
430
	 */
431
	protected boolean debug;
586
432
587
        listeners.put(USE_STYLESHEET_ACTION, useStylesheetAction);
433
	/**
588
        listeners.put(PLAY_ACTION, playAction);
434
	 * The auto adjust flag.
589
        listeners.put(PAUSE_ACTION, pauseAction);
435
	 */
590
        listeners.put(STOP_ACTION, stopAction);
436
	protected boolean autoAdjust = true;
591
        listeners.put(MONITOR_ACTION, new MonitorAction());
592
        listeners.put(DOM_VIEWER_ACTION, new DOMViewerAction());
593
        listeners.put(SET_TRANSFORM_ACTION, new SetTransformAction());
594
        listeners.put(FIND_DIALOG_ACTION, new FindDialogAction());
595
        listeners.put(THUMBNAIL_DIALOG_ACTION, new ThumbnailDialogAction());
596
        listeners.put(FLUSH_ACTION, new FlushAction());
597
        listeners.put(TOGGLE_DEBUGGER_ACTION, new ToggleDebuggerAction());
598
437
599
        JPanel p = null;
438
	/**
600
        try {
439
	 * Whether the update manager was stopped.
601
            // Create the menu
440
	 */
602
            MenuFactory mf = new MenuFactory(bundle, this);
441
	protected boolean managerStopped;
603
            JMenuBar mb =
604
                mf.createJMenuBar("MenuBar", application.getUISpecialization());
605
            setJMenuBar(mb);
606
442
607
            localHistory = new LocalHistory(mb, this);
443
	/**
444
	 * The SVG user agent.
445
	 */
446
	protected SVGUserAgent userAgent = new UserAgent();
608
447
609
            String[] uri = application.getVisitedURIs();
448
	/**
610
            for (int i=0; i<uri.length; i++) {
449
	 * The current document.
611
                if (uri[i] != null && !"".equals(uri[i])) {
450
	 */
612
                    localHistory.update(uri[i]);
451
	protected SVGDocument svgDocument;
613
                }
614
            }
615
            p = new JPanel(new BorderLayout());
616
452
617
            // Create the toolbar
453
	/**
618
            ToolBarFactory tbf = new ToolBarFactory(bundle, this);
454
	 * The descriptor associated with the current document.
619
            JToolBar tb = tbf.createJToolBar("ToolBar");
455
	 */
620
            tb.setFloatable(false);
456
	protected DocumentDescriptor docDescriptor;
621
            getContentPane().add(p, BorderLayout.NORTH);
622
            p.add(tb, BorderLayout.NORTH);
623
            p.add(new javax.swing.JSeparator(), BorderLayout.CENTER);
624
            p.add(locationBar = new LocationBar(), BorderLayout.SOUTH);
625
            locationBar.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
626
457
627
        } catch (MissingResourceException e) {
458
	/**
628
            System.out.println(e.getMessage());
459
	 * Document text, stored when the document is loaded
629
            System.exit(0);
460
	 */
630
        }
461
	protected String docText;
631
462
632
        svgCanvasPanel = new JPanel(new BorderLayout());
463
	/**
633
        svgCanvasPanel.setBorder(BorderFactory.createEtchedBorder());
464
	 * The URI chooser.
465
	 */
466
	protected URIChooser uriChooser;
634
467
635
        svgCanvasPanel.add(svgCanvas, BorderLayout.CENTER);
468
	/**
636
        p = new JPanel(new BorderLayout());
469
	 * The DOM viewer.
637
        p.add(svgCanvasPanel, BorderLayout.CENTER);
470
	 */
638
        p.add(statusBar = new StatusBar(), BorderLayout.SOUTH);
471
	protected DOMViewer domViewer;
639
472
640
        getContentPane().add(p, BorderLayout.CENTER);
473
	/**
474
	 * The Timeline viewer.
475
	 */
476
	protected TimelineViewer timelineViewer;
641
477
642
        svgCanvas.addSVGDocumentLoaderListener(this);
478
	/**
643
        svgCanvas.addGVTTreeBuilderListener(this);
479
	 * The Find dialog.
644
        svgCanvas.addSVGLoadEventDispatcherListener(this);
480
	 */
645
        svgCanvas.addGVTTreeRendererListener(this);
481
	protected FindDialog findDialog;
646
        svgCanvas.addLinkActivationListener(this);
647
        svgCanvas.addUpdateManagerListener(this);
648
482
649
        svgCanvas.addMouseMotionListener(new MouseMotionAdapter() {
483
	/**
650
                public void mouseMoved(MouseEvent e) {
484
	 * The Find dialog.
651
                    if (svgDocument == null) {
485
	 */
652
                        statusBar.setXPosition(e.getX());
486
	protected ThumbnailDialog thumbnailDialog;
653
                        statusBar.setYPosition(e.getY());
654
                    } else {
655
                        try {
656
                            AffineTransform at;
657
                            at = svgCanvas.getViewBoxTransform();
658
                            if (at != null) {
659
                                at = at.createInverse();
660
                                Point2D p2d =
661
                                    at.transform(new Point2D.Float(e.getX(), e.getY()),
662
                                                 null);
663
                                statusBar.setXPosition((float)p2d.getX());
664
                                statusBar.setYPosition((float)p2d.getY());
665
                                return;
666
                            }
667
                        } catch (NoninvertibleTransformException ex) {
668
                        }
669
                        statusBar.setXPosition(e.getX());
670
                        statusBar.setYPosition(e.getY());
671
                    }
672
                }
673
            });
674
        svgCanvas.addMouseListener(new MouseAdapter() {
675
                public void mouseExited(MouseEvent e) {
676
                    Dimension dim = svgCanvas.getSize();
677
                    if (svgDocument == null) {
678
                        statusBar.setWidth(dim.width);
679
                        statusBar.setHeight(dim.height);
680
                    } else {
681
                        try {
682
                            AffineTransform at;
683
                            at = svgCanvas.getViewBoxTransform();
684
                            if (at != null) {
685
                                at = at.createInverse();
686
                                Point2D o =
687
                                    at.transform(new Point2D.Float(0, 0),
688
                                                 null);
689
                                Point2D p2d =
690
                                    at.transform(new Point2D.Float(dim.width,
691
                                                                   dim.height),
692
                                                 null);
693
                                statusBar.setWidth((float)(p2d.getX() - o.getX()));
694
                                statusBar.setHeight((float)(p2d.getY() - o.getY()));
695
                                return;
696
                            }
697
                        } catch (NoninvertibleTransformException ex) {
698
                        }
699
                        statusBar.setWidth(dim.width);
700
                        statusBar.setHeight(dim.height);
701
                    }
702
                }
703
            });
704
        svgCanvas.addComponentListener(new ComponentAdapter() {
705
                public void componentResized(ComponentEvent e) {
706
                    Dimension dim = svgCanvas.getSize();
707
                    if (svgDocument == null) {
708
                        statusBar.setWidth(dim.width);
709
                        statusBar.setHeight(dim.height);
710
                    } else {
711
                        try {
712
                            AffineTransform at;
713
                            at = svgCanvas.getViewBoxTransform();
714
                            if (at != null) {
715
                                at = at.createInverse();
716
                                Point2D o =
717
                                    at.transform(new Point2D.Float(0, 0),
718
                                                 null);
719
                                Point2D p2d =
720
                                    at.transform(new Point2D.Float(dim.width,
721
                                                                   dim.height),
722
                                                 null);
723
                                statusBar.setWidth((float)(p2d.getX() - o.getX()));
724
                                statusBar.setHeight((float)(p2d.getY() - o.getY()));
725
                                return;
726
                            }
727
                        } catch (NoninvertibleTransformException ex) {
728
                        }
729
                        statusBar.setWidth(dim.width);
730
                        statusBar.setHeight(dim.height);
731
                    }
732
                }
733
            });
734
487
735
        locationBar.addActionListener(new AbstractAction() {
488
	/**
736
            public void actionPerformed(ActionEvent e) {
489
	 * The transform dialog
737
                String st = locationBar.getText().trim();
490
	 */
738
                int i = st.indexOf( '#' );
491
	protected JAffineTransformChooser.Dialog transformDialog;
739
                String t = "";
740
                if (i != -1) {
741
                    t = st.substring(i + 1);
742
                    st = st.substring(0, i);
743
                }
744
492
745
                if (st.equals(""))
493
	/**
746
                    return;
494
	 * The location bar.
495
	 */
496
	protected LocationBar locationBar;
747
497
748
                try{
498
	/**
749
                    File f = new File(st);
499
	 * The status bar.
750
                    if (f.exists()) {
500
	 */
751
                        if (f.isDirectory()) {
501
	protected StatusBar statusBar;
752
                            return;
753
                        } else {
754
                            try {
755
                                st = f.getCanonicalPath();
756
                                if (st.startsWith("/")) {
757
                                    st = "file:" + st;
758
                                } else {
759
                                    st = "file:/" + st;
760
                                }
761
                            } catch (IOException ex) {
762
                            }
763
                        }
764
                    }
765
                }catch(SecurityException se){
766
                    // Could not patch the file URI for security
767
                    // reasons (e.g., when run as an unsigned
768
                    // JavaWebStart jar): file access is not
769
                    // allowed. Loading will fail, but there is
770
                    // nothing more to do at this point.
771
                }
772
502
773
                String fi = svgCanvas.getFragmentIdentifier();
503
	/**
774
                if (svgDocument != null) {
504
	 * The initial frame title.
775
                    ParsedURL docPURL
505
	 */
776
                        = new ParsedURL(svgDocument.getURL());
506
	protected String title;
777
                    ParsedURL purl = new ParsedURL(docPURL, st);
778
                    fi = (fi == null) ? "" : fi;
779
                    if (docPURL.equals(purl) && t.equals(fi)) {
780
                        return;
781
                    }
782
                }
783
                if (t.length() != 0) {
784
                    st += '#' + t;
785
                }
786
                locationBar.setText(st);
787
                locationBar.addToHistory(st);
788
                showSVGDocument(st);
789
            }
790
        });
791
    }
792
507
793
    /**
508
	/**
794
     * Call dispose on canvas as well.
509
	 * The local history.
795
     */
510
	 */
796
    public void dispose() {
511
	protected LocalHistory localHistory;
797
        hideDebugger();
798
        svgCanvas.dispose();
799
        super.dispose();
800
    }
801
512
802
    /**
513
	/**
803
     * Whether to show the debug traces.
514
	 * The transform history.
804
     */
515
	 */
805
    public void setDebug(boolean b) {
516
	protected TransformHistory transformHistory = new TransformHistory();
806
        debug = b;
807
    }
808
517
809
    /**
518
	/**
810
     * Whether to auto adjust the canvas to the size of the document.
519
	 * The alternate style-sheet title.
811
     */
520
	 */
812
    public void setAutoAdjust(boolean b) {
521
	protected String alternateStyleSheet;
813
        autoAdjust = b;
814
    }
815
522
816
    /**
523
	/**
817
     * Returns the main JSVGCanvas of this frame.
524
	 * The debugger object.
818
     */
525
	 */
819
    public JSVGCanvas getJSVGCanvas() {
526
	protected Debugger debugger;
820
        return svgCanvas;
821
    }
822
527
823
    /**
528
	/**
824
     * Needed to work-around JFileChooser bug with abstract Files
529
	 * Creates a new SVG viewer frame.
825
     */
530
	 */
826
    private static File makeAbsolute(File f){
531
	public JSVGViewerFrame(Application app) {
827
        if(!f.isAbsolute()){
532
		application = app;
828
            return f.getAbsoluteFile();
829
        }
830
        return f;
831
    }
832
533
833
    /**
534
		addWindowListener(new WindowAdapter() {
834
     * Shows the Rhino debugger.
535
			public void windowClosing(WindowEvent e) {
835
     */
536
				application.closeJSVGViewerFrame(JSVGViewerFrame.this);
836
    public void showDebugger() {
537
			}
837
        if (debugger == null && Debugger.isPresent) {
538
		});
838
            debugger = new Debugger(this, locationBar.getText());
839
            debugger.initialize();
840
        }
841
    }
842
539
843
    /**
540
		//
844
     * Hides and destroys the Rhino debugger.
541
		// Set the frame's maximum size so that content
845
     */
542
		// bigger than the screen does not cause the creation
846
    public void hideDebugger() {
543
		// of unnecessary large images.
847
        if (debugger != null) {
544
		//
848
            debugger.clearAllBreakpoints();
545
		svgCanvas = new Canvas(userAgent, true, true) {
849
            debugger.go();
546
			Dimension screenSize;
850
            debugger.dispose();
851
            debugger = null;
852
        }
853
    }
854
547
855
    /**
548
			{
856
     * Rhino debugger class.
549
				screenSize = Toolkit.getDefaultToolkit().getScreenSize();
857
     */
550
				setMaximumSize(screenSize);
858
    protected static class Debugger {
551
			}
859
552
860
        /**
553
			public Dimension getPreferredSize() {
861
         * Whether the Rhino debugger classes are present.
554
				Dimension s = super.getPreferredSize();
862
         */
555
				if (s.width > screenSize.width)
863
        protected static boolean isPresent;
556
					s.width = screenSize.width;
557
				if (s.height > screenSize.height)
558
					s.height = screenSize.height;
559
				return s;
560
			}
864
561
865
        /**
562
			/**
866
         * The Rhino debugger class.
563
			 * This method is called when the component knows the desired size
867
         */
564
			 * of the window (based on width/height of outermost SVG element).
868
        protected static Class debuggerClass;
565
			 * We override it to immediately pack this frame.
566
			 */
567
			public void setMySize(Dimension d) {
568
				setPreferredSize(d);
569
				invalidate();
570
				if (JSVGViewerFrame.this.autoAdjust) {
571
					Platform.unmaximize(JSVGViewerFrame.this);
572
					JSVGViewerFrame.this.pack();
573
				}
574
			}
869
575
870
        /**
576
			public void setDisableInteractions(boolean b) {
871
         * The Rhino ContextFactory class.
577
				super.setDisableInteractions(b);
872
         */
873
        protected static Class contextFactoryClass;
874
578
875
        // Indexes into the debuggerMethods array.
579
				// Disable/Enable all our different ways to adjust the
876
        protected static final int CLEAR_ALL_BREAKPOINTS_METHOD = 0;
580
				// rendering transform (menus, toolbar, thumbnail, keyboard).
877
        protected static final int GO_METHOD                    = 1;
878
        protected static final int SET_EXIT_ACTION_METHOD       = 2;
879
        protected static final int ATTACH_TO_METHOD             = 3;
880
        protected static final int DETACH_METHOD                = 4;
881
        protected static final int DISPOSE_METHOD               = 5;
882
        protected static final int GET_DEBUG_FRAME_METHOD       = 6;
883
581
884
        /**
582
				((Action) listeners.get(SET_TRANSFORM_ACTION)).setEnabled(!b);
885
         * Rhino debugger class constructor.
886
         */
887
        protected static Constructor debuggerConstructor;
888
583
889
        /**
584
				if (thumbnailDialog != null)
890
         * Rhino debugger class methods.
585
					thumbnailDialog.setInteractionEnabled(!b);
891
         */
586
			}
892
        protected static Method[] debuggerMethods;
587
		};
893
588
894
        /**
589
		javax.swing.ActionMap map = svgCanvas.getActionMap();
895
         * The RhinoInterpreter class.
590
		map.put(FULL_SCREEN_ACTION, new FullScreenAction());
896
         */
591
		javax.swing.InputMap imap = svgCanvas
897
        protected static Class rhinoInterpreterClass;
592
				.getInputMap(JComponent.WHEN_FOCUSED);
593
		KeyStroke key = KeyStroke.getKeyStroke(KeyEvent.VK_F11, 0);
594
		imap.put(key, FULL_SCREEN_ACTION);
898
595
899
        /**
596
		svgCanvas.setDoubleBufferedRendering(true);
900
         * The {@code getContextFactory} method on the {@link
901
         * org.apache.batik.script.rhino.RhinoInterpreter} class.
902
         */
903
        protected static Method getContextFactoryMethod;
904
597
905
        static {
598
		listeners.put(ABOUT_ACTION, new AboutAction());
906
            try {
599
		listeners.put(OPEN_ACTION, new OpenAction());
907
                Class dc =
600
		listeners.put(OPEN_LOCATION_ACTION, new OpenLocationAction());
908
                    Class.forName("org.mozilla.javascript.tools.debugger.Main");
601
		listeners.put(NEW_WINDOW_ACTION, new NewWindowAction());
909
                Class cfc =
602
		listeners.put(RELOAD_ACTION, new ReloadAction());
910
                    Class.forName("org.mozilla.javascript.ContextFactory");
603
		listeners.put(SAVE_AS_ACTION, new SaveAsAction());
911
                rhinoInterpreterClass = Class.forName
604
		listeners.put(BACK_ACTION, backAction);
912
                    ("org.apache.batik.script.rhino.RhinoInterpreter");
605
		listeners.put(FORWARD_ACTION, forwardAction);
913
                debuggerConstructor =
606
		listeners.put(PRINT_ACTION, new PrintAction());
914
                    dc.getConstructor(new Class[] { String.class });
607
		listeners.put(EXPORT_AS_JPG_ACTION, new ExportAsJPGAction());
915
                debuggerMethods = new Method[] {
608
		listeners.put(EXPORT_AS_PNG_ACTION, new ExportAsPNGAction());
916
                    dc.getMethod("clearAllBreakpoints", (Class[]) null),
609
		listeners.put(EXPORT_AS_TIFF_ACTION, new ExportAsTIFFAction());
917
                    dc.getMethod("go", (Class[]) null),
610
		listeners.put(PREFERENCES_ACTION, new PreferencesAction());
918
                    dc.getMethod("setExitAction", new Class[] {Runnable.class}),
611
		listeners.put(CLOSE_ACTION, new CloseAction());
919
                    dc.getMethod("attachTo", new Class[] { cfc }),
612
		listeners.put(EXIT_ACTION, application.createExitAction(this));
920
                    dc.getMethod("detach", (Class[]) null),
613
		listeners.put(VIEW_SOURCE_ACTION, new ViewSourceAction());
921
                    dc.getMethod("dispose", (Class[]) null),
922
                    dc.getMethod("getDebugFrame", (Class[]) null)
923
                };
924
                getContextFactoryMethod =
925
                    rhinoInterpreterClass.getMethod("getContextFactory",
926
                                                    (Class[]) null);
927
                debuggerClass = dc;
928
                isPresent = true;
929
            } catch (ClassNotFoundException cnfe) {
930
            } catch (NoSuchMethodException nsme) {
931
            } catch (SecurityException se) {
932
            }
933
        }
934
614
935
        /**
615
		javax.swing.ActionMap cMap = svgCanvas.getActionMap();
936
         * The Rhino debugger instance.
616
		listeners.put(RESET_TRANSFORM_ACTION, cMap
937
         */
617
				.get(JSVGCanvas.RESET_TRANSFORM_ACTION));
938
        protected Object debuggerInstance;
618
		listeners.put(ZOOM_IN_ACTION, cMap.get(JSVGCanvas.ZOOM_IN_ACTION));
619
		listeners.put(ZOOM_OUT_ACTION, cMap.get(JSVGCanvas.ZOOM_OUT_ACTION));
939
620
940
        /**
621
		listeners.put(PREVIOUS_TRANSFORM_ACTION, previousTransformAction);
941
         * The JSVGViewerFrame.
622
		key = KeyStroke.getKeyStroke(KeyEvent.VK_K, KeyEvent.CTRL_MASK);
942
         */
623
		imap.put(key, previousTransformAction);
943
        protected JSVGViewerFrame svgFrame;
944
624
945
        /**
625
		listeners.put(NEXT_TRANSFORM_ACTION, nextTransformAction);
946
         * Creates a new Debugger.
626
		key = KeyStroke.getKeyStroke(KeyEvent.VK_L, KeyEvent.CTRL_MASK);
947
         */
627
		imap.put(key, nextTransformAction);
948
        public Debugger(JSVGViewerFrame frame, String url) {
949
            svgFrame = frame;
950
            try {
951
                debuggerInstance = debuggerConstructor.newInstance
952
                    (new Object[] { "JavaScript Debugger - " + url });
953
            } catch (IllegalAccessException iae) {
954
                throw new RuntimeException(iae.getMessage());
955
            } catch (InvocationTargetException ite) {
956
                ite.printStackTrace();
957
                throw new RuntimeException(ite.getMessage());
958
            } catch (InstantiationException ie) {
959
                throw new RuntimeException(ie.getMessage());
960
            }
961
        }
962
628
963
        /**
629
		listeners.put(USE_STYLESHEET_ACTION, useStylesheetAction);
964
         * Sets the document URL to use in the window title.
630
		listeners.put(PLAY_ACTION, playAction);
965
         */
631
		listeners.put(PAUSE_ACTION, pauseAction);
966
        public void setDocumentURL(String url) {
632
		listeners.put(STOP_ACTION, stopAction);
967
            getDebugFrame().setTitle("JavaScript Debugger - " + url);
633
		listeners.put(MONITOR_ACTION, new MonitorAction());
968
        }
634
		listeners.put(DOM_VIEWER_ACTION, new DOMViewerAction());
635
		listeners.put(TIMELINE_VIEWER_ACTION, new TimelineViewerAction());
636
		listeners.put(SET_TRANSFORM_ACTION, new SetTransformAction());
637
		listeners.put(FIND_DIALOG_ACTION, new FindDialogAction());
638
		listeners.put(THUMBNAIL_DIALOG_ACTION, new ThumbnailDialogAction());
639
		listeners.put(FLUSH_ACTION, new FlushAction());
640
		listeners.put(TOGGLE_DEBUGGER_ACTION, new ToggleDebuggerAction());
969
641
970
        /**
642
		JPanel p = null;
971
         * Initializes the debugger by massaging the GUI and attaching it
643
		try {
972
         * to the Rhino interpreter's {@link
644
			// Create the menu
973
         * org.mozilla.javascript.ContextFactory}.
645
			MenuFactory mf = new MenuFactory(bundle, this);
974
         */
646
			JMenuBar mb = mf.createJMenuBar("MenuBar", application
975
        public void initialize() {
647
					.getUISpecialization());
976
            // Customize the menubar a bit, disable menu
648
			setJMenuBar(mb);
977
            // items that can't be used and change 'Exit' to 'Close'.
978
            JFrame   debugGui = getDebugFrame();
979
            JMenuBar menuBar  = debugGui.getJMenuBar();
980
            JMenu    menu     = menuBar.getMenu(0);
981
            menu.getItem(0).setEnabled(false); // Open...
982
            menu.getItem(1).setEnabled(false); // Run...
983
            menu.getItem(3).setText
984
                (Resources.getString("Close.text")); // Exit -> "Close"
985
            menu.getItem(3).setAccelerator
986
                (KeyStroke.getKeyStroke(KeyEvent.VK_W, Event.CTRL_MASK));
987
649
988
            debugGui.setSize(600, 460);
650
			localHistory = new LocalHistory(mb, this);
989
            debugGui.pack();
990
            setExitAction(new Runnable() {
991
                    public void run() {
992
                        svgFrame.hideDebugger();
993
                    }});
994
            WindowAdapter wa = new WindowAdapter() {
995
                    public void windowClosing(WindowEvent e) {
996
                        svgFrame.hideDebugger();
997
                    }};
998
            debugGui.addWindowListener(wa);
999
            debugGui.setVisible(true);
1000
            attach();
1001
        }
1002
651
1003
        /**
652
			String[] uri = application.getVisitedURIs();
1004
         * Attaches the debugger to the canvas' current interpreter.
653
			for (int i = 0; i < uri.length; i++) {
1005
         */
654
				if (uri[i] != null && !"".equals(uri[i])) {
1006
        public void attach() {
655
					localHistory.update(uri[i]);
1007
            Object interpreter = svgFrame.svgCanvas.getRhinoInterpreter();
656
				}
1008
            if (interpreter != null) {
657
			}
1009
                attachTo(getContextFactory(interpreter));
658
			p = new JPanel(new BorderLayout());
1010
            }
1011
        }
1012
659
1013
        /**
660
			// Create the toolbar
1014
         * Calls {@code getDebugFrame} on {@link #debuggerInstance}.
661
			ToolBarFactory tbf = new ToolBarFactory(bundle, this);
1015
         */
662
			JToolBar tb = tbf.createJToolBar("ToolBar");
1016
        protected JFrame getDebugFrame() {
663
			tb.setFloatable(false);
1017
            try {
664
			getContentPane().add(p, BorderLayout.NORTH);
1018
                return (JFrame) debuggerMethods[GET_DEBUG_FRAME_METHOD].invoke
665
			p.add(tb, BorderLayout.NORTH);
1019
                    (debuggerInstance, (Object[]) null);
666
			p.add(new javax.swing.JSeparator(), BorderLayout.CENTER);
1020
            } catch (InvocationTargetException ite) {
667
			p.add(locationBar = new LocationBar(), BorderLayout.SOUTH);
1021
                throw new RuntimeException(ite.getMessage());
668
			locationBar.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
1022
            } catch (IllegalAccessException iae) {
1023
                throw new RuntimeException(iae.getMessage());
1024
            }
1025
        }
1026
669
1027
        /**
670
		} catch (MissingResourceException e) {
1028
         * Calls {@code setExitAction} on {@link #debuggerInstance}.
671
			System.out.println(e.getMessage());
1029
         */
672
			System.exit(0);
1030
        protected void setExitAction(Runnable r) {
673
		}
1031
            try {
1032
                debuggerMethods[SET_EXIT_ACTION_METHOD].invoke
1033
                    (debuggerInstance, new Object[] { r });
1034
            } catch (InvocationTargetException ite) {
1035
                throw new RuntimeException(ite.getMessage());
1036
            } catch (IllegalAccessException iae) {
1037
                throw new RuntimeException(iae.getMessage());
1038
            }
1039
        }
1040
674
1041
        /**
675
		svgCanvasPanel = new JPanel(new BorderLayout());
1042
         * Calls {@code attachTo} on {@link #debuggerInstance}.
676
		svgCanvasPanel.setBorder(BorderFactory.createEtchedBorder());
1043
         */
1044
        public void attachTo(Object contextFactory) {
1045
            try {
1046
                debuggerMethods[ATTACH_TO_METHOD].invoke
1047
                    (debuggerInstance, new Object[] { contextFactory });
1048
            } catch (InvocationTargetException ite) {
1049
                throw new RuntimeException(ite.getMessage());
1050
            } catch (IllegalAccessException iae) {
1051
                throw new RuntimeException(iae.getMessage());
1052
            }
1053
        }
1054
677
1055
        /**
678
		svgCanvasPanel.add(svgCanvas, BorderLayout.CENTER);
1056
         * Calls {@code detach} on {@link #debuggerInstance}.
679
		p = new JPanel(new BorderLayout());
1057
         */
680
		p.add(svgCanvasPanel, BorderLayout.CENTER);
1058
        public void detach() {
681
		p.add(statusBar = new StatusBar(), BorderLayout.SOUTH);
1059
            try {
1060
                debuggerMethods[DETACH_METHOD].invoke(debuggerInstance,
1061
                                                      (Object[]) null);
1062
            } catch (InvocationTargetException ite) {
1063
                throw new RuntimeException(ite.getMessage());
1064
            } catch (IllegalAccessException iae) {
1065
                throw new RuntimeException(iae.getMessage());
1066
            }
1067
        }
1068
682
1069
        /**
683
		getContentPane().add(p, BorderLayout.CENTER);
1070
         * Calls {@code go} on {@link #debuggerInstance}.
1071
         */
1072
        public void go() {
1073
            try {
1074
                debuggerMethods[GO_METHOD].invoke(debuggerInstance,
1075
                                                  (Object[]) null);
1076
            } catch (InvocationTargetException ite) {
1077
                throw new RuntimeException(ite.getMessage());
1078
            } catch (IllegalAccessException iae) {
1079
                throw new RuntimeException(iae.getMessage());
1080
            }
1081
        }
1082
684
1083
        /**
685
		svgCanvas.addSVGDocumentLoaderListener(this);
1084
         * Calls {@code clearAllBreakpoints} on {@link #debuggerInstance}.
686
		svgCanvas.addGVTTreeBuilderListener(this);
1085
         */
687
		svgCanvas.addSVGLoadEventDispatcherListener(this);
1086
        public void clearAllBreakpoints() {
688
		svgCanvas.addGVTTreeRendererListener(this);
1087
            try {
689
		svgCanvas.addLinkActivationListener(this);
1088
                debuggerMethods[CLEAR_ALL_BREAKPOINTS_METHOD].invoke
690
		svgCanvas.addUpdateManagerListener(this);
1089
                    (debuggerInstance, (Object[]) null);
1090
            } catch (InvocationTargetException ite) {
1091
                throw new RuntimeException(ite.getMessage());
1092
            } catch (IllegalAccessException iae) {
1093
                throw new RuntimeException(iae.getMessage());
1094
            }
1095
        }
1096
691
1097
        /**
692
		svgCanvas.addMouseMotionListener(new MouseMotionAdapter() {
1098
         * Calls {@code dispose} on {@link #debuggerInstance}.
693
			public void mouseMoved(MouseEvent e) {
1099
         */
694
				if (svgDocument == null) {
1100
        public void dispose() {
695
					statusBar.setXPosition(e.getX());
1101
            try {
696
					statusBar.setYPosition(e.getY());
1102
                debuggerMethods[DISPOSE_METHOD].invoke(debuggerInstance,
697
				} else {
1103
                                                       (Object[]) null);
698
					try {
1104
            } catch (InvocationTargetException ite) {
699
						AffineTransform at;
1105
                throw new RuntimeException(ite.getMessage());
700
						at = svgCanvas.getViewBoxTransform();
1106
            } catch (IllegalAccessException iae) {
701
						if (at != null) {
1107
                throw new RuntimeException(iae.getMessage());
702
							at = at.createInverse();
1108
            }
703
							Point2D p2d = at.transform(new Point2D.Float(e
1109
        }
704
									.getX(), e.getY()), null);
705
							statusBar.setXPosition((float) p2d.getX());
706
							statusBar.setYPosition((float) p2d.getY());
707
							return;
708
						}
709
					} catch (NoninvertibleTransformException ex) {
710
					}
711
					statusBar.setXPosition(e.getX());
712
					statusBar.setYPosition(e.getY());
713
				}
714
			}
715
		});
716
		svgCanvas.addMouseListener(new MouseAdapter() {
717
			public void mouseExited(MouseEvent e) {
718
				Dimension dim = svgCanvas.getSize();
719
				if (svgDocument == null) {
720
					statusBar.setWidth(dim.width);
721
					statusBar.setHeight(dim.height);
722
				} else {
723
					try {
724
						AffineTransform at;
725
						at = svgCanvas.getViewBoxTransform();
726
						if (at != null) {
727
							at = at.createInverse();
728
							Point2D o = at.transform(new Point2D.Float(0, 0),
729
									null);
730
							Point2D p2d = at.transform(new Point2D.Float(
731
									dim.width, dim.height), null);
732
							statusBar.setWidth((float) (p2d.getX() - o.getX()));
733
							statusBar
734
									.setHeight((float) (p2d.getY() - o.getY()));
735
							return;
736
						}
737
					} catch (NoninvertibleTransformException ex) {
738
					}
739
					statusBar.setWidth(dim.width);
740
					statusBar.setHeight(dim.height);
741
				}
742
			}
743
		});
744
		svgCanvas.addComponentListener(new ComponentAdapter() {
745
			public void componentResized(ComponentEvent e) {
746
				Dimension dim = svgCanvas.getSize();
747
				if (svgDocument == null) {
748
					statusBar.setWidth(dim.width);
749
					statusBar.setHeight(dim.height);
750
				} else {
751
					try {
752
						AffineTransform at;
753
						at = svgCanvas.getViewBoxTransform();
754
						if (at != null) {
755
							at = at.createInverse();
756
							Point2D o = at.transform(new Point2D.Float(0, 0),
757
									null);
758
							Point2D p2d = at.transform(new Point2D.Float(
759
									dim.width, dim.height), null);
760
							statusBar.setWidth((float) (p2d.getX() - o.getX()));
761
							statusBar
762
									.setHeight((float) (p2d.getY() - o.getY()));
763
							return;
764
						}
765
					} catch (NoninvertibleTransformException ex) {
766
					}
767
					statusBar.setWidth(dim.width);
768
					statusBar.setHeight(dim.height);
769
				}
770
			}
771
		});
1110
772
1111
        /**
773
		locationBar.addActionListener(new AbstractAction() {
1112
         * Calls {@code getContextFactory} on the given instance of
774
			public void actionPerformed(ActionEvent e) {
1113
         * {@link org.apache.batik.script.rhino.RhinoInterpreter}.
775
				String st = locationBar.getText().trim();
1114
         */
776
				int i = st.indexOf('#');
1115
        protected Object getContextFactory(Object rhinoInterpreter) {
777
				String t = "";
1116
            try {
778
				if (i != -1) {
1117
                return getContextFactoryMethod.invoke(rhinoInterpreter,
779
					t = st.substring(i + 1);
1118
                                                      (Object[]) null);
780
					st = st.substring(0, i);
1119
            } catch (InvocationTargetException ite) {
781
				}
1120
                throw new RuntimeException(ite.getMessage());
1121
            } catch (IllegalAccessException iae) {
1122
                throw new RuntimeException(iae.getMessage());
1123
            }
1124
        }
1125
    }
1126
782
1127
    /**
783
				if (st.equals(""))
1128
     * To show the about dialog
784
					return;
1129
     */
1130
    public class AboutAction extends AbstractAction {
1131
        public AboutAction(){
1132
        }
1133
785
1134
        public void actionPerformed(ActionEvent e){
786
				try {
1135
            AboutDialog dlg = new AboutDialog(JSVGViewerFrame.this);
787
					File f = new File(st);
1136
            // Work around pack() bug on some platforms
788
					if (f.exists()) {
1137
            dlg.setSize(dlg.getPreferredSize());
789
						if (f.isDirectory()) {
1138
            dlg.setLocationRelativeTo(JSVGViewerFrame.this);
790
							return;
1139
            dlg.setVisible(true);
791
						} else {
1140
            dlg.toFront();
792
							try {
1141
        }
793
								st = f.getCanonicalPath();
1142
    }
794
								if (st.startsWith("/")) {
795
									st = "file:" + st;
796
								} else {
797
									st = "file:/" + st;
798
								}
799
							} catch (IOException ex) {
800
							}
801
						}
802
					}
803
				} catch (SecurityException se) {
804
					// Could not patch the file URI for security
805
					// reasons (e.g., when run as an unsigned
806
					// JavaWebStart jar): file access is not
807
					// allowed. Loading will fail, but there is
808
					// nothing more to do at this point.
809
				}
1143
810
1144
    /**
811
				String fi = svgCanvas.getFragmentIdentifier();
1145
     * To open a new file.
812
				if (svgDocument != null) {
1146
     */
813
					ParsedURL docPURL = new ParsedURL(svgDocument.getURL());
1147
    public class OpenAction extends AbstractAction {
814
					ParsedURL purl = new ParsedURL(docPURL, st);
815
					fi = (fi == null) ? "" : fi;
816
					if (docPURL.equals(purl) && t.equals(fi)) {
817
						return;
818
					}
819
				}
820
				if (t.length() != 0) {
821
					st += '#' + t;
822
				}
823
				locationBar.setText(st);
824
				locationBar.addToHistory(st);
825
				showSVGDocument(st);
826
			}
827
		});
828
	}
1148
829
1149
        public OpenAction() {
830
	/**
1150
        }
831
	 * Call dispose on canvas as well.
1151
        public void actionPerformed(ActionEvent e) {
832
	 */
1152
            File f = null;
833
	public void dispose() {
1153
            if (Platform.isOSX) {
834
		hideDebugger();
1154
                FileDialog fileDialog =
835
		svgCanvas.dispose();
1155
                    new FileDialog(JSVGViewerFrame.this,
836
		super.dispose();
1156
                                   Resources.getString(OPEN_TITLE));
837
	}
1157
                fileDialog.setFilenameFilter(new FilenameFilter() {
1158
                    public boolean accept(File dir, String name) {
1159
                        Iterator iter = getHandlers().iterator();
1160
                        while (iter.hasNext()) {
1161
                            SquiggleInputHandler handler
1162
                                = (SquiggleInputHandler)iter.next();
1163
                            if (handler.accept(new File(dir, name))) {
1164
                                return true;
1165
                            }
1166
                        }
1167
                        return false;
1168
                    }
1169
                });
1170
                fileDialog.setVisible(true);
1171
                String filename = fileDialog.getFile();
1172
                if (fileDialog != null) {
1173
                    String dirname = fileDialog.getDirectory();
1174
                    f = new File(dirname, filename);
1175
                }
1176
            } else {
1177
                JFileChooser fileChooser = null;
1178
838
1179
                // Apply work around Windows problem when security is enabled,
839
	/**
1180
                // and when prior to JDK 1.4.
840
	 * Whether to show the debug traces.
1181
                String os = System.getProperty(PROPERTY_OS_NAME, PROPERTY_OS_NAME_DEFAULT);
841
	 */
1182
                SecurityManager sm = System.getSecurityManager();
842
	public void setDebug(boolean b) {
843
		debug = b;
844
	}
1183
845
1184
                if ( priorJDK1_4 && sm != null && os.indexOf(PROPERTY_OS_WINDOWS_PREFIX) != -1 ){
846
	/**
1185
                    fileChooser = new JFileChooser(makeAbsolute(currentPath),
847
	 * Whether to auto adjust the canvas to the size of the document.
1186
                                                   new WindowsAltFileSystemView());
848
	 */
1187
                } else {
849
	public void setAutoAdjust(boolean b) {
1188
                    fileChooser = new JFileChooser(makeAbsolute(currentPath));
850
		autoAdjust = b;
1189
                }
851
	}
1190
852
1191
                fileChooser.setFileHidingEnabled(false);
853
	/**
1192
                fileChooser.setFileSelectionMode
854
	 * Returns the main JSVGCanvas of this frame.
1193
                    (JFileChooser.FILES_ONLY);
855
	 */
856
	public JSVGCanvas getJSVGCanvas() {
857
		return svgCanvas;
858
	}
1194
859
1195
                //
860
	/**
1196
                // Add file filters from the handlers map
861
	 * Needed to work-around JFileChooser bug with abstract Files
1197
                //
862
	 */
1198
                Iterator iter = getHandlers().iterator();
863
	private static File makeAbsolute(File f) {
1199
                while (iter.hasNext()) {
864
		if (!f.isAbsolute()) {
1200
                    SquiggleInputHandler handler
865
			return f.getAbsoluteFile();
1201
                        = (SquiggleInputHandler)iter.next();
866
		}
1202
                    fileChooser.addChoosableFileFilter
867
		return f;
1203
                        (new SquiggleInputHandlerFilter(handler));
868
	}
1204
                }
1205
869
1206
                int choice = fileChooser.showOpenDialog(JSVGViewerFrame.this);
870
	/**
1207
                if (choice == JFileChooser.APPROVE_OPTION) {
871
	 * Shows the Rhino debugger.
1208
                    f = fileChooser.getSelectedFile();
872
	 */
1209
                    currentPath = f;
873
	public void showDebugger() {
1210
                }
874
		if (debugger == null && Debugger.isPresent) {
1211
            }
875
			debugger = new Debugger(this, locationBar.getText());
876
			debugger.initialize();
877
		}
878
	}
1212
879
1213
            if (f != null) {
880
	/**
1214
                try {
881
	 * Hides and destroys the Rhino debugger.
1215
                    String furl = f.toURL().toString();
882
	 */
1216
                    showSVGDocument(furl);
883
	public void hideDebugger() {
1217
                } catch (MalformedURLException ex) {
884
		if (debugger != null) {
1218
                    if (userAgent != null) {
885
			debugger.clearAllBreakpoints();
1219
                        userAgent.displayError(ex);
886
			debugger.go();
1220
                    }
887
			debugger.dispose();
1221
                }
888
			debugger = null;
1222
            }
889
		}
1223
        }
890
	}
1224
    }
1225
891
1226
    /**
892
	/**
1227
     * Shows the given document into the viewer frame
893
	 * Rhino debugger class.
1228
     */
894
	 */
1229
    public void showSVGDocument(String uri){
895
	protected static class Debugger {
1230
        try {
1231
            ParsedURL purl = new ParsedURL(uri);
1232
            SquiggleInputHandler
1233
                handler = getInputHandler(purl);
1234
896
1235
            handler.handle(purl,
897
		/**
1236
                           JSVGViewerFrame.this);
898
		 * Whether the Rhino debugger classes are present.
1237
        } catch (Exception e) {
899
		 */
1238
            if (userAgent != null) {
900
		protected static boolean isPresent;
1239
                userAgent.displayError(e);
1240
            }
1241
        }
1242
901
1243
    }
902
		/**
903
		 * The Rhino debugger class.
904
		 */
905
		protected static Class debuggerClass;
1244
906
1245
    /**
907
		/**
1246
     * Returns the input handler for the given URI
908
		 * The Rhino ContextFactory class.
1247
     */
909
		 */
1248
    public SquiggleInputHandler getInputHandler(ParsedURL purl) throws IOException {
910
		protected static Class contextFactoryClass;
1249
        Iterator iter = getHandlers().iterator();
1250
        SquiggleInputHandler handler = null;
1251
911
1252
        while (iter.hasNext()) {
912
		// Indexes into the debuggerMethods array.
1253
            SquiggleInputHandler curHandler =
913
		protected static final int CLEAR_ALL_BREAKPOINTS_METHOD = 0;
1254
                (SquiggleInputHandler)iter.next();
1255
            if (curHandler.accept(purl)) {
1256
                handler = curHandler;
1257
                break;
1258
            }
1259
        }
1260
914
1261
        // No handler found, use the default one.
915
		protected static final int GO_METHOD = 1;
1262
        if (handler == null) {
1263
            handler = defaultHandler;
1264
        }
1265
916
1266
        return handler;
917
		protected static final int SET_EXIT_ACTION_METHOD = 2;
1267
    }
1268
918
919
		protected static final int ATTACH_TO_METHOD = 3;
1269
920
1270
    /**
921
		protected static final int DETACH_METHOD = 4;
1271
     * Returns the list of input file handler.
1272
     */
1273
    protected static Vector getHandlers() {
1274
        if (handlers != null) {
1275
            return handlers;
1276
        }
1277
922
1278
        handlers = new Vector();
923
		protected static final int DISPOSE_METHOD = 5;
1279
        registerHandler(new SVGInputHandler());
1280
924
1281
        Iterator iter = Service.providers(SquiggleInputHandler.class);
925
		protected static final int GET_DEBUG_FRAME_METHOD = 6;
1282
        while (iter.hasNext()) {
1283
            SquiggleInputHandler handler
1284
                = (SquiggleInputHandler)iter.next();
1285
926
1286
            registerHandler(handler);
927
		/**
1287
        }
928
		 * Rhino debugger class constructor.
929
		 */
930
		protected static Constructor debuggerConstructor;
1288
931
1289
        return handlers;
932
		/**
1290
    }
933
		 * Rhino debugger class methods.
934
		 */
935
		protected static Method[] debuggerMethods;
1291
936
1292
    /**
937
		/**
1293
     * Registers an input file handler by adding it to the handlers map.
938
		 * The RhinoInterpreter class.
1294
     * @param handler the new input handler to register.
939
		 */
1295
     */
940
		protected static Class rhinoInterpreterClass;
1296
    public static synchronized
1297
        void registerHandler(SquiggleInputHandler handler) {
1298
        Vector handlers = getHandlers();
1299
        handlers.addElement(handler);
1300
    }
1301
941
1302
    /**
942
		/**
1303
     * To open a new document.
943
		 * The {@code getContextFactory} method on the {@link
1304
     */
944
		 * org.apache.batik.script.rhino.RhinoInterpreter} class.
1305
    public class OpenLocationAction extends AbstractAction {
945
		 */
1306
        public OpenLocationAction() {}
946
		protected static Method getContextFactoryMethod;
1307
        public void actionPerformed(ActionEvent e) {
1308
            if (uriChooser == null) {
1309
                uriChooser = new URIChooser(JSVGViewerFrame.this);
1310
                uriChooser.setFileFilter(new SVGFileFilter());
1311
                uriChooser.pack();
1312
                Rectangle fr = getBounds();
1313
                Dimension sd = uriChooser.getSize();
1314
                uriChooser.setLocation(fr.x + (fr.width  - sd.width) / 2,
1315
                                       fr.y + (fr.height - sd.height) / 2);
1316
            }
1317
            if (uriChooser.showDialog() == URIChooser.OK_OPTION) {
1318
                String s = uriChooser.getText();
1319
                if (s == null) return;
1320
                int i = s.indexOf( '#' );
1321
                String t = "";
1322
                if (i != -1) {
1323
                    t = s.substring(i + 1);
1324
                    s = s.substring(0, i);
1325
                }
1326
                if (!s.equals("")) {
1327
                    File f = new File(s);
1328
                    if (f.exists()) {
1329
                        if (f.isDirectory()) {
1330
                            s = null;
1331
                        } else {
1332
                            try {
1333
                                s = f.getCanonicalPath();
1334
                                if (s.startsWith("/")) {
1335
                                    s = "file:" + s;
1336
                                } else {
1337
                                    s = "file:/" + s;
1338
                                }
1339
                            } catch (IOException ex) {
1340
                            }
1341
                        }
1342
                    }
1343
                    if (s != null) {
1344
                        if (svgDocument != null) {
1345
                            ParsedURL docPURL
1346
                                = new ParsedURL(svgDocument.getURL());
1347
                            ParsedURL purl = new ParsedURL(docPURL, s);
1348
                            String fi = svgCanvas.getFragmentIdentifier();
1349
                            if (docPURL.equals(purl) && t.equals(fi)) {
1350
                                return;
1351
                            }
1352
                        }
1353
                        if (t.length() != 0) {
1354
                            s += '#' + t;
1355
                        }
1356
947
1357
                        showSVGDocument(s);
948
		static {
1358
                    }
949
			try {
1359
                }
950
				Class dc = Class
1360
            }
951
						.forName("org.mozilla.javascript.tools.debugger.Main");
1361
        }
952
				Class cfc = Class
1362
    }
953
						.forName("org.mozilla.javascript.ContextFactory");
954
				rhinoInterpreterClass = Class
955
						.forName("org.apache.batik.script.rhino.RhinoInterpreter");
956
				debuggerConstructor = dc
957
						.getConstructor(new Class[] { String.class });
958
				debuggerMethods = new Method[] {
959
						dc.getMethod("clearAllBreakpoints", (Class[]) null),
960
						dc.getMethod("go", (Class[]) null),
961
						dc.getMethod("setExitAction",
962
								new Class[] { Runnable.class }),
963
						dc.getMethod("attachTo", new Class[] { cfc }),
964
						dc.getMethod("detach", (Class[]) null),
965
						dc.getMethod("dispose", (Class[]) null),
966
						dc.getMethod("getDebugFrame", (Class[]) null) };
967
				getContextFactoryMethod = rhinoInterpreterClass.getMethod(
968
						"getContextFactory", (Class[]) null);
969
				debuggerClass = dc;
970
				isPresent = true;
971
			} catch (ClassNotFoundException cnfe) {
972
			} catch (NoSuchMethodException nsme) {
973
			} catch (SecurityException se) {
974
			}
975
		}
1363
976
1364
    /**
977
		/**
1365
     * To open a new window.
978
		 * The Rhino debugger instance.
1366
     */
979
		 */
1367
    public class NewWindowAction extends AbstractAction {
980
		protected Object debuggerInstance;
1368
        public NewWindowAction() {}
1369
        public void actionPerformed(ActionEvent e) {
1370
            JSVGViewerFrame vf = application.createAndShowJSVGViewerFrame();
1371
981
1372
            // Copy the current settings to the new window.
982
		/**
1373
            vf.autoAdjust = autoAdjust;
983
		 * The JSVGViewerFrame.
1374
            vf.debug = debug;
984
		 */
1375
            vf.svgCanvas.setProgressivePaint(svgCanvas.getProgressivePaint());
985
		protected JSVGViewerFrame svgFrame;
1376
            vf.svgCanvas.setDoubleBufferedRendering
1377
                (svgCanvas.getDoubleBufferedRendering());
1378
        }
1379
    }
1380
986
1381
    /**
987
		/**
1382
     * To show the preferences.
988
		 * Creates a new Debugger.
1383
     */
989
		 */
1384
    public class PreferencesAction extends AbstractAction {
990
		public Debugger(JSVGViewerFrame frame, String url) {
1385
        public PreferencesAction() {}
991
			svgFrame = frame;
1386
        public void actionPerformed(ActionEvent e) {
992
			try {
1387
            application.showPreferenceDialog(JSVGViewerFrame.this);
993
				debuggerInstance = debuggerConstructor
1388
        }
994
						.newInstance(new Object[] { "JavaScript Debugger - "
1389
    }
995
								+ url });
996
			} catch (IllegalAccessException iae) {
997
				throw new RuntimeException(iae.getMessage());
998
			} catch (InvocationTargetException ite) {
999
				ite.printStackTrace();
1000
				throw new RuntimeException(ite.getMessage());
1001
			} catch (InstantiationException ie) {
1002
				throw new RuntimeException(ie.getMessage());
1003
			}
1004
		}
1390
1005
1391
    /**
1006
		/**
1392
     * To close the last document.
1007
		 * Sets the document URL to use in the window title.
1393
     */
1008
		 */
1394
    public class CloseAction extends AbstractAction {
1009
		public void setDocumentURL(String url) {
1395
        public CloseAction() {}
1010
			getDebugFrame().setTitle("JavaScript Debugger - " + url);
1396
        public void actionPerformed(ActionEvent e) {
1011
		}
1397
            application.closeJSVGViewerFrame(JSVGViewerFrame.this);
1398
        }
1399
    }
1400
1012
1401
    /**
1013
		/**
1402
     * To reload the current document.
1014
		 * Initializes the debugger by massaging the GUI and attaching it to the
1403
     */
1015
		 * Rhino interpreter's {@link org.mozilla.javascript.ContextFactory}.
1404
    public class ReloadAction extends AbstractAction {
1016
		 */
1405
        public ReloadAction() {}
1017
		public void initialize() {
1406
        public void actionPerformed(ActionEvent e) {
1018
			// Customize the menubar a bit, disable menu
1407
            if ((e.getModifiers() & ActionEvent.SHIFT_MASK) == 1) {
1019
			// items that can't be used and change 'Exit' to 'Close'.
1408
                svgCanvas.flushImageCache();
1020
			JFrame debugGui = getDebugFrame();
1409
            }
1021
			JMenuBar menuBar = debugGui.getJMenuBar();
1410
            if (svgDocument != null) {
1022
			JMenu menu = menuBar.getMenu(0);
1411
                localHistory.reload();
1023
			menu.getItem(0).setEnabled(false); // Open...
1412
            }
1024
			menu.getItem(1).setEnabled(false); // Run...
1413
        }
1025
			menu.getItem(3).setText(Resources.getString("Close.text")); // Exit
1414
    }
1026
			// ->
1027
			// "Close"
1028
			menu.getItem(3).setAccelerator(
1029
					KeyStroke.getKeyStroke(KeyEvent.VK_W, Event.CTRL_MASK));
1415
1030
1416
    /**
1031
			debugGui.setSize(600, 460);
1417
     * To go back to the previous document
1032
			debugGui.pack();
1418
     */
1033
			setExitAction(new Runnable() {
1419
    public class BackAction extends    AbstractAction
1034
				public void run() {
1420
                            implements JComponentModifier {
1035
					svgFrame.hideDebugger();
1421
        List components = new LinkedList();
1036
				}
1422
        public BackAction() {}
1037
			});
1423
        public void actionPerformed(ActionEvent e) {
1038
			WindowAdapter wa = new WindowAdapter() {
1424
            if (localHistory.canGoBack()) {
1039
				public void windowClosing(WindowEvent e) {
1425
                localHistory.back();
1040
					svgFrame.hideDebugger();
1426
            }
1041
				}
1427
        }
1042
			};
1043
			debugGui.addWindowListener(wa);
1044
			debugGui.setVisible(true);
1045
			attach();
1046
		}
1428
1047
1429
        public void addJComponent(JComponent c) {
1048
		/**
1430
            components.add(c);
1049
		 * Attaches the debugger to the canvas' current interpreter.
1431
            c.setEnabled(false);
1050
		 */
1432
        }
1051
		public void attach() {
1052
			Object interpreter = svgFrame.svgCanvas.getRhinoInterpreter();
1053
			if (interpreter != null) {
1054
				attachTo(getContextFactory(interpreter));
1055
			}
1056
		}
1433
1057
1434
        protected void update() {
1058
		/**
1435
            boolean b = localHistory.canGoBack();
1059
		 * Calls {@code getDebugFrame} on {@link #debuggerInstance}.
1436
            Iterator it = components.iterator();
1060
		 */
1437
            while (it.hasNext()) {
1061
		protected JFrame getDebugFrame() {
1438
                ((JComponent)it.next()).setEnabled(b);
1062
			try {
1439
            }
1063
				return (JFrame) debuggerMethods[GET_DEBUG_FRAME_METHOD].invoke(
1440
        }
1064
						debuggerInstance, (Object[]) null);
1441
    }
1065
			} catch (InvocationTargetException ite) {
1066
				throw new RuntimeException(ite.getMessage());
1067
			} catch (IllegalAccessException iae) {
1068
				throw new RuntimeException(iae.getMessage());
1069
			}
1070
		}
1442
1071
1443
    /**
1072
		/**
1444
     * To go forward to the next document
1073
		 * Calls {@code setExitAction} on {@link #debuggerInstance}.
1445
     */
1074
		 */
1446
    public class ForwardAction extends    AbstractAction
1075
		protected void setExitAction(Runnable r) {
1447
                               implements JComponentModifier {
1076
			try {
1448
        List components = new LinkedList();
1077
				debuggerMethods[SET_EXIT_ACTION_METHOD].invoke(
1449
        public ForwardAction() {}
1078
						debuggerInstance, new Object[] { r });
1450
        public void actionPerformed(ActionEvent e) {
1079
			} catch (InvocationTargetException ite) {
1451
            if (localHistory.canGoForward()) {
1080
				throw new RuntimeException(ite.getMessage());
1452
                localHistory.forward();
1081
			} catch (IllegalAccessException iae) {
1453
            }
1082
				throw new RuntimeException(iae.getMessage());
1454
        }
1083
			}
1084
		}
1455
1085
1456
        public void addJComponent(JComponent c) {
1086
		/**
1457
            components.add(c);
1087
		 * Calls {@code attachTo} on {@link #debuggerInstance}.
1458
            c.setEnabled(false);
1088
		 */
1459
        }
1089
		public void attachTo(Object contextFactory) {
1090
			try {
1091
				debuggerMethods[ATTACH_TO_METHOD].invoke(debuggerInstance,
1092
						new Object[] { contextFactory });
1093
			} catch (InvocationTargetException ite) {
1094
				throw new RuntimeException(ite.getMessage());
1095
			} catch (IllegalAccessException iae) {
1096
				throw new RuntimeException(iae.getMessage());
1097
			}
1098
		}
1460
1099
1461
        protected void update() {
1100
		/**
1462
            boolean b = localHistory.canGoForward();
1101
		 * Calls {@code detach} on {@link #debuggerInstance}.
1463
            Iterator it = components.iterator();
1102
		 */
1464
            while (it.hasNext()) {
1103
		public void detach() {
1465
                ((JComponent)it.next()).setEnabled(b);
1104
			try {
1466
            }
1105
				debuggerMethods[DETACH_METHOD].invoke(debuggerInstance,
1467
        }
1106
						(Object[]) null);
1468
    }
1107
			} catch (InvocationTargetException ite) {
1108
				throw new RuntimeException(ite.getMessage());
1109
			} catch (IllegalAccessException iae) {
1110
				throw new RuntimeException(iae.getMessage());
1111
			}
1112
		}
1469
1113
1470
    /**
1114
		/**
1471
     * To print the current document.
1115
		 * Calls {@code go} on {@link #debuggerInstance}.
1472
     */
1116
		 */
1473
    public class PrintAction extends AbstractAction {
1117
		public void go() {
1474
        public PrintAction() {}
1118
			try {
1475
        public void actionPerformed(ActionEvent e) {
1119
				debuggerMethods[GO_METHOD].invoke(debuggerInstance,
1476
            if (svgDocument != null) {
1120
						(Object[]) null);
1477
                final SVGDocument doc = svgDocument;
1121
			} catch (InvocationTargetException ite) {
1478
                new Thread() {
1122
				throw new RuntimeException(ite.getMessage());
1479
                    public void run(){
1123
			} catch (IllegalAccessException iae) {
1480
                        String uri = doc.getURL();
1124
				throw new RuntimeException(iae.getMessage());
1481
                        String fragment = svgCanvas.getFragmentIdentifier();
1125
			}
1482
                        if (fragment != null) {
1126
		}
1483
                            uri += '#' +fragment;
1484
                        }
1485
1127
1486
                        //
1128
		/**
1487
                        // Build a PrintTranscoder to handle printing
1129
		 * Calls {@code clearAllBreakpoints} on {@link #debuggerInstance}.
1488
                        // of the svgDocument object
1130
		 */
1489
                        //
1131
		public void clearAllBreakpoints() {
1490
                        PrintTranscoder pt = new PrintTranscoder();
1132
			try {
1133
				debuggerMethods[CLEAR_ALL_BREAKPOINTS_METHOD].invoke(
1134
						debuggerInstance, (Object[]) null);
1135
			} catch (InvocationTargetException ite) {
1136
				throw new RuntimeException(ite.getMessage());
1137
			} catch (IllegalAccessException iae) {
1138
				throw new RuntimeException(iae.getMessage());
1139
			}
1140
		}
1491
1141
1492
                        //
1142
		/**
1493
                        // Set transcoding hints
1143
		 * Calls {@code dispose} on {@link #debuggerInstance}.
1494
                        //
1144
		 */
1495
                        if (application.getXMLParserClassName() != null) {
1145
		public void dispose() {
1496
                            pt.addTranscodingHint
1146
			try {
1497
                                (JPEGTranscoder.KEY_XML_PARSER_CLASSNAME,
1147
				debuggerMethods[DISPOSE_METHOD].invoke(debuggerInstance,
1498
                                    application.getXMLParserClassName());
1148
						(Object[]) null);
1499
                        }
1149
			} catch (InvocationTargetException ite) {
1150
				throw new RuntimeException(ite.getMessage());
1151
			} catch (IllegalAccessException iae) {
1152
				throw new RuntimeException(iae.getMessage());
1153
			}
1154
		}
1500
1155
1501
                        pt.addTranscodingHint(PrintTranscoder.KEY_SHOW_PAGE_DIALOG,
1156
		/**
1502
                                              Boolean.TRUE);
1157
		 * Calls {@code getContextFactory} on the given instance of
1158
		 * {@link org.apache.batik.script.rhino.RhinoInterpreter}.
1159
		 */
1160
		protected Object getContextFactory(Object rhinoInterpreter) {
1161
			try {
1162
				return getContextFactoryMethod.invoke(rhinoInterpreter,
1163
						(Object[]) null);
1164
			} catch (InvocationTargetException ite) {
1165
				throw new RuntimeException(ite.getMessage());
1166
			} catch (IllegalAccessException iae) {
1167
				throw new RuntimeException(iae.getMessage());
1168
			}
1169
		}
1170
	}
1503
1171
1172
	/**
1173
	 * To show the about dialog
1174
	 */
1175
	public class AboutAction extends AbstractAction {
1176
		public AboutAction() {
1177
		}
1504
1178
1505
                        pt.addTranscodingHint(PrintTranscoder.KEY_SHOW_PRINTER_DIALOG,
1179
		public void actionPerformed(ActionEvent e) {
1506
                                              Boolean.TRUE);
1180
			AboutDialog dlg = new AboutDialog(JSVGViewerFrame.this);
1181
			// Work around pack() bug on some platforms
1182
			dlg.setSize(dlg.getPreferredSize());
1183
			dlg.setLocationRelativeTo(JSVGViewerFrame.this);
1184
			dlg.setVisible(true);
1185
			dlg.toFront();
1186
		}
1187
	}
1507
1188
1508
                        //
1189
	/**
1509
                        // Do transcoding now
1190
	 * To open a new file.
1510
                        //
1191
	 */
1511
                        pt.transcode(new TranscoderInput(uri), null);
1192
	public class OpenAction extends AbstractAction {
1512
1193
1513
                        //
1194
		public OpenAction() {
1514
                        // Print
1195
		}
1515
                        //
1516
                        try {
1517
                            pt.print();
1518
                        } catch (PrinterException ex) {
1519
                            userAgent.displayError(ex);
1520
                        }
1521
                    }
1522
                }.start();
1523
            }
1524
        }
1525
    }
1526
1196
1527
    /**
1197
		public void actionPerformed(ActionEvent e) {
1528
     * To save the current document as SVG.
1198
			File f = null;
1529
     */
1199
			if (Platform.isOSX) {
1530
    public class SaveAsAction extends AbstractAction {
1200
				FileDialog fileDialog = new FileDialog(JSVGViewerFrame.this,
1531
        public SaveAsAction() {}
1201
						Resources.getString(OPEN_TITLE));
1202
				fileDialog.setFilenameFilter(new FilenameFilter() {
1203
					public boolean accept(File dir, String name) {
1204
						Iterator iter = getHandlers().iterator();
1205
						while (iter.hasNext()) {
1206
							SquiggleInputHandler handler = (SquiggleInputHandler) iter
1207
									.next();
1208
							if (handler.accept(new File(dir, name))) {
1209
								return true;
1210
							}
1211
						}
1212
						return false;
1213
					}
1214
				});
1215
				fileDialog.setVisible(true);
1216
				String filename = fileDialog.getFile();
1217
				if (fileDialog != null) {
1218
					String dirname = fileDialog.getDirectory();
1219
					f = new File(dirname, filename);
1220
				}
1221
			} else {
1222
				JFileChooser fileChooser = null;
1532
1223
1533
        public void actionPerformed(ActionEvent e) {
1224
				// Apply work around Windows problem when security is enabled,
1534
            JFileChooser fileChooser;
1225
				// and when prior to JDK 1.4.
1535
            fileChooser = new JFileChooser(makeAbsolute(currentSavePath));
1226
				String os = System.getProperty(PROPERTY_OS_NAME,
1536
            fileChooser.setDialogTitle(resources.getString("SaveAs.title"));
1227
						PROPERTY_OS_NAME_DEFAULT);
1537
            fileChooser.setFileHidingEnabled(false);
1228
				SecurityManager sm = System.getSecurityManager();
1538
            fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
1539
            fileChooser.addChoosableFileFilter(new ImageFileFilter(".svg"));
1540
1229
1541
            int choice = fileChooser.showSaveDialog(JSVGViewerFrame.this);
1230
				if (priorJDK1_4 && sm != null
1542
            if (choice != JFileChooser.APPROVE_OPTION)
1231
						&& os.indexOf(PROPERTY_OS_WINDOWS_PREFIX) != -1) {
1543
                return;
1232
					fileChooser = new JFileChooser(makeAbsolute(currentPath),
1233
							new WindowsAltFileSystemView());
1234
				} else {
1235
					fileChooser = new JFileChooser(makeAbsolute(currentPath));
1236
				}
1544
1237
1545
            final File f = fileChooser.getSelectedFile();
1238
				fileChooser.setFileHidingEnabled(false);
1239
				fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
1546
1240
1547
            SVGOptionPanel sop;
1241
				//
1548
            sop = SVGOptionPanel.showDialog(JSVGViewerFrame.this);
1242
				// Add file filters from the handlers map
1243
				//
1244
				Iterator iter = getHandlers().iterator();
1245
				while (iter.hasNext()) {
1246
					SquiggleInputHandler handler = (SquiggleInputHandler) iter
1247
							.next();
1248
					fileChooser
1249
							.addChoosableFileFilter(new SquiggleInputHandlerFilter(
1250
									handler));
1251
				}
1549
1252
1550
            final boolean useXMLBase  = sop.getUseXMLBase();
1253
				int choice = fileChooser.showOpenDialog(JSVGViewerFrame.this);
1551
            final boolean prettyPrint = sop.getPrettyPrint();
1254
				if (choice == JFileChooser.APPROVE_OPTION) {
1552
            sop = null;
1255
					f = fileChooser.getSelectedFile();
1256
					currentPath = f;
1257
				}
1258
			}
1553
1259
1554
            final SVGDocument svgDoc = svgCanvas.getSVGDocument();
1260
			if (f != null) {
1555
            if (svgDoc == null) return;
1261
				try {
1262
					String furl = f.toURL().toString();
1263
					showSVGDocument(furl);
1264
				} catch (MalformedURLException ex) {
1265
					if (userAgent != null) {
1266
						userAgent.displayError(ex);
1267
					}
1268
				}
1269
			}
1270
		}
1271
	}
1556
1272
1557
            statusBar.setMessage(resources.getString("Message.saveAs"));
1273
	/**
1558
            currentSavePath = f;
1274
	 * Shows the given document into the viewer frame
1559
            OutputStreamWriter w = null;
1275
	 */
1560
            try {
1276
	public void showSVGDocument(String uri) {
1561
                OutputStream tos = null;
1277
		try {
1562
                tos = new FileOutputStream(f);
1278
			ParsedURL purl = new ParsedURL(uri);
1563
                tos = new BufferedOutputStream(tos);
1279
			SquiggleInputHandler handler = getInputHandler(purl);
1564
                w = new OutputStreamWriter(tos, "utf-8");
1565
            } catch (Exception ex) {
1566
                userAgent.displayError(ex);
1567
                return;
1568
            }
1569
1280
1570
            final OutputStreamWriter writer  = w;
1281
			handler.handle(purl, JSVGViewerFrame.this);
1282
		} catch (Exception e) {
1283
			if (userAgent != null) {
1284
				userAgent.displayError(e);
1285
			}
1286
		}
1571
1287
1572
            final Runnable doneRun = new Runnable() {
1288
	}
1573
                    public void run() {
1574
                        String doneStr = resources.getString("Message.done");
1575
                        statusBar.setMessage(doneStr);
1576
                    }
1577
                };
1578
            Runnable r = new Runnable() {
1579
                    public void run() {
1580
                        try {
1581
                            // Write standard XML header.
1582
                            writer.write
1583
                                ("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
1584
                                writer.write (EOL);
1585
1289
1586
                            Node fc = svgDoc.getFirstChild();
1290
	/**
1587
                            if (fc.getNodeType() != Node.DOCUMENT_TYPE_NODE) {
1291
	 * Returns the input handler for the given URI
1588
                                // Not DT node in Document, so
1292
	 */
1589
                                // provide Document Type dec.
1293
	public SquiggleInputHandler getInputHandler(ParsedURL purl)
1590
                                writer.write ("<!DOCTYPE svg PUBLIC '");
1294
			throws IOException {
1591
                                writer.write (SVGConstants.SVG_PUBLIC_ID);
1295
		Iterator iter = getHandlers().iterator();
1592
                                writer.write ("' '");
1296
		SquiggleInputHandler handler = null;
1593
                                writer.write (SVGConstants.SVG_SYSTEM_ID);
1594
                                writer.write ("'>");
1595
                                writer.write (EOL);
1596
                                writer.write (EOL);
1597
                            }
1598
                            Element root = svgDoc.getRootElement();
1599
                            boolean doXMLBase = useXMLBase;
1600
                            if (root.hasAttributeNS
1601
                                (XMLConstants.XML_NAMESPACE_URI, "base"))
1602
                                doXMLBase = false;
1603
1297
1604
                            if (doXMLBase) {
1298
		while (iter.hasNext()) {
1605
                                root.setAttributeNS
1299
			SquiggleInputHandler curHandler = (SquiggleInputHandler) iter
1606
                                    (XMLConstants.XML_NAMESPACE_URI,
1300
					.next();
1607
                                     "xml:base",
1301
			if (curHandler.accept(purl)) {
1608
                                     svgDoc.getURL());
1302
				handler = curHandler;
1609
                            }
1303
				break;
1304
			}
1305
		}
1610
1306
1611
                            if (prettyPrint) {
1307
		// No handler found, use the default one.
1612
                                SVGTranscoder trans = new SVGTranscoder();
1308
		if (handler == null) {
1613
                                trans.transcode(new TranscoderInput(svgDoc),
1309
			handler = defaultHandler;
1614
                                                new TranscoderOutput(writer));
1310
		}
1615
                            } else {
1616
                                DOMUtilities.writeDocument(svgDoc, writer);
1617
                            }
1618
1311
1619
                            writer.close();
1312
		return handler;
1313
	}
1620
1314
1621
                            if (doXMLBase)
1315
	/**
1622
                                root.removeAttributeNS
1316
	 * Returns the list of input file handler.
1623
                                    (XMLConstants.XML_NAMESPACE_URI,
1317
	 */
1624
                                     "xml:base");
1318
	protected static Vector getHandlers() {
1319
		if (handlers != null) {
1320
			return handlers;
1321
		}
1625
1322
1626
                            if (EventQueue.isDispatchThread()) {
1323
		handlers = new Vector();
1627
                                doneRun.run();
1324
		registerHandler(new SVGInputHandler());
1628
                            } else {
1629
                                EventQueue.invokeLater(doneRun);
1630
                            }
1631
                        } catch (Exception ex) {
1632
                            userAgent.displayError(ex);
1633
                        }
1634
                    }
1635
                };
1636
1325
1637
            UpdateManager um = svgCanvas.getUpdateManager();
1326
		Iterator iter = Service.providers(SquiggleInputHandler.class);
1638
            if ((um != null) && (um.isRunning())) {
1327
		while (iter.hasNext()) {
1639
                um.getUpdateRunnableQueue().invokeLater(r);
1328
			SquiggleInputHandler handler = (SquiggleInputHandler) iter.next();
1640
            } else {
1641
                r.run();
1642
            }
1643
        }
1644
    }
1645
1329
1646
    /**
1330
			registerHandler(handler);
1647
     * To save the current document as JPG.
1331
		}
1648
     */
1649
    public class ExportAsJPGAction extends AbstractAction {
1650
        public ExportAsJPGAction() {}
1651
        public void actionPerformed(ActionEvent e) {
1652
            JFileChooser fileChooser =
1653
                new JFileChooser(makeAbsolute(currentSavePath));
1654
            fileChooser.setDialogTitle(resources.getString("ExportAsJPG.title"));
1655
            fileChooser.setFileHidingEnabled(false);
1656
            fileChooser.setFileSelectionMode
1657
                (JFileChooser.FILES_ONLY);
1658
            fileChooser.addChoosableFileFilter(new ImageFileFilter(".jpg"));
1659
1332
1660
            int choice = fileChooser.showSaveDialog(JSVGViewerFrame.this);
1333
		return handlers;
1661
            if (choice == JFileChooser.APPROVE_OPTION) {
1334
	}
1662
                float quality =
1663
                    JPEGOptionPanel.showDialog(JSVGViewerFrame.this);
1664
1335
1665
                final File f = fileChooser.getSelectedFile();
1336
	/**
1666
                BufferedImage buffer = svgCanvas.getOffScreen();
1337
	 * Registers an input file handler by adding it to the handlers map.
1667
                if (buffer != null) {
1338
	 * 
1668
                    statusBar.setMessage
1339
	 * @param handler
1669
                        (resources.getString("Message.exportAsJPG"));
1340
	 *            the new input handler to register.
1341
	 */
1342
	public static synchronized void registerHandler(SquiggleInputHandler handler) {
1343
		Vector handlers = getHandlers();
1344
		handlers.addElement(handler);
1345
	}
1670
1346
1671
                    // create a BufferedImage of the appropriate type
1347
	/**
1672
                    int w = buffer.getWidth();
1348
	 * To open a new document.
1673
                    int h = buffer.getHeight();
1349
	 */
1674
                    final ImageTranscoder trans = new JPEGTranscoder();
1350
	public class OpenLocationAction extends AbstractAction {
1675
                    if (application.getXMLParserClassName() != null) {
1351
		public OpenLocationAction() {
1676
                        trans.addTranscodingHint
1352
		}
1677
                            (JPEGTranscoder.KEY_XML_PARSER_CLASSNAME,
1678
                                application.getXMLParserClassName());
1679
                    }
1680
                    trans.addTranscodingHint
1681
                        (JPEGTranscoder.KEY_QUALITY, new Float(quality));
1682
1353
1683
                    final BufferedImage img = trans.createImage(w, h);
1354
		public void actionPerformed(ActionEvent e) {
1355
			if (uriChooser == null) {
1356
				uriChooser = new URIChooser(JSVGViewerFrame.this);
1357
				uriChooser.setFileFilter(new SVGFileFilter());
1358
				uriChooser.pack();
1359
				Rectangle fr = getBounds();
1360
				Dimension sd = uriChooser.getSize();
1361
				uriChooser.setLocation(fr.x + (fr.width - sd.width) / 2, fr.y
1362
						+ (fr.height - sd.height) / 2);
1363
			}
1364
			if (uriChooser.showDialog() == URIChooser.OK_OPTION) {
1365
				String s = uriChooser.getText();
1366
				if (s == null)
1367
					return;
1368
				int i = s.indexOf('#');
1369
				String t = "";
1370
				if (i != -1) {
1371
					t = s.substring(i + 1);
1372
					s = s.substring(0, i);
1373
				}
1374
				if (!s.equals("")) {
1375
					File f = new File(s);
1376
					if (f.exists()) {
1377
						if (f.isDirectory()) {
1378
							s = null;
1379
						} else {
1380
							try {
1381
								s = f.getCanonicalPath();
1382
								if (s.startsWith("/")) {
1383
									s = "file:" + s;
1384
								} else {
1385
									s = "file:/" + s;
1386
								}
1387
							} catch (IOException ex) {
1388
							}
1389
						}
1390
					}
1391
					if (s != null) {
1392
						if (svgDocument != null) {
1393
							ParsedURL docPURL = new ParsedURL(svgDocument
1394
									.getURL());
1395
							ParsedURL purl = new ParsedURL(docPURL, s);
1396
							String fi = svgCanvas.getFragmentIdentifier();
1397
							if (docPURL.equals(purl) && t.equals(fi)) {
1398
								return;
1399
							}
1400
						}
1401
						if (t.length() != 0) {
1402
							s += '#' + t;
1403
						}
1684
1404
1685
                    // paint the buffer to the image
1405
						showSVGDocument(s);
1686
                    Graphics2D g2d = img.createGraphics();
1406
					}
1687
                    g2d.setColor(Color.white);
1407
				}
1688
                    g2d.fillRect(0, 0, w, h);
1408
			}
1689
                    g2d.drawImage(buffer, null, 0, 0);
1409
		}
1690
                    new Thread() {
1410
	}
1691
                        public void run() {
1692
                            try {
1693
                                currentSavePath = f;
1694
                                OutputStream ostream =
1695
                                    new BufferedOutputStream(new FileOutputStream(f));
1696
                                trans.writeImage(img, new TranscoderOutput(ostream));
1697
                                ostream.close();
1698
                            } catch (Exception ex) { }
1699
                            statusBar.setMessage
1700
                                (resources.getString("Message.done"));
1701
                        }
1702
                    }.start();
1703
                }
1704
            }
1705
        }
1706
    }
1707
1411
1708
    /**
1412
	/**
1709
     * To save the current document as PNG.
1413
	 * To open a new window.
1710
     */
1414
	 */
1711
    public class ExportAsPNGAction extends AbstractAction {
1415
	public class NewWindowAction extends AbstractAction {
1712
        public ExportAsPNGAction() {}
1416
		public NewWindowAction() {
1713
        public void actionPerformed(ActionEvent e) {
1417
		}
1714
            JFileChooser fileChooser =
1715
                new JFileChooser(makeAbsolute(currentSavePath));
1716
            fileChooser.setDialogTitle(resources.getString("ExportAsPNG.title"));
1717
            fileChooser.setFileHidingEnabled(false);
1718
            fileChooser.setFileSelectionMode
1719
                (JFileChooser.FILES_ONLY);
1720
            fileChooser.addChoosableFileFilter(new ImageFileFilter(".png"));
1721
1418
1722
            int choice = fileChooser.showSaveDialog(JSVGViewerFrame.this);
1419
		public void actionPerformed(ActionEvent e) {
1723
            if (choice == JFileChooser.APPROVE_OPTION) {
1420
			JSVGViewerFrame vf = application.createAndShowJSVGViewerFrame();
1724
1421
1725
            // Start: By Jun Inamori (jun@oop-reserch.com)
1422
			// Copy the current settings to the new window.
1726
            boolean isIndexed = PNGOptionPanel.showDialog(JSVGViewerFrame.this);
1423
			vf.autoAdjust = autoAdjust;
1727
            // End: By Jun Inamori (jun@oop-reserch.com)
1424
			vf.debug = debug;
1425
			vf.svgCanvas.setProgressivePaint(svgCanvas.getProgressivePaint());
1426
			vf.svgCanvas.setDoubleBufferedRendering(svgCanvas
1427
					.getDoubleBufferedRendering());
1428
		}
1429
	}
1728
1430
1729
                final File f = fileChooser.getSelectedFile();
1431
	/**
1730
                BufferedImage buffer = svgCanvas.getOffScreen();
1432
	 * To show the preferences.
1731
                if (buffer != null) {
1433
	 */
1732
                    statusBar.setMessage
1434
	public class PreferencesAction extends AbstractAction {
1733
                        (resources.getString("Message.exportAsPNG"));
1435
		public PreferencesAction() {
1436
		}
1734
1437
1735
                    // create a BufferedImage of the appropriate type
1438
		public void actionPerformed(ActionEvent e) {
1736
                    int w = buffer.getWidth();
1439
			application.showPreferenceDialog(JSVGViewerFrame.this);
1737
                    int h = buffer.getHeight();
1440
		}
1738
                    final ImageTranscoder trans = new PNGTranscoder();
1441
	}
1739
                    if (application.getXMLParserClassName() != null) {
1740
                        trans.addTranscodingHint
1741
                            (JPEGTranscoder.KEY_XML_PARSER_CLASSNAME,
1742
                                application.getXMLParserClassName());
1743
                    }
1744
                    trans.addTranscodingHint(PNGTranscoder.KEY_FORCE_TRANSPARENT_WHITE,
1745
                                             Boolean.TRUE );
1746
1442
1747
            // Start: By Jun Inamori
1443
	/**
1748
            if(isIndexed){
1444
	 * To close the last document.
1749
                trans.addTranscodingHint(PNGTranscoder.KEY_INDEXED,new Integer(256));
1445
	 */
1750
            }
1446
	public class CloseAction extends AbstractAction {
1751
            // End: By Jun Inamori
1447
		public CloseAction() {
1448
		}
1752
1449
1753
                    final BufferedImage img = trans.createImage(w, h);
1450
		public void actionPerformed(ActionEvent e) {
1451
			application.closeJSVGViewerFrame(JSVGViewerFrame.this);
1452
		}
1453
	}
1754
1454
1755
                    // paint the buffer to the image
1455
	/**
1756
                    Graphics2D g2d = img.createGraphics();
1456
	 * To reload the current document.
1757
                    g2d.drawImage(buffer, null, 0, 0);
1457
	 */
1758
                    new Thread() {
1458
	public class ReloadAction extends AbstractAction {
1759
                        public void run() {
1459
		public ReloadAction() {
1760
                            try {
1460
		}
1761
                                currentSavePath = f;
1762
                                OutputStream ostream =
1763
                                    new BufferedOutputStream(new FileOutputStream(f));
1764
                                trans.writeImage(img,
1765
                                                 new TranscoderOutput(ostream));
1766
                                ostream.close();
1767
                            } catch (Exception ex) {}
1768
                            statusBar.setMessage
1769
                                (resources.getString("Message.done"));
1770
                        }
1771
                    }.start();
1772
                }
1773
            }
1774
        }
1775
    }
1776
1461
1777
    /**
1462
		public void actionPerformed(ActionEvent e) {
1778
     * To save the current document as TIFF.
1463
			if ((e.getModifiers() & ActionEvent.SHIFT_MASK) == 1) {
1779
     */
1464
				svgCanvas.flushImageCache();
1780
    public class ExportAsTIFFAction extends AbstractAction {
1465
			}
1781
        public ExportAsTIFFAction() {}
1466
			if (svgDocument != null) {
1782
        public void actionPerformed(ActionEvent e) {
1467
				localHistory.reload();
1783
            JFileChooser fileChooser =
1468
			}
1784
                new JFileChooser(makeAbsolute(currentSavePath));
1469
		}
1785
            fileChooser.setDialogTitle(resources.getString("ExportAsTIFF.title"));
1470
	}
1786
            fileChooser.setFileHidingEnabled(false);
1787
            fileChooser.setFileSelectionMode
1788
                (JFileChooser.FILES_ONLY);
1789
            fileChooser.addChoosableFileFilter(new ImageFileFilter(".tiff"));
1790
1471
1791
            int choice = fileChooser.showSaveDialog(JSVGViewerFrame.this);
1472
	/**
1792
            if (choice == JFileChooser.APPROVE_OPTION) {
1473
	 * To go back to the previous document
1793
                final File f = fileChooser.getSelectedFile();
1474
	 */
1794
                BufferedImage buffer = svgCanvas.getOffScreen();
1475
	public class BackAction extends AbstractAction implements
1795
                if (buffer != null) {
1476
			JComponentModifier {
1796
                    statusBar.setMessage
1477
		List components = new LinkedList();
1797
                        (resources.getString("Message.exportAsTIFF"));
1798
1478
1799
                    // create a BufferedImage of the appropriate type
1479
		public BackAction() {
1800
                    int w = buffer.getWidth();
1480
		}
1801
                    int h = buffer.getHeight();
1802
                    final ImageTranscoder trans = new TIFFTranscoder();
1803
                    if (application.getXMLParserClassName() != null) {
1804
                        trans.addTranscodingHint
1805
                            (JPEGTranscoder.KEY_XML_PARSER_CLASSNAME,
1806
                                application.getXMLParserClassName());
1807
                    }
1808
                    final BufferedImage img = trans.createImage(w, h);
1809
1481
1810
                    // paint the buffer to the image
1482
		public void actionPerformed(ActionEvent e) {
1811
                    Graphics2D g2d = img.createGraphics();
1483
			if (localHistory.canGoBack()) {
1812
                    g2d.drawImage(buffer, null, 0, 0);
1484
				localHistory.back();
1813
                    new Thread() {
1485
			}
1814
                        public void run() {
1486
		}
1815
                            try {
1816
                                currentSavePath = f;
1817
                                OutputStream ostream = new BufferedOutputStream
1818
                                    (new FileOutputStream(f));
1819
                                trans.writeImage
1820
                                    (img, new TranscoderOutput(ostream));
1821
                                ostream.close();
1822
                            } catch (Exception ex) {}
1823
                            statusBar.setMessage
1824
                                (resources.getString("Message.done"));
1825
                        }
1826
                    }.start();
1827
                }
1828
            }
1829
        }
1830
    }
1831
1487
1832
    /**
1488
		public void addJComponent(JComponent c) {
1833
     * To view the source of the current document.
1489
			components.add(c);
1834
     */
1490
			c.setEnabled(false);
1835
    public class ViewSourceAction extends AbstractAction {
1491
		}
1836
        public ViewSourceAction() {}
1837
        public void actionPerformed(ActionEvent e) {
1838
            if (svgDocument == null) {
1839
                return;
1840
            }
1841
1492
1842
            final ParsedURL u = new ParsedURL(svgDocument.getURL());
1493
		protected void update() {
1494
			boolean b = localHistory.canGoBack();
1495
			Iterator it = components.iterator();
1496
			while (it.hasNext()) {
1497
				((JComponent) it.next()).setEnabled(b);
1498
			}
1499
		}
1500
	}
1843
1501
1844
            final JFrame fr = new JFrame(u.toString());
1502
	/**
1845
            fr.setSize(resources.getInteger("ViewSource.width"),
1503
	 * To go forward to the next document
1846
                       resources.getInteger("ViewSource.height"));
1504
	 */
1847
            final JTextArea ta  = new JTextArea();
1505
	public class ForwardAction extends AbstractAction implements
1848
            ta.setLineWrap(true);
1506
			JComponentModifier {
1849
            ta.setFont(new Font("monospaced", Font.PLAIN, 12));
1507
		List components = new LinkedList();
1850
1508
1851
            JScrollPane scroll = new JScrollPane();
1509
		public ForwardAction() {
1852
            scroll.getViewport().add(ta);
1510
		}
1853
            scroll.setVerticalScrollBarPolicy
1854
                (JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
1855
            fr.getContentPane().add(scroll, BorderLayout.CENTER);
1856
1511
1857
            new Thread() {
1512
		public void actionPerformed(ActionEvent e) {
1858
                public void run() {
1513
			if (localHistory.canGoForward()) {
1859
                    char [] buffer = new char[4096];
1514
				localHistory.forward();
1515
			}
1516
		}
1860
1517
1861
                    try {
1518
		public void addJComponent(JComponent c) {
1862
                        Document  doc = new PlainDocument();
1519
			components.add(c);
1520
			c.setEnabled(false);
1521
		}
1863
1522
1864
                        ParsedURL purl = new ParsedURL(svgDocument.getURL());
1523
		protected void update() {
1865
                        InputStream is
1524
			boolean b = localHistory.canGoForward();
1866
                            = u.openStream(getInputHandler(purl).
1525
			Iterator it = components.iterator();
1867
                                           getHandledMimeTypes());
1526
			while (it.hasNext()) {
1868
                        // u.openStream(MimeTypeConstants.MIME_TYPES_SVG);
1527
				((JComponent) it.next()).setEnabled(b);
1528
			}
1529
		}
1530
	}
1869
1531
1870
                        Reader in = XMLUtilities.createXMLDocumentReader(is);
1532
	/**
1871
                        int len;
1533
	 * To print the current document.
1872
                        while ((len=in.read(buffer, 0, buffer.length)) != -1) {
1534
	 */
1873
                            doc.insertString(doc.getLength(),
1535
	public class PrintAction extends AbstractAction {
1874
                                             new String(buffer, 0, len), null);
1536
		public PrintAction() {
1875
                        }
1537
		}
1876
1538
1877
                        ta.setDocument(doc);
1539
		public void actionPerformed(ActionEvent e) {
1878
                        ta.setEditable(false);
1540
			if (svgDocument != null) {
1879
                        ta.setBackground(Color.white);
1541
				final SVGDocument doc = svgDocument;
1880
                        fr.setVisible(true);
1542
				new Thread() {
1881
                    } catch (Exception ex) {
1543
					public void run() {
1882
                        userAgent.displayError(ex);
1544
						String uri = doc.getURL();
1883
                    }
1545
						String fragment = svgCanvas.getFragmentIdentifier();
1884
                }
1546
						if (fragment != null) {
1885
            }.start();
1547
							uri += '#' + fragment;
1886
        }
1548
						}
1887
    }
1888
1549
1889
    /**
1550
						//
1890
     * To flush image cache (purely for debugging purposes)
1551
						// Build a PrintTranscoder to handle printing
1891
     */
1552
						// of the svgDocument object
1892
    public class FlushAction extends AbstractAction {
1553
						//
1893
        public FlushAction() {}
1554
						PrintTranscoder pt = new PrintTranscoder();
1894
        public void actionPerformed(ActionEvent e) {
1895
            svgCanvas.flush();
1896
            // Force redraw...
1897
            svgCanvas.setRenderingTransform(svgCanvas.getRenderingTransform());
1898
        }
1899
    }
1900
1555
1901
    /**
1556
						//
1902
     * To toggle visiblity of JavaScript Debugger.
1557
						// Set transcoding hints
1903
     */
1558
						//
1904
    public class ToggleDebuggerAction extends AbstractAction {
1559
						if (application.getXMLParserClassName() != null) {
1905
        public ToggleDebuggerAction() {
1560
							pt.addTranscodingHint(
1906
            super("Toggle Debugger Action");
1561
									JPEGTranscoder.KEY_XML_PARSER_CLASSNAME,
1907
        }
1562
									application.getXMLParserClassName());
1563
						}
1908
1564
1909
        public void actionPerformed(ActionEvent e) {
1565
						pt.addTranscodingHint(
1910
            if (debugger == null) {
1566
								PrintTranscoder.KEY_SHOW_PAGE_DIALOG,
1911
                showDebugger();
1567
								Boolean.TRUE);
1912
            } else {
1913
                hideDebugger();
1914
            }
1915
        }
1916
    }
1917
1568
1918
    /**
1569
						pt.addTranscodingHint(
1919
     * To go back to the previous transform
1570
								PrintTranscoder.KEY_SHOW_PRINTER_DIALOG,
1920
     */
1571
								Boolean.TRUE);
1921
    public class PreviousTransformAction extends    AbstractAction
1922
                                         implements JComponentModifier {
1923
        List components = new LinkedList();
1924
        public PreviousTransformAction() {}
1925
        public void actionPerformed(ActionEvent e) {
1926
            if (transformHistory.canGoBack()) {
1927
                transformHistory.back();
1928
                update();
1929
                nextTransformAction.update();
1930
                svgCanvas.setRenderingTransform(transformHistory.currentTransform());
1931
            }
1932
        }
1933
1572
1934
        public void addJComponent(JComponent c) {
1573
						//
1935
            components.add(c);
1574
						// Do transcoding now
1936
            c.setEnabled(false);
1575
						//
1937
        }
1576
						pt.transcode(new TranscoderInput(uri), null);
1938
1577
1939
        protected void update() {
1578
						//
1940
            boolean b = transformHistory.canGoBack();
1579
						// Print
1941
            Iterator it = components.iterator();
1580
						//
1942
            while (it.hasNext()) {
1581
						try {
1943
                ((JComponent)it.next()).setEnabled(b);
1582
							pt.print();
1944
            }
1583
						} catch (PrinterException ex) {
1945
        }
1584
							userAgent.displayError(ex);
1946
    }
1585
						}
1586
					}
1587
				}.start();
1588
			}
1589
		}
1590
	}
1947
1591
1948
    /**
1592
	/**
1949
     * To go forward to the next transform
1593
	 * To save the current document as SVG.
1950
     */
1594
	 */
1951
    public class NextTransformAction extends    AbstractAction
1595
	public class SaveAsAction extends AbstractAction {
1952
                                         implements JComponentModifier {
1596
		public SaveAsAction() {
1953
        List components = new LinkedList();
1597
		}
1954
        public NextTransformAction() {}
1955
        public void actionPerformed(ActionEvent e) {
1956
            if (transformHistory.canGoForward()) {
1957
                transformHistory.forward();
1958
                update();
1959
                previousTransformAction.update();
1960
                svgCanvas.setRenderingTransform(transformHistory.currentTransform());
1961
            }
1962
        }
1963
1598
1964
        public void addJComponent(JComponent c) {
1599
		public void actionPerformed(ActionEvent e) {
1965
            components.add(c);
1600
			JFileChooser fileChooser;
1966
            c.setEnabled(false);
1601
			fileChooser = new JFileChooser(makeAbsolute(currentSavePath));
1967
        }
1602
			fileChooser.setDialogTitle(resources.getString("SaveAs.title"));
1603
			fileChooser.setFileHidingEnabled(false);
1604
			fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
1605
			fileChooser.addChoosableFileFilter(new ImageFileFilter(".svg"));
1968
1606
1969
        protected void update() {
1607
			int choice = fileChooser.showSaveDialog(JSVGViewerFrame.this);
1970
            boolean b = transformHistory.canGoForward();
1608
			if (choice != JFileChooser.APPROVE_OPTION)
1971
            Iterator it = components.iterator();
1609
				return;
1972
            while (it.hasNext()) {
1973
                ((JComponent)it.next()).setEnabled(b);
1974
            }
1975
        }
1976
    }
1977
1610
1978
    /**
1611
			final File f = fileChooser.getSelectedFile();
1979
     * To apply the selected author stylesheet
1980
     */
1981
    public class UseStylesheetAction extends    AbstractAction
1982
                                     implements JComponentModifier {
1983
1612
1984
        List components = new LinkedList();
1613
			SVGOptionPanel sop;
1614
			sop = SVGOptionPanel.showDialog(JSVGViewerFrame.this);
1985
1615
1986
        public UseStylesheetAction() {}
1616
			final boolean useXMLBase = sop.getUseXMLBase();
1617
			final boolean prettyPrint = sop.getPrettyPrint();
1618
			sop = null;
1987
1619
1988
        public void actionPerformed(ActionEvent e) {
1620
			final SVGDocument svgDoc = svgCanvas.getSVGDocument();
1989
        }
1621
			if (svgDoc == null)
1622
				return;
1990
1623
1991
        public void addJComponent(JComponent c) {
1624
			statusBar.setMessage(resources.getString("Message.saveAs"));
1992
            components.add(c);
1625
			currentSavePath = f;
1993
            c.setEnabled(false);
1626
			OutputStreamWriter w = null;
1994
        }
1627
			try {
1628
				OutputStream tos = null;
1629
				tos = new FileOutputStream(f);
1630
				tos = new BufferedOutputStream(tos);
1631
				w = new OutputStreamWriter(tos, "utf-8");
1632
			} catch (Exception ex) {
1633
				userAgent.displayError(ex);
1634
				return;
1635
			}
1995
1636
1996
        protected void update() {
1637
			final OutputStreamWriter writer = w;
1997
            alternateStyleSheet = null;
1998
            Iterator it = components.iterator();
1999
            SVGDocument doc = svgCanvas.getSVGDocument();
2000
            while (it.hasNext()) {
2001
                JComponent stylesheetMenu = (JComponent)it.next();
2002
                stylesheetMenu.removeAll();
2003
                stylesheetMenu.setEnabled(false);
2004
1638
2005
                ButtonGroup buttonGroup = new ButtonGroup();
1639
			final Runnable doneRun = new Runnable() {
1640
				public void run() {
1641
					String doneStr = resources.getString("Message.done");
1642
					statusBar.setMessage(doneStr);
1643
				}
1644
			};
1645
			Runnable r = new Runnable() {
1646
				public void run() {
1647
					try {
1648
						// Write standard XML header.
1649
						writer
1650
								.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
1651
						writer.write(EOL);
2006
1652
2007
                for (Node n = doc.getFirstChild();
1653
						Node fc = svgDoc.getFirstChild();
2008
                     n != null && n.getNodeType() != Node.ELEMENT_NODE;
1654
						if (fc.getNodeType() != Node.DOCUMENT_TYPE_NODE) {
2009
                     n = n.getNextSibling()) {
1655
							// Not DT node in Document, so
2010
                    if (n instanceof StyleSheetProcessingInstruction) {
1656
							// provide Document Type dec.
2011
                        StyleSheetProcessingInstruction sspi;
1657
							writer.write("<!DOCTYPE svg PUBLIC '");
2012
                        sspi = (StyleSheetProcessingInstruction)n;
1658
							writer.write(SVGConstants.SVG_PUBLIC_ID);
2013
                        HashTable attrs = sspi.getPseudoAttributes();
1659
							writer.write("' '");
2014
                        final String title = (String)attrs.get("title");
1660
							writer.write(SVGConstants.SVG_SYSTEM_ID);
2015
                        String alt = (String)attrs.get("alternate");
1661
							writer.write("'>");
2016
                        if (title != null && "yes".equals(alt)) {
1662
							writer.write(EOL);
2017
                            JRadioButtonMenuItem button;
1663
							writer.write(EOL);
2018
                            button = new JRadioButtonMenuItem(title);
1664
						}
1665
						Element root = svgDoc.getRootElement();
1666
						boolean doXMLBase = useXMLBase;
1667
						if (root.hasAttributeNS(XMLConstants.XML_NAMESPACE_URI,
1668
								"base"))
1669
							doXMLBase = false;
2019
1670
2020
                            button.addActionListener
1671
						if (doXMLBase) {
2021
                                (new java.awt.event.ActionListener() {
1672
							root.setAttributeNS(XMLConstants.XML_NAMESPACE_URI,
2022
                                    public void actionPerformed(ActionEvent e) {
1673
									"xml:base", svgDoc.getURL());
2023
                                        SVGOMDocument doc;
1674
						}
2024
                                        doc = (SVGOMDocument)svgCanvas.getSVGDocument();
2025
                                        doc.clearViewCSS();
2026
                                        alternateStyleSheet = title;
2027
                                        svgCanvas.setSVGDocument(doc);
2028
                                    }
2029
                                });
2030
1675
2031
                            buttonGroup.add(button);
1676
						if (prettyPrint) {
2032
                            stylesheetMenu.add(button);
1677
							SVGTranscoder trans = new SVGTranscoder();
2033
                            stylesheetMenu.setEnabled(true);
1678
							trans.transcode(new TranscoderInput(svgDoc),
2034
                        }
1679
									new TranscoderOutput(writer));
2035
                    }
1680
						} else {
2036
                }
1681
							DOMUtilities.writeDocument(svgDoc, writer);
2037
            }
1682
						}
2038
        }
2039
    }
2040
1683
2041
    /**
1684
						writer.close();
2042
     * To restart after a pause.
2043
     */
2044
    public class PlayAction extends   AbstractAction
2045
                            implements JComponentModifier {
2046
        List components = new LinkedList();
2047
        public PlayAction() {}
2048
        public void actionPerformed(ActionEvent e) {
2049
            svgCanvas.resumeProcessing();
2050
        }
2051
1685
2052
        public void addJComponent(JComponent c) {
1686
						if (doXMLBase)
2053
            components.add(c);
1687
							root.removeAttributeNS(
2054
            c.setEnabled(false);
1688
									XMLConstants.XML_NAMESPACE_URI, "xml:base");
2055
        }
2056
1689
2057
        public void update(boolean enabled) {
1690
						if (EventQueue.isDispatchThread()) {
2058
            Iterator it = components.iterator();
1691
							doneRun.run();
2059
            while (it.hasNext()) {
1692
						} else {
2060
                ((JComponent)it.next()).setEnabled(enabled);
1693
							EventQueue.invokeLater(doneRun);
2061
            }
1694
						}
2062
        }
1695
					} catch (Exception ex) {
2063
    }
1696
						userAgent.displayError(ex);
1697
					}
1698
				}
1699
			};
2064
1700
2065
    /**
1701
			UpdateManager um = svgCanvas.getUpdateManager();
2066
     * To pause a document.
1702
			if ((um != null) && (um.isRunning())) {
2067
     */
1703
				um.getUpdateRunnableQueue().invokeLater(r);
2068
    public class PauseAction extends   AbstractAction
1704
			} else {
2069
                            implements JComponentModifier {
1705
				r.run();
2070
        List components = new LinkedList();
1706
			}
2071
        public PauseAction() {}
1707
		}
2072
        public void actionPerformed(ActionEvent e) {
1708
	}
2073
            svgCanvas.suspendProcessing();
2074
        }
2075
1709
2076
        public void addJComponent(JComponent c) {
1710
	/**
2077
            components.add(c);
1711
	 * To save the current document as JPG.
2078
            c.setEnabled(false);
1712
	 */
2079
        }
1713
	public class ExportAsJPGAction extends AbstractAction {
1714
		public ExportAsJPGAction() {
1715
		}
2080
1716
2081
        public void update(boolean enabled) {
1717
		public void actionPerformed(ActionEvent e) {
2082
            Iterator it = components.iterator();
1718
			JFileChooser fileChooser = new JFileChooser(
2083
            while (it.hasNext()) {
1719
					makeAbsolute(currentSavePath));
2084
                ((JComponent)it.next()).setEnabled(enabled);
1720
			fileChooser
2085
            }
1721
					.setDialogTitle(resources.getString("ExportAsJPG.title"));
2086
        }
1722
			fileChooser.setFileHidingEnabled(false);
2087
    }
1723
			fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
1724
			fileChooser.addChoosableFileFilter(new ImageFileFilter(".jpg"));
2088
1725
2089
    /**
1726
			int choice = fileChooser.showSaveDialog(JSVGViewerFrame.this);
2090
     * To stop the current processing.
1727
			if (choice == JFileChooser.APPROVE_OPTION) {
2091
     */
1728
				float quality = JPEGOptionPanel
2092
    public class StopAction extends    AbstractAction
1729
						.showDialog(JSVGViewerFrame.this);
2093
                            implements JComponentModifier {
2094
        List components = new LinkedList();
2095
        public StopAction() {}
2096
        public void actionPerformed(ActionEvent e) {
2097
            svgCanvas.stopProcessing();
2098
        }
2099
1730
2100
        public void addJComponent(JComponent c) {
1731
				final File f = fileChooser.getSelectedFile();
2101
            components.add(c);
1732
				BufferedImage buffer = svgCanvas.getOffScreen();
2102
            c.setEnabled(false);
1733
				if (buffer != null) {
2103
        }
1734
					statusBar.setMessage(resources
1735
							.getString("Message.exportAsJPG"));
2104
1736
2105
        public void update(boolean enabled) {
1737
					// create a BufferedImage of the appropriate type
2106
            Iterator it = components.iterator();
1738
					int w = buffer.getWidth();
2107
            while (it.hasNext()) {
1739
					int h = buffer.getHeight();
2108
                ((JComponent)it.next()).setEnabled(enabled);
1740
					final ImageTranscoder trans = new JPEGTranscoder();
2109
            }
1741
					if (application.getXMLParserClassName() != null) {
2110
        }
1742
						trans.addTranscodingHint(
2111
    }
1743
								JPEGTranscoder.KEY_XML_PARSER_CLASSNAME,
1744
								application.getXMLParserClassName());
1745
					}
1746
					trans.addTranscodingHint(JPEGTranscoder.KEY_QUALITY,
1747
							new Float(quality));
2112
1748
2113
    /**
1749
					final BufferedImage img = trans.createImage(w, h);
2114
     * To show the set transform dialog
2115
     */
2116
    public class SetTransformAction extends AbstractAction {
2117
        public SetTransformAction(){}
2118
        public void actionPerformed(ActionEvent e){
2119
            if (transformDialog == null){
2120
                transformDialog
2121
                    = JAffineTransformChooser.createDialog
2122
                    (JSVGViewerFrame.this,
2123
                     resources.getString("SetTransform.title"));
2124
            }
2125
1750
2126
            AffineTransform txf = transformDialog.showDialog();
1751
					// paint the buffer to the image
2127
            if(txf != null){
1752
					Graphics2D g2d = img.createGraphics();
2128
                AffineTransform at = svgCanvas.getRenderingTransform();
1753
					g2d.setColor(Color.white);
2129
                if(at == null){
1754
					g2d.fillRect(0, 0, w, h);
2130
                    at = new AffineTransform();
1755
					g2d.drawImage(buffer, null, 0, 0);
2131
                }
1756
					new Thread() {
1757
						public void run() {
1758
							try {
1759
								currentSavePath = f;
1760
								OutputStream ostream = new BufferedOutputStream(
1761
										new FileOutputStream(f));
1762
								trans.writeImage(img, new TranscoderOutput(
1763
										ostream));
1764
								ostream.close();
1765
							} catch (Exception ex) {
1766
							}
1767
							statusBar.setMessage(resources
1768
									.getString("Message.done"));
1769
						}
1770
					}.start();
1771
				}
1772
			}
1773
		}
1774
	}
2132
1775
2133
                txf.concatenate(at);
1776
	/**
2134
                svgCanvas.setRenderingTransform(txf);
1777
	 * To save the current document as PNG.
2135
            }
1778
	 */
2136
        }
1779
	public class ExportAsPNGAction extends AbstractAction {
2137
    }
1780
		public ExportAsPNGAction() {
1781
		}
2138
1782
2139
    /**
1783
		public void actionPerformed(ActionEvent e) {
2140
     * To display the memory monitor.
1784
			JFileChooser fileChooser = new JFileChooser(
2141
     */
1785
					makeAbsolute(currentSavePath));
2142
    public class MonitorAction extends AbstractAction {
1786
			fileChooser
2143
        public MonitorAction() {}
1787
					.setDialogTitle(resources.getString("ExportAsPNG.title"));
2144
        public void actionPerformed(ActionEvent e) {
1788
			fileChooser.setFileHidingEnabled(false);
2145
            if (memoryMonitorFrame == null) {
1789
			fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
2146
                memoryMonitorFrame = new MemoryMonitor();
1790
			fileChooser.addChoosableFileFilter(new ImageFileFilter(".png"));
2147
                Rectangle fr = getBounds();
2148
                Dimension md = memoryMonitorFrame.getSize();
2149
                memoryMonitorFrame.setLocation(fr.x + (fr.width  - md.width) / 2,
2150
                                               fr.y + (fr.height - md.height) / 2);
2151
            }
2152
            memoryMonitorFrame.setVisible(true);
2153
        }
2154
    }
2155
1791
2156
    /**
1792
			int choice = fileChooser.showSaveDialog(JSVGViewerFrame.this);
2157
     * To display the Find dialog
1793
			if (choice == JFileChooser.APPROVE_OPTION) {
2158
     */
2159
    public class FindDialogAction extends AbstractAction {
2160
        public FindDialogAction() {}
2161
        public void actionPerformed(ActionEvent e) {
2162
            if (findDialog == null) {
2163
                findDialog = new FindDialog(JSVGViewerFrame.this, svgCanvas);
2164
                findDialog.setGraphicsNode(svgCanvas.getGraphicsNode());
2165
                findDialog.pack();
2166
                Rectangle fr = getBounds();
2167
                Dimension td = findDialog.getSize();
2168
                findDialog.setLocation(fr.x + (fr.width  - td.width) / 2,
2169
                                       fr.y + (fr.height - td.height) / 2);
2170
            }
2171
            findDialog.setVisible(true);
2172
        }
2173
    }
2174
1794
2175
    /**
1795
				// Start: By Jun Inamori (jun@oop-reserch.com)
2176
     * To display the Thumbnail dialog
1796
				boolean isIndexed = PNGOptionPanel
2177
     */
1797
						.showDialog(JSVGViewerFrame.this);
2178
    public class ThumbnailDialogAction extends AbstractAction {
1798
				// End: By Jun Inamori (jun@oop-reserch.com)
2179
        public ThumbnailDialogAction() {}
2180
        public void actionPerformed(ActionEvent e) {
2181
            if (thumbnailDialog == null) {
2182
                thumbnailDialog
2183
                    = new ThumbnailDialog(JSVGViewerFrame.this, svgCanvas);
2184
                thumbnailDialog.pack();
2185
                Rectangle fr = getBounds();
2186
                Dimension td = thumbnailDialog.getSize();
2187
                thumbnailDialog.setLocation(fr.x + (fr.width  - td.width) / 2,
2188
                                            fr.y + (fr.height - td.height) / 2);
2189
            }
2190
            thumbnailDialog.setInteractionEnabled
2191
                (!svgCanvas.getDisableInteractions());
2192
            thumbnailDialog.setVisible(true);
2193
        }
2194
    }
2195
1799
2196
    /**
1800
				final File f = fileChooser.getSelectedFile();
2197
     * To display the document full screen
1801
				BufferedImage buffer = svgCanvas.getOffScreen();
2198
     */
1802
				if (buffer != null) {
2199
    public class FullScreenAction extends AbstractAction {
1803
					statusBar.setMessage(resources
2200
        public FullScreenAction() {}
1804
							.getString("Message.exportAsPNG"));
2201
1805
2202
        public void actionPerformed(ActionEvent e) {
1806
					// create a BufferedImage of the appropriate type
2203
            if (window == null || !window.isVisible()) {
1807
					int w = buffer.getWidth();
2204
                if (window == null) {
1808
					int h = buffer.getHeight();
2205
                    window = new JWindow(JSVGViewerFrame.this);
1809
					final ImageTranscoder trans = new PNGTranscoder();
2206
                    Dimension size = Toolkit.getDefaultToolkit().getScreenSize();
1810
					if (application.getXMLParserClassName() != null) {
2207
                    window.setSize(size);
1811
						trans.addTranscodingHint(
2208
                }
1812
								JPEGTranscoder.KEY_XML_PARSER_CLASSNAME,
2209
                // Go to full screen in JWindow)
1813
								application.getXMLParserClassName());
2210
                svgCanvas.getParent().remove(svgCanvas);
1814
					}
2211
                window.getContentPane().add(svgCanvas);
1815
					trans.addTranscodingHint(
2212
                window.setVisible(true);
1816
							PNGTranscoder.KEY_FORCE_TRANSPARENT_WHITE,
2213
                window.toFront();
1817
							Boolean.TRUE);
2214
                svgCanvas.requestFocus();
2215
            } else {
2216
                // Go back to JSVGViewerFrame display
2217
                svgCanvas.getParent().remove(svgCanvas);
2218
                svgCanvasPanel.add(svgCanvas, BorderLayout.CENTER);
2219
                window.setVisible(false);
2220
            }
2221
        }
2222
    }
2223
1818
2224
    /**
1819
					// Start: By Jun Inamori
2225
     * To display the DOM viewer of the document
1820
					if (isIndexed) {
2226
     */
1821
						trans.addTranscodingHint(PNGTranscoder.KEY_INDEXED,
2227
    public class DOMViewerAction extends AbstractAction {
1822
								new Integer(256));
2228
        public DOMViewerAction() {}
1823
					}
2229
        public void actionPerformed(ActionEvent e) {
1824
					// End: By Jun Inamori
2230
            if (domViewer == null) {
2231
                domViewer = new DOMViewer();
2232
                if (svgDocument != null) {
2233
                    domViewer.setDocument(svgDocument,
2234
                                          (ViewCSS)svgDocument.getDocumentElement());
2235
                }
2236
                Rectangle fr = getBounds();
2237
                Dimension td = domViewer.getSize();
2238
                domViewer.setLocation(fr.x + (fr.width  - td.width) / 2,
2239
                                      fr.y + (fr.height - td.height) / 2);
2240
            }
2241
            domViewer.setVisible(true);
2242
        }
2243
    }
2244
1825
2245
    // ActionMap /////////////////////////////////////////////////////
1826
					final BufferedImage img = trans.createImage(w, h);
2246
1827
2247
    /**
1828
					// paint the buffer to the image
2248
     * The map that contains the action listeners
1829
					Graphics2D g2d = img.createGraphics();
2249
     */
1830
					g2d.drawImage(buffer, null, 0, 0);
2250
    protected Map listeners = new HashMap();
1831
					new Thread() {
1832
						public void run() {
1833
							try {
1834
								currentSavePath = f;
1835
								OutputStream ostream = new BufferedOutputStream(
1836
										new FileOutputStream(f));
1837
								trans.writeImage(img, new TranscoderOutput(
1838
										ostream));
1839
								ostream.close();
1840
							} catch (Exception ex) {
1841
							}
1842
							statusBar.setMessage(resources
1843
									.getString("Message.done"));
1844
						}
1845
					}.start();
1846
				}
1847
			}
1848
		}
1849
	}
2251
1850
2252
    /**
1851
	/**
2253
     * Returns the action associated with the given string
1852
	 * To save the current document as TIFF.
2254
     * or null on error
1853
	 */
2255
     * @param key the key mapped with the action to get
1854
	public class ExportAsTIFFAction extends AbstractAction {
2256
     * @throws MissingListenerException if the action is not found
1855
		public ExportAsTIFFAction() {
2257
     */
1856
		}
2258
    public Action getAction(String key) throws MissingListenerException {
2259
        Action result = (Action)listeners.get(key);
2260
        //if (result == null) {
2261
        //result = canvas.getAction(key);
2262
        //}
2263
        if (result == null) {
2264
            throw new MissingListenerException("Can't find action.", RESOURCES, key);
2265
        }
2266
        return result;
2267
    }
2268
1857
2269
    // SVGDocumentLoaderListener ///////////////////////////////////////////
1858
		public void actionPerformed(ActionEvent e) {
1859
			JFileChooser fileChooser = new JFileChooser(
1860
					makeAbsolute(currentSavePath));
1861
			fileChooser.setDialogTitle(resources
1862
					.getString("ExportAsTIFF.title"));
1863
			fileChooser.setFileHidingEnabled(false);
1864
			fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
1865
			fileChooser.addChoosableFileFilter(new ImageFileFilter(".tiff"));
2270
1866
2271
    long time; // For debug.
1867
			int choice = fileChooser.showSaveDialog(JSVGViewerFrame.this);
1868
			if (choice == JFileChooser.APPROVE_OPTION) {
1869
				final File f = fileChooser.getSelectedFile();
1870
				BufferedImage buffer = svgCanvas.getOffScreen();
1871
				if (buffer != null) {
1872
					statusBar.setMessage(resources
1873
							.getString("Message.exportAsTIFF"));
2272
1874
2273
    /**
1875
					// create a BufferedImage of the appropriate type
2274
     * Called when the loading of a document was started.
1876
					int w = buffer.getWidth();
2275
     */
1877
					int h = buffer.getHeight();
2276
    public void documentLoadingStarted(SVGDocumentLoaderEvent e) {
1878
					final ImageTranscoder trans = new TIFFTranscoder();
2277
        String msg = resources.getString("Message.documentLoad");
1879
					if (application.getXMLParserClassName() != null) {
2278
        if (debug) {
1880
						trans.addTranscodingHint(
2279
            System.out.println(msg);
1881
								JPEGTranscoder.KEY_XML_PARSER_CLASSNAME,
2280
            time = System.currentTimeMillis();
1882
								application.getXMLParserClassName());
2281
        }
1883
					}
2282
        statusBar.setMainMessage(msg);
1884
					final BufferedImage img = trans.createImage(w, h);
2283
        stopAction.update(true);
2284
        svgCanvas.setCursor(WAIT_CURSOR);
2285
    }
2286
1885
1886
					// paint the buffer to the image
1887
					Graphics2D g2d = img.createGraphics();
1888
					g2d.drawImage(buffer, null, 0, 0);
1889
					new Thread() {
1890
						public void run() {
1891
							try {
1892
								currentSavePath = f;
1893
								OutputStream ostream = new BufferedOutputStream(
1894
										new FileOutputStream(f));
1895
								trans.writeImage(img, new TranscoderOutput(
1896
										ostream));
1897
								ostream.close();
1898
							} catch (Exception ex) {
1899
							}
1900
							statusBar.setMessage(resources
1901
									.getString("Message.done"));
1902
						}
1903
					}.start();
1904
				}
1905
			}
1906
		}
1907
	}
2287
1908
2288
    /**
1909
	/**
2289
     * Called when the loading of a document was completed.
1910
	 * To view the source of the current document.
2290
     */
1911
	 */
2291
    public void documentLoadingCompleted(SVGDocumentLoaderEvent e) {
1912
	public class ViewSourceAction extends AbstractAction {
2292
        if (debug) {
1913
		
2293
            System.out.print(resources.getString("Message.documentLoadTime"));
1914
		protected SourceViewFrame sourceViewFrame;
2294
            System.out.println((System.currentTimeMillis() - time) + " ms");
1915
		
2295
        }
1916
		protected Thread displayThread;
1917
		
1918
		public ViewSourceAction() {
1919
		}
2296
1920
2297
        setSVGDocument(e.getSVGDocument(),
1921
		public void actionPerformed(ActionEvent e) {
2298
                       e.getSVGDocument().getURL(),
1922
			if (svgDocument == null) {
2299
                       e.getSVGDocument().getTitle());
1923
				return;
2300
    }
1924
			}
2301
1925
2302
    /**
1926
			final ParsedURL u = new ParsedURL(svgDocument.getURL());
2303
     * Forces the viewer frame to show the input SVGDocument
2304
     */
2305
    public void setSVGDocument(SVGDocument svgDocument,
2306
                               String svgDocumentURL,
2307
                               String svgDocumentTitle) {
2308
        this.svgDocument = svgDocument;
2309
1927
2310
        if (domViewer != null) {
1928
			sourceViewFrame = new SourceViewFrame(application, userAgent);
2311
            if(domViewer.isVisible() && svgDocument != null) {
1929
			displayThread = new Thread() {
2312
                domViewer.setDocument(svgDocument,
1930
				public void run() {
2313
                                      (ViewCSS)svgDocument.getDocumentElement());
1931
//					char[] buffer = new char[4096];
2314
            } else {
2315
                domViewer.dispose();
2316
                domViewer = null;
2317
            }
2318
        }
2319
        stopAction.update(false);
2320
        svgCanvas.setCursor(DEFAULT_CURSOR);
2321
        String s = svgDocumentURL;
2322
        locationBar.setText(s);
2323
        if (debugger != null) {
2324
            debugger.detach();
2325
            debugger.setDocumentURL(s);
2326
        }
2327
        if (title == null) {
2328
            title = getTitle();
2329
        }
2330
1932
2331
        String dt = svgDocumentTitle;
1933
					try {
2332
        if (dt.length() != 0) {
1934
						StringBuilder sb = new StringBuilder();
2333
            setTitle(title + ": " + dt);
2334
        } else {
2335
            int i = s.lastIndexOf("/");
2336
            if (i == -1)
2337
                i = s.lastIndexOf("\\");
2338
            if (i == -1) {
2339
                setTitle(title + ": " + s);
2340
            } else {
2341
                setTitle(title + ": " + s.substring(i + 1));
2342
            }
2343
        }
2344
1935
2345
        localHistory.update(s);
1936
						ParsedURL purl = new ParsedURL(svgDocument.getURL());
2346
        application.addVisitedURI(s);
1937
						InputStream is = u.openStream(getInputHandler(purl)
2347
        backAction.update();
1938
								.getHandledMimeTypes());
2348
        forwardAction.update();
1939
						// u.openStream(MimeTypeConstants.MIME_TYPES_SVG);
2349
1940
2350
        transformHistory = new TransformHistory();
1941
//						Reader in = XMLUtilities.createXMLDocumentReader(is);
2351
        previousTransformAction.update();
1942
//						int len;
2352
        nextTransformAction.update();
1943
//						while ((len = in.read(buffer, 0, buffer.length)) != -1) {
1944
//							sb.append(new String(buffer, 0, len));
1945
//						}
2353
1946
2354
        useStylesheetAction.update();
1947
						BufferedReader reader = new BufferedReader(
2355
    }
1948
								new InputStreamReader(is));
1949
						String line;
2356
1950
2357
    /**
1951
						while ((line = reader.readLine()) != null) {
2358
     * Called when the loading of a document was cancelled.
1952
							sb.append(line + "\n");
2359
     */
1953
						}
2360
    public void documentLoadingCancelled(SVGDocumentLoaderEvent e) {
1954
						
2361
        String msg = resources.getString("Message.documentCancelled");
1955
						sourceViewFrame.setText(sb.toString());
2362
        if (debug) {
1956
						sourceViewFrame.setTitle(u.toString());
2363
            System.out.println(msg);
1957
						ImageIcon icon = new ImageIcon(getClass().getResource(
2364
        }
1958
								resources.getString("ViewSource.frameicon")));
2365
        statusBar.setMainMessage("");
1959
						sourceViewFrame.setIconImage(icon.getImage());
2366
        statusBar.setMessage(msg);
1960
						sourceViewFrame.setSize(resources.getInteger("ViewSource.width"),
2367
        stopAction.update(false);
1961
								resources.getInteger("ViewSource.height"));
2368
        svgCanvas.setCursor(DEFAULT_CURSOR);
1962
						sourceViewFrame.setVisible(true);
2369
    }
1963
					} catch (Exception ex) {
1964
						userAgent.displayError(ex);
1965
					}
1966
				}
1967
			};
1968
			displayThread.start();
1969
		}
1970
		
1971
		public SourceViewFrame getSourceViewFrame() {
1972
			return sourceViewFrame;
1973
		}
1974
		
1975
		public Thread getDisplayThread() {
1976
			return displayThread;
1977
		}
1978
	}
2370
1979
2371
    /**
1980
	/**
2372
     * Called when the loading of a document has failed.
1981
	 * To flush image cache (purely for debugging purposes)
2373
     */
1982
	 */
2374
    public void documentLoadingFailed(SVGDocumentLoaderEvent e) {
1983
	public class FlushAction extends AbstractAction {
2375
        String msg = resources.getString("Message.documentFailed");
1984
		public FlushAction() {
2376
        if (debug) {
1985
		}
2377
            System.out.println(msg);
2378
        }
2379
        statusBar.setMainMessage("");
2380
        statusBar.setMessage(msg);
2381
        stopAction.update(false);
2382
        svgCanvas.setCursor(DEFAULT_CURSOR);
2383
    }
2384
1986
2385
    // GVTTreeBuilderListener //////////////////////////////////////////////
1987
		public void actionPerformed(ActionEvent e) {
1988
			svgCanvas.flush();
1989
			// Force redraw...
1990
			svgCanvas.setRenderingTransform(svgCanvas.getRenderingTransform());
1991
		}
1992
	}
2386
1993
2387
    /**
1994
	/**
2388
     * Called when a build started.
1995
	 * To toggle visiblity of JavaScript Debugger.
2389
     * The data of the event is initialized to the old document.
1996
	 */
2390
     */
1997
	public class ToggleDebuggerAction extends AbstractAction {
2391
    public void gvtBuildStarted(GVTTreeBuilderEvent e) {
1998
		public ToggleDebuggerAction() {
2392
        String msg = resources.getString("Message.treeBuild");
1999
			super("Toggle Debugger Action");
2393
        if (debug) {
2000
		}
2394
            System.out.println(msg);
2395
            time = System.currentTimeMillis();
2396
        }
2397
        statusBar.setMainMessage(msg);
2398
        stopAction.update(true);
2399
        svgCanvas.setCursor(WAIT_CURSOR);
2400
    }
2401
2001
2402
    /**
2002
		public void actionPerformed(ActionEvent e) {
2403
     * Called when a build was completed.
2003
			if (debugger == null) {
2404
     */
2004
				showDebugger();
2405
    public void gvtBuildCompleted(GVTTreeBuilderEvent e) {
2005
			} else {
2406
        if (debug) {
2006
				hideDebugger();
2407
            System.out.print(resources.getString("Message.treeBuildTime"));
2007
			}
2408
            System.out.println((System.currentTimeMillis() - time) + " ms");
2008
		}
2409
        }
2009
	}
2410
        if (findDialog != null) {
2411
            if(findDialog.isVisible()) {
2412
                findDialog.setGraphicsNode(svgCanvas.getGraphicsNode());
2413
            } else {
2414
                findDialog.dispose();
2415
                findDialog = null;
2416
            }
2417
        }
2418
        stopAction.update(false);
2419
        svgCanvas.setCursor(DEFAULT_CURSOR);
2420
        svgCanvas.setSelectionOverlayXORMode
2421
            (application.isSelectionOverlayXORMode());
2422
        svgCanvas.requestFocus();  // request focus when load completes.
2423
        if (debugger != null) {
2424
            debugger.attach();
2425
        }
2426
    }
2427
2010
2428
    /**
2011
	/**
2429
     * Called when a build was cancelled.
2012
	 * To go back to the previous transform
2430
     */
2013
	 */
2431
    public void gvtBuildCancelled(GVTTreeBuilderEvent e) {
2014
	public class PreviousTransformAction extends AbstractAction implements
2432
        String msg = resources.getString("Message.treeCancelled");
2015
			JComponentModifier {
2433
        if (debug) {
2016
		List components = new LinkedList();
2434
            System.out.println(msg);
2435
        }
2436
        statusBar.setMainMessage("");
2437
        statusBar.setMessage(msg);
2438
        stopAction.update(false);
2439
        svgCanvas.setCursor(DEFAULT_CURSOR);
2440
        svgCanvas.setSelectionOverlayXORMode
2441
            (application.isSelectionOverlayXORMode());
2442
    }
2443
2017
2444
    /**
2018
		public PreviousTransformAction() {
2445
     * Called when a build failed.
2019
		}
2446
     */
2447
    public void gvtBuildFailed(GVTTreeBuilderEvent e) {
2448
        String msg = resources.getString("Message.treeFailed");
2449
        if (debug) {
2450
            System.out.println(msg);
2451
        }
2452
        statusBar.setMainMessage("");
2453
        statusBar.setMessage(msg);
2454
        stopAction.update(false);
2455
        svgCanvas.setCursor(DEFAULT_CURSOR);
2456
        svgCanvas.setSelectionOverlayXORMode
2457
            (application.isSelectionOverlayXORMode());
2458
        if (autoAdjust) {
2459
            pack();
2460
        }
2461
    }
2462
2020
2463
    // SVGLoadEventDispatcherListener //////////////////////////////////////
2021
		public void actionPerformed(ActionEvent e) {
2022
			if (transformHistory.canGoBack()) {
2023
				transformHistory.back();
2024
				update();
2025
				nextTransformAction.update();
2026
				svgCanvas.setRenderingTransform(transformHistory
2027
						.currentTransform());
2028
			}
2029
		}
2464
2030
2465
    /**
2031
		public void addJComponent(JComponent c) {
2466
     * Called when a onload event dispatch started.
2032
			components.add(c);
2467
     */
2033
			c.setEnabled(false);
2468
    public void svgLoadEventDispatchStarted(SVGLoadEventDispatcherEvent e) {
2034
		}
2469
        String msg = resources.getString("Message.onload");
2470
        if (debug) {
2471
            System.out.println(msg);
2472
            time = System.currentTimeMillis();
2473
        }
2474
        stopAction.update(true);
2475
        statusBar.setMainMessage(msg);
2476
    }
2477
2035
2478
    /**
2036
		protected void update() {
2479
     * Called when a onload event dispatch was completed.
2037
			boolean b = transformHistory.canGoBack();
2480
     */
2038
			Iterator it = components.iterator();
2481
    public void svgLoadEventDispatchCompleted(SVGLoadEventDispatcherEvent e) {
2039
			while (it.hasNext()) {
2482
        if (debug) {
2040
				((JComponent) it.next()).setEnabled(b);
2483
            System.out.print(resources.getString("Message.onloadTime"));
2041
			}
2484
            System.out.println((System.currentTimeMillis() - time) + " ms");
2042
		}
2485
        }
2043
	}
2486
        stopAction.update(false);
2487
        statusBar.setMainMessage("");
2488
        statusBar.setMessage(resources.getString("Message.done"));
2489
    }
2490
2044
2491
    /**
2045
	/**
2492
     * Called when a onload event dispatch was cancelled.
2046
	 * To go forward to the next transform
2493
     */
2047
	 */
2494
    public void svgLoadEventDispatchCancelled(SVGLoadEventDispatcherEvent e) {
2048
	public class NextTransformAction extends AbstractAction implements
2495
        String msg = resources.getString("Message.onloadCancelled");
2049
			JComponentModifier {
2496
        if (debug) {
2050
		List components = new LinkedList();
2497
            System.out.println(msg);
2498
        }
2499
        stopAction.update(false);
2500
        statusBar.setMainMessage("");
2501
        statusBar.setMessage(msg);
2502
    }
2503
2051
2504
    /**
2052
		public NextTransformAction() {
2505
     * Called when a onload event dispatch failed.
2053
		}
2506
     */
2507
    public void svgLoadEventDispatchFailed(SVGLoadEventDispatcherEvent e) {
2508
        String msg = resources.getString("Message.onloadFailed");
2509
        if (debug) {
2510
            System.out.println(msg);
2511
        }
2512
        stopAction.update(false);
2513
        statusBar.setMainMessage("");
2514
        statusBar.setMessage(msg);
2515
    }
2516
2054
2517
    // GVTTreeRendererListener /////////////////////////////////////////////
2055
		public void actionPerformed(ActionEvent e) {
2056
			if (transformHistory.canGoForward()) {
2057
				transformHistory.forward();
2058
				update();
2059
				previousTransformAction.update();
2060
				svgCanvas.setRenderingTransform(transformHistory
2061
						.currentTransform());
2062
			}
2063
		}
2518
2064
2519
    /**
2065
		public void addJComponent(JComponent c) {
2520
     * Called when a rendering is in its preparing phase.
2066
			components.add(c);
2521
     */
2067
			c.setEnabled(false);
2522
    public void gvtRenderingPrepare(GVTTreeRendererEvent e) {
2068
		}
2523
        if (debug) {
2524
            String msg = resources.getString("Message.treeRenderingPrep");
2525
            System.out.println(msg);
2526
            time = System.currentTimeMillis();
2527
        }
2528
        stopAction.update(true);
2529
        svgCanvas.setCursor(WAIT_CURSOR);
2530
        statusBar.setMainMessage(resources.getString("Message.treeRendering"));
2531
    }
2532
2069
2533
    /**
2070
		protected void update() {
2534
     * Called when a rendering started.
2071
			boolean b = transformHistory.canGoForward();
2535
     */
2072
			Iterator it = components.iterator();
2536
    public void gvtRenderingStarted(GVTTreeRendererEvent e) {
2073
			while (it.hasNext()) {
2537
        if (debug) {
2074
				((JComponent) it.next()).setEnabled(b);
2538
            String msg = resources.getString("Message.treeRenderingPrepTime");
2075
			}
2539
            System.out.print(msg);
2076
		}
2540
            System.out.println((System.currentTimeMillis() - time) + " ms");
2077
	}
2541
            time = System.currentTimeMillis();
2542
            msg = resources.getString("Message.treeRenderingStart");
2543
            System.out.println(msg);
2544
        }
2545
        // Do nothing
2546
    }
2547
2078
2548
    /**
2079
	/**
2549
     * Called when a rendering was completed.
2080
	 * To apply the selected author stylesheet
2550
     */
2081
	 */
2551
    public void gvtRenderingCompleted(GVTTreeRendererEvent e) {
2082
	public class UseStylesheetAction extends AbstractAction implements
2552
        if (debug) {
2083
			JComponentModifier {
2553
            String msg = resources.getString("Message.treeRenderingTime");
2554
            System.out.print(msg);
2555
            System.out.println((System.currentTimeMillis() - time) + " ms");
2556
        }
2557
        statusBar.setMainMessage("");
2558
        statusBar.setMessage(resources.getString("Message.done"));
2559
        if (!svgCanvas.isDynamic() || managerStopped) {
2560
            stopAction.update(false);
2561
        }
2562
        svgCanvas.setCursor(DEFAULT_CURSOR);
2563
2084
2564
        transformHistory.update(svgCanvas.getRenderingTransform());
2085
		List components = new LinkedList();
2565
        previousTransformAction.update();
2566
        nextTransformAction.update();
2567
    }
2568
2086
2569
    /**
2087
		public UseStylesheetAction() {
2570
     * Called when a rendering was cancelled.
2088
		}
2571
     */
2572
    public void gvtRenderingCancelled(GVTTreeRendererEvent e) {
2573
        String msg = resources.getString("Message.treeRenderingCancelled");
2574
        if (debug) {
2575
            System.out.println(msg);
2576
        }
2577
        statusBar.setMainMessage("");
2578
        statusBar.setMessage(msg);
2579
        if (!svgCanvas.isDynamic()) {
2580
            stopAction.update(false);
2581
        }
2582
        svgCanvas.setCursor(DEFAULT_CURSOR);
2583
    }
2584
2089
2585
    /**
2090
		public void actionPerformed(ActionEvent e) {
2586
     * Called when a rendering failed.
2091
		}
2587
     */
2588
    public void gvtRenderingFailed(GVTTreeRendererEvent e) {
2589
        String msg = resources.getString("Message.treeRenderingFailed");
2590
        if (debug) {
2591
            System.out.println(msg);
2592
        }
2593
        statusBar.setMainMessage("");
2594
        statusBar.setMessage(msg);
2595
        if (!svgCanvas.isDynamic()) {
2596
            stopAction.update(false);
2597
        }
2598
        svgCanvas.setCursor(DEFAULT_CURSOR);
2599
    }
2600
2092
2601
    // LinkActivationListener /////////////////////////////////////////
2093
		public void addJComponent(JComponent c) {
2094
			components.add(c);
2095
			c.setEnabled(false);
2096
		}
2602
2097
2603
    /**
2098
		protected void update() {
2604
     * Called when a link was activated.
2099
			alternateStyleSheet = null;
2605
     */
2100
			Iterator it = components.iterator();
2606
    public void linkActivated(LinkActivationEvent e) {
2101
			SVGDocument doc = svgCanvas.getSVGDocument();
2607
        String s = e.getReferencedURI();
2102
			while (it.hasNext()) {
2608
        if (svgDocument != null) {
2103
				JComponent stylesheetMenu = (JComponent) it.next();
2609
            ParsedURL docURL = new ParsedURL(svgDocument.getURL());
2104
				stylesheetMenu.removeAll();
2610
            ParsedURL url    = new ParsedURL(docURL, s);
2105
				stylesheetMenu.setEnabled(false);
2611
            if (!url.sameFile(docURL)) {
2612
                return;
2613
            }
2614
2106
2615
            if (s.indexOf( '#' ) != -1) {
2107
				ButtonGroup buttonGroup = new ButtonGroup();
2616
                localHistory.update(s);
2617
                locationBar.setText(s);
2618
                if (debugger != null) {
2619
                    debugger.detach();
2620
                    debugger.setDocumentURL(s);
2621
                }
2622
                application.addVisitedURI(s);
2623
                backAction.update();
2624
                forwardAction.update();
2625
2108
2626
                transformHistory = new TransformHistory();
2109
				for (Node n = doc.getFirstChild(); n != null
2627
                previousTransformAction.update();
2110
						&& n.getNodeType() != Node.ELEMENT_NODE; n = n
2628
                nextTransformAction.update();
2111
						.getNextSibling()) {
2629
            }
2112
					if (n instanceof StyleSheetProcessingInstruction) {
2630
        }
2113
						StyleSheetProcessingInstruction sspi;
2631
    }
2114
						sspi = (StyleSheetProcessingInstruction) n;
2115
						HashTable attrs = sspi.getPseudoAttributes();
2116
						final String title = (String) attrs.get("title");
2117
						String alt = (String) attrs.get("alternate");
2118
						if (title != null && "yes".equals(alt)) {
2119
							JRadioButtonMenuItem button;
2120
							button = new JRadioButtonMenuItem(title);
2632
2121
2633
    // UpdateManagerListener ////////////////////////////////////////////////
2122
							button
2123
									.addActionListener(new java.awt.event.ActionListener() {
2124
										public void actionPerformed(
2125
												ActionEvent e) {
2126
											SVGOMDocument doc;
2127
											doc = (SVGOMDocument) svgCanvas
2128
													.getSVGDocument();
2129
											doc.clearViewCSS();
2130
											alternateStyleSheet = title;
2131
											svgCanvas.setSVGDocument(doc);
2132
										}
2133
									});
2634
2134
2635
    /**
2135
							buttonGroup.add(button);
2636
     * Called when the manager was started.
2136
							stylesheetMenu.add(button);
2637
     */
2137
							stylesheetMenu.setEnabled(true);
2638
    public void managerStarted(UpdateManagerEvent e) {
2138
						}
2639
        if (debug) {
2139
					}
2640
            String msg = resources.getString("Message.updateManagerStarted");
2140
				}
2641
            System.out.println(msg);
2141
			}
2642
        }
2142
		}
2643
        managerStopped = false;
2143
	}
2644
        playAction.update(false);
2645
        pauseAction.update(true);
2646
        stopAction.update(true);
2647
    }
2648
2144
2649
    /**
2145
	/**
2650
     * Called when the manager was suspended.
2146
	 * To restart after a pause.
2651
     */
2147
	 */
2652
    public void managerSuspended(UpdateManagerEvent e) {
2148
	public class PlayAction extends AbstractAction implements
2653
        if (debug) {
2149
			JComponentModifier {
2654
            String msg = resources.getString("Message.updateManagerSuspended");
2150
		List components = new LinkedList();
2655
            System.out.println(msg);
2656
        }
2657
        playAction.update(true);
2658
        pauseAction.update(false);
2659
    }
2660
2151
2661
    /**
2152
		public PlayAction() {
2662
     * Called when the manager was resumed.
2153
		}
2663
     */
2664
    public void managerResumed(UpdateManagerEvent e) {
2665
        if (debug) {
2666
            String msg = resources.getString("Message.updateManagerResumed");
2667
            System.out.println(msg);
2668
        }
2669
        playAction.update(false);
2670
        pauseAction.update(true);
2671
    }
2672
2154
2673
    /**
2155
		public void actionPerformed(ActionEvent e) {
2674
     * Called when the manager was stopped.
2156
			svgCanvas.resumeProcessing();
2675
     */
2157
		}
2676
    public void managerStopped(UpdateManagerEvent e) {
2677
        if (debug) {
2678
            String msg = resources.getString("Message.updateManagerStopped");
2679
            System.out.println(msg);
2680
        }
2681
        managerStopped = true;
2682
        playAction.update(false);
2683
        pauseAction.update(false);
2684
        stopAction.update(false);
2685
    }
2686
2158
2687
    /**
2159
		public void addJComponent(JComponent c) {
2688
     * Called when an update started.
2160
			components.add(c);
2689
     */
2161
			c.setEnabled(false);
2690
    public void updateStarted(final UpdateManagerEvent e) {
2162
		}
2691
    }
2692
2163
2693
    /**
2164
		public void update(boolean enabled) {
2694
     * Called when an update was completed.
2165
			Iterator it = components.iterator();
2695
     */
2166
			while (it.hasNext()) {
2696
    public void updateCompleted(final UpdateManagerEvent e) {
2167
				((JComponent) it.next()).setEnabled(enabled);
2697
    }
2168
			}
2169
		}
2170
	}
2698
2171
2699
    /**
2172
	/**
2700
     * Called when an update failed.
2173
	 * To pause a document.
2701
     */
2174
	 */
2702
    public void updateFailed(UpdateManagerEvent e) {
2175
	public class PauseAction extends AbstractAction implements
2703
    }
2176
			JComponentModifier {
2177
		List components = new LinkedList();
2704
2178
2705
    /**
2179
		public PauseAction() {
2706
     * This class implements a SVG user agent.
2180
		}
2707
     */
2708
    protected class UserAgent implements SVGUserAgent {
2709
2181
2710
        /**
2182
		public void actionPerformed(ActionEvent e) {
2711
         * Creates a new SVGUserAgent.
2183
			svgCanvas.suspendProcessing();
2712
         */
2184
		}
2713
        protected UserAgent() {
2714
        }
2715
2185
2716
        /**
2186
		public void addJComponent(JComponent c) {
2717
         * Displays an error message.
2187
			components.add(c);
2718
         */
2188
			c.setEnabled(false);
2719
        public void displayError(String message) {
2189
		}
2720
            if (debug) {
2721
                System.err.println(message);
2722
            }
2723
            JOptionPane pane =
2724
                new JOptionPane(message, JOptionPane.ERROR_MESSAGE);
2725
            JDialog dialog = pane.createDialog(JSVGViewerFrame.this, "ERROR");
2726
            dialog.setModal(false);
2727
            dialog.setVisible(true);
2728
        }
2729
2190
2730
        /**
2191
		public void update(boolean enabled) {
2731
         * Displays an error resulting from the specified Exception.
2192
			Iterator it = components.iterator();
2732
         */
2193
			while (it.hasNext()) {
2733
        public void displayError(Exception ex) {
2194
				((JComponent) it.next()).setEnabled(enabled);
2734
            if (debug) {
2195
			}
2735
                ex.printStackTrace();
2196
		}
2736
            }
2197
	}
2737
            JErrorPane pane =
2738
                new JErrorPane(ex, JOptionPane.ERROR_MESSAGE);
2739
            JDialog dialog = pane.createDialog(JSVGViewerFrame.this, "ERROR");
2740
            dialog.setModal(false);
2741
            dialog.setVisible(true);
2742
        }
2743
2198
2744
        /**
2199
	/**
2745
         * Displays a message in the User Agent interface.
2200
	 * To stop the current processing.
2746
         * The given message is typically displayed in a status bar.
2201
	 */
2747
         */
2202
	public class StopAction extends AbstractAction implements
2748
        public void displayMessage(String message) {
2203
			JComponentModifier {
2749
            statusBar.setMessage(message);
2204
		List components = new LinkedList();
2750
        }
2751
2205
2752
        /**
2206
		public StopAction() {
2753
         * Shows an alert dialog box.
2207
		}
2754
         */
2755
        public void showAlert(String message) {
2756
            svgCanvas.showAlert(message);
2757
        }
2758
2208
2759
        /**
2209
		public void actionPerformed(ActionEvent e) {
2760
         * Shows a prompt dialog box.
2210
			svgCanvas.stopProcessing();
2761
         */
2211
		}
2762
        public String showPrompt(String message) {
2763
            return svgCanvas.showPrompt(message);
2764
        }
2765
2212
2766
        /**
2213
		public void addJComponent(JComponent c) {
2767
         * Shows a prompt dialog box.
2214
			components.add(c);
2768
         */
2215
			c.setEnabled(false);
2769
        public String showPrompt(String message, String defaultValue) {
2216
		}
2770
            return svgCanvas.showPrompt(message, defaultValue);
2771
        }
2772
2217
2773
        /**
2218
		public void update(boolean enabled) {
2774
         * Shows a confirm dialog box.
2219
			Iterator it = components.iterator();
2775
         */
2220
			while (it.hasNext()) {
2776
        public boolean showConfirm(String message) {
2221
				((JComponent) it.next()).setEnabled(enabled);
2777
            return svgCanvas.showConfirm(message);
2222
			}
2778
        }
2223
		}
2224
	}
2779
2225
2780
        /**
2226
	/**
2781
         * Returns the size of a px CSS unit in millimeters.
2227
	 * To show the set transform dialog
2782
         */
2228
	 */
2783
        public float getPixelUnitToMillimeter() {
2229
	public class SetTransformAction extends AbstractAction {
2784
            return 0.26458333333333333333333333333333f; // 96dpi
2230
		public SetTransformAction() {
2785
        }
2231
		}
2786
2232
2787
        /**
2233
		public void actionPerformed(ActionEvent e) {
2788
         * Returns the size of a px CSS unit in millimeters.
2234
			if (transformDialog == null) {
2789
         * This will be removed after next release.
2235
				transformDialog = JAffineTransformChooser.createDialog(
2790
         * @see #getPixelUnitToMillimeter()
2236
						JSVGViewerFrame.this, resources
2791
         */
2237
								.getString("SetTransform.title"));
2792
        public float getPixelToMM() {
2238
			}
2793
            return getPixelUnitToMillimeter();
2794
2239
2795
        }
2240
			AffineTransform txf = transformDialog.showDialog();
2241
			if (txf != null) {
2242
				AffineTransform at = svgCanvas.getRenderingTransform();
2243
				if (at == null) {
2244
					at = new AffineTransform();
2245
				}
2796
2246
2797
        /**
2247
				txf.concatenate(at);
2798
         * Returns the default font family.
2248
				svgCanvas.setRenderingTransform(txf);
2799
         */
2249
			}
2800
        public String getDefaultFontFamily() {
2250
		}
2801
            return application.getDefaultFontFamily();
2251
	}
2802
        }
2803
2252
2804
        /**
2253
	/**
2805
         * Returns the  medium font size.
2254
	 * To display the memory monitor.
2806
         */
2255
	 */
2807
        public float getMediumFontSize() {
2256
	public class MonitorAction extends AbstractAction {
2808
            // 9pt (72pt == 1in)
2257
		public MonitorAction() {
2809
            return 9f * 25.4f / (72f * getPixelUnitToMillimeter());
2258
		}
2810
        }
2811
2259
2812
        /**
2260
		public void actionPerformed(ActionEvent e) {
2813
         * Returns a lighter font-weight.
2261
			if (memoryMonitorFrame == null) {
2814
         */
2262
				memoryMonitorFrame = new MemoryMonitor();
2815
        public float getLighterFontWeight(float f) {
2263
				Rectangle fr = getBounds();
2816
            // Round f to nearest 100...
2264
				Dimension md = memoryMonitorFrame.getSize();
2817
            int weight = ((int)((f+50)/100))*100;
2265
				memoryMonitorFrame.setLocation(
2818
            switch (weight) {
2266
						fr.x + (fr.width - md.width) / 2, fr.y
2819
            case 100: return 100;
2267
								+ (fr.height - md.height) / 2);
2820
            case 200: return 100;
2268
			}
2821
            case 300: return 200;
2269
			memoryMonitorFrame.setVisible(true);
2822
            case 400: return 300;
2270
		}
2823
            case 500: return 400;
2271
	}
2824
            case 600: return 400;
2825
            case 700: return 400;
2826
            case 800: return 400;
2827
            case 900: return 400;
2828
            default:
2829
                throw new IllegalArgumentException("Bad Font Weight: " + f);
2830
            }
2831
        }
2832
2272
2833
        /**
2273
	/**
2834
         * Returns a bolder font-weight.
2274
	 * To display the Find dialog
2835
         */
2275
	 */
2836
        public float getBolderFontWeight(float f) {
2276
	public class FindDialogAction extends AbstractAction {
2837
            // Round f to nearest 100...
2277
		public FindDialogAction() {
2838
            int weight = ((int)((f+50)/100))*100;
2278
		}
2839
            switch (weight) {
2840
            case 100: return 600;
2841
            case 200: return 600;
2842
            case 300: return 600;
2843
            case 400: return 600;
2844
            case 500: return 600;
2845
            case 600: return 700;
2846
            case 700: return 800;
2847
            case 800: return 900;
2848
            case 900: return 900;
2849
            default:
2850
                throw new IllegalArgumentException("Bad Font Weight: " + f);
2851
            }
2852
        }
2853
2279
2280
		public void actionPerformed(ActionEvent e) {
2281
			if (findDialog == null) {
2282
				findDialog = new FindDialog(JSVGViewerFrame.this, svgCanvas);
2283
				findDialog.setGraphicsNode(svgCanvas.getGraphicsNode());
2284
				findDialog.pack();
2285
				Rectangle fr = getBounds();
2286
				Dimension td = findDialog.getSize();
2287
				findDialog.setLocation(fr.x + (fr.width - td.width) / 2, fr.y
2288
						+ (fr.height - td.height) / 2);
2289
			}
2290
			findDialog.setVisible(true);
2291
		}
2292
	}
2854
2293
2855
        /**
2294
	/**
2856
         * Returns the language settings.
2295
	 * To display the Thumbnail dialog
2857
         */
2296
	 */
2858
        public String getLanguages() {
2297
	public class ThumbnailDialogAction extends AbstractAction {
2859
            return application.getLanguages();
2298
		public ThumbnailDialogAction() {
2860
        }
2299
		}
2861
2300
2862
        /**
2301
		public void actionPerformed(ActionEvent e) {
2863
         * Returns the user stylesheet uri.
2302
			if (thumbnailDialog == null) {
2864
         * @return null if no user style sheet was specified.
2303
				thumbnailDialog = new ThumbnailDialog(JSVGViewerFrame.this,
2865
         */
2304
						svgCanvas);
2866
        public String getUserStyleSheetURI() {
2305
				thumbnailDialog.pack();
2867
            return application.getUserStyleSheetURI();
2306
				Rectangle fr = getBounds();
2868
        }
2307
				Dimension td = thumbnailDialog.getSize();
2308
				thumbnailDialog.setLocation(fr.x + (fr.width - td.width) / 2,
2309
						fr.y + (fr.height - td.height) / 2);
2310
			}
2311
			thumbnailDialog.setInteractionEnabled(!svgCanvas
2312
					.getDisableInteractions());
2313
			thumbnailDialog.setVisible(true);
2314
		}
2315
	}
2869
2316
2870
        /**
2317
	/**
2871
         * Returns the class name of the XML parser.
2318
	 * To display the document full screen
2872
         */
2319
	 */
2873
        public String getXMLParserClassName() {
2320
	public class FullScreenAction extends AbstractAction {
2874
            return application.getXMLParserClassName();
2321
		public FullScreenAction() {
2875
        }
2322
		}
2876
2323
2877
        /**
2324
		public void actionPerformed(ActionEvent e) {
2878
         * Returns true if the XML parser must be in validation mode, false
2325
			if (window == null || !window.isVisible()) {
2879
         * otherwise.
2326
				if (window == null) {
2880
         */
2327
					window = new JWindow(JSVGViewerFrame.this);
2881
        public boolean isXMLParserValidating() {
2328
					Dimension size = Toolkit.getDefaultToolkit()
2882
            return application.isXMLParserValidating();
2329
							.getScreenSize();
2883
        }
2330
					window.setSize(size);
2331
				}
2332
				// Go to full screen in JWindow)
2333
				svgCanvas.getParent().remove(svgCanvas);
2334
				window.getContentPane().add(svgCanvas);
2335
				window.setVisible(true);
2336
				window.toFront();
2337
				svgCanvas.requestFocus();
2338
			} else {
2339
				// Go back to JSVGViewerFrame display
2340
				svgCanvas.getParent().remove(svgCanvas);
2341
				svgCanvasPanel.add(svgCanvas, BorderLayout.CENTER);
2342
				window.setVisible(false);
2343
			}
2344
		}
2345
	}
2884
2346
2885
        /**
2347
	/**
2886
         * Returns this user agent's CSS media.
2348
	 * To display the DOM viewer of the document
2887
         */
2349
	 */
2888
        public String getMedia() {
2350
	public class DOMViewerAction extends AbstractAction {
2889
            return application.getMedia();
2351
		
2890
        }
2352
		public DOMViewerAction() {
2353
		}
2891
2354
2892
        /**
2355
		public void actionPerformed(ActionEvent e) {
2893
         * Returns this user agent's alternate style-sheet title.
2356
			if (domViewer == null) {
2894
         */
2357
				domViewer = new DOMViewer();
2895
        public String getAlternateStyleSheet() {
2358
				if (svgDocument != null) {
2896
            return alternateStyleSheet;
2359
					domViewer.setDocument(svgDocument, (ViewCSS) svgDocument
2897
        }
2360
							.getDocumentElement());
2361
				}
2362
				Rectangle fr = getBounds();
2363
				Dimension td = domViewer.getSize();
2364
				domViewer.setLocation(fr.x + (fr.width - td.width) / 2, fr.y
2365
						+ (fr.height - td.height) / 2);
2366
			}
2367
			domViewer.setVisible(true);
2368
		}
2369
		
2370
		public DOMViewer getDOMViewer() {
2371
			return domViewer;
2372
		}
2373
	}
2898
2374
2899
        /**
2375
	/**
2900
         * Opens a link.
2376
	 * To display the Timeline viewer of the document
2901
         * @param uri The document URI.
2377
	 */
2902
         * @param newc Whether the link should be activated in a new component.
2378
	public class TimelineViewerAction extends AbstractAction {
2903
         */
2379
		public TimelineViewerAction() {
2904
        public void openLink(String uri, boolean newc) {
2380
		}
2905
            if (newc) {
2906
                application.openLink(uri);
2907
            } else {
2908
                showSVGDocument(uri);
2909
            }
2910
        }
2911
2381
2912
        /**
2382
		public void actionPerformed(ActionEvent e) {
2913
         * Tells whether the given extension is supported by this
2383
			if (timelineViewer == null) {
2914
         * user agent.
2384
				timelineViewer = new TimelineViewer(svgDocument);
2915
         */
2385
				Rectangle fr = getBounds();
2916
        public boolean supportExtension(String s) {
2386
				Dimension td = timelineViewer.getSize();
2917
            return false;
2387
				timelineViewer.setLocation(fr.x + (fr.width - td.width) / 2, fr.y
2918
        }
2388
						+ (fr.height - td.height) / 2);
2389
			}
2390
			timelineViewer.setVisible(true);
2391
		}
2392
	}
2919
2393
2920
        public void handleElement(Element elt, Object data){
2394
	// ActionMap /////////////////////////////////////////////////////
2921
        }
2922
2395
2923
        /**
2396
	/**
2924
         * Returns the security settings for the given script
2397
	 * The map that contains the action listeners
2925
         * type, script url and document url
2398
	 */
2926
         *
2399
	protected Map listeners = new HashMap();
2927
         * @param scriptType type of script, as found in the
2928
         *        type attribute of the &lt;script&gt; element.
2929
         * @param scriptURL url for the script, as defined in
2930
         *        the script's xlink:href attribute. If that
2931
         *        attribute was empty, then this parameter should
2932
         *        be null
2933
         * @param docURL url for the document into which the
2934
         *        script was found.
2935
         */
2936
        public ScriptSecurity getScriptSecurity(String scriptType,
2937
                                                ParsedURL scriptURL,
2938
                                                ParsedURL docURL){
2939
            if (!application.canLoadScriptType(scriptType)) {
2940
                return new NoLoadScriptSecurity(scriptType);
2941
            } else {
2942
                switch(application.getAllowedScriptOrigin()) {
2943
                case ResourceOrigin.ANY:
2944
                    return new RelaxedScriptSecurity(scriptType,
2945
                                                     scriptURL,
2946
                                                     docURL);
2947
                case ResourceOrigin.DOCUMENT:
2948
                    return new DefaultScriptSecurity(scriptType,
2949
                                                     scriptURL,
2950
                                                     docURL);
2951
                case ResourceOrigin.EMBEDED:
2952
                    return new EmbededScriptSecurity(scriptType,
2953
                                                     scriptURL,
2954
                                                     docURL);
2955
                default:
2956
                    return new NoLoadScriptSecurity(scriptType);
2957
                }
2958
            }
2959
        }
2960
2400
2961
        /**
2401
	/**
2962
         * This method throws a SecurityException if the script
2402
	 * Returns the action associated with the given string or null on error
2963
         * of given type, found at url and referenced from docURL
2403
	 * 
2964
         * should not be loaded.
2404
	 * @param key
2965
         *
2405
	 *            the key mapped with the action to get
2966
         * This is a convenience method to call checkLoadScript
2406
	 * @throws MissingListenerException
2967
         * on the ScriptSecurity strategy returned by
2407
	 *             if the action is not found
2968
         * getScriptSecurity.
2408
	 */
2969
         *
2409
	public Action getAction(String key) throws MissingListenerException {
2970
         * @param scriptType type of script, as found in the
2410
		Action result = (Action) listeners.get(key);
2971
         *        type attribute of the &lt;script&gt; element.
2411
		// if (result == null) {
2972
         * @param scriptURL url for the script, as defined in
2412
		// result = canvas.getAction(key);
2973
         *        the script's xlink:href attribute. If that
2413
		// }
2974
         *        attribute was empty, then this parameter should
2414
		if (result == null) {
2975
         *        be null
2415
			throw new MissingListenerException("Can't find action.", RESOURCES,
2976
         * @param docURL url for the document into which the
2416
					key);
2977
         *        script was found.
2417
		}
2978
         */
2418
		return result;
2979
        public void checkLoadScript(String scriptType,
2419
	}
2980
                                    ParsedURL scriptURL,
2981
                                    ParsedURL docURL) throws SecurityException {
2982
            ScriptSecurity s = getScriptSecurity(scriptType,
2983
                                                     scriptURL,
2984
                                                     docURL);
2985
2420
2986
            if (s != null) {
2421
	// SVGDocumentLoaderListener ///////////////////////////////////////////
2987
                s.checkLoadScript();
2988
            }
2989
        }
2990
2422
2991
        /**
2423
	long time; // For debug.
2992
         * Returns the security settings for the given
2993
         * resource url and document url
2994
         *
2995
         * @param resourceURL url for the resource, as defined in
2996
         *        the resource's xlink:href attribute. If that
2997
         *        attribute was empty, then this parameter should
2998
         *        be null
2999
         * @param docURL url for the document into which the
3000
         *        resource was found.
3001
         */
3002
        public ExternalResourceSecurity
3003
            getExternalResourceSecurity(ParsedURL resourceURL,
3004
                                        ParsedURL docURL){
3005
            switch(application.getAllowedExternalResourceOrigin()) {
3006
            case ResourceOrigin.ANY:
3007
                return new RelaxedExternalResourceSecurity(resourceURL,
3008
                                                           docURL);
3009
            case ResourceOrigin.DOCUMENT:
3010
                return new DefaultExternalResourceSecurity(resourceURL,
3011
                                                           docURL);
3012
            case ResourceOrigin.EMBEDED:
3013
                return new EmbededExternalResourceSecurity(resourceURL);
3014
            default:
3015
                return new NoLoadExternalResourceSecurity();
3016
            }
3017
        }
3018
2424
3019
        /**
2425
	/**
3020
         * This method throws a SecurityException if the resource
2426
	 * Called when the loading of a document was started.
3021
         * found at url and referenced from docURL
2427
	 */
3022
         * should not be loaded.
2428
	public void documentLoadingStarted(SVGDocumentLoaderEvent e) {
3023
         *
2429
		String msg = resources.getString("Message.documentLoad");
3024
         * This is a convenience method to call checkLoadExternalResource
2430
		if (debug) {
3025
         * on the ExternalResourceSecurity strategy returned by
2431
			System.out.println(msg);
3026
         * getExternalResourceSecurity.
2432
			time = System.currentTimeMillis();
3027
         *
2433
		}
3028
         * @param resourceURL url for the script, as defined in
2434
		statusBar.setMainMessage(msg);
3029
         *        the resource's xlink:href attribute. If that
2435
		stopAction.update(true);
3030
         *        attribute was empty, then this parameter should
2436
		svgCanvas.setCursor(WAIT_CURSOR);
3031
         *        be null
2437
	}
3032
         * @param docURL url for the document into which the
3033
         *        resource was found.
3034
         */
3035
        public void
3036
            checkLoadExternalResource(ParsedURL resourceURL,
3037
                                      ParsedURL docURL) throws SecurityException {
3038
            ExternalResourceSecurity s
3039
                =  getExternalResourceSecurity(resourceURL, docURL);
3040
2438
3041
            if (s != null) {
2439
	/**
3042
                s.checkLoadExternalResource();
2440
	 * Called when the loading of a document was completed.
3043
            }
2441
	 */
3044
        }
2442
	public void documentLoadingCompleted(SVGDocumentLoaderEvent e) {
3045
    }
2443
		if (debug) {
2444
			System.out.print(resources.getString("Message.documentLoadTime"));
2445
			System.out.println((System.currentTimeMillis() - time) + " ms");
2446
		}
3046
2447
3047
    /**
2448
		setSVGDocument(e.getSVGDocument(), e.getSVGDocument().getURL(), e
3048
     * A FileFilter used when exporting the SVG document as an image.
2449
				.getSVGDocument().getTitle(), e.getDocumentDescriptor());
3049
     */
2450
	}
3050
    protected static class ImageFileFilter extends FileFilter {
3051
2451
3052
        /** The extension of the image filename. */
2452
	/**
3053
        protected String extension;
2453
	 * Forces the viewer frame to show the input SVGDocument
2454
	 */
2455
	public void setSVGDocument(SVGDocument svgDocument, String svgDocumentURL,
2456
			String svgDocumentTitle, DocumentDescriptor docDescriptor) {
2457
		this.svgDocument = svgDocument;
2458
		this.docDescriptor = docDescriptor;
3054
2459
3055
        public ImageFileFilter(String extension) {
2460
		if (domViewer != null) {
3056
            this.extension = extension;
2461
			if (domViewer.isVisible() && svgDocument != null) {
3057
        }
2462
				domViewer.setDocument(svgDocument, (ViewCSS) svgDocument
2463
						.getDocumentElement());
2464
			} else {
2465
				domViewer.dispose();
2466
				domViewer = null;
2467
			}
2468
		}
2469
		if (timelineViewer != null) {
2470
			if (timelineViewer.isVisible() && svgDocument != null) {
2471
//				timelineViewer.setDocument(svgDocument);
2472
			} else {
2473
//				timelineViewer.dispose();
2474
				timelineViewer = null;
2475
			}
2476
		}
2477
		stopAction.update(false);
2478
		svgCanvas.setCursor(DEFAULT_CURSOR);
2479
		String s = svgDocumentURL;
2480
		locationBar.setText(s);
2481
		if (debugger != null) {
2482
			debugger.detach();
2483
			debugger.setDocumentURL(s);
2484
		}
2485
		if (title == null) {
2486
			title = getTitle();
2487
		}
3058
2488
3059
        /**
2489
		String dt = svgDocumentTitle;
3060
         * Returns true if <tt>f</tt> is a file with the correct extension,
2490
		if (dt.length() != 0) {
3061
         * false otherwise.
2491
			setTitle(title + ": " + dt);
3062
         */
2492
		} else {
3063
        public boolean accept(File f) {
2493
			int i = s.lastIndexOf("/");
3064
            boolean accept = false;
2494
			if (i == -1)
3065
            String fileName = null;
2495
				i = s.lastIndexOf("\\");
3066
            if (f != null) {
2496
			if (i == -1) {
3067
                if (f.isDirectory()) {
2497
				setTitle(title + ": " + s);
3068
                    accept = true;
2498
			} else {
3069
                } else {
2499
				setTitle(title + ": " + s.substring(i + 1));
3070
                    fileName = f.getPath().toLowerCase();
2500
			}
3071
                    if (fileName.endsWith(extension)) {
2501
		}
3072
                        accept = true;
3073
                    }
3074
                }
3075
            }
3076
            return accept;
3077
        }
3078
2502
3079
        /**
2503
		localHistory.update(s);
3080
         * Returns the file description
2504
		application.addVisitedURI(s);
3081
         */
2505
		backAction.update();
3082
        public String getDescription() {
2506
		forwardAction.update();
3083
            return extension;
2507
3084
        }
2508
		transformHistory = new TransformHistory();
3085
    }
2509
		previousTransformAction.update();
2510
		nextTransformAction.update();
2511
2512
		useStylesheetAction.update();
2513
	}
2514
2515
	/**
2516
	 * Called when the loading of a document was cancelled.
2517
	 */
2518
	public void documentLoadingCancelled(SVGDocumentLoaderEvent e) {
2519
		String msg = resources.getString("Message.documentCancelled");
2520
		if (debug) {
2521
			System.out.println(msg);
2522
		}
2523
		statusBar.setMainMessage("");
2524
		statusBar.setMessage(msg);
2525
		stopAction.update(false);
2526
		svgCanvas.setCursor(DEFAULT_CURSOR);
2527
	}
2528
2529
	/**
2530
	 * Called when the loading of a document has failed.
2531
	 */
2532
	public void documentLoadingFailed(SVGDocumentLoaderEvent e) {
2533
		String msg = resources.getString("Message.documentFailed");
2534
		if (debug) {
2535
			System.out.println(msg);
2536
		}
2537
		statusBar.setMainMessage("");
2538
		statusBar.setMessage(msg);
2539
		stopAction.update(false);
2540
		svgCanvas.setCursor(DEFAULT_CURSOR);
2541
	}
2542
2543
	// GVTTreeBuilderListener //////////////////////////////////////////////
2544
2545
	/**
2546
	 * Called when a build started. The data of the event is initialized to the
2547
	 * old document.
2548
	 */
2549
	public void gvtBuildStarted(GVTTreeBuilderEvent e) {
2550
		String msg = resources.getString("Message.treeBuild");
2551
		if (debug) {
2552
			System.out.println(msg);
2553
			time = System.currentTimeMillis();
2554
		}
2555
		statusBar.setMainMessage(msg);
2556
		stopAction.update(true);
2557
		svgCanvas.setCursor(WAIT_CURSOR);
2558
	}
2559
2560
	/**
2561
	 * Called when a build was completed.
2562
	 */
2563
	public void gvtBuildCompleted(GVTTreeBuilderEvent e) {
2564
		if (debug) {
2565
			System.out.print(resources.getString("Message.treeBuildTime"));
2566
			System.out.println((System.currentTimeMillis() - time) + " ms");
2567
		}
2568
		if (findDialog != null) {
2569
			if (findDialog.isVisible()) {
2570
				findDialog.setGraphicsNode(svgCanvas.getGraphicsNode());
2571
			} else {
2572
				findDialog.dispose();
2573
				findDialog = null;
2574
			}
2575
		}
2576
		stopAction.update(false);
2577
		svgCanvas.setCursor(DEFAULT_CURSOR);
2578
		svgCanvas.setSelectionOverlayXORMode(application
2579
				.isSelectionOverlayXORMode());
2580
		svgCanvas.requestFocus(); // request focus when load completes.
2581
		if (debugger != null) {
2582
			debugger.attach();
2583
		}
2584
	}
2585
2586
	/**
2587
	 * Called when a build was cancelled.
2588
	 */
2589
	public void gvtBuildCancelled(GVTTreeBuilderEvent e) {
2590
		String msg = resources.getString("Message.treeCancelled");
2591
		if (debug) {
2592
			System.out.println(msg);
2593
		}
2594
		statusBar.setMainMessage("");
2595
		statusBar.setMessage(msg);
2596
		stopAction.update(false);
2597
		svgCanvas.setCursor(DEFAULT_CURSOR);
2598
		svgCanvas.setSelectionOverlayXORMode(application
2599
				.isSelectionOverlayXORMode());
2600
	}
2601
2602
	/**
2603
	 * Called when a build failed.
2604
	 */
2605
	public void gvtBuildFailed(GVTTreeBuilderEvent e) {
2606
		String msg = resources.getString("Message.treeFailed");
2607
		if (debug) {
2608
			System.out.println(msg);
2609
		}
2610
		statusBar.setMainMessage("");
2611
		statusBar.setMessage(msg);
2612
		stopAction.update(false);
2613
		svgCanvas.setCursor(DEFAULT_CURSOR);
2614
		svgCanvas.setSelectionOverlayXORMode(application
2615
				.isSelectionOverlayXORMode());
2616
		if (autoAdjust) {
2617
			pack();
2618
		}
2619
	}
2620
2621
	// SVGLoadEventDispatcherListener //////////////////////////////////////
2622
2623
	/**
2624
	 * Called when a onload event dispatch started.
2625
	 */
2626
	public void svgLoadEventDispatchStarted(SVGLoadEventDispatcherEvent e) {
2627
		String msg = resources.getString("Message.onload");
2628
		if (debug) {
2629
			System.out.println(msg);
2630
			time = System.currentTimeMillis();
2631
		}
2632
		stopAction.update(true);
2633
		statusBar.setMainMessage(msg);
2634
	}
2635
2636
	/**
2637
	 * Called when a onload event dispatch was completed.
2638
	 */
2639
	public void svgLoadEventDispatchCompleted(SVGLoadEventDispatcherEvent e) {
2640
		if (debug) {
2641
			System.out.print(resources.getString("Message.onloadTime"));
2642
			System.out.println((System.currentTimeMillis() - time) + " ms");
2643
		}
2644
		stopAction.update(false);
2645
		statusBar.setMainMessage("");
2646
		statusBar.setMessage(resources.getString("Message.done"));
2647
	}
2648
2649
	/**
2650
	 * Called when a onload event dispatch was cancelled.
2651
	 */
2652
	public void svgLoadEventDispatchCancelled(SVGLoadEventDispatcherEvent e) {
2653
		String msg = resources.getString("Message.onloadCancelled");
2654
		if (debug) {
2655
			System.out.println(msg);
2656
		}
2657
		stopAction.update(false);
2658
		statusBar.setMainMessage("");
2659
		statusBar.setMessage(msg);
2660
	}
2661
2662
	/**
2663
	 * Called when a onload event dispatch failed.
2664
	 */
2665
	public void svgLoadEventDispatchFailed(SVGLoadEventDispatcherEvent e) {
2666
		String msg = resources.getString("Message.onloadFailed");
2667
		if (debug) {
2668
			System.out.println(msg);
2669
		}
2670
		stopAction.update(false);
2671
		statusBar.setMainMessage("");
2672
		statusBar.setMessage(msg);
2673
	}
2674
2675
	// GVTTreeRendererListener /////////////////////////////////////////////
2676
2677
	/**
2678
	 * Called when a rendering is in its preparing phase.
2679
	 */
2680
	public void gvtRenderingPrepare(GVTTreeRendererEvent e) {
2681
		if (debug) {
2682
			String msg = resources.getString("Message.treeRenderingPrep");
2683
			System.out.println(msg);
2684
			time = System.currentTimeMillis();
2685
		}
2686
		stopAction.update(true);
2687
		svgCanvas.setCursor(WAIT_CURSOR);
2688
		statusBar.setMainMessage(resources.getString("Message.treeRendering"));
2689
	}
2690
2691
	/**
2692
	 * Called when a rendering started.
2693
	 */
2694
	public void gvtRenderingStarted(GVTTreeRendererEvent e) {
2695
		if (debug) {
2696
			String msg = resources.getString("Message.treeRenderingPrepTime");
2697
			System.out.print(msg);
2698
			System.out.println((System.currentTimeMillis() - time) + " ms");
2699
			time = System.currentTimeMillis();
2700
			msg = resources.getString("Message.treeRenderingStart");
2701
			System.out.println(msg);
2702
		}
2703
		// Do nothing
2704
	}
2705
2706
	/**
2707
	 * Called when a rendering was completed.
2708
	 */
2709
	public void gvtRenderingCompleted(GVTTreeRendererEvent e) {
2710
		if (debug) {
2711
			String msg = resources.getString("Message.treeRenderingTime");
2712
			System.out.print(msg);
2713
			System.out.println((System.currentTimeMillis() - time) + " ms");
2714
		}
2715
		statusBar.setMainMessage("");
2716
		statusBar.setMessage(resources.getString("Message.done"));
2717
		if (!svgCanvas.isDynamic() || managerStopped) {
2718
			stopAction.update(false);
2719
		}
2720
		svgCanvas.setCursor(DEFAULT_CURSOR);
2721
2722
		transformHistory.update(svgCanvas.getRenderingTransform());
2723
		previousTransformAction.update();
2724
		nextTransformAction.update();
2725
	}
2726
2727
	/**
2728
	 * Called when a rendering was cancelled.
2729
	 */
2730
	public void gvtRenderingCancelled(GVTTreeRendererEvent e) {
2731
		String msg = resources.getString("Message.treeRenderingCancelled");
2732
		if (debug) {
2733
			System.out.println(msg);
2734
		}
2735
		statusBar.setMainMessage("");
2736
		statusBar.setMessage(msg);
2737
		if (!svgCanvas.isDynamic()) {
2738
			stopAction.update(false);
2739
		}
2740
		svgCanvas.setCursor(DEFAULT_CURSOR);
2741
	}
2742
2743
	/**
2744
	 * Called when a rendering failed.
2745
	 */
2746
	public void gvtRenderingFailed(GVTTreeRendererEvent e) {
2747
		String msg = resources.getString("Message.treeRenderingFailed");
2748
		if (debug) {
2749
			System.out.println(msg);
2750
		}
2751
		statusBar.setMainMessage("");
2752
		statusBar.setMessage(msg);
2753
		if (!svgCanvas.isDynamic()) {
2754
			stopAction.update(false);
2755
		}
2756
		svgCanvas.setCursor(DEFAULT_CURSOR);
2757
	}
2758
2759
	// LinkActivationListener /////////////////////////////////////////
2760
2761
	/**
2762
	 * Called when a link was activated.
2763
	 */
2764
	public void linkActivated(LinkActivationEvent e) {
2765
		String s = e.getReferencedURI();
2766
		if (svgDocument != null) {
2767
			ParsedURL docURL = new ParsedURL(svgDocument.getURL());
2768
			ParsedURL url = new ParsedURL(docURL, s);
2769
			if (!url.sameFile(docURL)) {
2770
				return;
2771
			}
2772
2773
			if (s.indexOf('#') != -1) {
2774
				localHistory.update(s);
2775
				locationBar.setText(s);
2776
				if (debugger != null) {
2777
					debugger.detach();
2778
					debugger.setDocumentURL(s);
2779
				}
2780
				application.addVisitedURI(s);
2781
				backAction.update();
2782
				forwardAction.update();
2783
2784
				transformHistory = new TransformHistory();
2785
				previousTransformAction.update();
2786
				nextTransformAction.update();
2787
			}
2788
		}
2789
	}
2790
2791
	// UpdateManagerListener ////////////////////////////////////////////////
2792
2793
	/**
2794
	 * Called when the manager was started.
2795
	 */
2796
	public void managerStarted(UpdateManagerEvent e) {
2797
		if (debug) {
2798
			String msg = resources.getString("Message.updateManagerStarted");
2799
			System.out.println(msg);
2800
		}
2801
		managerStopped = false;
2802
		playAction.update(false);
2803
		pauseAction.update(true);
2804
		stopAction.update(true);
2805
	}
2806
2807
	/**
2808
	 * Called when the manager was suspended.
2809
	 */
2810
	public void managerSuspended(UpdateManagerEvent e) {
2811
		if (debug) {
2812
			String msg = resources.getString("Message.updateManagerSuspended");
2813
			System.out.println(msg);
2814
		}
2815
		playAction.update(true);
2816
		pauseAction.update(false);
2817
	}
2818
2819
	/**
2820
	 * Called when the manager was resumed.
2821
	 */
2822
	public void managerResumed(UpdateManagerEvent e) {
2823
		if (debug) {
2824
			String msg = resources.getString("Message.updateManagerResumed");
2825
			System.out.println(msg);
2826
		}
2827
		playAction.update(false);
2828
		pauseAction.update(true);
2829
	}
2830
2831
	/**
2832
	 * Called when the manager was stopped.
2833
	 */
2834
	public void managerStopped(UpdateManagerEvent e) {
2835
		if (debug) {
2836
			String msg = resources.getString("Message.updateManagerStopped");
2837
			System.out.println(msg);
2838
		}
2839
		managerStopped = true;
2840
		playAction.update(false);
2841
		pauseAction.update(false);
2842
		stopAction.update(false);
2843
	}
2844
2845
	/**
2846
	 * Called when an update started.
2847
	 */
2848
	public void updateStarted(final UpdateManagerEvent e) {
2849
	}
2850
2851
	/**
2852
	 * Called when an update was completed.
2853
	 */
2854
	public void updateCompleted(final UpdateManagerEvent e) {
2855
	}
2856
2857
	/**
2858
	 * Called when an update failed.
2859
	 */
2860
	public void updateFailed(UpdateManagerEvent e) {
2861
	}
2862
2863
	/**
2864
	 * This class implements a SVG user agent.
2865
	 */
2866
	protected class UserAgent implements SVGUserAgent {
2867
2868
		/**
2869
		 * Creates a new SVGUserAgent.
2870
		 */
2871
		protected UserAgent() {
2872
		}
2873
2874
		/**
2875
		 * Displays an error message.
2876
		 */
2877
		public void displayError(String message) {
2878
			if (debug) {
2879
				System.err.println(message);
2880
			}
2881
			JOptionPane pane = new JOptionPane(message,
2882
					JOptionPane.ERROR_MESSAGE);
2883
			JDialog dialog = pane.createDialog(JSVGViewerFrame.this, "ERROR");
2884
			dialog.setModal(false);
2885
			dialog.setVisible(true);
2886
		}
2887
2888
		/**
2889
		 * Displays an error resulting from the specified Exception.
2890
		 */
2891
		public void displayError(Exception ex) {
2892
			if (debug) {
2893
				ex.printStackTrace();
2894
			}
2895
			// JErrorPane pane =
2896
			// new JErrorPane(ex, JOptionPane.ERROR_MESSAGE);
2897
			ErrorConsole console = ErrorConsole.getInstance();
2898
			if (ex instanceof LiveAttributeException) {
2899
				LiveAttributeException lex = (LiveAttributeException) ex;
2900
				ParsedURL purl = new ParsedURL(svgDocument.getURL());
2901
				InputStream is = null;
2902
				try {
2903
					is = purl.openStream(getInputHandler(purl)
2904
							.getHandledMimeTypes());
2905
				} catch (IOException e) {
2906
					e.printStackTrace();
2907
					// do nothing, error console will report stream not
2908
					// available
2909
				}
2910
				AttributeErrorInfo info = new AttributeErrorInfo(lex, svgDocument
2911
						.getDocumentURI(), ErrorConsole.ERROR, is, lex
2912
						.getElement(), docDescriptor,
2913
						(ViewSourceAction) listeners.get(VIEW_SOURCE_ACTION),
2914
						(DOMViewerAction) listeners.get(DOM_VIEWER_ACTION));
2915
				console.add(info);
2916
			} else {
2917
				String uri;
2918
				if (svgDocument == null) {
2919
					uri = currentPath.getAbsolutePath();
2920
				} else {
2921
					uri = svgDocument.getDocumentURI();
2922
				}
2923
				ErrorInfo info = new ErrorInfo(ex,
2924
						uri, ErrorConsole.ERROR);
2925
				console.add(info);
2926
			}
2927
			ErrorConsole.showDialog(JSVGViewerFrame.this);
2928
		}
2929
2930
		/**
2931
		 * Displays a message in the User Agent interface. The given message is
2932
		 * typically displayed in a status bar.
2933
		 */
2934
		public void displayMessage(String message) {
2935
			statusBar.setMessage(message);
2936
		}
2937
2938
		/**
2939
		 * Shows an alert dialog box.
2940
		 */
2941
		public void showAlert(String message) {
2942
			svgCanvas.showAlert(message);
2943
		}
2944
2945
		/**
2946
		 * Shows a prompt dialog box.
2947
		 */
2948
		public String showPrompt(String message) {
2949
			return svgCanvas.showPrompt(message);
2950
		}
2951
2952
		/**
2953
		 * Shows a prompt dialog box.
2954
		 */
2955
		public String showPrompt(String message, String defaultValue) {
2956
			return svgCanvas.showPrompt(message, defaultValue);
2957
		}
2958
2959
		/**
2960
		 * Shows a confirm dialog box.
2961
		 */
2962
		public boolean showConfirm(String message) {
2963
			return svgCanvas.showConfirm(message);
2964
		}
2965
2966
		/**
2967
		 * Returns the size of a px CSS unit in millimeters.
2968
		 */
2969
		public float getPixelUnitToMillimeter() {
2970
			return 0.26458333333333333333333333333333f; // 96dpi
2971
		}
2972
2973
		/**
2974
		 * Returns the size of a px CSS unit in millimeters. This will be
2975
		 * removed after next release.
2976
		 * 
2977
		 * @see #getPixelUnitToMillimeter()
2978
		 */
2979
		public float getPixelToMM() {
2980
			return getPixelUnitToMillimeter();
2981
2982
		}
2983
2984
		/**
2985
		 * Returns the default font family.
2986
		 */
2987
		public String getDefaultFontFamily() {
2988
			return application.getDefaultFontFamily();
2989
		}
2990
2991
		/**
2992
		 * Returns the medium font size.
2993
		 */
2994
		public float getMediumFontSize() {
2995
			// 9pt (72pt == 1in)
2996
			return 9f * 25.4f / (72f * getPixelUnitToMillimeter());
2997
		}
2998
2999
		/**
3000
		 * Returns a lighter font-weight.
3001
		 */
3002
		public float getLighterFontWeight(float f) {
3003
			// Round f to nearest 100...
3004
			int weight = ((int) ((f + 50) / 100)) * 100;
3005
			switch (weight) {
3006
			case 100:
3007
				return 100;
3008
			case 200:
3009
				return 100;
3010
			case 300:
3011
				return 200;
3012
			case 400:
3013
				return 300;
3014
			case 500:
3015
				return 400;
3016
			case 600:
3017
				return 400;
3018
			case 700:
3019
				return 400;
3020
			case 800:
3021
				return 400;
3022
			case 900:
3023
				return 400;
3024
			default:
3025
				throw new IllegalArgumentException("Bad Font Weight: " + f);
3026
			}
3027
		}
3028
3029
		/**
3030
		 * Returns a bolder font-weight.
3031
		 */
3032
		public float getBolderFontWeight(float f) {
3033
			// Round f to nearest 100...
3034
			int weight = ((int) ((f + 50) / 100)) * 100;
3035
			switch (weight) {
3036
			case 100:
3037
				return 600;
3038
			case 200:
3039
				return 600;
3040
			case 300:
3041
				return 600;
3042
			case 400:
3043
				return 600;
3044
			case 500:
3045
				return 600;
3046
			case 600:
3047
				return 700;
3048
			case 700:
3049
				return 800;
3050
			case 800:
3051
				return 900;
3052
			case 900:
3053
				return 900;
3054
			default:
3055
				throw new IllegalArgumentException("Bad Font Weight: " + f);
3056
			}
3057
		}
3058
3059
		/**
3060
		 * Returns the language settings.
3061
		 */
3062
		public String getLanguages() {
3063
			return application.getLanguages();
3064
		}
3065
3066
		/**
3067
		 * Returns the user stylesheet uri.
3068
		 * 
3069
		 * @return null if no user style sheet was specified.
3070
		 */
3071
		public String getUserStyleSheetURI() {
3072
			return application.getUserStyleSheetURI();
3073
		}
3074
3075
		/**
3076
		 * Returns the class name of the XML parser.
3077
		 */
3078
		public String getXMLParserClassName() {
3079
			return application.getXMLParserClassName();
3080
		}
3081
3082
		/**
3083
		 * Returns true if the XML parser must be in validation mode, false
3084
		 * otherwise.
3085
		 */
3086
		public boolean isXMLParserValidating() {
3087
			return application.isXMLParserValidating();
3088
		}
3089
3090
		/**
3091
		 * Returns this user agent's CSS media.
3092
		 */
3093
		public String getMedia() {
3094
			return application.getMedia();
3095
		}
3096
3097
		/**
3098
		 * Returns this user agent's alternate style-sheet title.
3099
		 */
3100
		public String getAlternateStyleSheet() {
3101
			return alternateStyleSheet;
3102
		}
3103
3104
		/**
3105
		 * Opens a link.
3106
		 * 
3107
		 * @param uri
3108
		 *            The document URI.
3109
		 * @param newc
3110
		 *            Whether the link should be activated in a new component.
3111
		 */
3112
		public void openLink(String uri, boolean newc) {
3113
			if (newc) {
3114
				application.openLink(uri);
3115
			} else {
3116
				showSVGDocument(uri);
3117
			}
3118
		}
3119
3120
		/**
3121
		 * Tells whether the given extension is supported by this user agent.
3122
		 */
3123
		public boolean supportExtension(String s) {
3124
			return false;
3125
		}
3126
3127
		public void handleElement(Element elt, Object data) {
3128
		}
3129
3130
		/**
3131
		 * Returns the security settings for the given script type, script url
3132
		 * and document url
3133
		 * 
3134
		 * @param scriptType
3135
		 *            type of script, as found in the type attribute of the
3136
		 *            &lt;script&gt; element.
3137
		 * @param scriptURL
3138
		 *            url for the script, as defined in the script's xlink:href
3139
		 *            attribute. If that attribute was empty, then this
3140
		 *            parameter should be null
3141
		 * @param docURL
3142
		 *            url for the document into which the script was found.
3143
		 */
3144
		public ScriptSecurity getScriptSecurity(String scriptType,
3145
				ParsedURL scriptURL, ParsedURL docURL) {
3146
			if (!application.canLoadScriptType(scriptType)) {
3147
				return new NoLoadScriptSecurity(scriptType);
3148
			} else {
3149
				switch (application.getAllowedScriptOrigin()) {
3150
				case ResourceOrigin.ANY:
3151
					return new RelaxedScriptSecurity(scriptType, scriptURL,
3152
							docURL);
3153
				case ResourceOrigin.DOCUMENT:
3154
					return new DefaultScriptSecurity(scriptType, scriptURL,
3155
							docURL);
3156
				case ResourceOrigin.EMBEDED:
3157
					return new EmbededScriptSecurity(scriptType, scriptURL,
3158
							docURL);
3159
				default:
3160
					return new NoLoadScriptSecurity(scriptType);
3161
				}
3162
			}
3163
		}
3164
3165
		/**
3166
		 * This method throws a SecurityException if the script of given type,
3167
		 * found at url and referenced from docURL should not be loaded.
3168
		 * 
3169
		 * This is a convenience method to call checkLoadScript on the
3170
		 * ScriptSecurity strategy returned by getScriptSecurity.
3171
		 * 
3172
		 * @param scriptType
3173
		 *            type of script, as found in the type attribute of the
3174
		 *            &lt;script&gt; element.
3175
		 * @param scriptURL
3176
		 *            url for the script, as defined in the script's xlink:href
3177
		 *            attribute. If that attribute was empty, then this
3178
		 *            parameter should be null
3179
		 * @param docURL
3180
		 *            url for the document into which the script was found.
3181
		 */
3182
		public void checkLoadScript(String scriptType, ParsedURL scriptURL,
3183
				ParsedURL docURL) throws SecurityException {
3184
			ScriptSecurity s = getScriptSecurity(scriptType, scriptURL, docURL);
3185
3186
			if (s != null) {
3187
				s.checkLoadScript();
3188
			}
3189
		}
3190
3191
		/**
3192
		 * Returns the security settings for the given resource url and document
3193
		 * url
3194
		 * 
3195
		 * @param resourceURL
3196
		 *            url for the resource, as defined in the resource's
3197
		 *            xlink:href attribute. If that attribute was empty, then
3198
		 *            this parameter should be null
3199
		 * @param docURL
3200
		 *            url for the document into which the resource was found.
3201
		 */
3202
		public ExternalResourceSecurity getExternalResourceSecurity(
3203
				ParsedURL resourceURL, ParsedURL docURL) {
3204
			switch (application.getAllowedExternalResourceOrigin()) {
3205
			case ResourceOrigin.ANY:
3206
				return new RelaxedExternalResourceSecurity(resourceURL, docURL);
3207
			case ResourceOrigin.DOCUMENT:
3208
				return new DefaultExternalResourceSecurity(resourceURL, docURL);
3209
			case ResourceOrigin.EMBEDED:
3210
				return new EmbededExternalResourceSecurity(resourceURL);
3211
			default:
3212
				return new NoLoadExternalResourceSecurity();
3213
			}
3214
		}
3215
3216
		/**
3217
		 * This method throws a SecurityException if the resource found at url
3218
		 * and referenced from docURL should not be loaded.
3219
		 * 
3220
		 * This is a convenience method to call checkLoadExternalResource on the
3221
		 * ExternalResourceSecurity strategy returned by
3222
		 * getExternalResourceSecurity.
3223
		 * 
3224
		 * @param resourceURL
3225
		 *            url for the script, as defined in the resource's
3226
		 *            xlink:href attribute. If that attribute was empty, then
3227
		 *            this parameter should be null
3228
		 * @param docURL
3229
		 *            url for the document into which the resource was found.
3230
		 */
3231
		public void checkLoadExternalResource(ParsedURL resourceURL,
3232
				ParsedURL docURL) throws SecurityException {
3233
			ExternalResourceSecurity s = getExternalResourceSecurity(
3234
					resourceURL, docURL);
3235
3236
			if (s != null) {
3237
				s.checkLoadExternalResource();
3238
			}
3239
		}
3240
	}
3241
3242
	/**
3243
	 * A FileFilter used when exporting the SVG document as an image.
3244
	 */
3245
	protected static class ImageFileFilter extends FileFilter {
3246
3247
		/** The extension of the image filename. */
3248
		protected String extension;
3249
3250
		public ImageFileFilter(String extension) {
3251
			this.extension = extension;
3252
		}
3253
3254
		/**
3255
		 * Returns true if <tt>f</tt> is a file with the correct extension,
3256
		 * false otherwise.
3257
		 */
3258
		public boolean accept(File f) {
3259
			boolean accept = false;
3260
			String fileName = null;
3261
			if (f != null) {
3262
				if (f.isDirectory()) {
3263
					accept = true;
3264
				} else {
3265
					fileName = f.getPath().toLowerCase();
3266
					if (fileName.endsWith(extension)) {
3267
						accept = true;
3268
					}
3269
				}
3270
			}
3271
			return accept;
3272
		}
3273
3274
		/**
3275
		 * Returns the file description
3276
		 */
3277
		public String getDescription() {
3278
			return extension;
3279
		}
3280
	}
3086
}
3281
}
(-)sources/org/apache/batik/apps/svgbrowser/XMLInputHandler.java (-2 / +3 lines)
Lines 213-219 Link Here
213
        sw.close();
213
        sw.close();
214
214
215
        String parser = XMLResourceDescriptor.getXMLParserClassName();
215
        String parser = XMLResourceDescriptor.getXMLParserClassName();
216
        SAXSVGDocumentFactory f = new SAXSVGDocumentFactory(parser);
216
        SAXSVGDocumentFactory f = new SAXSVGDocumentFactory(parser, true);
217
        SVGDocument outDoc = null;
217
        SVGDocument outDoc = null;
218
218
219
        try {
219
        try {
Lines 234-240 Link Here
234
        svgViewerFrame.getJSVGCanvas().setSVGDocument(outDoc);
234
        svgViewerFrame.getJSVGCanvas().setSVGDocument(outDoc);
235
        svgViewerFrame.setSVGDocument(outDoc,
235
        svgViewerFrame.setSVGDocument(outDoc,
236
                                      uri,
236
                                      uri,
237
                                      outDoc.getTitle());
237
                                      outDoc.getTitle(),
238
                                      f.getDocumentDescriptor());
238
    }
239
    }
239
240
240
    /**
241
    /**
(-)sources/org/apache/batik/util/gui/DOMViewer.java (-1 / +57 lines)
Lines 24-32 Link Here
24
import java.awt.event.ActionEvent;
24
import java.awt.event.ActionEvent;
25
import java.awt.event.ItemEvent;
25
import java.awt.event.ItemEvent;
26
import java.awt.event.ItemListener;
26
import java.awt.event.ItemListener;
27
28
import java.util.ArrayList;
27
import java.util.ArrayList;
29
import java.util.Collections;
28
import java.util.Collections;
29
import java.util.Enumeration;
30
import java.util.HashMap;
30
import java.util.HashMap;
31
import java.util.Locale;
31
import java.util.Locale;
32
import java.util.Map;
32
import java.util.Map;
Lines 52-57 Link Here
52
import javax.swing.tree.DefaultTreeModel;
52
import javax.swing.tree.DefaultTreeModel;
53
import javax.swing.tree.MutableTreeNode;
53
import javax.swing.tree.MutableTreeNode;
54
import javax.swing.tree.TreeNode;
54
import javax.swing.tree.TreeNode;
55
import javax.swing.tree.TreePath;
55
56
56
import org.apache.batik.bridge.svg12.ContentManager;
57
import org.apache.batik.bridge.svg12.ContentManager;
57
import org.apache.batik.bridge.svg12.DefaultXBLManager;
58
import org.apache.batik.bridge.svg12.DefaultXBLManager;
Lines 170-175 Link Here
170
    }
171
    }
171
172
172
    /**
173
    /**
174
     * Sets the node to be selected, none if node is null
175
     */
176
    public void setSelectionNode(Node node) {
177
    	panel.setSelectionNode(node);
178
    }
179
    
180
    /**
181
     * Sets the nodes to be selected, none if nodes is null
182
     */
183
    public void setSelectionNodes(Node[] nodes) {
184
    	panel.setSelectionNodes(nodes);
185
    }
186
    
187
    /**
173
     * Returns the action associated with the given string
188
     * Returns the action associated with the given string
174
     * or null on error
189
     * or null on error
175
     * @param key the key mapped with the action to get
190
     * @param key the key mapped with the action to get
Lines 412-417 Link Here
412
            return result;
427
            return result;
413
        }
428
        }
414
429
430
        public void setSelectionNode(Node node) {
431
        	if (node == null) {
432
        		setSelectionNodes(null);
433
        	} else {
434
        		setSelectionNodes(new Node[]{node});
435
        	}
436
        }
437
        
438
        public void setSelectionNodes(Node[] nodes) {
439
        	tree.setSelectionRow(-1);
440
        	if (nodes == null) {
441
        		return;
442
        	}
443
        	for (int i = 0; i < nodes.length; i++) {
444
        		DefaultMutableTreeNode treeNode = findNode(tree, nodes[i]);
445
        		if (treeNode != null) {
446
        			TreePath path = new TreePath(treeNode.getPath());
447
        			tree.setSelectionPath(path);
448
        		}
449
        	}
450
        }
451
        
452
		/**
453
		 * Returns the node in the tree that represents the given node in the
454
		 * document, or null if not found.
455
		 */
456
		protected DefaultMutableTreeNode findNode(JTree theTree, Node node) {
457
			DefaultMutableTreeNode root = (DefaultMutableTreeNode) theTree
458
					.getModel().getRoot();
459
			Enumeration treeNodes = root.breadthFirstEnumeration();
460
			while (treeNodes.hasMoreElements()) {
461
				DefaultMutableTreeNode currentNode = (DefaultMutableTreeNode) treeNodes
462
						.nextElement();
463
				NodeInfo userObject = (NodeInfo) currentNode.getUserObject();
464
				if (userObject.getNode() == node) {
465
					return currentNode;
466
				}
467
			}
468
			return null;
469
		}
470
415
        /**
471
        /**
416
         * To listen to the tree selection.
472
         * To listen to the tree selection.
417
         */
473
         */
(-)sources/org/apache/batik/util/gui/resource/JFramesView.java (+380 lines)
Line 0 Link Here
1
/*
2
3
 Licensed to the Apache Software Foundation (ASF) under one or more
4
 contributor license agreements.  See the NOTICE file distributed with
5
 this work for additional information regarding copyright ownership.
6
 The ASF licenses this file to You under the Apache License, Version 2.0
7
 (the "License"); you may not use this file except in compliance with
8
 the License.  You may obtain a copy of the License at
9
10
 http://www.apache.org/licenses/LICENSE-2.0
11
12
 Unless required by applicable law or agreed to in writing, software
13
 distributed under the License is distributed on an "AS IS" BASIS,
14
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
 See the License for the specific language governing permissions and
16
 limitations under the License.
17
18
 */
19
package org.apache.batik.util.gui.resource;
20
21
import java.awt.BasicStroke;
22
import java.awt.BorderLayout;
23
import java.awt.Color;
24
import java.awt.Component;
25
import java.awt.Dimension;
26
import java.awt.FontMetrics;
27
import java.awt.Graphics;
28
import java.awt.Graphics2D;
29
import java.awt.Polygon;
30
import java.awt.Rectangle;
31
import java.awt.Stroke;
32
import java.awt.event.ActionEvent;
33
import java.awt.event.AdjustmentEvent;
34
import java.awt.event.AdjustmentListener;
35
import java.awt.event.MouseAdapter;
36
import java.awt.event.MouseEvent;
37
import java.awt.event.MouseListener;
38
import java.awt.event.MouseMotionAdapter;
39
import java.awt.event.MouseMotionListener;
40
import java.util.HashMap;
41
import java.util.Locale;
42
import java.util.Map;
43
import java.util.ResourceBundle;
44
45
import javax.swing.AbstractAction;
46
import javax.swing.Action;
47
import javax.swing.BorderFactory;
48
import javax.swing.Box;
49
import javax.swing.BoxLayout;
50
import javax.swing.JButton;
51
import javax.swing.JComponent;
52
import javax.swing.JLabel;
53
import javax.swing.JPanel;
54
import javax.swing.JPopupMenu;
55
import javax.swing.JScrollBar;
56
import javax.swing.JScrollPane;
57
import javax.swing.border.BevelBorder;
58
59
public class JFramesView extends JPanel implements ActionMap {
60
61
	/**
62
	 * The resource file name
63
	 */
64
	protected static final String RESOURCES = "org.apache.batik.util.gui.resource.resources.JTimeline";
65
66
	/**
67
	 * The resource bundle
68
	 */
69
	protected static ResourceBundle bundle;
70
71
	/**
72
	 * The resource manager
73
	 */
74
	protected static ResourceManager resources;
75
76
	static {
77
		bundle = ResourceBundle.getBundle(RESOURCES, Locale.getDefault());
78
		resources = new ResourceManager(bundle);
79
	}
80
81
	/**
82
	 * The button factory.
83
	 */
84
	protected ButtonFactory bf = new ButtonFactory(bundle, this);
85
86
	/**
87
	 * The menu factory.
88
	 */
89
	protected MenuFactory mf = new MenuFactory(bundle, this);
90
91
	private JTimelineSlider sliderPanel;
92
93
	private JPopupMenu cornerPopup;
94
95
	private JLabel timerLabel;
96
97
	private int precisionMillis = 100;
98
99
	private int pixelsPerUnit = 50;
100
101
	private float value = 1;
102
103
	private int knobPosition;
104
105
	private JScrollPane framesScrollPane;
106
	
107
	private JScrollBar verticalScrollBar;
108
	
109
	public JFramesView() {
110
		super(new BorderLayout());
111
112
		actions.put("CornerButtonAction", new CornerButtonAction());
113
		actions.put("IncreaseUnitSizeMenuItemAction",
114
				new IncreaseUnitSizeMenuItemAction());
115
		actions.put("DecreaseUnitSizeMenuItemAction",
116
				new DecreaseUnitSizeMenuItemAction());
117
118
		sliderPanel = new JTimelineSlider();
119
120
		framesScrollPane = new JScrollPane(
121
				new JTimelineFramesPanel());
122
		framesScrollPane.setBorder(null);
123
		framesScrollPane
124
				.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
125
		framesScrollPane
126
				.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
127
		framesScrollPane.setColumnHeaderView(sliderPanel);
128
129
		JButton cornerButton = bf.createJButton("CornerButton");
130
		cornerButton.setFocusable(false);
131
		cornerPopup = new JPopupMenu();
132
		cornerPopup.add(mf.createJMenuItem("IncreaseUnitSizeMenuItem"));
133
		cornerPopup.add(mf.createJMenuItem("DecreaseUnitSizeMenuItem"));
134
		framesScrollPane
135
				.setCorner(JScrollPane.UPPER_RIGHT_CORNER, cornerButton);
136
		add(framesScrollPane);
137
138
		Box footerPanel = new Box(BoxLayout.X_AXIS);
139
		add(footerPanel, BorderLayout.SOUTH);
140
		timerLabel = new JLabel("-- : -- : --");
141
		timerLabel.setBorder(BorderFactory
142
				.createBevelBorder(BevelBorder.LOWERED));
143
		footerPanel.add(timerLabel);
144
		JScrollBar horizScrollBar = new JScrollBar(JScrollBar.HORIZONTAL);
145
		int prefHeight = horizScrollBar.getPreferredSize().height;
146
		footerPanel
147
				.setMaximumSize(new Dimension(Integer.MAX_VALUE, prefHeight));
148
		footerPanel.setMinimumSize(new Dimension(0, prefHeight));
149
		footerPanel.setPreferredSize(footerPanel.getMinimumSize());
150
		footerPanel.add(horizScrollBar);
151
		footerPanel.add(Box.createHorizontalStrut(framesScrollPane
152
				.getVerticalScrollBar().getPreferredSize().width));
153
	}
154
155
	public JScrollBar getVerticalScrollBar() {
156
		return verticalScrollBar;
157
	}
158
159
	public void setVerticalScrollBar(JScrollBar verticalScrollBar) {
160
		this.verticalScrollBar = verticalScrollBar;
161
		add(verticalScrollBar, BorderLayout.EAST);
162
		verticalScrollBar.addAdjustmentListener(new AdjustmentListener() {
163
			public void adjustmentValueChanged(AdjustmentEvent e) {
164
				
165
			}
166
		});
167
	}
168
169
	/**
170
	 * The map that contains the actions
171
	 */
172
	protected Map actions = new HashMap();
173
174
	/**
175
	 * Returns the action associated with the given string or null on error
176
	 * 
177
	 * @param key
178
	 *            the key mapped with the action to get
179
	 * @throws MissingListenerException
180
	 *             if the action is not found
181
	 */
182
	public Action getAction(String key) throws MissingListenerException {
183
		return (Action) actions.get(key);
184
	}
185
186
	protected class CornerButtonAction extends AbstractAction {
187
188
		public void actionPerformed(ActionEvent evt) {
189
			Component invoker = (Component) evt.getSource();
190
			cornerPopup.show(invoker, 0, invoker.getHeight());
191
		}
192
	}
193
194
	protected class IncreaseUnitSizeMenuItemAction extends AbstractAction {
195
196
		public void actionPerformed(ActionEvent evt) {
197
			// TODO:
198
			// Increase unit size in timeline slider
199
		}
200
	}
201
202
	protected class DecreaseUnitSizeMenuItemAction extends AbstractAction {
203
204
		public void actionPerformed(ActionEvent evt) {
205
			// TODO:
206
			// Decrease unit size in timeline slider
207
		}
208
	}
209
210
	public void paint(Graphics g) {
211
		knobPosition = (int) (value * pixelsPerUnit) + SLIDER_X_OFFSET;
212
213
		super.paint(g);
214
	}
215
216
	public static final int SLIDER_X_OFFSET = 10;
217
218
	private static final Color SLIDER_KNOB_FILL_COLOR = new Color(0x77FF7777,
219
			true);
220
221
	private static final Color SLIDER_KNOB_STROKE_COLOR = new Color(0x00FF0000);
222
223
	private static final Stroke SLIDER_KNOB_STROKE = new BasicStroke(1,
224
			BasicStroke.CAP_SQUARE, BasicStroke.JOIN_BEVEL, 5.0f,
225
			new float[] { 5.0f }, 0.0f);
226
227
	private class JTimelineSlider extends JComponent {
228
229
		private boolean paintTrack = false;
230
231
		private Polygon knob;
232
233
		private Rectangle knobBounds;
234
235
		private boolean over;
236
237
		private MouseMotionListener mml = new MouseMotionAdapter() {
238
			public void mouseMoved(MouseEvent e) {
239
				int x = e.getX(), y = e.getY();
240
				boolean b = knobBounds.contains(x, y);
241
				if (b != b) {
242
					repaint();
243
				}
244
				over = b;
245
			}
246
247
			public void mouseDragged(MouseEvent e) {
248
				if (over) {
249
					int x = e.getX();
250
					if (x >= SLIDER_X_OFFSET) {
251
						value = (float) (x - SLIDER_X_OFFSET) / pixelsPerUnit;
252
						JFramesView.this.repaint();
253
					}
254
				}
255
			}
256
		};
257
258
		public JTimelineSlider() {
259
			int height = 30;
260
261
			setMaximumSize(new Dimension(Integer.MAX_VALUE, height));
262
			setMinimumSize(new Dimension(0, height));
263
			setPreferredSize(getMinimumSize());
264
			setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
265
			addMouseMotionListener(mml);
266
267
			int pos = height / 2 - 3;
268
			knob = new Polygon();
269
			knob.addPoint(-4, -pos);
270
			knob.addPoint(4, -pos);
271
			knob.addPoint(4, pos);
272
			knob.addPoint(-4, pos);
273
			knob.addPoint(-4, -pos);
274
275
			knobBounds = new Rectangle(6, height);
276
		}
277
278
		protected void paintComponent(Graphics g) {
279
			super.paintComponent(g);
280
281
			Dimension size = getSize();
282
			if (paintTrack) {
283
				int pos = size.height / 2;
284
				g.setColor(Color.gray);
285
				g.fillRect(0, pos - 1, size.width, 2);
286
				g.setColor(Color.white);
287
				g.drawLine(0, pos + 1, size.width, pos + 1);
288
			}
289
290
			int dx = pixelsPerUnit * precisionMillis / 1000;
291
			FontMetrics fm = g.getFontMetrics();
292
			int timeUnit = 0;
293
			for (int i = SLIDER_X_OFFSET; i < size.width; i += pixelsPerUnit) {
294
				String str = timeUnit++ + "";
295
				int strWidth = fm.stringWidth(str), strHeight = fm.getHeight()
296
						- fm.getDescent();
297
				g.setColor(getBackground());
298
				g.fillRect(i - strWidth / 2, (size.height - strHeight) / 2,
299
						strWidth, strHeight);
300
				g.setColor(Color.black);
301
				g.drawString(str, i - strWidth / 2,
302
						(size.height + strHeight) / 2);
303
				g.setColor(Color.gray);
304
				g.drawLine(i, size.height - 2, i, size.height - 7);
305
				g.drawLine(i, 2, i, 7);
306
				g.setColor(Color.lightGray);
307
				for (int j = i + dx; j < i + pixelsPerUnit; j += dx) {
308
					g.drawLine(j, size.height - 2, j, size.height - 5);
309
					g.drawLine(j, 2, j, 5);
310
				}
311
			}
312
313
			// Paint knob
314
			int x = knobPosition;
315
			int y = size.height / 2;
316
			knobBounds.x = x - knobBounds.width / 2;
317
			knobBounds.y = y - knobBounds.height / 2;
318
319
			g.translate(x, y);
320
			g.setColor(SLIDER_KNOB_FILL_COLOR);
321
			g.fillPolygon(knob);
322
			g.setColor(SLIDER_KNOB_STROKE_COLOR);
323
			g.drawPolygon(knob);
324
			g.translate(-x, -y);
325
		}
326
	}
327
328
	private class JTimelineFramesPanel extends JPanel {
329
330
		private boolean inside;
331
332
		private int hoverPosition;
333
		
334
		private MouseListener ml = new MouseAdapter() {
335
			public void mouseEntered(MouseEvent e) {
336
				inside = true;
337
				JFramesView.this.repaint();
338
			}
339
340
			public void mouseExited(MouseEvent e) {
341
				inside = false;
342
				JFramesView.this.repaint();
343
			}
344
		};
345
346
		private MouseMotionListener mml = new MouseMotionAdapter() {
347
			public void mouseMoved(MouseEvent e) {
348
				int x = e.getX() - SLIDER_X_OFFSET;
349
				int dx = pixelsPerUnit * precisionMillis / 1000;
350
				hoverPosition = SLIDER_X_OFFSET + x - x % dx;
351
				JFramesView.this.repaint();
352
			}
353
		};
354
355
		public JTimelineFramesPanel() {
356
			addMouseListener(ml);
357
			addMouseMotionListener(mml);
358
		}
359
360
		protected void paintComponent(Graphics g) {
361
			Dimension size = getSize();
362
			
363
			int dx = pixelsPerUnit * precisionMillis / 1000;
364
			g.setColor(Color.lightGray);
365
			for (int i = SLIDER_X_OFFSET; i < size.width; i += dx) {
366
				g.drawLine(i, 0, i, size.height);
367
			}
368
369
			g.setColor(SLIDER_KNOB_STROKE_COLOR);
370
			g.drawLine(knobPosition, 0, knobPosition, size.height);
371
			
372
			if (inside) {
373
				Graphics2D g2 = (Graphics2D)g;
374
				g2.setStroke(SLIDER_KNOB_STROKE);
375
				
376
				g2.drawLine(hoverPosition, 0, hoverPosition, size.height);
377
			}
378
		}
379
	}
380
}
(-)sources/org/apache/batik/util/gui/resource/ButtonFactory.java (+26 lines)
Lines 28-33 Link Here
28
import javax.swing.JButton;
28
import javax.swing.JButton;
29
import javax.swing.JCheckBox;
29
import javax.swing.JCheckBox;
30
import javax.swing.JRadioButton;
30
import javax.swing.JRadioButton;
31
import javax.swing.JToggleButton;
31
32
32
/**
33
/**
33
 * This class represents a button factory which builds
34
 * This class represents a button factory which builds
Lines 123-128 Link Here
123
    }
124
    }
124
125
125
    /**
126
    /**
127
     * Creates and returns a new swing button initialised
128
     * to be used as a toolbar toggle button
129
     * @param name the name of the button in the resource bundle
130
     * @throws MissingResourceException if key is not the name of a button.
131
     *         It is not thrown if the mnemonic and the action keys are missing
132
     * @throws ResourceFormatException if the mnemonic is not a single
133
     *         character
134
     * @throws MissingListenerException if the button action is not found in
135
     *         the action map
136
     */
137
    public JToggleButton createJToolbarToggleButton(String name)
138
        throws MissingResourceException,
139
               ResourceFormatException,
140
               MissingListenerException {
141
        JToggleButton result;
142
        try {
143
            result = new JToolbarToggleButton(getString(name+TEXT_SUFFIX));
144
        } catch (MissingResourceException e) {
145
            result = new JToolbarToggleButton();
146
        }
147
        initializeButton(result, name);
148
        return result;
149
    }
150
151
    /**
126
     * Creates and returns a new swing radio button
152
     * Creates and returns a new swing radio button
127
     * @param name the name of the button in the resource bundle
153
     * @param name the name of the button in the resource bundle
128
     * @throws MissingResourceException if key is not the name of a button.
154
     * @throws MissingResourceException if key is not the name of a button.
(-)sources/org/apache/batik/util/gui/resource/Hyperlink.java (+72 lines)
Line 0 Link Here
1
package org.apache.batik.util.gui.resource;
2
3
import java.awt.Cursor;
4
import java.awt.event.MouseAdapter;
5
import java.awt.event.MouseEvent;
6
import java.awt.event.MouseListener;
7
8
import javax.swing.JLabel;
9
10
public class Hyperlink extends JLabel {
11
	private MouseListener ml = new MouseAdapter() {
12
		public void mouseClicked(MouseEvent e) {
13
			if (callback != null) {
14
				callback.linkClicked(new HyperlinkEvent(Hyperlink.this.getCommand()));
15
			}
16
		}
17
	};
18
	
19
	private HyperlinkCallback callback;
20
	
21
	private String command;
22
	
23
	private static final String HTML_TEXT = "<html><font color=\"blue\"><u>__HTML_TEXT__</u></font></html>";
24
	
25
	private String text;
26
	
27
	public Hyperlink(String text, HyperlinkCallback callback) {
28
		this.callback = callback;
29
		setLinkText(text);
30
		setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
31
		addMouseListener(ml);
32
	}
33
34
	public String getLinkText() {
35
		return text;
36
	}
37
	
38
	public void setLinkText(String text) {
39
		this.text = text;
40
		super.setText(HTML_TEXT.replace("__HTML_TEXT__", text));
41
	}
42
43
	public String getCommand() {
44
		return command;
45
	}
46
47
	public void setCommand(String command) {
48
		this.command = command;
49
	}
50
51
	public static class HyperlinkEvent {
52
		
53
		private String command;
54
		
55
		public HyperlinkEvent(String command) {
56
			this.command = command;
57
		}
58
59
		public String getCommand() {
60
			return command;
61
		}
62
63
		public void setCommand(String command) {
64
			this.command = command;
65
		}
66
	}
67
	
68
	public static interface HyperlinkCallback {
69
		public void linkClicked(HyperlinkEvent e);
70
	}
71
}
72
(-)sources/org/apache/batik/util/gui/resource/JToolbarButton.java (-1 / +9 lines)
Lines 23-28 Link Here
23
import java.awt.event.MouseEvent;
23
import java.awt.event.MouseEvent;
24
24
25
import javax.swing.JButton;
25
import javax.swing.JButton;
26
import javax.swing.UIManager;
26
27
27
/**
28
/**
28
 * This class represents the buttons used in toolbars.
29
 * This class represents the buttons used in toolbars.
Lines 57-63 Link Here
57
        }
58
        }
58
        setBorderPainted(false);
59
        setBorderPainted(false);
59
        setMargin(new Insets(2, 2, 2, 2));
60
        setMargin(new Insets(2, 2, 2, 2));
60
        addMouseListener(new MouseListener());
61
62
        // Windows XP look and feel seems to have a bug due to which the
63
        // size of the parent container changes when the border painted
64
        // property is set. Temporary fix: disable mouseover behavior if
65
        // installed lnf is Windows XP
66
        if (!UIManager.getLookAndFeel().getName().equals("Windows")) {
67
	        addMouseListener(new MouseListener());
68
        }
61
    }
69
    }
62
70
63
    /**
71
    /**
(-)sources/org/apache/batik/util/gui/resource/JDocumentTree.java (+375 lines)
Line 0 Link Here
1
package org.apache.batik.util.gui.resource;
2
3
import java.awt.BorderLayout;
4
import java.awt.Color;
5
import java.awt.Component;
6
import java.awt.Dimension;
7
import java.awt.GradientPaint;
8
import java.awt.Graphics;
9
import java.awt.Graphics2D;
10
import java.awt.Paint;
11
import java.awt.event.MouseAdapter;
12
import java.awt.event.MouseEvent;
13
import java.util.ArrayList;
14
import java.util.Locale;
15
import java.util.ResourceBundle;
16
17
import javax.swing.BorderFactory;
18
import javax.swing.DefaultListModel;
19
import javax.swing.ImageIcon;
20
import javax.swing.JComponent;
21
import javax.swing.JLabel;
22
import javax.swing.JList;
23
import javax.swing.JPanel;
24
import javax.swing.JScrollBar;
25
import javax.swing.JScrollPane;
26
import javax.swing.ListCellRenderer;
27
28
import org.w3c.dom.Document;
29
import org.w3c.dom.NamedNodeMap;
30
import org.w3c.dom.Node;
31
import org.w3c.dom.NodeList;
32
33
public class JDocumentTree extends JPanel {
34
35
	/**
36
	 * The resource file name
37
	 */
38
	protected static final String RESOURCES = "org.apache.batik.util.gui.resource.resources.JDocumentTree";
39
40
	/**
41
	 * The resource bundle
42
	 */
43
	protected static ResourceBundle bundle;
44
45
	/**
46
	 * The resource manager
47
	 */
48
	protected static ResourceManager resources;
49
50
	static {
51
		bundle = ResourceBundle.getBundle(RESOURCES, Locale.getDefault());
52
		resources = new ResourceManager(bundle);
53
	}
54
55
	private JList nodeList;
56
57
	private JScrollPane nodeListScrollPane;
58
59
	private DocumentTreeNode rootNode;
60
61
	public JDocumentTree() {
62
		this(null);
63
	}
64
65
	public JDocumentTree(Document document) {
66
		super(new BorderLayout());
67
68
		nodeList = new JList(new DefaultListModel()) {
69
			public String getToolTipText(MouseEvent e) {
70
		        int index = locationToIndex(e.getPoint());
71
		        if (index >= 0) {
72
		          DocumentTreeNode docTreeNode = (DocumentTreeNode)getModel().getElementAt(index);
73
		          return docTreeNode.getToolTipText();
74
		        } else {
75
		          return null;
76
		        }
77
			}
78
		};
79
		nodeList.setFixedCellHeight(25);
80
		nodeList.setCellRenderer(new DocTreeCellRenderer());
81
		nodeListScrollPane = new JScrollPane(nodeList);
82
		nodeListScrollPane
83
				.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
84
		nodeListScrollPane.setBorder(null);
85
		add(nodeListScrollPane);
86
87
		nodeList.addMouseListener(new MouseAdapter() {
88
			public void mouseClicked(MouseEvent e) {
89
				if (e.getClickCount() == 2) {
90
					DocumentTreeNode selectedNode = (DocumentTreeNode) nodeList
91
							.getSelectedValue();
92
					selectedNode.setExpanded(!selectedNode.isExpanded());
93
					rebuildNodeList(nodeList, rootNode);
94
				}
95
			}
96
		});
97
		
98
		setDocument(document);
99
	}
100
101
	public void setDocument(Document document) {
102
		if (document == null) {
103
			DefaultListModel model = (DefaultListModel)nodeList.getModel();
104
			model.removeAllElements();
105
		} else {
106
			Node root = document.getDocumentElement();
107
			rootNode = parse(root, null);
108
			rebuildNodeList(nodeList, rootNode);
109
		}
110
	}
111
112
	public JScrollBar getVerticalScrollBar() {
113
		return nodeListScrollPane.getVerticalScrollBar();
114
	}
115
116
	public void setVerticalScrollBar(JScrollBar verticalScrollBar) {
117
		nodeListScrollPane.setVerticalScrollBar(verticalScrollBar);
118
	}
119
120
	private void rebuildNodeList(JList nodeList, DocumentTreeNode node) {
121
		DefaultListModel listModel = (DefaultListModel) nodeList.getModel();
122
		listModel.clear();
123
		addNode(listModel, node);
124
	}
125
126
	private void addNode(DefaultListModel listModel, DocumentTreeNode node) {
127
		DocumentTreeNode parent = node.getParent();
128
		if (parent == null || parent.isExpanded()) {
129
			listModel.addElement(node);
130
			DocumentTreeNode[] children = node.getChildren();
131
			if (children != null) {
132
				for (int i = 0; i < children.length; i++) {
133
					addNode(listModel, children[i]);
134
				}
135
			}
136
		}
137
	}
138
139
	private DocumentTreeNode parse(Node node, DocumentTreeNode parent) {
140
		if (node == null) {
141
			return null;
142
		}
143
		ArrayList childDocNodes = null;
144
		DocumentTreeNode docNode = new DocumentTreeNode(parent, node
145
				.getNodeName(), node.getNodeValue(), Node.ELEMENT_NODE);
146
		NamedNodeMap attrMap = node.getAttributes();
147
		for (int i = 0; i < attrMap.getLength(); i++) {
148
			Node item = attrMap.item(i);
149
			int type = item.getNodeType();
150
			if (type == Node.ATTRIBUTE_NODE) {
151
				if (childDocNodes == null) {
152
					childDocNodes = new ArrayList();
153
				}
154
				DocumentTreeNode attrNode = new DocumentTreeNode(docNode, item.getNodeName(), item.getNodeValue(), Node.ATTRIBUTE_NODE);
155
				childDocNodes.add(attrNode);
156
			}
157
		}
158
		NodeList childNodes = node.getChildNodes();
159
		for (int i = 0; i < childNodes.getLength(); i++) {
160
			Node item = childNodes.item(i);
161
			int type = item.getNodeType();
162
			if (type == Node.ELEMENT_NODE) {
163
				if (childDocNodes == null) {
164
					childDocNodes = new ArrayList();
165
				}
166
				DocumentTreeNode childDocNode = parse(item, docNode);
167
				if (childDocNode != null) {
168
					childDocNodes.add(childDocNode);
169
				}
170
			}
171
		}
172
		if (childDocNodes != null) {
173
			docNode.setChildren((DocumentTreeNode[]) childDocNodes
174
					.toArray(new DocumentTreeNode[0]));
175
		}
176
177
		return docNode;
178
	}
179
180
	private class DocumentTreeNode {
181
182
		private String text;
183
184
		private String toolTipText;
185
		
186
		private DocumentTreeNode parent;
187
188
		private int type;
189
190
		private int depth;
191
192
		private DocumentTreeNode[] children;
193
194
		private boolean expanded = true;
195
196
		private boolean locked = false;
197
198
		public DocumentTreeNode(DocumentTreeNode parent, String name, String value, int type) {
199
			this.parent = parent;
200
			this.type = type;
201
			this.depth = parent == null ? 0 : parent.depth + 1;
202
			this.setText(name);
203
			this.setToolTipText(value);
204
		}
205
206
		public DocumentTreeNode getParent() {
207
			return parent;
208
		}
209
210
		public int getDepth() {
211
			return depth;
212
		}
213
214
		public DocumentTreeNode[] getChildren() {
215
			return children;
216
		}
217
218
		public int getChildCount() {
219
			return children == null ? 0 : children.length;
220
		}
221
222
		public void setChildren(DocumentTreeNode[] children) {
223
			this.children = children;
224
			if (children != null) {
225
				for (int i = 0; i < children.length; i++) {
226
					children[i].parent = this;
227
				}
228
			}
229
		}
230
231
		public boolean isExpanded() {
232
			if (parent == null) {
233
				return true;
234
			}
235
			if (!expanded) {
236
				return false;
237
			}
238
			return parent.isExpanded();
239
		}
240
241
		public void setExpanded(boolean expanded) {
242
			this.expanded = expanded;
243
		}
244
245
		public String getText() {
246
			return text;
247
		}
248
249
		public void setText(String text) {
250
			this.text = text;
251
		}
252
253
		public int getType() {
254
			return type;
255
		}
256
257
		public void setType(int type) {
258
			this.type = type;
259
		}
260
261
		public String getToolTipText() {
262
			return toolTipText;
263
		}
264
265
		public void setToolTipText(String toolTipText) {
266
			this.toolTipText = toolTipText;
267
		}
268
	}
269
270
	private class DocTreeCellRenderer extends JLabel implements
271
			ListCellRenderer {
272
273
		private class PaintAttributes {
274
			public Paint paint, paintHighlight;
275
276
			public Color colorText, colorHighlightText;
277
		}
278
279
		private final ImageIcon SPACER_ICON = getIcon("TreeNodeSpacer.icon");
280
281
		private final ImageIcon CLOSED_ICON = getIcon("TreeNodeClosed.icon");
282
283
		private final ImageIcon OPENED_ICON = getIcon("TreeNodeOpened.icon");
284
285
		private final ImageIcon LEAF_ICON = getIcon("TreeLeaf.icon");
286
287
		private final ImageIcon LOCK_ICON = getIcon("TreeNodeLocked.icon");
288
289
		private PaintAttributes elementPaint;
290
291
		private PaintAttributes attributePaint;
292
293
		private boolean selected;
294
295
		private int type;
296
297
		private boolean locked = true;
298
299
		public DocTreeCellRenderer() {
300
			setIcon(SPACER_ICON);
301
302
			Dimension dim = getPreferredSize();
303
			elementPaint = new PaintAttributes();
304
			elementPaint.paint = new Color(234, 234, 234);
305
			elementPaint.paintHighlight = new GradientPaint(0, 0, Color.gray,
306
					0, 2 * dim.height, Color.white);
307
			elementPaint.colorText = Color.black;
308
			elementPaint.colorHighlightText = Color.white;
309
310
			attributePaint = new PaintAttributes();
311
			attributePaint.paint = new Color(216, 216, 216);
312
			attributePaint.paintHighlight = new GradientPaint(0, 0,
313
					Color.darkGray, 0, 2 * dim.height, Color.lightGray);
314
			attributePaint.colorText = Color.black;
315
			attributePaint.colorHighlightText = Color.white;
316
		}
317
318
		private ImageIcon getIcon(String name) {
319
			return new ImageIcon(JDocumentTree.this.getClass().getResource(
320
					resources.getString(name)));
321
		}
322
323
		protected void paintComponent(Graphics g) {
324
			Dimension size = getSize();
325
			Graphics2D g2 = (Graphics2D) g;
326
			PaintAttributes paintAttributes;
327
			switch (type) {
328
			case Node.ATTRIBUTE_NODE:
329
				paintAttributes = attributePaint;
330
				break;
331
			case Node.ELEMENT_NODE:
332
			default:
333
				paintAttributes = elementPaint;
334
				break;
335
			}
336
			g2.setPaint(selected ? paintAttributes.paintHighlight : paintAttributes.paint);
337
			g2.fillRect(0, 0, size.width, size.height);
338
339
			g2.setColor(Color.lightGray);
340
			g2.drawLine(0, size.height - 2, size.width, size.height - 2);
341
			g2.setColor(Color.white);
342
			g2.drawLine(0, size.height - 1, size.width, size.height - 1);
343
344
			setForeground(selected ? paintAttributes.colorHighlightText : paintAttributes.colorText);
345
			super.paintComponent(g);
346
347
			g.setColor(Color.white);
348
			int x, y;
349
			x = size.width - 18;
350
			y = (size.height - 16) / 2;
351
			g.draw3DRect(x, y, 16, 16, false);
352
			if (locked) {
353
				LOCK_ICON.paintIcon(this, g, x, y);
354
			}
355
		}
356
357
		public Component getListCellRendererComponent(JList list, Object value,
358
				int index, boolean selected, boolean cellHasFocus) {
359
			DocumentTreeNode node = (DocumentTreeNode) value;
360
			this.selected = selected;
361
			this.type = node.getType();
362
			setText(node.getText());
363
			setBorder(BorderFactory.createEmptyBorder(0, node.depth * 10, 0, 0));
364
			if (node.getChildren() == null || node.getChildCount() == 0) {// leaf
365
				setIcon(LEAF_ICON);
366
			} else if (node.isExpanded()) {
367
				setIcon(OPENED_ICON);
368
			} else {
369
				setIcon(CLOSED_ICON);
370
			}
371
372
			return this;
373
		}
374
	}
375
}
(-)sources/org/apache/batik/util/gui/resource/JToolbarToggleButton.java (+84 lines)
Line 0 Link Here
1
/*
2
3
   Licensed to the Apache Software Foundation (ASF) under one or more
4
   contributor license agreements.  See the NOTICE file distributed with
5
   this work for additional information regarding copyright ownership.
6
   The ASF licenses this file to You under the Apache License, Version 2.0
7
   (the "License"); you may not use this file except in compliance with
8
   the License.  You may obtain a copy of the License at
9
10
       http://www.apache.org/licenses/LICENSE-2.0
11
12
   Unless required by applicable law or agreed to in writing, software
13
   distributed under the License is distributed on an "AS IS" BASIS,
14
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
   See the License for the specific language governing permissions and
16
   limitations under the License.
17
18
 */
19
package org.apache.batik.util.gui.resource;
20
21
import java.awt.Insets;
22
import java.awt.event.MouseAdapter;
23
import java.awt.event.MouseEvent;
24
25
import javax.swing.JToggleButton;
26
import javax.swing.UIManager;
27
28
import org.apache.batik.util.gui.resource.JToolbarButton.MouseListener;
29
30
/**
31
 * This class represents the buttons used in toolbars.
32
 *
33
 * @author <a href="mailto:stephane@hillion.org">Stephane Hillion</a>
34
 * @version $Id: JToolbarButton.java 498555 2007-01-22 08:09:33Z cam $
35
 */
36
public class JToolbarToggleButton extends JToggleButton {
37
    /**
38
     * Creates a new toolbar button.
39
     */
40
    public JToolbarToggleButton() {
41
        initialize();
42
    }
43
44
    /**
45
     * Creates a new toolbar button.
46
     * @param txt The button text.
47
     */
48
    public JToolbarToggleButton(String txt) {
49
        super(txt);
50
        initialize();
51
    }
52
53
    /**
54
     * Initializes the button.
55
     */
56
    protected void initialize() {
57
        if (!System.getProperty("java.version").startsWith("1.3")) {
58
            setOpaque(false);
59
            setBackground(new java.awt.Color(0, 0, 0, 0));
60
        }
61
        setBorderPainted(false);
62
        setMargin(new Insets(2, 2, 2, 2));
63
64
        // Windows XP look and feel seems to have a bug due to which the
65
        // size of the parent container changes when the border painted
66
        // property is set. Temporary fix: disable mouseover behavior if
67
        // installed lnf is Windows XP
68
        if (!UIManager.getLookAndFeel().getName().equals("Windows")) {
69
	        addMouseListener(new MouseListener());
70
        }
71
    }
72
73
    /**
74
     * To manage the mouse interactions.
75
     */
76
    protected class MouseListener extends MouseAdapter {
77
        public void mouseEntered(MouseEvent ev) {
78
            setBorderPainted(true);
79
        }
80
        public void mouseExited(MouseEvent ev) {
81
            setBorderPainted(false);
82
        }
83
    }
84
}
(-)sources/org/apache/batik/util/gui/TimelineViewer.java (+222 lines)
Line 0 Link Here
1
package org.apache.batik.util.gui;
2
3
import java.awt.BorderLayout;
4
import java.awt.Container;
5
import java.awt.Dimension;
6
import java.awt.event.ActionEvent;
7
import java.io.File;
8
import java.util.HashMap;
9
import java.util.Locale;
10
import java.util.Map;
11
import java.util.ResourceBundle;
12
13
import javax.swing.AbstractAction;
14
import javax.swing.Action;
15
import javax.swing.JDialog;
16
import javax.swing.JFrame;
17
import javax.swing.JPanel;
18
import javax.swing.JScrollBar;
19
import javax.swing.JSeparator;
20
import javax.swing.JSplitPane;
21
import javax.swing.JToolBar;
22
23
import org.apache.batik.dom.svg.SAXSVGDocumentFactory;
24
import org.apache.batik.util.gui.resource.ActionMap;
25
import org.apache.batik.util.gui.resource.JDocumentTree;
26
import org.apache.batik.util.gui.resource.JFramesView;
27
import org.apache.batik.util.gui.resource.MissingListenerException;
28
import org.apache.batik.util.gui.resource.ResourceManager;
29
import org.apache.batik.util.gui.resource.ToolBarFactory;
30
import org.w3c.dom.Document;
31
import org.w3c.dom.svg.SVGDocument;
32
33
public class TimelineViewer extends JFrame implements ActionMap {
34
35
	/**
36
	 * The resource file name
37
	 */
38
	protected static final String RESOURCES = "org.apache.batik.util.gui.resources.TimelineViewer";
39
40
	/**
41
	 * The resource bundle
42
	 */
43
	protected static ResourceBundle bundle;
44
45
	/**
46
	 * The resource manager
47
	 */
48
	protected static ResourceManager resources;
49
50
	static {
51
		bundle = ResourceBundle.getBundle(RESOURCES, Locale.getDefault());
52
		resources = new ResourceManager(bundle);
53
	}
54
55
	/**
56
	 * The toolbar factory.
57
	 */
58
	protected ToolBarFactory tf = new ToolBarFactory(bundle, this);
59
60
	private Document document;
61
62
	private JDocumentTree docTree;
63
	
64
	public TimelineViewer() {
65
		this(null);
66
	}
67
68
	public TimelineViewer(Document document) {
69
		super("Timeline Viewer");
70
		
71
		Container contentPane = getContentPane();
72
		contentPane.setPreferredSize(new Dimension(800, 300));
73
74
		JSplitPane splitPane = new JSplitPane();
75
		splitPane.setResizeWeight(0.0);
76
		JPanel leftPane = new JPanel();
77
		splitPane.setLeftComponent(leftPane);
78
79
		leftPane.setLayout(new BorderLayout());
80
		leftPane.setMinimumSize(new Dimension(300, 0));
81
		leftPane.setPreferredSize(getMinimumSize());
82
		leftPane.add(createToolBar(), BorderLayout.NORTH);
83
84
		JScrollBar scrollBar = new JScrollBar(JScrollBar.VERTICAL, 0, 1, 0, 100);
85
		docTree = new JDocumentTree(document);
86
		docTree.setVerticalScrollBar(scrollBar);
87
		leftPane.add(docTree);
88
89
		JFramesView framesView = new JFramesView();
90
		framesView.setVerticalScrollBar(scrollBar);
91
		splitPane.setRightComponent(framesView);
92
		contentPane.add(splitPane);
93
		
94
		pack();
95
	}
96
	
97
	private JPanel createToolBar() {
98
		JPanel toolbarPanel = new JPanel(new BorderLayout());
99
		JToolBar toolbar = tf.createJToolBar("ToolBar");
100
		toolbar.setFloatable(false);
101
102
		toolbarPanel.add(toolbar);
103
		toolbarPanel.add(new JSeparator(), BorderLayout.SOUTH);
104
105
		return toolbarPanel;
106
	}
107
108
    /**
109
     * Sets the document to display.
110
     */
111
    public void setDocument(Document doc) {
112
        document = doc;
113
        docTree.setDocument(document);
114
    }
115
116
	
117
	/**
118
	 * The map that contains the actions
119
	 */
120
	protected Map actions = new HashMap();
121
122
	/**
123
	 * Returns the action associated with the given string or null on error
124
	 * 
125
	 * @param key
126
	 *            the key mapped with the action to get
127
	 * @throws MissingListenerException
128
	 *             if the action is not found
129
	 */
130
	public Action getAction(String key) throws MissingListenerException {
131
		return (Action) actions.get(key);
132
	}
133
134
	/**
135
	 * The action associated with the 'All' button.
136
	 */
137
	protected class DisplayAllButtonAction extends AbstractAction {
138
139
		public void actionPerformed(ActionEvent evt) {
140
		}
141
	}
142
143
	public static void main(String[] args) throws Exception {
144
		File file = new File(System.getProperty("user.home")
145
				+ "/Desktop/batikws/xml-batik/rect.svg");
146
		SAXSVGDocumentFactory f = new SAXSVGDocumentFactory(null, true);
147
		SVGDocument doc = (SVGDocument) f.createDocument(file.toURL()
148
				.toString());
149
		
150
		JFrame tv = new TimelineViewer(doc);
151
		tv.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
152
		tv.setVisible(true);
153
	}
154
155
//	private class DocTreeCellRenderer extends Box implements
156
//			TreeCellRenderer {
157
//
158
//		private final ImageIcon SPACER_ICON = getIcon("TreeNodeSpacer.icon");
159
//
160
//		private final ImageIcon CLOSED_ICON = getIcon("TreeNodeClosed.icon");
161
//
162
//		private final ImageIcon OPENED_ICON = getIcon("TreeNodeOpened.icon");
163
//
164
//		private final ImageIcon LEAF_ICON = getIcon("TreeLeaf.icon");
165
//
166
//		private Paint gradient;
167
//
168
//		private JLabel label;
169
//
170
//		private JLabel icon;
171
//
172
//		public DocTreeCellRenderer() {
173
//			super(BoxLayout.X_AXIS);
174
//			setOpaque(false);
175
//
176
//			icon = new JLabel(SPACER_ICON);
177
//			add(icon);
178
//
179
//			label = new JLabel();
180
//			add(label);
181
//			
182
//			Dimension dim = getPreferredSize();
183
//			gradient = new GradientPaint(0, 0, Color.white, 0,
184
//					2 * dim.height, Color.gray);
185
//		}
186
//
187
//		public void setBounds(int x, int y, int width, int height) {
188
//			super.setBounds(x, y, docTree.getWidth(), height);
189
//			System.out.println(getBounds());
190
//		}
191
//		
192
//		private ImageIcon getIcon(String name) {
193
//			String uri = resources.getString(name);
194
//			System.out.println(uri);
195
//			return new ImageIcon(TimelineViewer.this.getClass().getResource(
196
//					uri));
197
//		}
198
//
199
//		protected void paintComponent(Graphics g) {
200
//			Graphics2D g2 = (Graphics2D) g;
201
//			g2.setPaint(gradient);
202
//			g2.fillRect(0, 0, getWidth(), getHeight());
203
//
204
//			super.paintComponent(g);
205
//		}
206
//
207
//		public Component getTreeCellRendererComponent(JTree tree, Object value,
208
//				boolean selected, boolean expanded, boolean leaf, int row,
209
//				boolean hasFocus) {
210
//			label.setText(value.toString());
211
//
212
//			if (leaf) {
213
//				icon.setIcon(LEAF_ICON);
214
//			} else if (expanded) {
215
//				icon.setIcon(OPENED_ICON);
216
//			} else {
217
//				icon.setIcon(CLOSED_ICON);
218
//			}
219
//			return this;
220
//		}
221
//	}
222
}
(-)sources/org/apache/batik/util/gui/ErrorConsole.java (+1027 lines)
Line 0 Link Here
1
package org.apache.batik.util.gui;
2
3
import java.awt.BorderLayout;
4
import java.awt.Color;
5
import java.awt.Component;
6
import java.awt.Container;
7
import java.awt.Dimension;
8
import java.awt.FlowLayout;
9
import java.awt.Font;
10
import java.awt.Frame;
11
import java.awt.GradientPaint;
12
import java.awt.Graphics;
13
import java.awt.Graphics2D;
14
import java.awt.SystemColor;
15
import java.awt.Toolkit;
16
import java.awt.datatransfer.Clipboard;
17
import java.awt.datatransfer.StringSelection;
18
import java.awt.event.ActionEvent;
19
import java.awt.event.ActionListener;
20
import java.awt.event.ItemEvent;
21
import java.awt.event.ItemListener;
22
import java.awt.event.MouseAdapter;
23
import java.awt.event.MouseEvent;
24
import java.awt.event.MouseListener;
25
import java.awt.image.BufferedImage;
26
import java.io.BufferedReader;
27
import java.io.File;
28
import java.io.IOException;
29
import java.io.InputStream;
30
import java.io.InputStreamReader;
31
import java.io.PrintWriter;
32
import java.io.StringWriter;
33
import java.util.ArrayList;
34
import java.util.Enumeration;
35
import java.util.HashMap;
36
import java.util.Iterator;
37
import java.util.LinkedList;
38
import java.util.List;
39
import java.util.Locale;
40
import java.util.Map;
41
import java.util.ResourceBundle;
42
import java.util.Timer;
43
import java.util.TimerTask;
44
45
import javax.imageio.ImageIO;
46
import javax.swing.AbstractAction;
47
import javax.swing.AbstractButton;
48
import javax.swing.Action;
49
import javax.swing.BorderFactory;
50
import javax.swing.Box;
51
import javax.swing.BoxLayout;
52
import javax.swing.ButtonGroup;
53
import javax.swing.ButtonModel;
54
import javax.swing.ImageIcon;
55
import javax.swing.JButton;
56
import javax.swing.JDialog;
57
import javax.swing.JLabel;
58
import javax.swing.JOptionPane;
59
import javax.swing.JPanel;
60
import javax.swing.JPopupMenu;
61
import javax.swing.JScrollBar;
62
import javax.swing.JScrollPane;
63
import javax.swing.JTextArea;
64
import javax.swing.JTextPane;
65
import javax.swing.JToggleButton;
66
import javax.swing.JToolBar;
67
import javax.swing.SwingConstants;
68
import javax.swing.text.BadLocationException;
69
import javax.swing.text.DefaultHighlighter;
70
import javax.swing.text.Highlighter;
71
72
import org.apache.batik.apps.svgbrowser.JSVGViewerFrame.DOMViewerAction;
73
import org.apache.batik.apps.svgbrowser.JSVGViewerFrame.ViewSourceAction;
74
import org.apache.batik.apps.svgbrowser.srcview.SourceViewFrame;
75
import org.apache.batik.dom.AbstractDocument;
76
import org.apache.batik.dom.svg.LiveAttributeException;
77
import org.apache.batik.dom.svg.SAXSVGDocumentFactory;
78
import org.apache.batik.dom.util.DocumentDescriptor;
79
import org.apache.batik.util.gui.resource.ActionMap;
80
import org.apache.batik.util.gui.resource.ButtonFactory;
81
import org.apache.batik.util.gui.resource.JToolbarSeparator;
82
import org.apache.batik.util.gui.resource.MenuFactory;
83
import org.apache.batik.util.gui.resource.MissingListenerException;
84
import org.apache.batik.util.gui.resource.ResourceManager;
85
import org.w3c.dom.Element;
86
import org.w3c.dom.Node;
87
import org.w3c.dom.NodeList;
88
import org.w3c.dom.svg.SVGDocument;
89
90
public class ErrorConsole implements ActionMap {
91
92
	public static class ErrorInfo {
93
		public Throwable throwable;
94
95
		public String uri;
96
97
		public int type;
98
99
		public ErrorInfo(Throwable throwable, String uri, int type) {
100
			this.throwable = throwable;
101
			this.uri = uri;
102
			this.type = type;
103
		}
104
	}
105
106
	public static class AttributeErrorInfo extends ErrorInfo {
107
		public InputStream inputStream;
108
109
		public Element element;
110
111
		public DocumentDescriptor docDescriptor;
112
113
		public ViewSourceAction viewSourceAction;
114
115
		public DOMViewerAction viewDOMAction;
116
117
		public AttributeErrorInfo(LiveAttributeException lex, String uri,
118
				int type, InputStream inputStream, Element element,
119
				DocumentDescriptor docDescriptor) {
120
			this(lex, uri, type, inputStream, element, docDescriptor, null,
121
					null);
122
		}
123
124
		public AttributeErrorInfo(LiveAttributeException lex, String uri,
125
				int type, InputStream inputStream, Element element,
126
				DocumentDescriptor docDescriptor,
127
				ViewSourceAction viewSourceAction, DOMViewerAction viewDOMAction) {
128
			super(lex, uri, type);
129
			this.inputStream = inputStream;
130
			this.element = element;
131
			this.docDescriptor = docDescriptor;
132
			this.viewSourceAction = viewSourceAction;
133
			this.viewDOMAction = viewDOMAction;
134
		}
135
	}
136
137
	public static final int ALL = -1, ERROR = 1, WARNING = 2, INFORMATION = 4;
138
139
	/**
140
	 * The resource file name
141
	 */
142
	protected static final String RESOURCES = "org.apache.batik.util.gui.resources.ErrorConsole";
143
144
	/**
145
	 * The resource bundle
146
	 */
147
	protected static ResourceBundle bundle;
148
149
	/**
150
	 * The resource manager
151
	 */
152
	protected static ResourceManager resources;
153
154
	static {
155
		bundle = ResourceBundle.getBundle(RESOURCES, Locale.getDefault());
156
		resources = new ResourceManager(bundle);
157
	}
158
159
	/**
160
	 * The button factory.
161
	 */
162
	protected ButtonFactory bf = new ButtonFactory(bundle, this);
163
164
	/**
165
	 * The menu factory.
166
	 */
167
	protected MenuFactory mf = new MenuFactory(bundle, this);
168
169
	private Box consoleList;
170
171
	private ButtonGroup errorGroup;
172
173
	private int displayType;
174
175
	private boolean sortOrderAscending = true;
176
177
	private JPopupMenu popupMenu;
178
179
	private Container contentPane;
180
181
	public ErrorConsole() {
182
		actions.put("DisplayAllButtonAction", new DisplayAllButtonAction());
183
		actions.put("DisplayErrorsButtonAction",
184
				new DisplayErrorsButtonAction());
185
		actions.put("DisplayWarningsButtonAction",
186
				new DisplayWarningsButtonAction());
187
		actions.put("DisplayMessagesButtonAction",
188
				new DisplayMessagesButtonAction());
189
		actions.put("ClearButtonAction", new ClearButtonAction());
190
191
		actions.put("FirstLastSortMenuAction", new FirstLastSortMenuAction());
192
		actions.put("LastFirstSortMenuAction", new LastFirstSortMenuAction());
193
		actions.put("CopyMenuAction", new CopyMenuAction());
194
195
		contentPane = new JPanel(new BorderLayout());
196
197
		JPanel errorPanel = new JPanel(new BorderLayout());
198
		errorPanel.setBackground(Color.white);
199
200
		JScrollPane errorScrollPane = new JScrollPane(errorPanel);
201
		errorScrollPane
202
				.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
203
		contentPane.add(errorScrollPane);
204
205
		errorGroup = new ButtonGroup();
206
207
		consoleList = new Box(BoxLayout.Y_AXIS);
208
		errorPanel.add(consoleList, BorderLayout.NORTH);
209
210
		popupMenu = createPopupMenu();
211
212
		contentPane.add(createToolBar(), BorderLayout.NORTH);
213
		contentPane.setPreferredSize(new Dimension(550, 400));
214
	}
215
216
	private JToolBar createToolBar() {
217
		JToolBar toolbar = new JToolBar();
218
		toolbar.setFloatable(false);
219
220
		BooleanButtonGroup displayGroup = new BooleanButtonGroup();
221
222
		JToggleButton displayAll = bf
223
				.createJToolbarToggleButton("DisplayAllButton");
224
		displayGroup.add(displayAll);
225
		displayAll.setSelected(true);
226
		displayType(ALL, true);
227
		toolbar.add(displayAll);
228
229
		JToggleButton displayErrors = bf
230
				.createJToolbarToggleButton("DisplayErrorsButton");
231
		displayGroup.addOr(displayErrors);
232
		toolbar.add(displayErrors);
233
234
		JToggleButton displayWarnings = bf
235
				.createJToolbarToggleButton("DisplayWarningsButton");
236
		displayGroup.addOr(displayWarnings);
237
		toolbar.add(displayWarnings);
238
239
		JToggleButton displayMessages = bf
240
				.createJToolbarToggleButton("DisplayMessagesButton");
241
		displayGroup.addOr(displayMessages);
242
		toolbar.add(displayMessages);
243
244
		toolbar.add(new JToolbarSeparator());
245
246
		JButton clear = bf.createJToolbarButton("ClearButton");
247
		displayGroup.add(clear);
248
		toolbar.add(clear);
249
250
		return toolbar;
251
	}
252
253
	private class BooleanButtonGroup extends ButtonGroup implements
254
			ItemListener {
255
256
		private List orElements = new ArrayList();
257
258
		private AbstractButton orButton = new JToggleButton();
259
260
		public BooleanButtonGroup() {
261
			orButton.addItemListener(this);
262
			add(orButton);
263
		}
264
265
		public void itemStateChanged(ItemEvent e) {
266
			if (e.getStateChange() == ItemEvent.DESELECTED) {
267
				if (e.getSource() == orButton) {
268
					for (Iterator i = orElements.iterator(); i.hasNext();) {
269
						AbstractButton button = (AbstractButton) i.next();
270
						button.setSelected(false);
271
					}
272
				} else if (orButton.isSelected()) {
273
					boolean selected = false;
274
					for (Iterator i = orElements.iterator(); i.hasNext();) {
275
						AbstractButton button = (AbstractButton) i.next();
276
						if (button.isSelected()) {
277
							selected = true;
278
							break;
279
						}
280
					}
281
					if (!selected) {
282
						((AbstractButton) e.getSource()).setSelected(true);
283
					}
284
				}
285
			} else if (e.getStateChange() == ItemEvent.SELECTED) {
286
				setSelected(((AbstractButton) e.getSource()).getModel(), true);
287
			}
288
		}
289
290
		public void addOr(AbstractButton button) {
291
			orElements.add(button);
292
			button.addItemListener(this);
293
		}
294
295
		public void setSelected(ButtonModel model, boolean selected) {
296
			for (Iterator i = orElements.iterator(); i.hasNext();) {
297
				AbstractButton button = (AbstractButton) i.next();
298
				if (button.getModel() == model) {
299
					orButton.setSelected(selected);
300
					return;
301
				}
302
			}
303
			super.setSelected(model, selected);
304
		}
305
	}
306
307
	private JPopupMenu createPopupMenu() {
308
		JPopupMenu popupMenu = mf.createJMenu("PopupMenu").getPopupMenu();
309
		return popupMenu;
310
	}
311
312
	protected static ErrorConsole instance;
313
314
	public static ErrorConsole getInstance() {
315
		if (instance == null) {
316
			instance = new ErrorConsole();
317
		}
318
		return instance;
319
	}
320
321
	protected static JDialog dialog;
322
323
	public static void showDialog(Component owner) {
324
		Frame f = JOptionPane.getFrameForComponent(owner);
325
		if (dialog != null && dialog.getOwner() != f) {
326
			dialog.dispose();
327
			dialog = null;
328
		}
329
		if (dialog == null) {
330
			dialog = new JDialog(f, "Error Console");
331
			dialog.getContentPane().add(getInstance().contentPane,
332
					BorderLayout.CENTER);
333
334
			dialog.pack();
335
			dialog.setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE);
336
			dialog.setLocationRelativeTo(dialog.getOwner());
337
		}
338
		dialog.setVisible(true);
339
	}
340
341
	public void add(ErrorInfo info) {
342
		ErrorButton errorButton = new ErrorButton(info);
343
		errorButton.setPopupMenu(popupMenu);
344
		consoleList.add(errorButton);
345
		errorGroup.add(errorButton);
346
		errorButton.setVisible((displayType & errorButton.getType()) > 0);
347
	}
348
349
	public void add(AttributeErrorInfo info) {
350
		ErrorButton errorButton = new ErrorButton(info);
351
		errorButton.setPopupMenu(popupMenu);
352
		consoleList.add(errorButton);
353
		errorGroup.add(errorButton);
354
		errorButton.setVisible((displayType & errorButton.getType()) > 0);
355
	}
356
357
	/**
358
	 * The map that contains the actions
359
	 */
360
	protected Map actions = new HashMap();
361
362
	/**
363
	 * Returns the action associated with the given string or null on error
364
	 * 
365
	 * @param key
366
	 *            the key mapped with the action to get
367
	 * @throws MissingListenerException
368
	 *             if the action is not found
369
	 */
370
	public Action getAction(String key) throws MissingListenerException {
371
		return (Action) actions.get(key);
372
	}
373
374
	/**
375
	 * The action associated with the 'All' button.
376
	 */
377
	protected class DisplayAllButtonAction extends AbstractAction {
378
379
		public void actionPerformed(ActionEvent evt) {
380
			displayType(ALL, true);
381
		}
382
	}
383
384
	/**
385
	 * The action associated with the 'Errors' button.
386
	 */
387
	protected class DisplayErrorsButtonAction extends AbstractAction {
388
389
		public void actionPerformed(ActionEvent evt) {
390
			boolean selected = ((AbstractButton) evt.getSource()).isSelected();
391
			displayType(ERROR, selected);
392
		}
393
	}
394
395
	/**
396
	 * The action associated with the 'Warnings' button.
397
	 */
398
	protected class DisplayWarningsButtonAction extends AbstractAction {
399
400
		public void actionPerformed(ActionEvent evt) {
401
			boolean selected = ((AbstractButton) evt.getSource()).isSelected();
402
			displayType(WARNING, selected);
403
		}
404
	}
405
406
	/**
407
	 * The action associated with the 'Messages' button.
408
	 */
409
	protected class DisplayMessagesButtonAction extends AbstractAction {
410
411
		public void actionPerformed(ActionEvent evt) {
412
			boolean selected = ((AbstractButton) evt.getSource()).isSelected();
413
			displayType(INFORMATION, selected);
414
		}
415
	}
416
417
	/**
418
	 * The action associated with the 'Clear' button.
419
	 */
420
	protected class ClearButtonAction extends AbstractAction {
421
422
		public void actionPerformed(ActionEvent evt) {
423
			clearType(displayType);
424
			consoleList.revalidate();
425
		}
426
	}
427
428
	/**
429
	 * The action associated with the 'First to Last Sort' menu item.
430
	 */
431
	protected class FirstLastSortMenuAction extends AbstractAction {
432
433
		public void actionPerformed(ActionEvent evt) {
434
			if (sortOrderAscending) {
435
				return;
436
			}
437
			reverseComponentOrder(consoleList);
438
			sortOrderAscending = true;
439
		}
440
	}
441
442
	/**
443
	 * The action associated with the 'Last to First Sort' menu item.
444
	 */
445
	protected class LastFirstSortMenuAction extends AbstractAction {
446
447
		public void actionPerformed(ActionEvent evt) {
448
			if (!sortOrderAscending) {
449
				return;
450
			}
451
			reverseComponentOrder(consoleList);
452
			sortOrderAscending = false;
453
		}
454
	}
455
456
	private void reverseComponentOrder(Container container) {
457
		Component[] components = container.getComponents();
458
		consoleList.removeAll();
459
		for (int i = components.length - 1; i >= 0; i--) {
460
			consoleList.add(components[i]);
461
		}
462
		consoleList.revalidate();
463
	}
464
465
	/**
466
	 * The action associated with the 'Copy' menu item.
467
	 */
468
	protected class CopyMenuAction extends AbstractAction {
469
470
		public void actionPerformed(ActionEvent evt) {
471
			Component[] components = consoleList.getComponents();
472
			StringBuilder copyText = new StringBuilder();
473
			for (int i = 0; i < components.length; i++) {
474
				ErrorButton eb = (ErrorButton) components[i];
475
				if (eb.isSelected()) {
476
					copyText.append(eb.getMessageText() + "\n");
477
					copyText.append(eb.getDetailText() + "\n\n");
478
				}
479
			}
480
			String s = copyText.toString().trim();
481
			if (!s.equals("")) {
482
				Clipboard clipboard = Toolkit.getDefaultToolkit()
483
						.getSystemClipboard();
484
				clipboard.setContents(new StringSelection(s), null);
485
			}
486
		}
487
	}
488
489
	private void clearType(int type) {
490
		Component[] components = consoleList.getComponents();
491
		for (int i = 0; i < components.length; i++) {
492
			ErrorButton eb = (ErrorButton) components[i];
493
			if ((eb.getType() & type) > 0) {
494
				consoleList.remove(eb);
495
				errorGroup.remove(eb);
496
			}
497
		}
498
	}
499
500
	private void displayType(int type, boolean visible) {
501
		if (displayType < 0) {
502
			displayType = 0;
503
		}
504
		if (visible) {
505
			displayType |= type;
506
		} else {
507
			displayType &= ~type;
508
		}
509
		Component[] components = consoleList.getComponents();
510
		for (int i = 0; i < components.length; i++) {
511
			ErrorButton eb = (ErrorButton) components[i];
512
			eb.setVisible((displayType & eb.getType()) > 0);
513
		}
514
	}
515
516
	private class ErrorButton extends JToggleButton {
517
518
		private int type;
519
520
		private JTextPane messageText;
521
522
		private ImageIcon icon;
523
524
		private GradientPaint gradient;
525
526
		private JPanel details;
527
528
		private JPopupMenu popupMenu;
529
530
		private JScrollPane detailScrollPane;
531
532
		private JTextArea detailText;
533
534
		private Throbber throbber;
535
536
		private Box actionsPanel;
537
538
		private ItemListener il = new ItemListener() {
539
			public void itemStateChanged(ItemEvent e) {
540
				if (e.getStateChange() == ItemEvent.SELECTED) {
541
					details.setVisible(true);
542
				} else if (e.getStateChange() == ItemEvent.DESELECTED) {
543
					details.setVisible(false);
544
				} else {
545
					return;
546
				}
547
				repaint();
548
			}
549
		};
550
551
		private MouseListener ml = new MouseAdapter() {
552
			public void mousePressed(MouseEvent e) {
553
				if (e.isPopupTrigger()) {
554
					popupMenu.show(ErrorButton.this, e.getX(), e.getY());
555
				}
556
			}
557
558
			public void mouseReleased(MouseEvent e) {
559
				if (e.isPopupTrigger()) {
560
					popupMenu.show(ErrorButton.this, e.getX(), e.getY());
561
				}
562
			}
563
		};
564
565
		protected ErrorButton(int type) {
566
			this.type = type;
567
568
			setLayout(new BorderLayout(10, 10));
569
			setContentAreaFilled(false);
570
			setBorderPainted(false);
571
			setOpaque(false);
572
			setFocusPainted(false);
573
			setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
574
			addItemListener(il);
575
			addMouseListener(ml);
576
577
			String s;
578
			switch (type) {
579
			case WARNING:
580
				s = resources.getString("ErrorButton.warning_icon");
581
				break;
582
			case INFORMATION:
583
				s = resources.getString("ErrorButton.message_icon");
584
				break;
585
			case ERROR:
586
			default:
587
				s = resources.getString("ErrorButton.error_icon");
588
				break;
589
			}
590
			icon = new ImageIcon(getClass().getResource(s));
591
			add(new JLabel(icon), BorderLayout.WEST);
592
593
			Box centerPane = new Box(BoxLayout.Y_AXIS);
594
			add(centerPane);
595
596
			messageText = new JTextPane();
597
			messageText.setEditable(false);
598
			messageText.setOpaque(false);
599
			messageText.addMouseListener(new MouseAdapter() {
600
				public void mouseClicked(MouseEvent e) {
601
					passEvent(e);
602
				}
603
604
				public void mousePressed(MouseEvent e) {
605
					passEvent(e);
606
				}
607
608
				public void mouseReleased(MouseEvent e) {
609
					passEvent(e);
610
				}
611
612
				private void passEvent(MouseEvent e) {
613
					e.setSource(ErrorButton.this);
614
					ErrorButton.this.dispatchEvent(e);
615
				}
616
			});
617
			centerPane.add(messageText, BorderLayout.NORTH);
618
619
			details = new JPanel(new BorderLayout());
620
			details.setOpaque(false);
621
			details.setVisible(false);
622
			add(details, BorderLayout.SOUTH);
623
624
			detailText = new JTextArea();
625
			detailText.setFont(new Font("Monospaced", Font.PLAIN, 12));
626
			detailText.setEditable(false);
627
			detailText.setLineWrap(true);
628
			throbber = new Throbber();
629
			detailScrollPane = new JScrollPane();
630
			detailScrollPane.setPreferredSize(new Dimension(300, 100));
631
			final JPanel detailPanel = new JPanel(new BorderLayout());
632
			detailPanel.add(detailScrollPane);
633
			actionsPanel = new Box(BoxLayout.X_AXIS);
634
			actionsPanel.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
635
			detailPanel.add(actionsPanel, BorderLayout.SOUTH);
636
			detailPanel.setOpaque(false);
637
			detailPanel.setVisible(false);
638
			final String hideDetails = resources.getString("ShowDetails.text0");
639
			final String showDetails = resources.getString("ShowDetails.text1");
640
			final JButton btnShowDetails = new JButton(showDetails);
641
			btnShowDetails.addActionListener(new ActionListener() {
642
				public void actionPerformed(ActionEvent e) {
643
					boolean visible = detailPanel.isVisible();
644
					detailPanel.setVisible(!visible);
645
					btnShowDetails.setText(visible ? showDetails : hideDetails);
646
				}
647
			});
648
			JPanel button = new JPanel(new FlowLayout(FlowLayout.LEADING));
649
			button.setOpaque(false);
650
			button.add(btnShowDetails);
651
			details.add(button, BorderLayout.NORTH);
652
			details.add(detailPanel);
653
654
			Dimension dim = getPreferredSize();
655
			gradient = new GradientPaint(0, 0, new Color(217, 226, 234), 0,
656
					2 * dim.height, new Color(193, 207, 221));
657
658
		}
659
660
		public ErrorButton(final ErrorInfo info) {
661
			this(info.type);
662
663
			setMessageText(info.throwable.getMessage());
664
665
			StringWriter sw = new StringWriter();
666
			info.throwable.printStackTrace(new PrintWriter(sw));
667
			sw.flush();
668
			setDetailText(sw.toString());
669
		}
670
671
		private TextInfo textInfo;
672
673
		private JButton viewSourceButton;
674
675
		private JButton viewDOMButton;
676
677
		public ErrorButton(final AttributeErrorInfo info) {
678
			this(info.type);
679
680
			// Get reference to original element if this is a clone
681
			AbstractDocument doc = (AbstractDocument) info.element
682
					.getOwnerDocument();
683
			Element importedNode = (Element) doc.getImportedNode(info.element);
684
			if (importedNode != null) {
685
				info.element = importedNode;
686
			}
687
			final Element element = info.element;
688
689
			if (info.viewSourceAction != null) {
690
				viewSourceButton = new JButton(resources
691
						.getString("ViewSource.text"));
692
				AbstractAction viewSourceActionDecorator = new AbstractAction() {
693
					public void actionPerformed(final ActionEvent e) {
694
						new Thread() {
695
							public void run() {
696
								info.viewSourceAction.actionPerformed(e);
697
								try {
698
									info.viewSourceAction.getDisplayThread()
699
											.join();
700
									SourceViewFrame svf = info.viewSourceAction
701
											.getSourceViewFrame();
702
703
									int locline = info.docDescriptor
704
											.getLocationLine(element), loccol = info.docDescriptor
705
											.getLocationColumn(element);
706
707
									String text = textInfo
708
											.getFormattedText(false);
709
									int endOffset = textInfo.getOffset(locline,
710
											loccol, false) - 1;
711
712
									// find end of line
713
									for (; endOffset < text.length()
714
											&& text.charAt(endOffset) != '\n'; endOffset++)
715
										;
716
717
									// find beginning of tag
718
									int startOffset = endOffset - 1;
719
									boolean foundTagBegin = false;
720
									for (; startOffset >= 0 && !foundTagBegin
721
											|| text.charAt(startOffset) != '\n'; startOffset--) {
722
										if (text.charAt(startOffset) == '<') {
723
											foundTagBegin = true;
724
										}
725
									}
726
									startOffset++;
727
728
									if (startOffset >= 0 && endOffset >= 0) {
729
										svf.select(startOffset, endOffset);
730
									}
731
								} catch (InterruptedException ex) {
732
									ex.printStackTrace();
733
								}
734
							}
735
						}.start();
736
					}
737
				};
738
				viewSourceButton.addActionListener(viewSourceActionDecorator);
739
				viewSourceButton.setEnabled(false);
740
				actionsPanel.add(viewSourceButton);
741
				actionsPanel.add(Box.createHorizontalStrut(5));
742
			}
743
744
			if (info.viewDOMAction != null) {
745
				viewDOMButton = new JButton(resources.getString("ViewDOM.text"));
746
				AbstractAction viewDOMActionDecorator = new AbstractAction() {
747
					public void actionPerformed(ActionEvent e) {
748
						info.viewDOMAction.actionPerformed(e);
749
						DOMViewer domViewer = info.viewDOMAction.getDOMViewer();
750
						domViewer.setSelectionNode(element);
751
					}
752
				};
753
				viewDOMButton.addActionListener(viewDOMActionDecorator);
754
				actionsPanel.add(viewDOMButton);
755
				actionsPanel.add(Box.createHorizontalStrut(5));
756
			}
757
758
			detailScrollPane.setViewportView(throbber);
759
			throbber.start();
760
			new Thread() {
761
				public void run() {
762
					LiveAttributeException lex = (LiveAttributeException) info.throwable;
763
					String attrName = lex.getAttributeName();
764
					String eltName = lex.getElement().getNodeName();
765
					setMessageText("Error in parsing value for property '"
766
							+ attrName + "' of element <" + eltName
767
							+ ">. Declaration dropped");
768
					String text;
769
					int endOffset = 0, startOffset;
770
					int locline = info.docDescriptor.getLocationLine(element), loccol = info.docDescriptor
771
							.getLocationColumn(element);
772
					try {
773
						Thread.sleep(3000);
774
775
						if (info.inputStream == null) {
776
							throw new NullPointerException(
777
									"Document text not available");
778
						} else {
779
							LinkedList lineList = new LinkedList();
780
							BufferedReader reader = new BufferedReader(
781
									new InputStreamReader(info.inputStream));
782
							String line;
783
784
							while ((line = reader.readLine()) != null) {
785
								lineList.add(line);
786
							}
787
							String[] lines = (String[]) lineList
788
									.toArray(new String[0]);
789
							textInfo = new TextInfo(lines);
790
							text = textInfo.getFormattedText(true);
791
							endOffset = textInfo.getOffset(locline, loccol,
792
									true) - 1;
793
						}
794
						setDetailText(text);
795
796
						Highlighter highlighter = detailText.getHighlighter();
797
						highlighter.removeAllHighlights();
798
799
						// find end of line
800
						for (; endOffset >= 0 && endOffset < text.length()
801
								&& text.charAt(endOffset) != '\n'; endOffset++)
802
							;
803
804
						// find beginning of tag
805
						startOffset = endOffset - 1;
806
						boolean foundTagBegin = false;
807
						for (; startOffset >= 0
808
								&& (!foundTagBegin || text.charAt(startOffset) != '\n'); startOffset--) {
809
							if (text.charAt(startOffset) == '<') {
810
								foundTagBegin = true;
811
							}
812
						}
813
						startOffset++;
814
815
						if (startOffset >= 0 && endOffset < text.length()) {
816
							try {
817
								highlighter
818
										.addHighlight(
819
												startOffset,
820
												endOffset,
821
												new DefaultHighlighter.DefaultHighlightPainter(
822
														Color.yellow));
823
							} catch (BadLocationException e) {
824
							}
825
						}
826
827
						if (viewSourceButton != null) {
828
							viewSourceButton.setEnabled(true);
829
						}
830
					} catch (Exception e) {
831
						e.printStackTrace();
832
						setDetailText("Error parsing file: " + info.uri);
833
					}
834
835
					throbber.stop();
836
					detailScrollPane.setViewportView(detailText);
837
					if (locline >= 0) {
838
						JScrollBar vsb = detailScrollPane
839
								.getVerticalScrollBar();
840
						vsb.setValue(vsb.getUnitIncrement(JScrollBar.VERTICAL)
841
								* (locline - 5));
842
					}
843
				}
844
			}.start();
845
		}
846
847
		protected class TextInfo {
848
			private String[] lines;
849
850
			private int indent;
851
852
			public TextInfo(String[] lines) {
853
				this.lines = lines.clone();
854
				indent = 1;
855
				int len = lines.length;
856
				while ((int) (len /= 10) > 0) {
857
					indent++;
858
				}
859
			}
860
861
			public String getFormattedText(boolean showLineNumbers) {
862
				StringBuilder sb = new StringBuilder();
863
				if (showLineNumbers) {
864
					String format = "%" + indent + "d: %s\n";
865
					for (int i = 0; i < lines.length; i++) {
866
						sb.append(String.format(format, i + 1, lines[i]));
867
					}
868
				} else {
869
					for (int i = 0; i < lines.length; i++) {
870
						sb.append(lines[i] + "\n");
871
					}
872
				}
873
874
				return sb.toString();
875
			}
876
877
			public int getOffset(int locline, int loccol,
878
					boolean withLineNumbers) {
879
				int offset = 0;
880
				for (int i = 0; i < locline; i++) {
881
					if (i < locline - 1) {
882
						offset += lines[i].length();
883
					} else if (i == locline - 1) {
884
						offset += loccol;
885
					}
886
				}
887
				offset += (withLineNumbers ? (indent + 3) : 1) * locline - 1;
888
				return offset;
889
			}
890
		}
891
892
		protected class Throbber extends JLabel {
893
			private ImageIcon[] tiles;
894
895
			private Timer timer;
896
897
			private int currentTileIndex;
898
899
			public Throbber() {
900
				setOpaque(false);
901
				setText(resources.getString("Throbber.text"));
902
				setHorizontalAlignment(SwingConstants.CENTER);
903
				setVerticalAlignment(SwingConstants.CENTER);
904
				setFont(new Font("Sans Serif", Font.PLAIN, 12));
905
906
				BufferedImage image;
907
				try {
908
					image = ImageIO.read(getClass().getResource(
909
							resources.getString("Throbber.image")));
910
					tiles = new ImageIcon[32];
911
					int width = image.getWidth(), height = image.getHeight();
912
					int twidth = width / 8, theight = height / 4;
913
					int index = 0;
914
					for (int y = theight; y <= height; y += theight) {
915
						for (int x = twidth; x <= width; x += twidth) {
916
							tiles[index++] = new ImageIcon(image.getSubimage(x
917
									- twidth, y - theight, twidth, theight));
918
						}
919
					}
920
921
				} catch (IOException e) {
922
					tiles = null;
923
				} finally {
924
					image = null;
925
				}
926
			}
927
928
			public void start() {
929
				stop();
930
				timer = new Timer();
931
				TimerTask timerTask = new TimerTask() {
932
					public void run() {
933
						currentTileIndex = (currentTileIndex + 1)
934
								% tiles.length;
935
						if (currentTileIndex == 0) {
936
							currentTileIndex = 1;
937
						}
938
						setIcon(tiles[currentTileIndex]);
939
					}
940
				};
941
				timer.scheduleAtFixedRate(timerTask, 0, 30);
942
			}
943
944
			public void stop() {
945
				if (timer != null) {
946
					timer.cancel();
947
				}
948
			}
949
		}
950
951
		public void paintComponent(Graphics g) {
952
			Graphics2D g2 = (Graphics2D) g;
953
			int width = getWidth(), height = getHeight();
954
			g2.setPaint(isSelected() ? gradient : Color.white);
955
			g2.fillRect(0, 0, width, height);
956
			g2.setColor(SystemColor.controlShadow);
957
			g2.drawLine(0, height - 1, width, height - 1);
958
			super.paintComponent(g);
959
		}
960
961
		public int getType() {
962
			return type;
963
		}
964
965
		public void setType(int type) {
966
			this.type = type;
967
			repaint();
968
		}
969
970
		public JPopupMenu getPopupMenu() {
971
			return popupMenu;
972
		}
973
974
		public void setPopupMenu(JPopupMenu popupMenu) {
975
			this.popupMenu = popupMenu;
976
		}
977
978
		public String getMessageText() {
979
			return messageText.getText();
980
		}
981
982
		public void setMessageText(String text) {
983
			messageText.setText(text);
984
		}
985
986
		public String getDetailText() {
987
			return detailText.getText();
988
		}
989
990
		public void setDetailText(String text) {
991
			detailText.setText(text);
992
		}
993
	}
994
995
	private static Element findElementByTagName(Node node, String tagName) {
996
		if (node.getNodeType() == Node.ELEMENT_NODE
997
				&& node.getNodeName().equals(tagName)) {
998
			return (Element) node;
999
		}
1000
		NodeList list = node.getChildNodes();
1001
		for (int i = 0; i < list.getLength(); i++) {
1002
			Element e = findElementByTagName(list.item(i), tagName);
1003
			if (e != null) {
1004
				return e;
1005
			}
1006
		}
1007
		return null;
1008
	}
1009
1010
	public static void main(String[] args) throws Exception {
1011
		ErrorConsole ec = ErrorConsole.getInstance();
1012
		File file = new File(System.getProperty("user.home")
1013
				+ "/Desktop/batikws/xml-batik/rect.svg");
1014
		SAXSVGDocumentFactory f = new SAXSVGDocumentFactory(null, true);
1015
		SVGDocument doc = (SVGDocument) f.createDocument(file.toURL()
1016
				.toString());
1017
		Element elt = findElementByTagName(doc.getDocumentElement(), "rect");
1018
		DocumentDescriptor desc = f.getDocumentDescriptor();
1019
		// ec.add(elt, doc, desc, new FileInputStream(file),
1020
		// JOptionPane.ERROR_MESSAGE);
1021
		// ec.add(new Exception("Test Exception"), null,
1022
		// JOptionPane.WARNING_MESSAGE);
1023
		// ec.add(new Exception("Test Exception"), null,
1024
		// JOptionPane.INFORMATION_MESSAGE);
1025
		ErrorConsole.showDialog(null);
1026
	}
1027
}
(-)resources/org/apache/batik/apps/svgbrowser/resources/GUI.properties (+9 lines)
Lines 23-28 Link Here
23
23
24
ViewSource.width = 750
24
ViewSource.width = 750
25
ViewSource.height = 500
25
ViewSource.height = 500
26
ViewSource.frameicon = resources/squiggleIcon.png
26
27
27
28
28
#
29
#
Lines 401-406 Link Here
401
ScriptDebugger.mnemonic    = S
402
ScriptDebugger.mnemonic    = S
402
ScriptDebugger.action      = ToggleDebuggerAction
403
ScriptDebugger.action      = ToggleDebuggerAction
403
404
405
TimelineViewer.type            = ITEM
406
TimelineViewer.text            = Timeline Viewer...
407
TimelineViewer.icon            = resources/timeline-viewer-small.png
408
TimelineViewer.icon.OSX        =
409
TimelineViewer.mnemonic        = T
410
TimelineViewer.action          = TimelineViewerAction
411
TimelineViewer.accelerator     = ctrl F9
412
TimelineViewer.accelerator.OSX = meta F9
404
413
405
# Help menu ##################
414
# Help menu ##################
406
Help = About
415
Help = About
(-)resources/org/apache/batik/util/gui/resources/TimelineViewer.properties (+40 lines)
Line 0 Link Here
1
# -----------------------------------------------------------------------------
2
#
3
#   Licensed to the Apache Software Foundation (ASF) under one or more
4
#   contributor license agreements.  See the NOTICE file distributed with
5
#   this work for additional information regarding copyright ownership.
6
#   The ASF licenses this file to You under the Apache License, Version 2.0
7
#   (the "License"); you may not use this file except in compliance with
8
#   the License.  You may obtain a copy of the License at
9
#
10
#       http://www.apache.org/licenses/LICENSE-2.0
11
#
12
#   Unless required by applicable law or agreed to in writing, software
13
#   distributed under the License is distributed on an "AS IS" BASIS,
14
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
#   See the License for the specific language governing permissions and
16
#   limitations under the License.
17
#
18
# The resources for the ErrorConsole
19
#
20
# Author: singh.jasleen@gmail.com
21
# $Id: ErrorConsole.properties 475477 2006-11-15 22:44:28Z cam $
22
# -----------------------------------------------------------------------------
23
24
StartButton.icon     = resources/start.png
25
StartButton.tooltip  = Start
26
27
BackwardButton.icon     = resources/backward.png
28
BackwardButton.tooltip  = Backward
29
30
PlayButton.icon     = resources/play.png
31
PlayButton.tooltip  = Play
32
33
ForwardButton.icon     = resources/forward.png
34
ForwardButton.tooltip  = Forward
35
36
EndButton.icon     = resources/end.png
37
EndButton.tooltip  = End
38
39
ToolBar = StartButton BackwardButton PlayButton ForwardButton \
40
			EndButton
(-)resources/org/apache/batik/util/gui/resources/ErrorConsole.properties (+88 lines)
Line 0 Link Here
1
# -----------------------------------------------------------------------------
2
#
3
#   Licensed to the Apache Software Foundation (ASF) under one or more
4
#   contributor license agreements.  See the NOTICE file distributed with
5
#   this work for additional information regarding copyright ownership.
6
#   The ASF licenses this file to You under the Apache License, Version 2.0
7
#   (the "License"); you may not use this file except in compliance with
8
#   the License.  You may obtain a copy of the License at
9
#
10
#       http://www.apache.org/licenses/LICENSE-2.0
11
#
12
#   Unless required by applicable law or agreed to in writing, software
13
#   distributed under the License is distributed on an "AS IS" BASIS,
14
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
#   See the License for the specific language governing permissions and
16
#   limitations under the License.
17
#
18
# The resources for the ErrorConsole
19
#
20
# Author: singh.jasleen@gmail.com
21
# $Id: ErrorConsole.properties 475477 2006-11-15 22:44:28Z cam $
22
# -----------------------------------------------------------------------------
23
24
Heading.text = SVG Error:
25
26
DisplayAllButton.text     = All
27
DisplayAllButton.icon     = resources/all.png
28
DisplayAllButton.mnemonic = A
29
DisplayAllButton.action   = DisplayAllButtonAction
30
DisplayAllButton.tooltip  = Show all entries
31
32
DisplayErrorsButton.text     = Errors
33
DisplayErrorsButton.icon     = resources/errors.png
34
DisplayErrorsButton.mnemonic = E
35
DisplayErrorsButton.action   = DisplayErrorsButtonAction
36
DisplayErrorsButton.tooltip  = Show/hide all errors
37
38
DisplayWarningsButton.text     = Warnings
39
DisplayWarningsButton.icon     = resources/warnings.png
40
DisplayWarningsButton.mnemonic = W
41
DisplayWarningsButton.action   = DisplayWarningsButtonAction
42
DisplayWarningsButton.tooltip  = Show/hide all warnings
43
44
DisplayMessagesButton.text     = Messages
45
DisplayMessagesButton.icon     = resources/messages.png
46
DisplayMessagesButton.mnemonic = M
47
DisplayMessagesButton.action   = DisplayMessagesButtonAction
48
DisplayMessagesButton.tooltip  = Show/hide all messages
49
50
ClearButton.text     = Clear
51
ClearButton.icon     = resources/clear.png
52
ClearButton.mnemonic = C
53
ClearButton.action   = ClearButtonAction
54
ClearButton.tooltip  = Permanently remove all entries
55
56
ErrorButton.warning_icon = resources/warning-small.png
57
ErrorButton.message_icon = resources/message-small.png
58
ErrorButton.error_icon = resources/error-small.png
59
60
FirstLastSortMenuItem.text     = First > Last Sort Order
61
FirstLastSortMenuItem.type     = ITEM
62
FirstLastSortMenuItem.mnemonic = F
63
FirstLastSortMenuItem.action   = FirstLastSortMenuAction
64
65
LastFirstSortMenuItem.text     = Last > First Sort Order
66
LastFirstSortMenuItem.type     = ITEM
67
LastFirstSortMenuItem.mnemonic = L
68
LastFirstSortMenuItem.action   = LastFirstSortMenuAction
69
70
CopyMenuItem.text        = Copy (Ctrl+C)
71
CopyMenuItem.type        = ITEM
72
CopyMenuItem.mnemonic    = C
73
CopyMenuItem.accelerator = ctrl C
74
CopyMenuItem.action      = CopyMenuAction
75
76
PopupMenu = FirstLastSortMenuItem LastFirstSortMenuItem - \
77
            CopyMenuItem
78
PopupMenu.text = ErrorConsolePoupup
79
80
Throbber.text  = Loading...
81
Throbber.image = resources/process-working.png
82
83
ViewSource.text = View Source
84
85
ViewDOM.text    = View DOM
86
87
ShowDetails.text0 = << Hide Details
88
ShowDetails.text1 = Show Details >>

Return to bug 42741