Source code: com/robrohan/editorkit/XMLEditorPane.java
1 /*
2 * Treebeard: an xml xslt transfomer
3 * Copyright (C) 2002 Rob Rohan
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 675 Mass Ave, Cambridge, MA 02139, USA.
17 *
18 * Email: me@robrohan.com
19 *
20 * XMLEditorPane.java
21 *
22 * Created on July 26, 2002, 9:09 PM
23 */
24
25 package com.robrohan.editorkit;
26
27 import java.awt.event.ActionListener;
28 import java.awt.event.ActionEvent;
29 import org.syntax.jedit.tokenmarker.Token;
30 import javax.swing.AbstractAction;
31 import javax.swing.Action;
32 import javax.swing.ImageIcon;
33 import org.syntax.jedit.SyntaxStyle;
34 import java.awt.Color;
35 import org.xml.sax.*;
36
37 /**
38 * this is the main component for entering text (xml or xslt)
39 * @author rob
40 */
41 public class XMLEditorPane extends org.syntax.jedit.JEditTextArea
42 implements javax.swing.event.UndoableEditListener {
43
44 /** all the actions this pane can have */
45 java.util.Hashtable actionHash = new java.util.Hashtable();
46 /** the right click menu (context menu) */
47 javax.swing.JPopupMenu rmenu;
48 /** handle to the file loader (used to get files from the web or disk) */
49 com.robrohan.treebeard.LoadFile fileLoader;
50 javax.swing.JFileChooser fileChooser;
51 /** the SAXFactory to use (set by caller) */
52 public String SAXFactory = "org.apache.xerces.jaxp.SAXParserFactoryImpl";
53 /** for pane undos */
54 public javax.swing.undo.UndoManager undo = new javax.swing.undo.UndoManager();
55 /** the file this pane has loaded */
56 private java.io.File currentFile;
57 /** any validation errors will be bubbled up to the container */
58 public String valErrors="";
59 /** the icons */
60 private ImageIcon load_icon, save_icon, undo_icon, redo_icon;
61 /** flag to say if the xml file is in the pane or just referenced on disk */
62 private boolean fileReferenced=false;
63 /** encoding type for this pane */
64 public String encodingtype = "UTF-8";
65 /** pointer to this pane (used in inner classes) */
66 public final XMLEditorPane panePtr;
67
68 private javax.swing.Timer timer;
69
70
71 /** Creates a new instance of XMLEditorPane
72 * @param type The type of syntax highlighting to use (what kind of document this is)
73 */
74 public XMLEditorPane(String type){
75
76 createNewDocument(type);
77
78 panePtr = this;
79
80 //make a load file dialog
81 fileLoader = new com.robrohan.treebeard.LoadFile(null, true);
82 com.robrohan.tools.FrameTools.center(fileLoader);
83
84 rmenu = new javax.swing.JPopupMenu();
85 javax.swing.JMenuItem tmp;
86
87 ///////////////////////////////////////////////////////////////////////
88 tmp = new javax.swing.JMenuItem("Cut");
89 rmenu.add(tmp);//.setAccelerator(javax.swing.KeyStroke.getKeyStroke("control X"));
90 tmp.addActionListener(new ActionListener(){
91 public void actionPerformed(ActionEvent ev){
92 cut();
93 }
94 }
95 );
96
97 tmp = new javax.swing.JMenuItem("Copy");
98 rmenu.add(tmp);//.setAccelerator(javax.swing.KeyStroke.getKeyStroke("control C"));
99 tmp.addActionListener(new ActionListener(){
100 public void actionPerformed(ActionEvent ev){
101 copy();
102 }
103 }
104 );
105
106 tmp = new javax.swing.JMenuItem("Paste");
107 rmenu.add(tmp); //.setAccelerator(javax.swing.KeyStroke.getKeyStroke("control V"));
108 tmp.addActionListener(new ActionListener(){
109 public void actionPerformed(ActionEvent ev){
110 paste();
111 }
112 }
113 );
114
115 ///////////////////////////////////////////////////
116 rmenu.add(new javax.swing.JSeparator());
117
118 rmenu.add(new com.robrohan.editorkit.XMLEditorPane.undoAction());
119 rmenu.add(new com.robrohan.editorkit.XMLEditorPane.redoAction());
120
121
122 ///////////////////////////////////////////////////
123 rmenu.add(new javax.swing.JSeparator());
124
125 rmenu.add(new com.robrohan.editorkit.XMLEditorPane.commentSection());
126 rmenu.add(new com.robrohan.editorkit.XMLEditorPane.goToLine());
127
128 //////////////////////////////////////////////////
129 rmenu.add(new javax.swing.JSeparator());
130
131 javax.swing.JMenu enctypes = new javax.swing.JMenu("Set Encoding");
132
133 tmp = new javax.swing.JMenuItem("ISO-8859-1");
134 enctypes.add(tmp);
135 tmp.addActionListener(new ActionListener(){
136 public void actionPerformed(ActionEvent ev){
137 encodingtype = "ISO-8859-1";
138 }
139 }
140 );
141
142 tmp = new javax.swing.JMenuItem("UTF-8");
143 enctypes.add(tmp);
144 tmp.addActionListener(new ActionListener(){
145 public void actionPerformed(ActionEvent ev){
146 encodingtype = "UTF-8";
147 }
148 }
149 );
150
151 tmp = new javax.swing.JMenuItem("UTF-16");
152 enctypes.add(tmp);
153 tmp.addActionListener(new ActionListener(){
154 public void actionPerformed(ActionEvent ev){
155 encodingtype = "UTF-16";
156 }
157 }
158 );
159 rmenu.add(enctypes);
160 ///////////////////////////////////////////////////
161 tmp = new javax.swing.JMenuItem("Save File");
162 rmenu.add(tmp);
163 tmp.addActionListener(new ActionListener(){
164 public void actionPerformed(ActionEvent ev){
165 save();
166 }
167 }
168 );
169 ///////////////////////////////////////////////////
170 rmenu.add(new javax.swing.JSeparator());
171
172 rmenu.add(new com.robrohan.editorkit.XMLEditorPane.fileProperties());
173 rmenu.add(new com.robrohan.editorkit.XMLEditorPane.validateAction());
174
175 //////////////////////////////////////////////////
176 //rmenu.add(new javax.swing.JSeparator());
177 //rmenu.add(new XMLEditorPane.loadFileAction());
178
179 setRightClickPopup(rmenu);
180
181 //hopefully set in fangorn
182 if(fileChooser == null){
183 fileChooser = new javax.swing.JFileChooser();
184 }
185
186 load_icon = new ImageIcon(
187 getClass().getResource("/com/robrohan/treebeard/images/diskget_sm.gif")
188 );
189 save_icon = new ImageIcon(
190 getClass().getResource("/com/robrohan/treebeard/images/diskwrite_sm.gif")
191 );
192 undo_icon = new ImageIcon(
193 getClass().getResource("/com/robrohan/treebeard/images/undo_sm.gif")
194 );
195 redo_icon = new ImageIcon(
196 getClass().getResource("/com/robrohan/treebeard/images/redo_sm.gif")
197 );
198
199 getDocument().addUndoableEditListener(this);
200
201 }
202
203 /** Creates a new document and sets a syntax highlighting type
204 * @param contenttype the type of document to create
205 */
206 public void createNewDocument(String contenttype){
207 this.createNewDocument(contenttype,"");
208 }
209
210 /** Creates a new document, sets a syntax highlighting type, and adds default text
211 * @param contenttype the type of document to create
212 * @param defaultText the default text for this document
213 */
214 public void createNewDocument(String contenttype, String defaultText){
215 SyntaxStyle[] styles = new SyntaxStyle[Token.ID_COUNT];
216
217 //TODO: hu... you can tell.
218 setDocument(new org.syntax.jedit.SyntaxDocument());
219 if(contenttype.equals("text/xsl")){
220 setTokenMarker(new org.syntax.jedit.tokenmarker.XSLTokenMarker());
221
222 styles[Token.COMMENT1] = new SyntaxStyle(new Color(0xa1a3a1),true,true);
223 styles[Token.COMMENT2] = new SyntaxStyle(Color.black,false,true);
224 styles[Token.KEYWORD1] = new SyntaxStyle(Color.black,false,true);
225 styles[Token.KEYWORD2] = new SyntaxStyle(new Color(0x0f5111),false,false);
226 styles[Token.KEYWORD3] = new SyntaxStyle(Color.black,false,true);
227 styles[Token.LITERAL1] = new SyntaxStyle(new Color(0xa3a1a1),false,false);
228 styles[Token.LITERAL2] = new SyntaxStyle(new Color(0xa3a1a1),false,true);
229 styles[Token.LABEL] = new SyntaxStyle(new Color(0x0f5111),false,true);
230 styles[Token.OPERATOR] = new SyntaxStyle(new Color(0x060e68),false,true);
231 styles[Token.INVALID] = new SyntaxStyle(Color.red,false,true);
232 getPainter().setStyles(styles);
233 getPainter().setInvalidLinesPainted(true);
234 getPainter().setLineHighlightEnabled(true);
235
236 //scan the document for changes every 3 seconds
237 //this may need to be adjusted depending on performance
238 if(timer == null){
239 timer = new javax.swing.Timer(3000, new java.awt.event.ActionListener() {
240 public void actionPerformed(ActionEvent evt) {
241 doAnalyze();
242 }
243 });
244 timer.start();
245 }
246 }else if(contenttype.equals("text/xml")){
247 setTokenMarker(new org.syntax.jedit.tokenmarker.XMLTokenMarker());
248 styles[Token.COMMENT1] = new SyntaxStyle(Color.green,true,false);
249 styles[Token.COMMENT2] = new SyntaxStyle(Color.black,false,true);
250 styles[Token.KEYWORD1] = new SyntaxStyle(Color.blue,false,true);
251 styles[Token.KEYWORD2] = new SyntaxStyle(Color.black,false,false);
252 styles[Token.KEYWORD3] = new SyntaxStyle(Color.black,false,true);
253 styles[Token.LITERAL1] = new SyntaxStyle(new Color(0xa3a1a1),false,true);
254 styles[Token.LITERAL2] = new SyntaxStyle(new Color(0xa3a1a1),false,true);
255 styles[Token.LABEL] = new SyntaxStyle(Color.black,false,false);
256 styles[Token.OPERATOR] = new SyntaxStyle(Color.black,false,true);
257 styles[Token.INVALID] = new SyntaxStyle(Color.red,false,true);
258 getPainter().setStyles(styles);
259 getPainter().setLineHighlightEnabled(false);
260
261 if(timer != null){
262 timer.stop();
263 timer = null;
264 }
265
266 }else if(contenttype.equals("text/html")){
267 setTokenMarker(new org.syntax.jedit.tokenmarker.HTMLTokenMarker());
268 styles[Token.COMMENT1] = new SyntaxStyle(Color.green,true,false);
269 styles[Token.COMMENT2] = new SyntaxStyle(Color.black,false,true);
270 styles[Token.KEYWORD1] = new SyntaxStyle(Color.blue,false,true);
271 styles[Token.KEYWORD2] = new SyntaxStyle(Color.black,false,false);
272 styles[Token.KEYWORD3] = new SyntaxStyle(Color.black,false,true);
273 styles[Token.LITERAL1] = new SyntaxStyle(Color.magenta,false,false);
274 styles[Token.LITERAL2] = new SyntaxStyle(Color.magenta,false,true);
275 styles[Token.LABEL] = new SyntaxStyle(Color.black,false,false);
276 styles[Token.OPERATOR] = new SyntaxStyle(Color.yellow,false,true);
277 styles[Token.INVALID] = new SyntaxStyle(Color.red,false,true);
278 getPainter().setStyles(styles);
279 getPainter().setLineHighlightEnabled(false);
280 if(timer != null){
281 timer.stop();
282 timer = null;
283 }
284 }else{
285 setTokenMarker(new org.syntax.jedit.tokenmarker.JavaScriptTokenMarker());
286 if(timer != null){
287 timer.stop();
288 timer = null;
289 }
290 }
291
292 setText(defaultText);
293 currentFile=null;
294 undo.discardAllEdits();
295 getDocument().addUndoableEditListener(this);
296 setCaretPosition(0);
297 setEnabled(true);
298 fileReferenced=false;
299 }
300
301 /** Set this panes text from an input stream
302 * @param iso the stream that has the text to load
303 */
304 public void setText(java.io.InputStream iso){
305 StringBuffer sb = new StringBuffer();
306 int a;
307
308 try{
309 java.io.InputStreamReader isr
310 = new java.io.InputStreamReader(iso,encodingtype);
311
312 while((a = isr.read()) != -1){
313 //read everything from the input stream
314 //while((a = iso.read()) != -1){
315 sb.append((char)a);
316 }
317 isr.close();
318 iso.close();
319 }catch(Exception e){
320 System.err.println("EditorPane::setText(iso): " + e);
321 }
322
323 //update the text area
324 setText(sb.toString());
325 }
326
327
328 /** gets the current file
329 * @return the current file object
330 */
331 public java.io.File getCurrentFile(){
332 return currentFile;
333 }
334
335 /** Adds an undo event to the undo tracker
336 * @param a the event that happened
337 */
338 public void undoableEditHappened(javax.swing.event.UndoableEditEvent a) {
339 undo.addEdit(a.getEdit());
340 }
341
342 /** Gets a handle to the undo action to envoke undos from outside the class
343 * @return the undo Action object
344 */
345 public Action getUndoAction(){
346 return new com.robrohan.editorkit.XMLEditorPane.undoAction();
347 }
348
349 /** Gets a handle to the redo action to envoke redos from outside the class
350 * @return the undo Action object
351 */
352 public Action getRedoAction(){
353 return new com.robrohan.editorkit.XMLEditorPane.redoAction();
354 }
355
356 class undoAction extends AbstractAction {
357 public undoAction(){
358 super("Undo", undo_icon);
359 //putValue(Action.ACCELERATOR_KEY, javax.swing.KeyStroke.getKeyStroke("control Z"));
360 }
361
362 public void actionPerformed(ActionEvent evt){
363 try{
364 if(undo.canUndo()) undo.undo();
365
366 }catch (javax.swing.undo.CannotUndoException e){
367 System.err.println("XMLEditorPane::undoAction: " + e);
368 e.printStackTrace(System.err);
369 }
370 }
371 }
372
373 class redoAction extends AbstractAction {
374 public redoAction(){
375 super("Redo", redo_icon);
376 //putValue(Action.ACCELERATOR_KEY, javax.swing.KeyStroke.getKeyStroke("control Y"));
377 }
378
379 public void actionPerformed(ActionEvent evt){
380 try{
381 if(undo.canRedo()) undo.redo();
382 }catch (javax.swing.undo.CannotUndoException e){
383 System.err.println("XMLEditorPane::redoAction: " + e);
384 e.printStackTrace(System.err);
385 }
386 }
387 }
388
389 class commentSection extends AbstractAction {
390 public commentSection(){
391 super("Comment Selection");
392 //putValue(Action.ACCELERATOR_KEY, javax.swing.KeyStroke.getKeyStroke("control shift C"));
393 }
394
395 public void actionPerformed(ActionEvent a) {
396 try{
397 setSelectedText("<!-- " + getSelectedText() + " -->");
398 }catch(Exception e){
399 System.err.println("XMLEditorPane::commentSection: " + e);
400 }
401 }
402 }
403
404 class goToLine extends AbstractAction{
405 public goToLine(){
406 super("Go To Line...");
407 //putValue(Action.ACCELERATOR_KEY, javax.swing.KeyStroke.getKeyStroke("control G"));
408 }
409
410 public void actionPerformed(ActionEvent ae){
411 //String resp = javax.swing.JOptionPane.showInputDialog(null,"Go to Line:");
412 String resp = javax.swing.JOptionPane.showInternalInputDialog(panePtr,"Go to line:");
413 if(resp != null && Integer.parseInt(resp) > 0 && Integer.parseInt(resp) < getLineCount()){
414 try{
415 scrollTo(Integer.parseInt(resp)-1,0);
416 setCaretPosition(getLineStartOffset(Integer.parseInt(resp)-1));
417 }catch(Exception e){
418 System.err.println("XMLEditorPane::goToLine: " + e);
419 e.printStackTrace(System.err);
420 }
421 }
422 }
423 }
424
425 class fileProperties extends AbstractAction {
426 public fileProperties(){
427 super("File Properties");
428 }
429
430 public void actionPerformed(ActionEvent ae){
431 String info = "";
432 if(currentFile != null){
433 info += "Name: " + currentFile.getName() + "\n";
434 info += "Path: " + currentFile.getAbsolutePath() + "\n";
435 info += "Writeable: " + currentFile.canWrite() + "\n";
436 info += "Still Exists: " + currentFile.exists() + "\n";
437 info += "LastModified: " + new java.util.Date(currentFile.lastModified()) + "\n";
438 }else{
439 info += "File not saved locally.\n";
440 }
441 if(!isReferenced()){
442 info += "Number of lines: " + (getLineCount() - 1) + "\n";
443 }else{
444 info += "Referenced Source\n";
445 }
446 info += "Encoding: " + encodingtype + "\n";
447 javax.swing.JOptionPane.showInternalMessageDialog(panePtr,info);
448 }
449 }
450
451 class loadFileAction extends AbstractAction {
452 public loadFileAction(){
453 super("Load File", load_icon);
454 }
455
456 public void actionPerformed(ActionEvent actionEvent) {
457 openFile("Load File");
458 }
459 }
460
461 class saveAsFileAction extends AbstractAction {
462 public saveAsFileAction(){
463 super("Save As", save_icon);
464 }
465
466 public void actionPerformed(ActionEvent actionEvent) {
467 saveAs();
468 }
469 }
470
471 class saveFileAction extends AbstractAction {
472 public saveFileAction(){
473 super("Save", save_icon);
474 }
475
476 public void actionPerformed(ActionEvent actionEvent) {
477 if(currentFile != null){
478 save();
479 }else{
480 saveAs();
481 }
482 }
483 }
484
485
486 class validateAction extends AbstractAction {
487 public validateAction(){
488 super("Validate");
489 }
490
491 public void actionPerformed(ActionEvent actionEvent) {
492 valErrors="";
493 doValidate();
494
495 if(valErrors == ""){
496 //javax.swing.JOptionPane.showMessageDialog(null,"Document Valid.");
497 javax.swing.JOptionPane.showInternalMessageDialog(panePtr,"Document Valid.");
498 }else{
499 javax.swing.JOptionPane.showInternalMessageDialog(panePtr,"Document Not Valid.\n See error window for details.");
500 tellMessage(valErrors);
501 }
502 }
503 }
504 ////////////////////////////////////////////////////////////////////////////
505 /** Gets a handle to the save action to envoke saves from outside the class
506 * @return the save Action
507 */
508 public Action getSaveAction(){
509 return new com.robrohan.editorkit.XMLEditorPane.saveFileAction();
510 }
511
512 /** Gets a handle to the saveas action to envoke saveas' from outside the class
513 * @return the saveas Action object
514 */
515 public Action getSaveAsAction(){
516 return new com.robrohan.editorkit.XMLEditorPane.saveAsFileAction();
517 }
518
519 /** Gets a handle to the load action to envoke loads from outside the class
520 * @return the load Action object
521 */
522 public Action getLoadAction(){
523 return new com.robrohan.editorkit.XMLEditorPane.loadFileAction();
524 }
525
526 ///////////////////////////////////////////////////////////////////////////
527 private void tellMessage(String message){
528 //javax.swing.JOptionPane.showMessageDialog(this,message);
529 System.err.println(message);
530 }
531
532 /** envokes the right click menu (context menu)
533 * @param e the mouse event to check for right clicks
534 */
535 public void processMouseEvent(java.awt.event.MouseEvent e){
536 if(e.isPopupTrigger()){
537 rmenu.show(this, e.getX(), e.getY());
538 }else{
539 super.processMouseEvent(e);
540 }
541 }
542 /**
543 * top the analyzer from parsing the textArea
544 * (looking for namespaces and such)
545 */
546 public void stopAnalyzer(){
547 if(timer != null){
548 //I SAID STOP!
549 while(timer.isRunning()){
550 timer.stop();
551 }
552 }
553 }
554 /**
555 * kill the analyzer (looking for namespaces and such)
556 */
557 public void killAnalyzer(){
558 stopAnalyzer();
559 timer = null;
560 }
561
562 /** Validates this panes contents. This function uses the currently select
563 * xml parser so if it does not do validation, this will not do anything.
564 * It will write any errors to the valErrors String
565 */
566 public void doValidate(){
567 System.setProperty("javax.xml.parsers.SAXParserFactory", SAXFactory);
568 //this will fail if they haven't set the SAXFactory yet.
569 try{
570 javax.xml.parsers.SAXParserFactory factory = javax.xml.parsers.SAXParserFactory.newInstance();
571 factory.setNamespaceAware(true);
572
573 factory.setValidating(true);
574
575 org.xml.sax.XMLReader xmlReader = factory.newSAXParser().getXMLReader();
576 xmlReader.setErrorHandler(new com.robrohan.editorkit.XMLEditorPane.errorHandler());
577
578 org.xml.sax.InputSource input = new org.xml.sax.InputSource(
579 new java.io.ByteArrayInputStream(this.getDocument().getText(0,this.getDocument().getLength()).getBytes())
580 );
581
582 xmlReader.parse(input);
583 }catch(Exception e){
584 valErrors += e.toString();
585 }
586 }
587 //report validation errors
588 class errorHandler implements org.xml.sax.ErrorHandler {
589 public void error(org.xml.sax.SAXParseException sAXParseException) throws org.xml.sax.SAXException {
590 valErrors += "error: " + sAXParseException.toString() + "\n";
591 }
592 public void fatalError(org.xml.sax.SAXParseException sAXParseException) throws org.xml.sax.SAXException {
593 valErrors += "fatal: " + sAXParseException.toString() + "\n";
594 }
595 public void warning(org.xml.sax.SAXParseException sAXParseException) throws org.xml.sax.SAXException {
596 valErrors += "warning: " + sAXParseException.toString() + "\n";
597 }
598 }
599
600 //////////////////////////////////////////////////////////////////////////////
601 /**
602 * parse the textAreas contents and look for namespaces. This will be used
603 * in codecompletion / insite stuff eventually
604 */
605 public void doAnalyze(){
606 System.setProperty("javax.xml.parsers.SAXParserFactory", SAXFactory);
607 //this will fail if they haven't set the SAXFactory yet.
608
609 //dont bother if there is nothing there or this is not an XSLT type document
610 //(it takes too much time if I do all types of xml documents - but I want to!
611 //so I shall find a way (someday)
612 if(getText().length() <= 0
613 || !(this.getTokenMarker() instanceof org.syntax.jedit.tokenmarker.XSLTokenMarker))
614 return;
615
616 try{
617 javax.xml.parsers.SAXParserFactory factory = javax.xml.parsers.SAXParserFactory.newInstance();
618 factory.setNamespaceAware(true);
619 factory.setValidating(false);
620
621 org.xml.sax.XMLReader xmlReader = factory.newSAXParser().getXMLReader();
622
623 //use the analyze handler
624 xmlReader.setErrorHandler(
625 new com.robrohan.editorkit.XMLEditorPane.AnalyzeHandler()
626 );
627 //and parser
628 xmlReader.setContentHandler(new XMLEditorPane.AnalyzeParser());
629
630 org.xml.sax.InputSource input = new org.xml.sax.InputSource(
631 new java.io.ByteArrayInputStream(
632 this.getDocument().getText(0,this.getDocument().getLength()).getBytes()
633 )
634 );
635
636 xmlReader.parse(input);
637 }catch(Exception e){
638 //hush :)
639 //System.err.println("XMLEditorPane::doAnalyze: " + e.toString());
640 //e.printStackTrace(System.err);
641 }
642 repaint();
643 }
644
645 //scan the document for text additions
646 class AnalyzeParser implements org.xml.sax.ContentHandler {
647 public void characters(char[] ch, int start, int length) throws SAXException {;}
648 public void endDocument() throws SAXException {;}
649 public void endElement(String namespaceURI, String localName, String qName) throws SAXException {
650 // System.err.println("endEle : " + localName);
651 // System.err.println("endEle : " + qName);
652 }
653 public void endPrefixMapping(String prefix) throws SAXException {
654 // System.err.println("endPre: " + prefix);
655 }
656 public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {;}
657 public void processingInstruction(String target, String data) throws SAXException {
658 // System.err.println("PI: " + target);
659 // System.err.println("PI: " + data);
660 }
661 public void setDocumentLocator(Locator locator) {;}
662 public void skippedEntity(String name) throws SAXException {;}
663 public void startDocument() throws SAXException {;}
664 public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
665 // System.err.println("startEle: " + localName);
666 // System.err.println("startEle: " + qName);
667 // System.err.println("startEleAtt: " + atts.getLength());
668 }
669 public void startPrefixMapping(String prefix, String uri) throws SAXException {
670 //System.err.println("startPre: " + prefix);
671 //System.err.println("startURI: " + uri);
672
673 //if the keyword is not in the keyword list add it
674 if(prefix.length() > 0 && !isKeywordAdded(prefix)){
675 addKeyword(prefix,org.syntax.jedit.tokenmarker.Token.LABEL);
676 }
677 }
678 }
679 class AnalyzeHandler implements org.xml.sax.ErrorHandler {
680 public void error(org.xml.sax.SAXParseException sAXParseException) throws org.xml.sax.SAXException {;}
681 public void fatalError(org.xml.sax.SAXParseException sAXParseException) throws org.xml.sax.SAXException {
682 //System.err.println("fatal: " + sAXParseException.toString());
683 // these are what we want
684 String linetext="";
685 try{
686 linetext = getLineText(getCaretLine());
687 org.apache.regexp.RE r = new org.apache.regexp.RE("[\\<][a-zA-Z0-9_]*[\\:]");
688 r.match(linetext);
689
690 if(r.getParen(0) != null){
691 System.err.println("You want: " +
692 r.getParen(0).substring(1,(r.getParen(0).length()-1))
693 );
694 }
695
696 }catch(Exception e){
697 System.err.println("Can't find namespace? " + e.toString());
698 }
699 }
700 public void warning(org.xml.sax.SAXParseException sAXParseException) throws org.xml.sax.SAXException{;}
701 }
702
703 ////////////////////////////////////////////////////////////////////////////
704
705 ////////////////////////////////////////////////////////////////////////////
706 /** checks to see if a keyword is already listed in the TokenMarker
707 * this is crazy, but it works
708 */
709 public boolean isKeywordAdded(String keyword){
710 byte isthere = (
711 (org.syntax.jedit.tokenmarker.XSLTokenMarker)getTokenMarker()
712 ).getKeywords().lookup(
713 new javax.swing.text.Segment(
714 keyword.toCharArray(), 0, keyword.length()
715 ),
716 0,
717 keyword.length()
718 );
719
720 //0=not added anything else = added
721 if(isthere == org.syntax.jedit.tokenmarker.Token.NULL){
722 return false;
723 }else{
724 return true;
725 }
726 }
727
728 /** add a keyword to the keyword list (in tokenmarker) and set the type
729 * heavly tied to jedit
730 */
731 public void addKeyword(String keyword, byte type){
732 ((org.syntax.jedit.tokenmarker.XSLTokenMarker)getTokenMarker()
733 ).getKeywords().add(
734 keyword,
735 type
736 );
737 }
738
739 ////////////////////////////////////////////////////////////////////////////
740 ////////////////////////////////////////////////////////////////////////////
741 /** Envokes the loadFile dialog and then trys to open the file from the
742 * fileLoader dialog box. Can load either a file off disk or from an
743 * http(s) address.
744 * @param title the file loader dialog title (i.e. "select xml document to open")
745 */
746 public void openFile(String title){
747 fileLoader.setFileName("");
748 fileLoader.setTitle(title);
749 fileLoader.show();
750
751 String fileURI = fileLoader.getFileURI();
752 boolean ref = fileLoader.isReference();
753
754 //if there is something to load and it is not a file reference
755 if(fileURI != null && !fileURI.equals("") && !ref ){
756 try{
757 //if its a url
758 if(fileURI.startsWith("http://") || fileURI.startsWith("https://")){
759 //load url
760 final String filename = fileURI;
761 Thread w = new Thread(){
762 public void run(){
763 try{
764 setPage(filename);
765 }catch(Exception e){
766 e.printStackTrace(System.err);
767 System.err.println("Couldn't load URL because: " + e.toString());
768 }
769 }
770 };
771 w.start();
772 }else{
773 //load localfile
774 final String filename = fileURI;
775 Thread w = new Thread(){
776 public void run(){
777 loadFile(new java.io.File(filename));
778 }
779 };
780 w.start();
781 }
782 }catch (Exception e){
783 //e.printStackTrace(System.err);
784 System.err.println("*** Couldn't load file because: " + e + " ***");
785 fileURI = "Error.";
786 tellMessage(e.toString());
787 }
788 //otherwise if it is a file reference
789 }else if(fileURI != null && !fileURI.equals("") && ref){
790 if(fileURI.startsWith("http://") || fileURI.startsWith("https://")){
791 //reference http files
792 }else{
793 //reference local file
794 createNewDocument("text/xml","");
795 currentFile = new java.io.File(fileURI);
796 this.add(new javax.swing.JLabel(
797 new javax.swing.ImageIcon(getClass().getResource("/com/robrohan/treebeard/images/xmldoc_sm.gif")))
798 );
799 fileReferenced=true;
800 setEnabled(false);
801 }
802 }
803
804 }
805 /** to tell if the file is loaded into this pane, or just referenced.
806 * @return true if the file is referenced
807 */
808 public boolean isReferenced(){
809 return fileReferenced;
810 }
811 private void setPage(String URI){
812 try{
813 java.net.URL url = new java.net.URL(URI);
814 java.net.URLConnection site = url.openConnection();
815
816 //java.io.BufferedReader bin = new java.io.BufferedReader(new java.io.FileReader(file));
817 java.io.BufferedReader bin = new java.io.BufferedReader(
818 new java.io.InputStreamReader(site.getInputStream())
819 );
820 //using a buffer instead of right to the box, this seems
821 //to work a lot faster/better
822 StringBuffer filecontents = new StringBuffer();
823
824 String boxfill;
825 while((boxfill = bin.readLine()) != null){
826 filecontents.append(boxfill + "\n");
827 }
828
829 createNewDocument(guessFileType(URI),filecontents.toString());
830 setCaretPosition(0);
831
832 }catch (Exception e){
833 System.err.println("Could not load file because: " + e);
834 tellMessage(e.toString());
835 }
836 }
837
838 protected void loadFile(java.io.File file){
839 try{
840 //clear the textbox
841 //this.setText("");
842
843 java.io.BufferedReader bin = new java.io.BufferedReader(new java.io.FileReader(file));
844
845 //using a buffer instead of right to the box, this seems
846 //to work a lot faster/better
847 StringBuffer filecontents = new StringBuffer();
848
849 String boxfill;
850 while((boxfill = bin.readLine()) != null){
851 filecontents.append(boxfill + "\n");
852 }
853
854 createNewDocument(guessFileType(file.getName()),filecontents.toString());
855 setCaretPosition(0);
856
857 currentFile = file;
858
859 }catch (Exception e){
860 System.err.println("Could not load file because: " + e);
861 tellMessage(e.toString());
862 }
863 }
864 private String guessFileType(String filename){
865 //try to guess what type of file this is
866 if(filename.toString().toLowerCase().endsWith(".html")
867 || filename.toString().toLowerCase().endsWith(".htm")){
868
869 return "text/html";
870 }else if(filename.toString().toLowerCase().endsWith(".xsl")
871 || filename.toString().toLowerCase().endsWith(".xslt")){
872
873 return "text/xsl";
874 }else{
875 //leave the default xml becuase query URL's might have
876 //extra params (and xml = html right now anyway) should
877 //replace with a URI.getFileName() etc...
878 return "text/xml";
879 }
880 }
881
882 private void save(){
883 if(this.currentFile != null)
884 saveFile(this.currentFile);
885 else
886 saveAs();
887 }
888
889 /** Envokes the saveas dialog to save this panes contents to disk */
890 public void saveAs(){
891 fileChooser.setName("");
892 fileChooser.setDialogTitle("Save As");
893 fileChooser.showSaveDialog(null);
894
895 if(fileChooser.getSelectedFile() != null && !fileChooser.getSelectedFile().equals("")){
896 saveFile(fileChooser.getSelectedFile());
897 this.currentFile = fileChooser.getSelectedFile();
898 }
899 }
900
901
902 private void saveFile(java.io.File file){
903 try{
904 java.io.BufferedWriter bout = new java.io.BufferedWriter(new java.io.FileWriter(file));
905 bout.write(this.getText().toString());
906 bout.flush();
907 bout.close();
908
909 }catch (Exception e){
910 System.err.println("Could not save file because: " + e);
911 e.printStackTrace(System.err);
912 //tellError();
913 }
914 }
915 }