KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jface > internal > text > html > BrowserInformationControl


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jface.internal.text.html;
12
13 import java.io.IOException JavaDoc;
14 import java.io.StringReader JavaDoc;
15 import java.util.Iterator JavaDoc;
16
17 import org.eclipse.swt.SWT;
18 import org.eclipse.swt.SWTError;
19 import org.eclipse.swt.browser.Browser;
20 import org.eclipse.swt.browser.LocationAdapter;
21 import org.eclipse.swt.browser.LocationEvent;
22 import org.eclipse.swt.custom.StyleRange;
23 import org.eclipse.swt.events.DisposeEvent;
24 import org.eclipse.swt.events.DisposeListener;
25 import org.eclipse.swt.events.FocusEvent;
26 import org.eclipse.swt.events.FocusListener;
27 import org.eclipse.swt.events.KeyEvent;
28 import org.eclipse.swt.events.KeyListener;
29 import org.eclipse.swt.graphics.Color;
30 import org.eclipse.swt.graphics.Font;
31 import org.eclipse.swt.graphics.FontData;
32 import org.eclipse.swt.graphics.Point;
33 import org.eclipse.swt.graphics.Rectangle;
34 import org.eclipse.swt.graphics.TextLayout;
35 import org.eclipse.swt.graphics.TextStyle;
36 import org.eclipse.swt.layout.GridData;
37 import org.eclipse.swt.layout.GridLayout;
38 import org.eclipse.swt.widgets.Composite;
39 import org.eclipse.swt.widgets.Display;
40 import org.eclipse.swt.widgets.Event;
41 import org.eclipse.swt.widgets.Label;
42 import org.eclipse.swt.widgets.Listener;
43 import org.eclipse.swt.widgets.Menu;
44 import org.eclipse.swt.widgets.Shell;
45
46 import org.eclipse.core.runtime.ListenerList;
47
48 import org.eclipse.jface.text.IInformationControl;
49 import org.eclipse.jface.text.IInformationControlExtension;
50 import org.eclipse.jface.text.IInformationControlExtension3;
51 import org.eclipse.jface.text.IInformationControlExtension4;
52 import org.eclipse.jface.text.TextPresentation;
53
54
55 /**
56  * Displays textual information in a {@link org.eclipse.swt.browser.Browser} widget.
57  * <p>
58  * Moved into this package from <code>org.eclipse.jface.internal.text.revisions</code>.</p>
59  * <p>
60  * This class may be instantiated; it is not intended to be subclassed.</p>
61  * <p>
62  * Current problems:
63  * <ul>
64  * <li>the size computation is too small</li>
65  * <li>focusLost event is not sent - see https://bugs.eclipse.org/bugs/show_bug.cgi?id=84532</li>
66  * </ul>
67  * </p>
68  *
69  * @since 3.2
70  */

71 public class BrowserInformationControl implements IInformationControl, IInformationControlExtension, IInformationControlExtension3, IInformationControlExtension4, DisposeListener {
72
73
74     /**
75      * Tells whether the SWT Browser widget and hence this information
76      * control is available.
77      *
78      * @param parent the parent component used for checking or <code>null</code> if none
79      * @return <code>true</code> if this control is available
80      */

81     public static boolean isAvailable(Composite parent) {
82         if (!fgAvailabilityChecked) {
83             try {
84                 Browser browser= new Browser(parent, SWT.NONE);
85                 browser.dispose();
86                 fgIsAvailable= true;
87             } catch (SWTError er) {
88                 fgIsAvailable= false;
89             } finally {
90                 fgAvailabilityChecked= true;
91             }
92         }
93
94         return fgIsAvailable;
95     }
96
97
98     /** Border thickness in pixels. */
99     private static final int BORDER= 1;
100     
101     /**
102      * Minimal size constraints.
103      * @since 3.2
104      */

105     private static final int MIN_WIDTH= 80;
106     private static final int MIN_HEIGHT= 80;
107
108     
109     /**
110      * Availability checking cache.
111      */

112     private static boolean fgIsAvailable= false;
113     private static boolean fgAvailabilityChecked= false;
114
115     /** The control's shell */
116     private Shell fShell;
117     /** The control's browser widget */
118     private Browser fBrowser;
119     /** Tells whether the browser has content */
120     private boolean fBrowserHasContent;
121     /** The control width constraint */
122     private int fMaxWidth= SWT.DEFAULT;
123     /** The control height constraint */
124     private int fMaxHeight= SWT.DEFAULT;
125     private Font fStatusTextFont;
126     private Label fStatusTextField;
127     private String JavaDoc fStatusFieldText;
128     private boolean fHideScrollBars;
129     private Listener fDeactivateListener;
130     private ListenerList fFocusListeners= new ListenerList();
131     private Label fSeparator;
132     private String JavaDoc fInputText;
133     private TextLayout fTextLayout;
134
135     private TextStyle fBoldStyle;
136
137     /**
138      * Creates a default information control with the given shell as parent. The given
139      * information presenter is used to process the information to be displayed. The given
140      * styles are applied to the created styled text widget.
141      *
142      * @param parent the parent shell
143      * @param shellStyle the additional styles for the shell
144      * @param style the additional styles for the styled text widget
145      */

146     public BrowserInformationControl(Shell parent, int shellStyle, int style) {
147         this(parent, shellStyle, style, null);
148     }
149
150     /**
151      * Creates a default information control with the given shell as parent. The given
152      * information presenter is used to process the information to be displayed. The given
153      * styles are applied to the created styled text widget.
154      *
155      * @param parent the parent shell
156      * @param shellStyle the additional styles for the shell
157      * @param style the additional styles for the styled text widget
158      * @param statusFieldText the text to be used in the optional status field
159      * or <code>null</code> if the status field should be hidden
160      */

161     public BrowserInformationControl(Shell parent, int shellStyle, int style, String JavaDoc statusFieldText) {
162         fStatusFieldText= statusFieldText;
163         
164         fShell= new Shell(parent, SWT.NO_FOCUS | SWT.ON_TOP | shellStyle);
165         Display display= fShell.getDisplay();
166         fShell.setBackground(display.getSystemColor(SWT.COLOR_BLACK));
167         fTextLayout= new TextLayout(display);
168
169         Composite composite= fShell;
170         GridLayout layout= new GridLayout(1, false);
171         int border= ((shellStyle & SWT.NO_TRIM) == 0) ? 0 : BORDER;
172         layout.marginHeight= border;
173         layout.marginWidth= border;
174         composite.setLayout(layout);
175         
176         if (statusFieldText != null) {
177             composite= new Composite(composite, SWT.NONE);
178             layout= new GridLayout(1, false);
179             layout.marginHeight= 0;
180             layout.marginWidth= 0;
181             layout.verticalSpacing= 1;
182             layout.horizontalSpacing= 1;
183             composite.setLayout(layout);
184             
185             GridData gd= new GridData(GridData.FILL_BOTH);
186             composite.setLayoutData(gd);
187             
188             composite.setForeground(display.getSystemColor(SWT.COLOR_INFO_FOREGROUND));
189             composite.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND));
190         }
191
192         // Browser field
193
fBrowser= new Browser(composite, SWT.NONE);
194         fHideScrollBars= (style & SWT.V_SCROLL) == 0 && (style & SWT.H_SCROLL) == 0;
195         
196         GridData gd= new GridData(GridData.BEGINNING | GridData.FILL_BOTH);
197         fBrowser.setLayoutData(gd);
198         
199         fBrowser.setForeground(display.getSystemColor(SWT.COLOR_INFO_FOREGROUND));
200         fBrowser.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND));
201         fBrowser.addKeyListener(new KeyListener() {
202
203             public void keyPressed(KeyEvent e) {
204                 if (e.character == 0x1B) // ESC
205
fShell.dispose();
206             }
207
208             public void keyReleased(KeyEvent e) {}
209         });
210         /*
211          * XXX revisit when the Browser support is better
212          * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=107629. Choosing a link to a
213          * non-available target will show an error dialog behind the ON_TOP shell that seemingly
214          * blocks the workbench. Disable links completely for now.
215          */

216         fBrowser.addLocationListener(new LocationAdapter() {
217             /*
218              * @see org.eclipse.swt.browser.LocationAdapter#changing(org.eclipse.swt.browser.LocationEvent)
219              */

220             public void changing(LocationEvent event) {
221                 String JavaDoc location= event.location;
222                 /*
223                  * Using the Browser.setText API triggers a location change to "about:blank" with
224                  * the mozilla widget. The Browser on carbon uses yet another kind of special
225                  * initialization URLs.
226                  * TODO remove this code once https://bugs.eclipse.org/bugs/show_bug.cgi?id=130314 is fixed
227                  */

228                 if (!"about:blank".equals(location) && !("carbon".equals(SWT.getPlatform()) && location.startsWith("applewebdata:"))) //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
229
event.doit= false;
230             }
231         });
232
233         // Replace browser's built-in context menu with none
234
fBrowser.setMenu(new Menu(fShell, SWT.NONE));
235
236         // Status field
237
if (statusFieldText != null) {
238
239             fSeparator= new Label(composite, SWT.SEPARATOR | SWT.HORIZONTAL | SWT.LINE_DOT);
240             fSeparator.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
241
242             // Status field label
243
fStatusTextField= new Label(composite, SWT.RIGHT);
244             fStatusTextField.setText(statusFieldText);
245             Font font= fStatusTextField.getFont();
246             FontData[] fontDatas= font.getFontData();
247             for (int i= 0; i < fontDatas.length; i++)
248                 fontDatas[i].setHeight(fontDatas[i].getHeight() * 9 / 10);
249             fStatusTextFont= new Font(fStatusTextField.getDisplay(), fontDatas);
250             fStatusTextField.setFont(fStatusTextFont);
251             gd= new GridData(GridData.FILL_HORIZONTAL | GridData.HORIZONTAL_ALIGN_BEGINNING | GridData.VERTICAL_ALIGN_BEGINNING);
252             fStatusTextField.setLayoutData(gd);
253
254             fStatusTextField.setForeground(display.getSystemColor(SWT.COLOR_WIDGET_DARK_SHADOW));
255
256             fStatusTextField.setBackground(display.getSystemColor(SWT.COLOR_INFO_BACKGROUND));
257         }
258
259         addDisposeListener(this);
260         createTextLayout();
261     }
262
263     /**
264      * Creates a default information control with the given shell as parent. The given
265      * information presenter is used to process the information to be displayed. The given
266      * styles are applied to the created styled text widget.
267      *
268      * @param parent the parent shell
269      * @param style the additional styles for the browser widget
270      */

271     public BrowserInformationControl(Shell parent,int style) {
272         this(parent, SWT.TOOL | SWT.NO_TRIM, style);
273     }
274
275     /**
276      * Creates a default information control with the given shell as parent.
277      * No information presenter is used to process the information
278      * to be displayed. No additional styles are applied to the styled text widget.
279      *
280      * @param parent the parent shell
281      */

282     public BrowserInformationControl(Shell parent) {
283         this(parent, SWT.NONE);
284     }
285
286
287     /*
288      * @see IInformationControl#setInformation(String)
289      */

290     public void setInformation(String JavaDoc content) {
291         fBrowserHasContent= content != null && content.length() > 0;
292
293         if (!fBrowserHasContent)
294             content= "<html><body ></html>"; //$NON-NLS-1$
295

296         fInputText= content;
297
298         int shellStyle= fShell.getStyle();
299         boolean RTL= (shellStyle & SWT.RIGHT_TO_LEFT) != 0;
300
301         String JavaDoc[] styles= null;
302         if (RTL && !fHideScrollBars)
303             styles= new String JavaDoc[] { "direction:rtl;", "word-wrap:break-word;" }; //$NON-NLS-1$ //$NON-NLS-2$
304
else if (RTL && fHideScrollBars)
305             styles= new String JavaDoc[] { "direction:rtl;", "overflow:hidden;", "word-wrap:break-word;" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
306
else if (fHideScrollBars && true)
307             styles= new String JavaDoc[] { "overflow:hidden;", "word-wrap: break-word;" }; //$NON-NLS-1$ //$NON-NLS-2$
308

309         if (styles != null) {
310             StringBuffer JavaDoc buffer= new StringBuffer JavaDoc(content);
311             HTMLPrinter.insertStyles(buffer, styles);
312             content= buffer.toString();
313         }
314         
315         fBrowser.setText(content);
316     
317     }
318
319     /*
320      * @see org.eclipse.jdt.internal.ui.text.IInformationControlExtension4#setStatusText(java.lang.String)
321      * @since 3.2
322      */

323     public void setStatusText(String JavaDoc statusFieldText) {
324         fStatusFieldText= statusFieldText;
325     }
326
327     /*
328      * @see IInformationControl#setVisible(boolean)
329      */

330     public void setVisible(boolean visible) {
331         if (fShell.isVisible() == visible)
332             return;
333         
334         if (visible) {
335             if (fStatusTextField != null) {
336                 boolean state= fStatusFieldText != null;
337                 if (state)
338                     fStatusTextField.setText(fStatusFieldText);
339                 fStatusTextField.setVisible(state);
340                 fSeparator.setVisible(state);
341             }
342         }
343
344         fShell.setVisible(visible);
345         if (!visible)
346             setInformation(""); //$NON-NLS-1$
347
}
348
349     /**
350      * Creates and initializes the text layout used
351      * to compute the size hint.
352      *
353      * @since 3.2
354      */

355     private void createTextLayout() {
356         fTextLayout= new TextLayout(fBrowser.getDisplay());
357         
358         // Initialize fonts
359
Font font= fBrowser.getFont();
360         fTextLayout.setFont(font);
361         fTextLayout.setWidth(-1);
362         FontData[] fontData= font.getFontData();
363         for (int i= 0; i < fontData.length; i++)
364             fontData[i].setStyle(SWT.BOLD);
365         font= new Font(fShell.getDisplay(), fontData);
366         fBoldStyle= new TextStyle(font, null, null);
367         
368         // Compute and set tab width
369
fTextLayout.setText(" "); //$NON-NLS-1$
370
int tabWidth = fTextLayout.getBounds().width;
371         fTextLayout.setTabs(new int[] {tabWidth});
372
373         fTextLayout.setText(""); //$NON-NLS-1$
374
}
375
376     /*
377      * @see IInformationControl#dispose()
378      */

379     public void dispose() {
380         fTextLayout.dispose();
381         fTextLayout= null;
382         fBoldStyle.font.dispose();
383         fBoldStyle= null;
384         if (fShell != null && !fShell.isDisposed())
385             fShell.dispose();
386         else
387             widgetDisposed(null);
388     }
389
390     /*
391      * @see org.eclipse.swt.events.DisposeListener#widgetDisposed(org.eclipse.swt.events.DisposeEvent)
392      */

393     public void widgetDisposed(DisposeEvent event) {
394         if (fStatusTextFont != null && !fStatusTextFont.isDisposed())
395             fStatusTextFont.dispose();
396
397         fShell= null;
398         fBrowser= null;
399         fStatusTextFont= null;
400     }
401
402     /*
403      * @see IInformationControl#setSize(int, int)
404      */

405     public void setSize(int width, int height) {
406         fShell.setSize(Math.min(width, fMaxWidth), Math.min(height, fMaxHeight));
407     }
408
409     /*
410      * @see IInformationControl#setLocation(Point)
411      */

412     public void setLocation(Point location) {
413         fShell.setLocation(location);
414     }
415
416     /*
417      * @see IInformationControl#setSizeConstraints(int, int)
418      */

419     public void setSizeConstraints(int maxWidth, int maxHeight) {
420         fMaxWidth= maxWidth;
421         fMaxHeight= maxHeight;
422     }
423
424     /*
425      * @see IInformationControl#computeSizeHint()
426      */

427     public Point computeSizeHint() {
428         TextPresentation presentation= new TextPresentation();
429         HTML2TextReader reader= new HTML2TextReader(new StringReader JavaDoc(fInputText), presentation);
430         String JavaDoc text;
431         try {
432             text= reader.getString();
433         } catch (IOException JavaDoc e) {
434             text= ""; //$NON-NLS-1$
435
}
436
437         fTextLayout.setText(text);
438         Iterator JavaDoc iter= presentation.getAllStyleRangeIterator();
439         while (iter.hasNext()) {
440             StyleRange sr= (StyleRange)iter.next();
441             if (sr.fontStyle == SWT.BOLD)
442                 fTextLayout.setStyle(fBoldStyle, sr.start, sr.start + sr.length - 1);
443         }
444         Rectangle bounds= fTextLayout.getBounds();
445         int width= bounds.width;
446         int height= bounds.height;
447         
448         width += 15;
449         height += 25;
450
451         if (fStatusFieldText != null && fSeparator != null) {
452             fTextLayout.setText(fStatusFieldText);
453             Rectangle statusBounds= fTextLayout.getBounds();
454             Rectangle separatorBounds= fSeparator.getBounds();
455             width= Math.max(width, statusBounds.width);
456             height= height + statusBounds.height + separatorBounds.height;
457         }
458
459         // Apply size constraints
460
if (fMaxWidth != SWT.DEFAULT)
461             width= Math.min(fMaxWidth, width);
462         if (fMaxHeight != SWT.DEFAULT)
463             height= Math.min(fMaxHeight, height);
464
465         // Ensure minimal size
466
width= Math.max(MIN_WIDTH, width);
467         height= Math.max(MIN_HEIGHT, height);
468         
469         return new Point(width, height);
470     }
471
472     /*
473      * @see org.eclipse.jface.text.IInformationControlExtension3#computeTrim()
474      */

475     public Rectangle computeTrim() {
476         return fShell.computeTrim(0, 0, 0, 0);
477     }
478
479     /*
480      * @see org.eclipse.jface.text.IInformationControlExtension3#getBounds()
481      */

482     public Rectangle getBounds() {
483         return fShell.getBounds();
484     }
485
486     /*
487      * @see org.eclipse.jface.text.IInformationControlExtension3#restoresLocation()
488      */

489     public boolean restoresLocation() {
490         return false;
491     }
492
493     /*
494      * @see org.eclipse.jface.text.IInformationControlExtension3#restoresSize()
495      */

496     public boolean restoresSize() {
497         return false;
498     }
499
500     /*
501      * @see IInformationControl#addDisposeListener(DisposeListener)
502      */

503     public void addDisposeListener(DisposeListener listener) {
504         fShell.addDisposeListener(listener);
505     }
506
507     /*
508      * @see IInformationControl#removeDisposeListener(DisposeListener)
509      */

510     public void removeDisposeListener(DisposeListener listener) {
511         fShell.removeDisposeListener(listener);
512     }
513
514     /*
515      * @see IInformationControl#setForegroundColor(Color)
516      */

517     public void setForegroundColor(Color foreground) {
518         fBrowser.setForeground(foreground);
519     }
520
521     /*
522      * @see IInformationControl#setBackgroundColor(Color)
523      */

524     public void setBackgroundColor(Color background) {
525         fBrowser.setBackground(background);
526     }
527
528     /*
529      * @see IInformationControl#isFocusControl()
530      */

531     public boolean isFocusControl() {
532         return fBrowser.isFocusControl();
533     }
534
535     /*
536      * @see IInformationControl#setFocus()
537      */

538     public void setFocus() {
539         fShell.forceFocus();
540         fBrowser.setFocus();
541     }
542
543     /*
544      * @see IInformationControl#addFocusListener(FocusListener)
545      */

546     public void addFocusListener(final FocusListener listener) {
547         fBrowser.addFocusListener(listener);
548
549         /*
550          * FIXME: This is a workaround for bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=84532
551          * (Browser widget does not send focusLost event)
552          */

553         if (fFocusListeners.isEmpty()) {
554             fDeactivateListener= new Listener() {
555                 public void handleEvent(Event event) {
556                     Object JavaDoc[] listeners= fFocusListeners.getListeners();
557                     for (int i = 0; i < listeners.length; i++)
558                         ((FocusListener)listeners[i]).focusLost(new FocusEvent(event));
559                 }
560             };
561             fBrowser.getShell().addListener(SWT.Deactivate, fDeactivateListener);
562         }
563         fFocusListeners.add(listener);
564     }
565
566     /*
567      * @see IInformationControl#removeFocusListener(FocusListener)
568      */

569     public void removeFocusListener(FocusListener listener) {
570         fBrowser.removeFocusListener(listener);
571
572         /*
573          * FIXME: This is a workaround for bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=84532
574          * (Browser widget does not send focusLost event)
575          */

576         fFocusListeners.remove(listener);
577         if (fFocusListeners.isEmpty()) {
578             fBrowser.getShell().removeListener(SWT.Deactivate, fDeactivateListener);
579             fDeactivateListener= null;
580         }
581     }
582
583     /*
584      * @see IInformationControlExtension#hasContents()
585      */

586     public boolean hasContents() {
587         return fBrowserHasContent;
588     }
589 }
590
Popular Tags