initial version
[phpeclipse.git] / net.sourceforge.phpeclipse.webbrowser / src / net / sourceforge / phpeclipse / webbrowser / internal / WebBrowser.java
1 /**
2  * Copyright (c) 2003 IBM Corporation and others. All rights reserved.   This program and the accompanying materials are made
3  * available under the terms of the Common Public License v1.0 which accompanies this distribution, and is available at
4  * http://www.eclipse.org/legal/cpl-v10.html  * Contributors: IBM - Initial API and implementation
5  */
6
7 //TODO 1. Handle the sizing of a popup running in shelled out secondary window.
8 //TODO 2. Support printing: waiting on eclipse bug 47937/44823.
9 package net.sourceforge.phpeclipse.webbrowser.internal;
10
11 import java.util.*;
12
13 import net.sourceforge.phpeclipse.webbrowser.IURLMap;
14
15 import org.eclipse.swt.SWT;
16 import org.eclipse.swt.widgets.*;
17 import org.eclipse.swt.layout.FillLayout;
18 import org.eclipse.swt.layout.GridData;
19 import org.eclipse.swt.layout.GridLayout;
20 import org.eclipse.swt.dnd.Clipboard;
21 import org.eclipse.swt.events.*;
22 import org.eclipse.swt.graphics.Point;
23 import org.eclipse.swt.graphics.Rectangle;
24 import org.eclipse.ui.help.WorkbenchHelp;
25 import org.eclipse.swt.browser.*;
26
27 public class WebBrowser extends Composite {
28   protected Composite toolbarComp;
29
30   protected Composite statusComp;
31
32   protected Combo combo;
33
34   protected Clipboard clipboard;
35
36   protected boolean showToolbar;
37
38   protected ToolItem back;
39
40   protected ToolItem forward;
41
42   protected ToolItem stop;
43
44   protected ToolItem favorites;
45
46   protected ToolItem refresh;
47
48   protected BusyIndicator busy;
49
50   protected boolean showStatusbar;
51
52   protected ProgressBar progress;
53
54   protected Label status;
55
56   private static int MAX_HISTORY = 50;
57
58   protected static java.util.List history;
59
60   protected Browser browser;
61
62   protected Shell shell;
63
64   protected WebBrowserEditor editor;
65
66   protected String title;
67
68   public WebBrowser(Composite parent, final boolean showToolbar, final boolean showStatusbar) {
69     super(parent, SWT.NONE);
70
71     this.showToolbar = showToolbar;
72     this.showStatusbar = showStatusbar;
73
74     GridLayout layout = new GridLayout();
75     layout.marginHeight = 3;
76     layout.marginWidth = 3;
77     layout.horizontalSpacing = 3;
78     layout.verticalSpacing = 3;
79     layout.numColumns = 1;
80     setLayout(layout);
81     setLayoutData(new GridData(GridData.FILL_BOTH));
82     clipboard = new Clipboard(parent.getDisplay());
83     WorkbenchHelp.setHelp(this, ContextIds.WEB_BROWSER);
84
85     if (showToolbar) {
86       toolbarComp = new Composite(this, SWT.NONE);
87       GridLayout outerLayout = new GridLayout();
88       outerLayout.numColumns = 2;
89       outerLayout.marginWidth = 0;
90       outerLayout.marginHeight = 0;
91       toolbarComp.setLayout(outerLayout);
92       toolbarComp.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_BEGINNING | GridData.FILL_HORIZONTAL));
93
94       // create the top line, with a combo box for history and a "go" button
95       Composite top = new Composite(toolbarComp, SWT.NONE);
96       GridLayout topLayout = new GridLayout();
97       topLayout.numColumns = 2;
98       topLayout.marginWidth = 0;
99       topLayout.marginHeight = 0;
100       top.setLayout(topLayout);
101       top.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_CENTER | GridData.FILL_HORIZONTAL));
102
103       combo = new Combo(top, SWT.DROP_DOWN);
104
105       updateHistory();
106
107       combo.addSelectionListener(new SelectionAdapter() {
108         public void widgetSelected(SelectionEvent we) {
109           try {
110             if (combo.getSelectionIndex() != -1)
111               setURL(combo.getItem(combo.getSelectionIndex()));
112           } catch (Exception e) {
113           }
114         }
115       });
116       combo.addListener(SWT.DefaultSelection, new Listener() {
117         public void handleEvent(Event e) {
118           setURL(combo.getText());
119         }
120       });
121       combo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
122       WorkbenchHelp.setHelp(combo, ContextIds.WEB_BROWSER_URL);
123
124       ToolBar toolbar = new ToolBar(top, SWT.FLAT);
125       fillToolBar(toolbar);
126
127       new ToolItem(toolbar, SWT.SEPARATOR);
128
129       busy = new BusyIndicator(toolbarComp, SWT.NONE);
130       busy.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_END));
131     }
132
133     // create a new SWT Web browser widget, checking once again to make sure we can use it in this environment
134     if (WebBrowserUtil.canUseInternalWebBrowser() & WebBrowserUtil.isInternalBrowserOperational())
135       this.browser = new Browser(this, SWT.NONE);
136     else {
137       WebBrowserUtil.openError(WebBrowserUIPlugin.getResource("%errorCouldNotLaunchInternalWebBrowser"));
138       return;
139     }
140
141     if (showToolbar) {
142       back.setEnabled(browser.isBackEnabled());
143       forward.setEnabled(browser.isForwardEnabled());
144     }
145
146     WorkbenchHelp.setHelp(browser, ContextIds.WEB_BROWSER_WEB);
147     GridData data = new GridData();
148     data.horizontalAlignment = GridData.FILL;
149     data.verticalAlignment = GridData.FILL;
150     data.horizontalSpan = 3;
151     data.grabExcessHorizontalSpace = true;
152     data.grabExcessVerticalSpace = true;
153     browser.setLayoutData(data);
154
155     if (showStatusbar)
156       createStatusArea(this);
157
158     addBrowserListeners();
159   }
160
161   /**
162    *  
163    */
164   protected void addBrowserListeners() {
165     if (showStatusbar) {
166       // respond to Browser StatusTextEvents events by updating the status Text label
167       browser.addStatusTextListener(new StatusTextListener() {
168         public void changed(StatusTextEvent event) {
169           status.setText(event.text);
170         }
171       });
172     }
173
174     /**
175      * Add listener for new window creation so that we can instead of opening a separate new window in which the session is lost, we
176      * can instead open a new window in a new shell within the browser area thereby maintaining the session.
177      */
178     browser.addOpenWindowListener(new OpenWindowListener() {
179       public void open(WindowEvent event) {
180         Shell shell2 = new Shell(getDisplay());
181         shell2.setLayout(new FillLayout());
182         shell2.setText(WebBrowserUIPlugin.getResource("%viewWebBrowserTitle"));
183         shell2.setImage(getShell().getImage());
184         WebBrowser browser2 = new WebBrowser(shell2, showToolbar, showStatusbar);
185         browser2.shell = shell2;
186         event.browser = browser2.browser;
187         shell2.open();
188       }
189     });
190
191     browser.addCloseWindowListener(new CloseWindowListener() {
192       public void close(WindowEvent event) {
193         // if shell is not null, it must be a secondary popup window, else its an editor window
194         if (shell != null)
195           shell.dispose();
196         else
197           editor.closeEditor();
198       }
199     });
200
201     browser.addProgressListener(new ProgressListener() {
202       public void changed(ProgressEvent event) {
203         if (event.total == 0)
204           return;
205
206         boolean done = (event.current == event.total);
207
208         int percentProgress = event.current * 100 / event.total;
209         if (showStatusbar) {
210           if (done)
211             progress.setSelection(0);
212           else
213             progress.setSelection(percentProgress);
214         }
215
216         if (showToolbar) {
217           if (!busy.isBusy() && (percentProgress > 0 && percentProgress < 100)) {
218             busy.setBusy(true);
219           }
220           // Once the progress hits 100 percent, done, set busy to false
221           else if (busy.isBusy() && done) {
222             busy.setBusy(false);
223           }
224         }
225       }
226
227       public void completed(ProgressEvent event) {
228         if (showStatusbar)
229           progress.setSelection(0);
230         if (showToolbar) {
231           busy.setBusy(false);
232           back.setEnabled(browser.isBackEnabled());
233           forward.setEnabled(browser.isForwardEnabled());
234         }
235       }
236     });
237
238     if (showToolbar) {
239       browser.addLocationListener(new LocationListener() {
240         public void changed(LocationEvent event) {
241           if (!event.top)
242             return;
243           if (!isHome()) {
244             combo.setText(event.location);
245             addToHistory(event.location);
246             updateHistory();
247           } else
248             combo.setText("");
249         }
250
251         public void changing(LocationEvent event) {
252         }
253       });
254     }
255
256     browser.addTitleListener(new TitleListener() {
257       public void changed(TitleEvent event) {
258         title = event.title;
259       }
260     });
261   }
262
263   /**
264    * Return the underlying browser control.
265    * 
266    * @return org.eclipse.swt.browser.Browser
267    */
268   public Browser getBrowser() {
269     return browser;
270   }
271
272   /**
273    *  
274    */
275   protected void forward() {
276     browser.forward();
277   }
278
279   /**
280    *  
281    */
282   protected void back() {
283     browser.back();
284   }
285
286   /**
287    *  
288    */
289   protected void stop() {
290     browser.stop();
291   }
292
293   /**
294    *  
295    */
296   protected void navigate(String url) {
297     Trace.trace(Trace.FINER, "Navigate: " + url);
298     if (url != null && url.equals(getURL())) {
299       refresh();
300       return;
301     }
302     browser.setUrl(url);
303   }
304
305   /**
306    * Refresh the currently viewed page.
307    */
308   public void refresh() {
309     browser.refresh();
310   }
311
312   protected void setURL(String url, boolean browse) {
313     Trace.trace(Trace.FINEST, "setURL: " + url + " " + browse);
314     if (url == null) {
315       home();
316       return;
317     }
318
319     if (url.endsWith(WebBrowserPreference.getHomePageURL().substring(9)))
320       return;
321
322     // check URL maps
323     Iterator iterator = WebBrowserUtil.getURLMaps().iterator();
324     String newURL = null;
325     while (iterator.hasNext() && newURL == null) {
326       try {
327         IURLMap map = (IURLMap) iterator.next();
328         newURL = map.getMappedURL(url);
329       } catch (Exception e) {
330       }
331     }
332     if (newURL != null)
333       url = newURL;
334
335     if (browse)
336       navigate(url);
337
338     addToHistory(url);
339     updateHistory();
340   }
341
342   protected void addToHistory(String url) {
343     if (history == null)
344       history = WebBrowserPreference.getInternalWebBrowserHistory();
345     int found = -1;
346     int size = history.size();
347     for (int i = 0; i < size; i++) {
348       String s = (String) history.get(i);
349       if (s.equals(url)) {
350         found = i;
351         break;
352       }
353     }
354
355     if (found == -1) {
356       if (size >= MAX_HISTORY)
357         history.remove(size - 1);
358       history.add(0, url);
359       WebBrowserPreference.setInternalWebBrowserHistory(history);
360     } else if (found != 0) {
361       history.remove(found);
362       history.add(0, url);
363       WebBrowserPreference.setInternalWebBrowserHistory(history);
364     }
365   }
366
367   public void setURL(String url) {
368     setURL(url, true);
369   }
370
371   /**
372    * Creates the Web browser status area.
373    */
374   private void createStatusArea(Composite parent) {
375     Composite composite = new Composite(parent, SWT.NONE);
376     GridLayout layout = new GridLayout();
377     layout.numColumns = 2;
378     layout.marginHeight = 0;
379     layout.marginWidth = 0;
380     layout.horizontalSpacing = 4;
381     layout.verticalSpacing = 0;
382     composite.setLayout(layout);
383     composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
384
385     // Add a label for displaying status messages as they are received from the control
386     status = new Label(composite, SWT.SINGLE | SWT.READ_ONLY);
387     GridData gridData = new GridData(GridData.FILL_HORIZONTAL | GridData.VERTICAL_ALIGN_FILL);
388     gridData.horizontalIndent = 2;
389     status.setLayoutData(gridData);
390
391     // Add a progress bar to display downloading progress information
392     progress = new ProgressBar(composite, SWT.BORDER);
393     gridData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING | GridData.VERTICAL_ALIGN_FILL);
394     gridData.widthHint = 100;
395     gridData.heightHint = 10;
396     progress.setLayoutData(gridData);
397   }
398
399   /**
400    *  
401    */
402   public void dispose() {
403     super.dispose();
404
405     showStatusbar = false;
406     showToolbar = false;
407
408     if (busy != null)
409       busy.dispose();
410     busy = null;
411
412     browser = null;
413   }
414
415   /**
416    * Populate the toolbar.
417    * 
418    * @param toolbar
419    *          org.eclipse.swt.widgets.ToolBar
420    */
421   private void fillToolBar(final ToolBar toolbar) {
422     ToolItem go = new ToolItem(toolbar, SWT.NONE);
423     go.setImage(ImageResource.getImage(ImageResource.IMG_ELCL_NAV_GO));
424     go.setHotImage(ImageResource.getImage(ImageResource.IMG_CLCL_NAV_GO));
425     go.setDisabledImage(ImageResource.getImage(ImageResource.IMG_DLCL_NAV_GO));
426     go.setToolTipText(WebBrowserUIPlugin.getResource("%actionWebBrowserGo"));
427     go.addSelectionListener(new SelectionAdapter() {
428       public void widgetSelected(SelectionEvent event) {
429         setURL(combo.getText());
430       }
431     });
432
433     new ToolItem(toolbar, SWT.SEPARATOR);
434
435     favorites = new ToolItem(toolbar, SWT.DROP_DOWN);
436     favorites.setImage(ImageResource.getImage(ImageResource.IMG_ELCL_NAV_FAVORITES));
437     favorites.setHotImage(ImageResource.getImage(ImageResource.IMG_CLCL_NAV_FAVORITES));
438     favorites.setDisabledImage(ImageResource.getImage(ImageResource.IMG_DLCL_NAV_FAVORITES));
439     favorites.setToolTipText(WebBrowserUIPlugin.getResource("%actionWebBrowserFavorites"));
440
441     favorites.addSelectionListener(new SelectionAdapter() {
442       public void widgetSelected(SelectionEvent event) {
443         if (event.detail == SWT.ARROW) {
444           Rectangle r = favorites.getBounds();
445           showFavorites(toolbar, toolbar.toDisplay(r.x, r.y + r.height));
446         } else
447           addFavorite();
448       }
449     });
450
451     // create back and forward actions
452     back = new ToolItem(toolbar, SWT.NONE);
453     back.setImage(ImageResource.getImage(ImageResource.IMG_ELCL_NAV_BACKWARD));
454     back.setHotImage(ImageResource.getImage(ImageResource.IMG_CLCL_NAV_BACKWARD));
455     back.setDisabledImage(ImageResource.getImage(ImageResource.IMG_DLCL_NAV_BACKWARD));
456     back.setToolTipText(WebBrowserUIPlugin.getResource("%actionWebBrowserBack"));
457     back.addSelectionListener(new SelectionAdapter() {
458       public void widgetSelected(SelectionEvent event) {
459         back();
460       }
461     });
462
463     forward = new ToolItem(toolbar, SWT.NONE);
464     forward.setImage(ImageResource.getImage(ImageResource.IMG_ELCL_NAV_FORWARD));
465     forward.setHotImage(ImageResource.getImage(ImageResource.IMG_CLCL_NAV_FORWARD));
466     forward.setDisabledImage(ImageResource.getImage(ImageResource.IMG_DLCL_NAV_FORWARD));
467     forward.setToolTipText(WebBrowserUIPlugin.getResource("%actionWebBrowserForward"));
468     forward.addSelectionListener(new SelectionAdapter() {
469       public void widgetSelected(SelectionEvent event) {
470         forward();
471       }
472     });
473
474     // create refresh, stop, and print actions
475     stop = new ToolItem(toolbar, SWT.NONE);
476     stop.setImage(ImageResource.getImage(ImageResource.IMG_ELCL_NAV_STOP));
477     stop.setHotImage(ImageResource.getImage(ImageResource.IMG_CLCL_NAV_STOP));
478     stop.setDisabledImage(ImageResource.getImage(ImageResource.IMG_DLCL_NAV_STOP));
479     stop.setToolTipText(WebBrowserUIPlugin.getResource("%actionWebBrowserStop"));
480     stop.addSelectionListener(new SelectionAdapter() {
481       public void widgetSelected(SelectionEvent event) {
482         stop();
483       }
484     });
485
486     refresh = new ToolItem(toolbar, SWT.NONE);
487     refresh.setImage(ImageResource.getImage(ImageResource.IMG_ELCL_NAV_REFRESH));
488     refresh.setHotImage(ImageResource.getImage(ImageResource.IMG_CLCL_NAV_REFRESH));
489     refresh.setDisabledImage(ImageResource.getImage(ImageResource.IMG_DLCL_NAV_REFRESH));
490     refresh.setToolTipText(WebBrowserUIPlugin.getResource("%actionWebBrowserRefresh"));
491     refresh.addSelectionListener(new SelectionAdapter() {
492       public void widgetSelected(SelectionEvent event) {
493         refresh();
494       }
495     });
496   }
497
498   protected void addFavorite() {
499     java.util.List list = WebBrowserPreference.getInternalWebBrowserFavorites();
500     Favorite f = new Favorite(title, browser.getUrl());
501     if (!list.contains(f)) {
502       list.add(f);
503       WebBrowserPreference.setInternalWebBrowserFavorites(list);
504     }
505   }
506
507   protected void showFavorites(Control parent, Point p) {
508     Menu perspectiveBarMenu = null;
509     if (perspectiveBarMenu == null) {
510       Menu menu = new Menu(parent);
511
512       // locked favorites
513       Iterator iterator = WebBrowserUtil.getLockedFavorites().iterator();
514       if (iterator.hasNext()) {
515         while (iterator.hasNext()) {
516           final Favorite f = (Favorite) iterator.next();
517           MenuItem item = new MenuItem(menu, SWT.NONE);
518           item.setText(f.getName());
519           item.setImage(ImageResource.getImage(ImageResource.IMG_FAVORITE));
520           item.addSelectionListener(new SelectionAdapter() {
521             public void widgetSelected(SelectionEvent event) {
522               setURL(f.getURL());
523             }
524           });
525         }
526
527         new MenuItem(menu, SWT.SEPARATOR);
528       }
529
530       iterator = WebBrowserPreference.getInternalWebBrowserFavorites().iterator();
531       if (!iterator.hasNext()) {
532         MenuItem item = new MenuItem(menu, SWT.NONE);
533         item.setText(WebBrowserUIPlugin.getResource("%actionWebBrowserNoFavorites"));
534       }
535       while (iterator.hasNext()) {
536         final Favorite f = (Favorite) iterator.next();
537         MenuItem item = new MenuItem(menu, SWT.NONE);
538         item.setText(f.getName());
539         item.setImage(ImageResource.getImage(ImageResource.IMG_FAVORITE));
540         item.addSelectionListener(new SelectionAdapter() {
541           public void widgetSelected(SelectionEvent event) {
542             setURL(f.getURL());
543           }
544         });
545       }
546
547       new MenuItem(menu, SWT.SEPARATOR);
548
549       MenuItem item = new MenuItem(menu, SWT.NONE);
550       item.setText(WebBrowserUIPlugin.getResource("%actionWebBrowserOrganizeFavorites"));
551       item.addSelectionListener(new SelectionAdapter() {
552         public void widgetSelected(SelectionEvent event) {
553           OrganizeFavoritesDialog dialog = new OrganizeFavoritesDialog(shell);
554           dialog.open();
555         }
556       });
557
558       perspectiveBarMenu = menu;
559     }
560
561     if (perspectiveBarMenu != null) {
562       perspectiveBarMenu.setLocation(p.x, p.y);
563       perspectiveBarMenu.setVisible(true);
564     }
565   }
566
567   public void home() {
568     navigate(WebBrowserPreference.getHomePageURL());
569   }
570
571   /**
572    * Returns true if the homepage is currently being displayed.
573    * 
574    * @return boolean
575    */
576   protected boolean isHome() {
577     return getURL() != null && getURL().endsWith(WebBrowserPreference.getHomePageURL().substring(9));
578   }
579
580   protected String getURL() {
581     return browser.getUrl();
582   }
583
584   /**
585    * Update the history list to the global copy.
586    */
587   protected void updateHistory() {
588     if (combo == null)
589       return;
590
591     String temp = combo.getText();
592     if (history == null)
593       history = WebBrowserPreference.getInternalWebBrowserHistory();
594
595     String[] historyList = new String[history.size()];
596     history.toArray(historyList);
597     combo.setItems(historyList);
598
599     combo.setText(temp);
600   }
601
602   public void addProgressListener(ProgressListener listener) {
603     browser.addProgressListener(listener);
604   }
605
606   public void addStatusTextListener(StatusTextListener listener) {
607     browser.addStatusTextListener(listener);
608   }
609
610   public void addTitleListener(TitleListener listener) {
611     browser.addTitleListener(listener);
612   }
613 }