fixed bug #1115300, #1115292
[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     if (WebBrowserUtil.isInternalBrowserOperational())
136       this.browser = new Browser(this, SWT.NONE);
137     else {
138       WebBrowserUtil.openError(WebBrowserUIPlugin.getResource("%errorCouldNotLaunchInternalWebBrowser"));
139       return;
140     }
141
142     if (showToolbar) {
143       back.setEnabled(browser.isBackEnabled());
144       forward.setEnabled(browser.isForwardEnabled());
145     }
146
147     WorkbenchHelp.setHelp(browser, ContextIds.WEB_BROWSER_WEB);
148     GridData data = new GridData();
149     data.horizontalAlignment = GridData.FILL;
150     data.verticalAlignment = GridData.FILL;
151     data.horizontalSpan = 3;
152     data.grabExcessHorizontalSpace = true;
153     data.grabExcessVerticalSpace = true;
154     browser.setLayoutData(data);
155
156     if (showStatusbar)
157       createStatusArea(this);
158
159     addBrowserListeners();
160   }
161
162   /**
163    *  
164    */
165   protected void addBrowserListeners() {
166     if (showStatusbar) {
167       // respond to Browser StatusTextEvents events by updating the status Text label
168       browser.addStatusTextListener(new StatusTextListener() {
169         public void changed(StatusTextEvent event) {
170           status.setText(event.text);
171         }
172       });
173     }
174
175     /**
176      * Add listener for new window creation so that we can instead of opening a separate new window in which the session is lost, we
177      * can instead open a new window in a new shell within the browser area thereby maintaining the session.
178      */
179     browser.addOpenWindowListener(new OpenWindowListener() {
180       public void open(WindowEvent event) {
181         Shell shell2 = new Shell(getDisplay());
182         shell2.setLayout(new FillLayout());
183         shell2.setText(WebBrowserUIPlugin.getResource("%viewWebBrowserTitle"));
184         shell2.setImage(getShell().getImage());
185         WebBrowser browser2 = new WebBrowser(shell2, showToolbar, showStatusbar);
186         browser2.shell = shell2;
187         event.browser = browser2.browser;
188         shell2.open();
189       }
190     });
191
192     browser.addCloseWindowListener(new CloseWindowListener() {
193       public void close(WindowEvent event) {
194         // if shell is not null, it must be a secondary popup window, else its an editor window
195         if (shell != null)
196           shell.dispose();
197         else
198           editor.closeEditor();
199       }
200     });
201
202     browser.addProgressListener(new ProgressListener() {
203       public void changed(ProgressEvent event) {
204         if (event.total == 0)
205           return;
206
207         boolean done = (event.current == event.total);
208
209         int percentProgress = event.current * 100 / event.total;
210         if (showStatusbar) {
211           if (done)
212             progress.setSelection(0);
213           else
214             progress.setSelection(percentProgress);
215         }
216
217         if (showToolbar) {
218           if (!busy.isBusy() && (percentProgress > 0 && percentProgress < 100)) {
219             busy.setBusy(true);
220           }
221           // Once the progress hits 100 percent, done, set busy to false
222           else if (busy.isBusy() && done) {
223             busy.setBusy(false);
224           }
225         }
226       }
227
228       public void completed(ProgressEvent event) {
229         if (showStatusbar)
230           progress.setSelection(0);
231         if (showToolbar) {
232           busy.setBusy(false);
233           back.setEnabled(browser.isBackEnabled());
234           forward.setEnabled(browser.isForwardEnabled());
235         }
236       }
237     });
238
239     if (showToolbar) {
240       browser.addLocationListener(new LocationListener() {
241         public void changed(LocationEvent event) {
242           if (!event.top)
243             return;
244           if (!isHome()) {
245             combo.setText(event.location);
246             addToHistory(event.location);
247             updateHistory();
248           } else
249             combo.setText("");
250         }
251
252         public void changing(LocationEvent event) {
253         }
254       });
255     }
256
257     browser.addTitleListener(new TitleListener() {
258       public void changed(TitleEvent event) {
259         title = event.title;
260       }
261     });
262   }
263
264   /**
265    * Return the underlying browser control.
266    * 
267    * @return org.eclipse.swt.browser.Browser
268    */
269   public Browser getBrowser() {
270     return browser;
271   }
272
273   /**
274    *  
275    */
276   protected void forward() {
277     browser.forward();
278   }
279
280   /**
281    *  
282    */
283   protected void back() {
284     browser.back();
285   }
286
287   /**
288    *  
289    */
290   protected void stop() {
291     browser.stop();
292   }
293
294   /**
295    *  
296    */
297   protected void navigate(String url) {
298     Trace.trace(Trace.FINER, "Navigate: " + url);
299     if (url != null && url.equals(getURL())) {
300       refresh();
301       return;
302     }
303     browser.setUrl(url);
304   }
305
306   /**
307    * Refresh the currently viewed page.
308    */
309   public void refresh() {
310     browser.refresh();
311   }
312
313   protected void setURL(String url, boolean browse) {
314     Trace.trace(Trace.FINEST, "setURL: " + url + " " + browse);
315     if (url == null) {
316       home();
317       return;
318     }
319
320     if (url.endsWith(WebBrowserPreference.getHomePageURL().substring(9)))
321       return;
322
323     // check URL maps
324     Iterator iterator = WebBrowserUtil.getURLMaps().iterator();
325     String newURL = null;
326     while (iterator.hasNext() && newURL == null) {
327       try {
328         IURLMap map = (IURLMap) iterator.next();
329         newURL = map.getMappedURL(url);
330       } catch (Exception e) {
331       }
332     }
333     if (newURL != null)
334       url = newURL;
335
336     if (browse)
337       navigate(url);
338
339     addToHistory(url);
340     updateHistory();
341   }
342
343   protected void addToHistory(String url) {
344     if (history == null)
345       history = WebBrowserPreference.getInternalWebBrowserHistory();
346     int found = -1;
347     int size = history.size();
348     for (int i = 0; i < size; i++) {
349       String s = (String) history.get(i);
350       if (s.equals(url)) {
351         found = i;
352         break;
353       }
354     }
355
356     if (found == -1) {
357       if (size >= MAX_HISTORY)
358         history.remove(size - 1);
359       history.add(0, url);
360       WebBrowserPreference.setInternalWebBrowserHistory(history);
361     } else if (found != 0) {
362       history.remove(found);
363       history.add(0, url);
364       WebBrowserPreference.setInternalWebBrowserHistory(history);
365     }
366   }
367
368   public void setURL(String url) {
369     setURL(url, true);
370   }
371
372   /**
373    * Creates the Web browser status area.
374    */
375   private void createStatusArea(Composite parent) {
376     Composite composite = new Composite(parent, SWT.NONE);
377     GridLayout layout = new GridLayout();
378     layout.numColumns = 2;
379     layout.marginHeight = 0;
380     layout.marginWidth = 0;
381     layout.horizontalSpacing = 4;
382     layout.verticalSpacing = 0;
383     composite.setLayout(layout);
384     composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
385
386     // Add a label for displaying status messages as they are received from the control
387     status = new Label(composite, SWT.SINGLE | SWT.READ_ONLY);
388     GridData gridData = new GridData(GridData.FILL_HORIZONTAL | GridData.VERTICAL_ALIGN_FILL);
389     gridData.horizontalIndent = 2;
390     status.setLayoutData(gridData);
391
392     // Add a progress bar to display downloading progress information
393     progress = new ProgressBar(composite, SWT.BORDER);
394     gridData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING | GridData.VERTICAL_ALIGN_FILL);
395     gridData.widthHint = 100;
396     gridData.heightHint = 10;
397     progress.setLayoutData(gridData);
398   }
399
400   /**
401    *  
402    */
403   public void dispose() {
404     super.dispose();
405
406     showStatusbar = false;
407     showToolbar = false;
408
409     if (busy != null)
410       busy.dispose();
411     busy = null;
412
413     browser = null;
414   }
415
416   /**
417    * Populate the toolbar.
418    * 
419    * @param toolbar
420    *          org.eclipse.swt.widgets.ToolBar
421    */
422   private void fillToolBar(final ToolBar toolbar) {
423     ToolItem go = new ToolItem(toolbar, SWT.NONE);
424     go.setImage(ImageResource.getImage(ImageResource.IMG_ELCL_NAV_GO));
425     go.setHotImage(ImageResource.getImage(ImageResource.IMG_CLCL_NAV_GO));
426     go.setDisabledImage(ImageResource.getImage(ImageResource.IMG_DLCL_NAV_GO));
427     go.setToolTipText(WebBrowserUIPlugin.getResource("%actionWebBrowserGo"));
428     go.addSelectionListener(new SelectionAdapter() {
429       public void widgetSelected(SelectionEvent event) {
430         setURL(combo.getText());
431       }
432     });
433
434     new ToolItem(toolbar, SWT.SEPARATOR);
435
436     favorites = new ToolItem(toolbar, SWT.DROP_DOWN);
437     favorites.setImage(ImageResource.getImage(ImageResource.IMG_ELCL_NAV_FAVORITES));
438     favorites.setHotImage(ImageResource.getImage(ImageResource.IMG_CLCL_NAV_FAVORITES));
439     favorites.setDisabledImage(ImageResource.getImage(ImageResource.IMG_DLCL_NAV_FAVORITES));
440     favorites.setToolTipText(WebBrowserUIPlugin.getResource("%actionWebBrowserFavorites"));
441
442     favorites.addSelectionListener(new SelectionAdapter() {
443       public void widgetSelected(SelectionEvent event) {
444         if (event.detail == SWT.ARROW) {
445           Rectangle r = favorites.getBounds();
446           showFavorites(toolbar, toolbar.toDisplay(r.x, r.y + r.height));
447         } else
448           addFavorite();
449       }
450     });
451
452     // create back and forward actions
453     back = new ToolItem(toolbar, SWT.NONE);
454     back.setImage(ImageResource.getImage(ImageResource.IMG_ELCL_NAV_BACKWARD));
455     back.setHotImage(ImageResource.getImage(ImageResource.IMG_CLCL_NAV_BACKWARD));
456     back.setDisabledImage(ImageResource.getImage(ImageResource.IMG_DLCL_NAV_BACKWARD));
457     back.setToolTipText(WebBrowserUIPlugin.getResource("%actionWebBrowserBack"));
458     back.addSelectionListener(new SelectionAdapter() {
459       public void widgetSelected(SelectionEvent event) {
460         back();
461       }
462     });
463
464     forward = new ToolItem(toolbar, SWT.NONE);
465     forward.setImage(ImageResource.getImage(ImageResource.IMG_ELCL_NAV_FORWARD));
466     forward.setHotImage(ImageResource.getImage(ImageResource.IMG_CLCL_NAV_FORWARD));
467     forward.setDisabledImage(ImageResource.getImage(ImageResource.IMG_DLCL_NAV_FORWARD));
468     forward.setToolTipText(WebBrowserUIPlugin.getResource("%actionWebBrowserForward"));
469     forward.addSelectionListener(new SelectionAdapter() {
470       public void widgetSelected(SelectionEvent event) {
471         forward();
472       }
473     });
474
475     // create refresh, stop, and print actions
476     stop = new ToolItem(toolbar, SWT.NONE);
477     stop.setImage(ImageResource.getImage(ImageResource.IMG_ELCL_NAV_STOP));
478     stop.setHotImage(ImageResource.getImage(ImageResource.IMG_CLCL_NAV_STOP));
479     stop.setDisabledImage(ImageResource.getImage(ImageResource.IMG_DLCL_NAV_STOP));
480     stop.setToolTipText(WebBrowserUIPlugin.getResource("%actionWebBrowserStop"));
481     stop.addSelectionListener(new SelectionAdapter() {
482       public void widgetSelected(SelectionEvent event) {
483         stop();
484       }
485     });
486
487     refresh = new ToolItem(toolbar, SWT.NONE);
488     refresh.setImage(ImageResource.getImage(ImageResource.IMG_ELCL_NAV_REFRESH));
489     refresh.setHotImage(ImageResource.getImage(ImageResource.IMG_CLCL_NAV_REFRESH));
490     refresh.setDisabledImage(ImageResource.getImage(ImageResource.IMG_DLCL_NAV_REFRESH));
491     refresh.setToolTipText(WebBrowserUIPlugin.getResource("%actionWebBrowserRefresh"));
492     refresh.addSelectionListener(new SelectionAdapter() {
493       public void widgetSelected(SelectionEvent event) {
494         refresh();
495       }
496     });
497   }
498
499   protected void addFavorite() {
500     java.util.List list = WebBrowserPreference.getInternalWebBrowserFavorites();
501     Favorite f = new Favorite(title, browser.getUrl());
502     if (!list.contains(f)) {
503       list.add(f);
504       WebBrowserPreference.setInternalWebBrowserFavorites(list);
505     }
506   }
507
508   protected void showFavorites(Control parent, Point p) {
509     Menu perspectiveBarMenu = null;
510     if (perspectiveBarMenu == null) {
511       Menu menu = new Menu(parent);
512
513       // locked favorites
514       Iterator iterator = WebBrowserUtil.getLockedFavorites().iterator();
515       if (iterator.hasNext()) {
516         while (iterator.hasNext()) {
517           final Favorite f = (Favorite) iterator.next();
518           MenuItem item = new MenuItem(menu, SWT.NONE);
519           item.setText(f.getName());
520           item.setImage(ImageResource.getImage(ImageResource.IMG_FAVORITE));
521           item.addSelectionListener(new SelectionAdapter() {
522             public void widgetSelected(SelectionEvent event) {
523               setURL(f.getURL());
524             }
525           });
526         }
527
528         new MenuItem(menu, SWT.SEPARATOR);
529       }
530
531       iterator = WebBrowserPreference.getInternalWebBrowserFavorites().iterator();
532       if (!iterator.hasNext()) {
533         MenuItem item = new MenuItem(menu, SWT.NONE);
534         item.setText(WebBrowserUIPlugin.getResource("%actionWebBrowserNoFavorites"));
535       }
536       while (iterator.hasNext()) {
537         final Favorite f = (Favorite) iterator.next();
538         MenuItem item = new MenuItem(menu, SWT.NONE);
539         item.setText(f.getName());
540         item.setImage(ImageResource.getImage(ImageResource.IMG_FAVORITE));
541         item.addSelectionListener(new SelectionAdapter() {
542           public void widgetSelected(SelectionEvent event) {
543             setURL(f.getURL());
544           }
545         });
546       }
547
548       new MenuItem(menu, SWT.SEPARATOR);
549
550       MenuItem item = new MenuItem(menu, SWT.NONE);
551       item.setText(WebBrowserUIPlugin.getResource("%actionWebBrowserOrganizeFavorites"));
552       item.addSelectionListener(new SelectionAdapter() {
553         public void widgetSelected(SelectionEvent event) {
554           OrganizeFavoritesDialog dialog = new OrganizeFavoritesDialog(shell);
555           dialog.open();
556         }
557       });
558
559       perspectiveBarMenu = menu;
560     }
561
562     if (perspectiveBarMenu != null) {
563       perspectiveBarMenu.setLocation(p.x, p.y);
564       perspectiveBarMenu.setVisible(true);
565     }
566   }
567
568   public void home() {
569     navigate(WebBrowserPreference.getHomePageURL());
570   }
571
572   /**
573    * Returns true if the homepage is currently being displayed.
574    * 
575    * @return boolean
576    */
577   protected boolean isHome() {
578     return getURL() != null && getURL().endsWith(WebBrowserPreference.getHomePageURL().substring(9));
579   }
580
581   protected String getURL() {
582     return browser.getUrl();
583   }
584
585   /**
586    * Update the history list to the global copy.
587    */
588   protected void updateHistory() {
589     if (combo == null)
590       return;
591
592     String temp = combo.getText();
593     if (history == null)
594       history = WebBrowserPreference.getInternalWebBrowserHistory();
595
596     String[] historyList = new String[history.size()];
597     history.toArray(historyList);
598     combo.setItems(historyList);
599
600     combo.setText(temp);
601   }
602
603   public void addProgressListener(ProgressListener listener) {
604     browser.addProgressListener(listener);
605   }
606
607   public void addStatusTextListener(StatusTextListener listener) {
608     browser.addStatusTextListener(listener);
609   }
610
611   public void addTitleListener(TitleListener listener) {
612     browser.addTitleListener(listener);
613   }
614 }