KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jdesktop > jdic > browser > WebBrowser


1 /*
2  * Copyright (C) 2004 Sun Microsystems, Inc. All rights reserved. Use is
3  * subject to license terms.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the Lesser GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18  * USA.
19  */

20
21 package org.jdesktop.jdic.browser;
22
23 import java.util.Vector JavaDoc;
24 import java.net.URL JavaDoc;
25 import java.net.MalformedURLException JavaDoc;
26 import java.awt.*;
27 import java.awt.event.*;
28 import java.security.*;
29
30 import org.jdesktop.jdic.init.JdicInitException;
31 import org.jdesktop.jdic.init.JdicManager;
32 import org.jdesktop.jdic.browser.internal.WebBrowserUtil;
33
34 /**
35  * A <code>WebBrowser</code> component represents a blank rectangular area of
36  * the screen onto which the application can display webpages or from which the
37  * application can trap events from the browser window. In order to show <code>
38  * WebBrowser</code> component in GUI, users need to add <code>WebBrowser</code>
39  * to a top-level container, such as <code>Frame</code>.
40  * <p>
41  * The class that is interested in processing a <code>WebBrowser</code> event
42  * should implement interface <code>WebBrowserListener</code>, and the object
43  * created with that class should use WebBrowser's <code>addWebBrowserListener
44  * </code> method to register as a listener.
45  * <p>
46  * As an AWT component, a <code>WebBrowser</code> component must be hosted by
47  * a native container somewhere higher up in the component tree (for example,
48  * by a JPanel object).
49  *
50  * @see WebBrowserEvent
51  * @see WebBrowserListener
52  *
53  * @author Kyle Yuan
54  * @version 0.1, 03/07/17
55  */

56 public class WebBrowser extends Canvas
57 {
58     private MyFocusListener focusListener = new MyFocusListener();
59     // eventThread should be initialized after JdicManager.initShareNative()
60
// in static block.
61
private static NativeEventThread eventThread;
62     private Vector JavaDoc webBrowserListeners = new Vector JavaDoc();
63     private int instanceNum;
64     private static int lastInstanceNum = 0;
65     
66     // WebBrowser status.
67
private boolean isInitialized = false;
68     private boolean isBackEnabled = false;
69     private boolean isForwardEnabled = false;
70     private String JavaDoc initFailureMessage = "WebBrowser is not initialized.";
71
72     static {
73         // Add the initialization code from package org.jdesktop.jdic.init.
74
// To set the environment variables or initialize the set up for
75
// native libraries and executable files.
76
try {
77             JdicManager jm = JdicManager.getManager();
78             jm.initShareNative();
79             jm.initBrowserNative();
80         } catch (JdicInitException e){
81             e.printStackTrace();
82         }
83         eventThread = new NativeEventThread();
84         
85         AccessController.doPrivileged(
86                 new PrivilegedAction() {
87                     public Object JavaDoc run() {
88                         System.loadLibrary("jdic");
89                         return null; // nothing to return
90
}
91                 }
92             );
93     }
94
95     void setInitialized(boolean b) {
96         isInitialized = b;
97     }
98
99     void setInitFailureMessage(String JavaDoc msg) {
100         initFailureMessage = msg;
101     }
102
103     /**
104      * Constructs a new <code>WebBrowser</code> object with no URL specified.
105      */

106     public WebBrowser() {
107         this(null);
108     }
109
110     /**
111      * Constructs a new <code>WebBrowser</code> with an URL specified.
112      */

113     public WebBrowser(URL JavaDoc url) {
114         synchronized(this) {
115             instanceNum = lastInstanceNum;
116             lastInstanceNum++;
117         }
118         eventThread.attachWebBrowser(this);
119
120         if (0 == instanceNum) {
121             eventThread.start();
122             eventThread.fireNativeEvent(instanceNum, NativeEventData.EVENT_INIT);
123         }
124
125         if (null != url) {
126             setURL(url);
127         }
128
129         setFocusable(true);
130         addFocusListener(focusListener);
131     }
132
133     /**
134      * Creates the peer for this WebBrowser component. The peer allows us to
135      * modify the appearance of the WebBrowser component without changing its
136      * functionality.
137      */

138     public void addNotify() {
139         boolean flag = super.isDisplayable();
140         super.addNotify();
141         if(!flag) {
142             eventThread.fireNativeEvent(instanceNum,
143                     NativeEventData.EVENT_CREATEWINDOW);
144         }
145     }
146     
147     /**
148      * Makes this WebBrowser component undisplayable by destroying it native
149      * screen resource.
150      * <p>
151      * This method is called by the toolkit internally and should not be called
152      * directly by programs.
153      */

154     public void removeNotify() {
155         Thread JavaDoc disposeThread = new Thread JavaDoc() {
156             public void run() {
157                 synchronized( WebBrowser.this ){
158                     eventThread.fireNativeEvent(instanceNum,
159                             NativeEventData.EVENT_DESTROYWINDOW);
160                     try {
161                         // wait untill we get the message
162
// WebBrowserEvent.WEBBROWSER_DESTROYWINDOW_SUCC
163
// from native process.
164
WebBrowser.this.wait();
165                     } catch (InterruptedException JavaDoc e) {
166                     }
167                 }
168                 WebBrowser.super.removeNotify();
169                 setInitialized(false);
170             }
171         };
172
173         disposeThread.start();
174     }
175
176     /**
177      * Moves and resizes this component. The new location of the top-left
178      * corner is specified by <code>x</code> and <code>y</code>, and the new
179      * size is specified by <code>width</code> and <code>height</code>.
180      *
181      * @param x - the new x-coordinate of this component
182      * @param y - the new y-coordinate of this component
183      * @param width - the new width of this component
184      * @param height - the new height of this component
185      */

186     public void setBounds(int x, int y, int width, int height) {
187         super.setBounds(x, y, width, height);
188         eventThread.fireNativeEvent(instanceNum,
189                 NativeEventData.EVENT_SET_BOUNDS,
190                 new Rectangle(x, y, width, height));
191     }
192
193     /*
194      * Dispatches a WebBrowserEvent to the Java embeddor, called by
195      * NativeEventThread.processIncomingMessage.
196      */

197     void dispatchWebBrowserEvent(WebBrowserEvent e) {
198         int eid = e.getID();
199
200         WebBrowserUtil.trace("Got event from NativeEventThread " + eid);
201
202         // native browser needs immediate return value for these two events.
203
// Special trigger messages beginning with a '@' character, to give
204
// the native browser a yes or no to continue an operation(navigating
205
// an URL or openning a new window).
206
String JavaDoc msg = "@" + instanceNum + "," + eid + ",";
207         if (WebBrowserEvent.WEBBROWSER_BEFORE_NAVIGATE == eid) {
208             URL JavaDoc url = null;
209             try {
210                 url = new URL JavaDoc(e.getData());
211             } catch (MalformedURLException JavaDoc ex1) {
212                 try {
213                     // IE omits the file:/ protocol for local files, append it.
214
if (!WebBrowserUtil.isDefaultBrowserMozilla()) {
215                         url = new URL JavaDoc("file:/" + e.getData());
216                     }
217                 } catch (MalformedURLException JavaDoc ex2) {
218                 }
219             }
220             
221             msg += willOpenURL(url) ? "0" : "1";
222             eventThread.messenger.sendMessage(msg);
223             return;
224         }
225         else if (WebBrowserEvent.WEBBROWSER_BEFORE_NEWWINDOW == eid) {
226             msg += willOpenWindow() ? "0" : "1";
227             eventThread.messenger.sendMessage(msg);
228             return;
229         }
230         else if (WebBrowserEvent.WEBBROWSER_COMMAND_STATE_CHANGE == eid) {
231             String JavaDoc data = e.getData();
232             if (data.startsWith("forward")) {
233                 isForwardEnabled = data.substring(8).equals("1");
234                 WebBrowserUtil.trace("Forward State changed = "
235                         + isForwardEnabled);
236             }
237             else if (data.startsWith("back")) {
238                 isBackEnabled = data.substring(5).equals("1");
239                 WebBrowserUtil.trace("Back State changed = " + isBackEnabled);
240             }
241             return;
242         }
243         else if (WebBrowserEvent.WEBBROWSER_FOCUS_REQUEST == eid) {
244             WebBrowserUtil.trace("Got event from brower: Focus request.");
245             requestFocus();
246             return;
247         }
248         else if (WebBrowserEvent.WEBBROWSER_DESTROYWINDOW_SUCC == eid){
249             WebBrowserUtil.trace("Got event from brower: Destory window " +
250                     "succeeds.");
251             synchronized(this){
252                 // notify the disposeThread in removeNotify().
253
this.notify();
254             }
255        }
256
257         // for the normal case, call the corresponding method in listeners.
258
int size;
259         Vector JavaDoc tl;
260         synchronized (this) {
261             size = webBrowserListeners.size();
262             if (size == 0) {
263                 return;
264             }
265
266             tl = (Vector JavaDoc) webBrowserListeners.clone();
267         }
268
269         for (int i = 0; i < size; ++i) {
270             WebBrowserListener listener = (WebBrowserListener) tl.elementAt(i);
271             switch (eid) {
272                 case WebBrowserEvent.WEBBROWSER_DOWNLOAD_STARTED:
273                     listener.downloadStarted(e);
274                     break;
275                 case WebBrowserEvent.WEBBROWSER_DOWNLOAD_COMPLETED:
276                     listener.downloadCompleted(e);
277                     break;
278                 case WebBrowserEvent.WEBBROWSER_DOWNLOAD_PROGRESS:
279                     listener.downloadProgress(e);
280                     break;
281                 case WebBrowserEvent.WEBBROWSER_DOWNLOAD_ERROR:
282                     listener.downloadError(e);
283                     break;
284                 case WebBrowserEvent.WEBBROWSER_DOCUMENT_COMPLETED:
285                     listener.documentCompleted(e);
286                     break;
287                 case WebBrowserEvent.WEBBROWSER_TITLE_CHANGE:
288                     listener.titleChange(e);
289                     break;
290                 case WebBrowserEvent.WEBBROWSER_STATUSTEXT_CHANGE:
291                     listener.statusTextChange(e);
292                     break;
293             }
294         }
295     }
296
297     /**
298      * Adds a <code>WebBrowserEvent</code> listener to the listener list.
299      * If listener is null, no exception is thrown and no action is performed.
300      *
301      * @param listener the WebBrowser event listener.
302      */

303     public synchronized void addWebBrowserListener(
304             WebBrowserListener listener) {
305         if (! webBrowserListeners.contains(listener)) {
306             webBrowserListeners.addElement(listener);
307         }
308     }
309
310     /**
311      * Removes a <code>WebBrowserEvent</code> listener from the listener list.
312      * If listener is null, no exception is thrown and no action is performed.
313      * If the listener is not in the listener list, no listener is removed.
314      *
315      * @param listener the WebBrowser event listener.
316      */

317     public synchronized void removeWebBrowserListener(
318             WebBrowserListener listener) {
319
320         if (listener == null)
321             return;
322         
323         webBrowserListeners.removeElement(listener);
324     }
325
326     /**
327      * Returns an array of all the registered WebBrowser listeners.
328      *
329      * @return all of this component's <code>WebBrowserListener</code>s or an
330      * empty array if no component listeners are currently registered.
331      * @since 0.9
332      */

333     public WebBrowserListener[] getWebBrowserListeners() {
334         return (WebBrowserListener[])webBrowserListeners.toArray();
335     }
336
337     /**
338      * Returns the URL of the resource that is currently being displayed.
339      *
340      * @return the current URL being display, or <code>null</code> if no URL is
341      * currently displayed or the WebBrowser is not yet initialized.
342      */

343     public URL JavaDoc getURL() {
344         eventThread.fireNativeEvent(instanceNum, NativeEventData.EVENT_GETURL);
345
346         if (waitForResult() == true) {
347             try {
348                 return new URL JavaDoc(eventThread.eventRetString);
349             }
350             catch (Exception JavaDoc e) {
351             }
352         }
353         return null;
354     }
355
356     /**
357      * Sets the loaded page to be a blank page.
358      *
359      */

360     public void setURL() {
361         eventThread.fireNativeEvent(instanceNum,
362                 NativeEventData.EVENT_NAVIGATE, "about:blank");
363     }
364
365     /**
366      * Navigates to a resource identified by an URL using HTTP GET method.
367      *
368      * @param url the URL to navigate.
369      */

370     public void setURL(URL JavaDoc url) {
371         setURL(url, null);
372     }
373
374     /**
375      * Navigates to a resource identified by an URL using HTTP POST method.
376      *
377      * @param url the URL to navigate.
378      * @param postData data to send to the server during the HTTP POST
379      * transaction.
380      */

381     public void setURL(URL JavaDoc url, String JavaDoc postData) {
382         if (postData == null) {
383             eventThread.fireNativeEvent(instanceNum,
384                     NativeEventData.EVENT_NAVIGATE, url.toString());
385         }
386         else {
387             eventThread.fireNativeEvent(instanceNum,
388                     NativeEventData.EVENT_NAVIGATE_POST, url.toString());
389             eventThread.fireNativeEvent(instanceNum,
390                     NativeEventData.EVENT_NAVIGATE_POSTDATA, postData);
391         }
392     }
393
394     /**
395      * Navigates backward one item in the history list.
396      */

397     public void back() {
398         eventThread.fireNativeEvent(instanceNum, NativeEventData.EVENT_GOBACK);
399     }
400
401     /**
402      * Navigates forward one item in the history list.
403      */

404     public void forward() {
405         eventThread.fireNativeEvent(instanceNum, NativeEventData.EVENT_GOFORWARD);
406     }
407
408     /**
409      * Reloads the URL that is currently displayed in the WebBrowser component.
410      */

411     public void refresh() {
412         eventThread.fireNativeEvent(instanceNum, NativeEventData.EVENT_REFRESH);
413     }
414
415     /**
416      * Stops any page loading and rendering activities.
417      */

418     public void stop() {
419         eventThread.fireNativeEvent(instanceNum, NativeEventData.EVENT_STOP);
420     }
421
422     /**
423      * Sets new HTML content.
424      *
425      * @param htmlContent the HTML content to set.
426      * @since 0.9
427      */

428     public void setContent(String JavaDoc htmlContent) {
429         eventThread.fireNativeEvent(instanceNum,
430                 NativeEventData.EVENT_SETCONTENT, htmlContent);
431     }
432
433     /**
434      * Returns the HTML content of a document, opened in a browser.
435      *
436      * @return the HTML content of a document, opened in a browser.
437      * @since 0.9
438      */

439     public String JavaDoc getContent() {
440         eventThread.fireNativeEvent(instanceNum,
441                                     NativeEventData.EVENT_GETCONTENT);
442
443         if (waitForResult() == true) {
444             try {
445                 return eventThread.eventRetString;
446             }
447             catch (Exception JavaDoc e) {
448             }
449         }
450         return null;
451     }
452
453     /**
454      * Executes specified JavaScript code in a currently opened document.
455      * This should not be called until after a documentComplete event is
456      * fired in <code>WebBrowserListener</code>.
457      *
458      * @return the result of JavaScript execution, if there is any.
459      * @since 0.9
460      */

461     public String JavaDoc executeScript(java.lang.String JavaDoc javaScript) {
462         eventThread.fireNativeEvent(instanceNum,
463                                     NativeEventData.EVENT_EXECUTESCRIPT,
464                                     javaScript);
465
466         if (waitForResult() == true) {
467             try {
468                 return eventThread.eventRetString;
469             }
470             catch (Exception JavaDoc e) {
471             }
472         }
473         return null;
474     }
475     
476     /**
477      * Enables or disables debug message output. Debug message out is disabled
478      * initially by default. Calls it via reflection when necessary.
479      *
480      * @param b if <code>true</true>, debug message output is enabled;
481      * otherwise debug message output is disabled.
482      */

483     public static void setDebug(boolean b) {
484         WebBrowserUtil.enableDebugMessages(b);
485     }
486
487     /**
488      * Returns a <code>Status</code> object, which indicates the status of this
489      * <code>WebBrowser</code> object.
490      *
491      * @deprecated The <code>WebBrowser.Status</code> inner class is deprecated
492      * as of release 0.9 of JDIC. Its APIs have been moved to this
493      * <code>Browser</code> class. This API is no longer used, and
494      * will be removed in a future release.
495      * @see Status
496      */

497     public Status getStatus() {
498         return new Status(this);
499     }
500
501     /**
502      * Returns the name of the embedded browser's native binary, which runs as
503      * a standalone native process.
504      *
505      * @deprecated As of release 0.9 of JDIC. This method was unnecessarily
506      * exposed and will be removed in a future release.
507      */

508     public static String JavaDoc getBrowserBinary () {
509         return WebBrowserUtil.getEmbedBinaryName();
510     }
511     
512     /**
513      * Checks whether this <code>WebBrowser</code> object is initialized
514      * successfully.
515      *
516      * @return <code>true</code> if the <code>WebBrowser</code> object is
517      * initialized successfully; otherwise, <code>false</code>.
518      */

519     public boolean isInitialized() {
520         return isInitialized;
521     }
522
523     /**
524      * Checks whether this <code>WebBrowser</code> object's back command
525      * is enabled.
526      *
527      * @return <code>true</code> if the WebBrowser can navigate to the
528      * previous session history item, and <code>false</code> otherwise.
529      * @see #back
530      */

531     public boolean isBackEnabled() {
532         return isBackEnabled;
533     }
534
535     /**
536      * Checks whether this <code>WebBrowser</code> object's forward command
537      * is enabled.
538      *
539      * @return <code>true</code> if the WebBrowser can navigate to the
540      * next session history item, and <code>false</code> otherwise.
541      * @see #forward
542      */

543     public boolean isForwardEnabled() {
544         return isForwardEnabled;
545     }
546
547     /**
548      * Called before a navigation occurs.
549      * <p>
550      * A subclass can override this method to block the navigation or allow it
551      * to proceed.
552      *
553      * @param url the URL to navigate to.
554      * @return <code>false</code> will block the navigation from starting;
555      * <code>true</code> otherwise. By default, it returns <code>
556      * true</code>.
557      */

558     protected boolean willOpenURL(URL JavaDoc url) {
559         if (null == url)
560             return true;
561
562         WebBrowserUtil.trace("URL = " + url.toString());
563         SecurityManager JavaDoc security = System.getSecurityManager();
564         if (security != null) {
565             try {
566                 security.checkConnect(url.getHost(), url.getPort());
567             }
568             catch (AccessControlException e){
569                 return false;
570             }
571         }
572         return true;
573     }
574
575     /**
576      * Called when a new window is to be created for displaying a resource.
577      * <p>
578      * A subclass can override this method to block the creation of a new
579      * window or allow it to proceed.
580      *
581      * @return <code>false</code> will block the creation of a new window;
582      * <code>true</code> otherwise. By default, it returns <code>
583      * true</code>.
584      */

585     protected boolean willOpenWindow() {
586         return true;
587     }
588
589     int getInstanceNum() {
590         return instanceNum;
591     }
592
593     /**
594      * Waits for a result returned from the native embedded browser.
595      * <p>
596      * This method is called by methods requiring a return value, such as
597      * getURL, getContent, executeScript.
598      */

599     private boolean waitForResult() {
600         if (! isInitialized) {
601             WebBrowserUtil.trace("You can't call this method before " +
602                     "WebBrowser is initialized!");
603             return false;
604         }
605
606         boolean ret = false;
607         synchronized(this) {
608             try {
609                 wait();
610                 ret = true;
611             }
612             catch (Exception JavaDoc e) {
613                 System.out.println(e.getMessage());
614             }
615         }
616         return ret;
617     }
618
619     int getNativeWindow() {
620         // The java.home property value is required to load jawt.dll on Windows.
621
return nativeGetWindow(System.getProperty("java.home"));
622     }
623     
624     /* native functions */
625     private native int nativeGetWindow(String JavaDoc javaHome);
626     
627     /**
628      * An inner class which is used for retrieving the WebBrowser's properties,
629      * such as the initialization status, back and forward status.
630      *
631      * @deprecated As of release 0.9 of JDIC. Its APIs have been moved to
632      * <code>org.jdesktop.jdic.browser.WebBrowser</code> class.
633      * Will be removed in a future release.
634      */

635     public static class Status {
636         WebBrowser webBrowser;
637
638         Status (WebBrowser curWebBrowser) {
639             webBrowser = curWebBrowser;
640         }
641
642         /**
643          * Checks whether this <code>WebBrowser</code> object is initialized
644          * successfully.
645          *
646          * @deprecated As of release 0.9 of JDIC, replaced by
647          * <code>WebBrowser.isInitialized()</code>.
648          * @return <code>true</code> if the <code>WebBrowser</code> object is
649          * initialized successfully; otherwise, <code>false</code>.
650          */

651         public boolean isInitialized() {
652             return webBrowser.isInitialized();
653         }
654
655         /**
656          * Checks whether this <code>WebBrowser</code> object's back command
657          * is enabled.
658          *
659          * @deprecated As of release 0.9 of JDIC, replaced by
660          * <code>WebBrowser.isBackEnabled()</code>.
661          * @return <code>true</code> if the WebBrowser can navigate to the
662          * previous session history item, and <code>false</code>
663          * otherwise.
664          * @see #back
665          */

666         public boolean isBackEnabled() {
667             return webBrowser.isBackEnabled();
668         }
669
670         /**
671          * Checks whether this <code>WebBrowser</code> object's forward command
672          * is enabled.
673          *
674          * @deprecated As of release 0.9 of JDIC, replaced by
675          * <code>WebBrowser.isForwardEnabled()</code>.
676          * @return <code>true</code> if the WebBrowser can navigate to the
677          * next session history item, and <code>false</code> otherwise.
678          * @see #forward
679          */

680         public boolean isForwardEnabled() {
681             return webBrowser.isForwardEnabled();
682         }
683     }
684
685     class MyFocusListener implements FocusListener {
686         public void focusGained(FocusEvent e) {
687             WebBrowserUtil.trace("\nMyFocusListener: focusGained\n");
688             eventThread.fireNativeEvent(instanceNum,
689                     NativeEventData.EVENT_FOCUSGAINED);
690         }
691
692         public void focusLost(FocusEvent e) {
693             WebBrowserUtil.trace("\nMyFocusListener: focusLost\n");
694             eventThread.fireNativeEvent(instanceNum,
695                     NativeEventData.EVENT_FOCUSLOST);
696         }
697     }
698 }
699
Popular Tags