001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.webclient;
043:
044: import java.awt.*;
045: import java.awt.event.*;
046: import java.beans.*;
047: import java.net.*;
048: import java.util.*;
049: import javax.swing.SwingUtilities;
050:
051: import org.openide.*;
052: import org.openide.awt.*;
053:
054: import org.mozilla.util.*;
055: import org.mozilla.webclient.*;
056:
057: import org.openide.util.NbBundle;
058: import org.openide.util.RequestProcessor;
059:
060: /**
061: * Real implementation of Mozilla browser functionality needed by IDE.
062: *
063: * @author Radim.Kubacki@sun.com
064: */
065: class WebclientBrowserImpl extends HtmlBrowser.Impl {
066:
067: private static boolean debug = true;
068:
069: // variables .................................................................
070:
071: /** browser factory */
072: private WebclientBrowser factory;
073:
074: /** browser controller */
075: private BrowserControl browserControl;
076: /** browser visual component */
077: private WebclientBrowserComponent browser;
078:
079: /** WindowControl for embedding */
080: private WindowControl winCtrl;
081: /** browser navigation interface */
082: private Navigation navigation;
083: /** browser history interface */
084: private History browserHistory;
085:
086: /** browser event interface */
087: private EventRegistration eventRegistration;
088:
089: /** current URL */
090: private URL url;
091: /** standart helper variable */
092: private PropertyChangeSupport pcs;
093:
094: /** Current status message. */
095: private String statusMessage = ""; // NOI18N
096:
097: /** Current value of title property. */
098: private String title = ""; // NOI18N
099:
100: // init ......................................................................
101:
102: /**
103: * Creates instance of browser.
104: */
105: public WebclientBrowserImpl(WebclientBrowser fact) {
106: pcs = new PropertyChangeSupport(this );
107: this .factory = fact;
108:
109: // Create the browser
110: try {
111: // This is a workaround - webclient requires jawt but it is not loaded yet (IDE is Swing app)
112: System.loadLibrary("jawt"); // NOI18N
113:
114: if (factory.getAppData() != null)
115: BrowserControlFactory.setAppData(factory.getAppData()
116: .getAbsolutePath());
117: else
118: throw new IllegalStateException(NbBundle.getMessage(
119: WebclientBrowserImpl.class,
120: "ERR_appData_path_is_not_set"));
121:
122: browserControl = BrowserControlFactory.newBrowserControl();
123:
124: winCtrl = (WindowControl) browserControl
125: .queryInterface(BrowserControl.WINDOW_CONTROL_NAME);
126: if (debug)
127: System.out.println("NativeWebShell="
128: + winCtrl.getNativeWebShell()); // NOI18N
129:
130: browser = new WebclientBrowserComponent(this );
131:
132: } catch (Exception e) {
133: ErrorManager.getDefault().annotate(
134: e,
135: NbBundle.getMessage(WebclientBrowserImpl.class,
136: "ERR_Cannot_init_impl"));
137: ErrorManager.getDefault().notify(ErrorManager.EXCEPTION, e);
138: }
139: }
140:
141: public void initialize() {
142: browser.setVisible(true);
143: if (navigation == null) {
144: try {
145: // PENDING: Need to wait until it gets inited
146: for (int i = 0; i < 20; i++) {
147: if (debug)
148: System.out.println("Checking (" + i
149: + ") NativeWebShell="
150: + winCtrl.getNativeWebShell()); // NOI18N
151: if (winCtrl.getNativeWebShell() != -1)
152: break;
153: try {
154: Thread.currentThread().sleep(1000);
155: } catch (InterruptedException e) { // do nothing
156: }
157: }
158: if (winCtrl.getNativeWebShell() == -1)
159: throw new IllegalStateException(
160: "Cannot get native web shell"); // NOI18N
161:
162: navigation = (Navigation) browserControl
163: .queryInterface(BrowserControl.NAVIGATION_NAME);
164: CurrentPage currentPage = (CurrentPage) browserControl
165: .queryInterface(BrowserControl.CURRENT_PAGE_NAME);
166: browserHistory = (History) browserControl
167: .queryInterface(BrowserControl.HISTORY_NAME);
168:
169: eventRegistration = (EventRegistration) browserControl
170: .queryInterface(BrowserControl.EVENT_REGISTRATION_NAME);
171: eventRegistration
172: .addDocumentLoadListener(new DocumentLoadListener() {
173: public void eventDispatched(
174: WebclientEvent event) {
175: String old = statusMessage;
176: int eventType = (int) event.getType();
177:
178: if (eventType == (int) DocumentLoadEvent.START_DOCUMENT_LOAD_EVENT_MASK) {
179: setStatusMessage(NbBundle
180: .getMessage(
181: WebclientBrowserImpl.class,
182: "MSG_Loading"));
183: Object o = event.getEventData();
184: if (debug)
185: System.out
186: .println("start evt data: "
187: + o
188: + " class "
189: + ((o != null) ? o
190: .getClass()
191: .getName()
192: : "null"));
193: if (o != null) {
194: if (o instanceof String) {
195: try {
196: url = new URL(
197: (String) o);
198: pcs.firePropertyChange(
199: PROP_URL, null,
200: null);
201: } catch (MalformedURLException ex) {
202: // do nothing - URL won't be updated
203: }
204: } else if (o instanceof URL) {
205: url = (URL) o;
206: pcs.firePropertyChange(
207: PROP_URL, null,
208: null);
209: }
210: }
211: } else if (eventType == (int) DocumentLoadEvent.END_DOCUMENT_LOAD_EVENT_MASK) {
212: setStatusMessage(NbBundle
213: .getMessage(
214: WebclientBrowserImpl.class,
215: "MSG_Done"));
216: pcs.firePropertyChange(null, null,
217: null);
218: if (debug)
219: System.out
220: .println("end evt data: "
221: + event
222: .getEventData());
223: } else if (eventType == (int) DocumentLoadEvent.START_URL_LOAD_EVENT_MASK
224: || eventType == (int) DocumentLoadEvent.END_URL_LOAD_EVENT_MASK
225: || eventType == (int) DocumentLoadEvent.FETCH_INTERRUPT_EVENT_MASK
226: || eventType == (int) DocumentLoadEvent.PROGRESS_URL_LOAD_EVENT_MASK
227: || eventType == (int) DocumentLoadEvent.STATUS_URL_LOAD_EVENT_MASK
228: || eventType == (int) DocumentLoadEvent.UNKNOWN_CONTENT_EVENT_MASK) {
229: if (event.getEventData() instanceof String)
230: setStatusMessage((String) event
231: .getEventData());
232: }
233: }
234: });
235:
236: } catch (Exception e) {
237: ErrorManager.getDefault().annotate(
238: e,
239: NbBundle.getMessage(WebclientBrowserImpl.class,
240: "ERR_Cannot_init_impl"));
241: ErrorManager.getDefault().notify(
242: ErrorManager.EXCEPTION, e);
243: }
244: }
245:
246: }
247:
248: /**
249: * Closes BrowserControl resources
250: */
251: public void destroy() {
252: /*
253: System.out.println("destroy");
254: BrowserControlFactory.deleteBrowserControl(browserControl);
255: browserControl = null;
256: // if it is last
257: try {
258: BrowserControlFactory.appTerminate();
259: }
260: catch (Exception ex) {
261: ex.printStackTrace();
262: }
263: */
264: }
265:
266: // HtmpBrowser.Impl implementation ...........................................
267:
268: /**
269: * Returns visual component of html browser.
270: * Actually returns null to allow custom window handling.
271: *
272: * @return <CODE>null</CODE>.
273: */
274: public java.awt.Component getComponent() {
275: return null;
276: }
277:
278: /**
279: * Reloads current html page.
280: */
281: public void reloadDocument() {
282: initialize();
283: navigation.refresh(Navigation.LOAD_FORCE_RELOAD);
284: }
285:
286: /**
287: * Stops loading of current html page.
288: */
289: public void stopLoading() {
290: initialize();
291: navigation.stop();
292: }
293:
294: /**
295: * Sets current URL.
296: *
297: * @param url URL to show in the browser.
298: */
299: public void setURL(URL url) {
300: if (SwingUtilities.isEventDispatchThread()) {
301: final URL newUrl = url;
302: RequestProcessor.getDefault().post(new Runnable() {
303: public void run() {
304: WebclientBrowserImpl.this .setURL(newUrl);
305: }
306: });
307: return;
308: }
309:
310: try {
311: initialize();
312: URL old = getURL();
313:
314: // internal protocols cannot be displayed in external viewer
315: if (isInternalProtocol(url.getProtocol())) {
316: url = URLUtil.createExternalURL(url);
317: }
318:
319: if ((old != null) && old.equals(url)) {
320: navigation.refresh(Navigation.LOAD_FORCE_RELOAD);
321: } else {
322: WindowControl winCtrl = (WindowControl) browserControl
323: .queryInterface(BrowserControl.WINDOW_CONTROL_NAME);
324: this .url = url;
325: navigation.loadURL(url.toString());
326: pcs.firePropertyChange(PROP_URL, old, url);
327: }
328: } catch (Exception e) {
329: e.printStackTrace();
330: }
331: }
332:
333: /**
334: * Returns current URL.
335: *
336: * @return current URL.
337: */
338: public URL getURL() {
339: return url;
340: }
341:
342: /**
343: * Returns status message representing status of html browser.
344: *
345: * @return status message.
346: */
347: public String getStatusMessage() {
348: return statusMessage;
349: }
350:
351: void setStatusMessage(String msg) {
352: // XXX might be better to use own status bar
353: StatusDisplayer.getDefault().setStatusText(msg);
354: String old = statusMessage;
355: statusMessage = msg;
356: pcs.firePropertyChange(PROP_STATUS_MESSAGE, old, statusMessage);
357: }
358:
359: /** Returns title of the displayed page.
360: * @return title
361: */
362: public String getTitle() {
363: return title;
364: }
365:
366: /** Is forward button enabled?
367: * @return true if it is
368: */
369: public boolean isForward() {
370: if (url == null)
371: return false;
372: initialize();
373: return browserHistory.canForward();
374: }
375:
376: /** Moves the browser forward. Failure is ignored.
377: */
378: public void forward() {
379: initialize();
380: browserHistory.forward();
381: }
382:
383: /** Is backward button enabled?
384: * @return true if it is
385: */
386: public boolean isBackward() {
387: if (url == null)
388: return false;
389: initialize();
390: return browserHistory.canBack();
391: }
392:
393: /** Moves the browser forward. Failure is ignored.
394: */
395: public void backward() {
396: initialize();
397: browserHistory.back();
398: }
399:
400: /** Is history button enabled?
401: * @return true if it is
402: */
403: public boolean isHistory() {
404: if (url == null)
405: return false;
406: initialize();
407: return (browserHistory.getHistoryLength() > 0);
408: }
409:
410: /** Invoked when the history button is pressed.
411: */
412: public void showHistory() {
413: // PENDING: use history manager
414: }
415:
416: /**
417: * Adds PropertyChangeListener to this browser.
418: *
419: * @param l Listener to add.
420: */
421: public void addPropertyChangeListener(PropertyChangeListener l) {
422: pcs.addPropertyChangeListener(l);
423: }
424:
425: /**
426: * Removes PropertyChangeListener from this browser.
427: *
428: * @param l Listener to remove.
429: */
430: public void removePropertyChangeListener(PropertyChangeListener l) {
431: pcs.removePropertyChangeListener(l);
432: }
433:
434: // other methods ..............................................................
435:
436: /**
437: * Returns BrowserControl interface
438: */
439: public BrowserControl getBrowserControl() {
440: return browserControl;
441: }
442:
443: /**
444: * Returns whether given protocol is internal or not.
445: * (Internal protocols cannot be displayed by external viewers.
446: * They must be wrapped somehow.)
447: *
448: * @return true if protocol is internal, false otherwise
449: */
450: protected final static boolean isInternalProtocol(String protocol) {
451: if (protocol.startsWith("nb")) // NOI18N
452: return true;
453:
454: return false;
455: }
456: }
|