1   package gate.swing;
2   
3   import java.awt.event.ActionEvent;
4   import java.io.IOException;
5   import java.net.URL;
6   import java.util.LinkedList;
7   import java.util.Vector;
8   
9   import javax.swing.*;
10  import javax.swing.event.HyperlinkEvent;
11  import javax.swing.event.HyperlinkListener;
12  import javax.swing.text.html.HTMLDocument;
13  import javax.swing.text.html.HTMLFrameHyperlinkEvent;
14  
15  import gate.event.StatusListener;
16  import gate.gui.MainFrame;
17  import gate.util.Err;
18  
19  /**
20   * An enhanced version of {@link javax.swing.JEditorPane} that is able of
21   * handling hyperlinks from the HTML document displayed.
22   */
23  public class XJEditorPane extends JEditorPane {
24  
25    public XJEditorPane(){
26      super();
27      init();
28    }
29  
30    public XJEditorPane(String url) throws IOException{
31      super(url);
32      init();
33    }
34  
35    public XJEditorPane(URL initialPage)throws IOException{
36      super(initialPage);
37      init();
38    }
39  
40    protected void init(){
41      initLocalData();
42      initListeners();
43    }//protected void init()
44  
45    protected void initLocalData(){
46      backUrls = new LinkedList();
47      forwardUrls = new LinkedList();
48      try{
49        backAction = new BackAction();
50        forwardAction = new ForwardAction();
51      }catch(IOException ioe){
52        Err.prln("Resource mising! Is your classpath OK?");
53        ioe.printStackTrace(Err.getPrintWriter());
54      }
55    }//protected void initLocalData()
56  
57    protected void initListeners(){
58      addHyperlinkListener(new HyperlinkListener() {
59        public void hyperlinkUpdate(HyperlinkEvent e){
60          if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED){
61            if (e instanceof HTMLFrameHyperlinkEvent) {
62                HTMLFrameHyperlinkEvent  evt = (HTMLFrameHyperlinkEvent)e;
63                HTMLDocument doc = (HTMLDocument)getDocument();
64                doc.processHTMLFrameHyperlinkEvent(evt);
65            }else{
66              try {
67                backUrls.addLast(getPage());
68                forwardUrls.clear();
69                setPage(e.getURL());
70              }catch (Throwable t){
71                t.printStackTrace(Err.getPrintWriter());
72              }
73            }
74          }else if(e.getEventType() == HyperlinkEvent.EventType.ENTERED){
75            fireStatusChanged(e.getURL().toExternalForm());
76          }else if(e.getEventType() == HyperlinkEvent.EventType.EXITED){
77            fireStatusChanged("");
78          }
79        }//public void hyperlinkUpdate(HyperlinkEvent e)
80      });
81    }//protected void initListeners()
82  
83    public Action getForwardAction(){
84      return forwardAction;
85    }
86  
87    public Action getBackAction(){
88      return backAction;
89    }
90  
91    public void setPage(URL page) throws IOException{
92      try{
93        super.setPage(page);
94      }catch(Exception e){
95        fireStatusChanged(e.toString());
96        e.printStackTrace(Err.getPrintWriter());
97      }
98      updateEnableState();
99    }
100 
101   class ForwardAction extends AbstractAction{
102     private ForwardAction() throws IOException{
103       super("Forward", MainFrame.getIcon("forward.gif"));
104     }
105 
106     public void actionPerformed(ActionEvent e){
107       backUrls.addLast(getPage());
108       try{
109         setPage((URL)forwardUrls.removeFirst());
110       }catch(IOException ioe){
111         ioe.printStackTrace(Err.getPrintWriter());
112       }
113     }
114   }//class ForwardAction extends AbstractAction
115 
116   class BackAction extends AbstractAction{
117     private BackAction() throws IOException{
118       super("Back", new ImageIcon(new URL("gate:/img/back.gif")));
119     }
120 
121     public void actionPerformed(ActionEvent e){
122       forwardUrls.addFirst(getPage());
123       try{
124         setPage((URL)backUrls.removeLast());
125       }catch(IOException ioe){
126         ioe.printStackTrace(Err.getPrintWriter());
127       }
128     }
129   }//class ForwardAction extends AbstractAction
130 
131 
132   /**
133    * Updates the enabled/disabled state for the back/forward actions
134    */
135   protected void updateEnableState(){
136     forwardAction.setEnabled(!forwardUrls.isEmpty());
137     backAction.setEnabled(!backUrls.isEmpty());
138   }
139   public synchronized void removeStatusListener(StatusListener l) {
140     if (statusListeners != null && statusListeners.contains(l)) {
141       Vector v = (Vector) statusListeners.clone();
142       v.removeElement(l);
143       statusListeners = v;
144     }
145   }
146   public synchronized void addStatusListener(StatusListener l) {
147     Vector v = statusListeners == null ? new Vector(2) : (Vector) statusListeners.clone();
148     if (!v.contains(l)) {
149       v.addElement(l);
150       statusListeners = v;
151     }
152   }
153 
154   protected LinkedList backUrls;
155   protected LinkedList forwardUrls;
156   protected Action backAction;
157   protected Action forwardAction;
158   private transient Vector statusListeners;
159   protected void fireStatusChanged(String e) {
160     if (statusListeners != null) {
161       Vector listeners = statusListeners;
162       int count = listeners.size();
163       for (int i = 0; i < count; i++) {
164         ((StatusListener) listeners.elementAt(i)).statusChanged(e);
165       }
166     }
167   }
168 }//public class XJEditorPane extends JEditorPane
169