Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

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 }