KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sslexplorer > agent > client > gui > swt > SWTSystemTrayGUI


1 /*
2  * SSL-Explorer
3  *
4  * Copyright (C) 2003-2006 3SP LTD. All Rights Reserved
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2 of
9  * the License, or (at your option) any later version.
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public
16  * License along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */

19             
20 package com.sslexplorer.agent.client.gui.swt;
21
22 import java.io.IOException JavaDoc;
23 import java.io.InputStream JavaDoc;
24 import java.text.MessageFormat JavaDoc;
25 import java.util.ArrayList JavaDoc;
26 import java.util.Hashtable JavaDoc;
27 import java.util.List JavaDoc;
28
29 import org.eclipse.swt.SWT;
30 import org.eclipse.swt.events.SelectionEvent;
31 import org.eclipse.swt.events.SelectionListener;
32 import org.eclipse.swt.graphics.Image;
33 import org.eclipse.swt.graphics.Point;
34 import org.eclipse.swt.layout.FillLayout;
35 import org.eclipse.swt.layout.GridData;
36 import org.eclipse.swt.layout.GridLayout;
37 import org.eclipse.swt.widgets.Composite;
38 import org.eclipse.swt.widgets.Display;
39 import org.eclipse.swt.widgets.Event;
40 import org.eclipse.swt.widgets.Label;
41 import org.eclipse.swt.widgets.Listener;
42 import org.eclipse.swt.widgets.Menu;
43 import org.eclipse.swt.widgets.MenuItem;
44 import org.eclipse.swt.widgets.MessageBox;
45 import org.eclipse.swt.widgets.Shell;
46 import org.eclipse.swt.widgets.Tray;
47 import org.eclipse.swt.widgets.TrayItem;
48
49 import com.maverick.http.HttpAuthenticator;
50 import com.sslexplorer.agent.client.ActionCallback;
51 import com.sslexplorer.agent.client.Agent;
52 import com.sslexplorer.agent.client.AgentAction;
53 import com.sslexplorer.agent.client.AgentClientGUI;
54 import com.sslexplorer.agent.client.Console;
55 import com.sslexplorer.agent.client.PortMonitor;
56 import com.sslexplorer.agent.client.TaskProgress;
57 import com.sslexplorer.agent.client.util.BrowserLauncher;
58
59 /**
60  * {@link AbstractAWTGUI} implementation that uses the system tray API provided
61  * with SWT.
62  *
63  * @author Brett Smith <a HREF="mailto: brett@3sp.com">&lt;brett@3sp.com&gt;</a>
64  */

65 public class SWTSystemTrayGUI implements AgentClientGUI {
66
67     // #ifdef DEBUG
68
static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(SWTSystemTrayGUI.class);
69     // #endif
70

71     final int IDLE_ICON = 0;
72     final int TX_ICON = 1;
73     final int RX_ICON = 2;
74     final int TXRX_ICON = 3;
75     final int DISCONNECTED_ICON = 4;
76
77     /**
78      * Default timeout
79      */

80     public final static int DEFAULT_TIMEOUT = 10000;
81
82     // Private instance variables
83

84     private Image[] icons;
85     private Tray tray;
86     private TrayItem trayItem;
87     private Display display;
88     private Agent agent;
89     private Menu popupMenu;
90     private Shell shell;
91     private Object JavaDoc initLock = new Object JavaDoc() {
92     };
93     private SWTBalloonWindow balloon;
94     private Label messageLabel;
95     private PortMonitor portMonitor;
96     private PopupTimer popupTimer;
97     private Console console;
98     private int menuIdx = 0;
99
100     private Hashtable JavaDoc menuLookup = new Hashtable JavaDoc();
101     private Hashtable JavaDoc menuItemLookup = new Hashtable JavaDoc();
102
103     /*
104      * (non-Javadoc)
105      *
106      * @see com.sslexplorer.vpn.client.VPNClientGUI#init(com.sslexplorer.vpn.client.VPNClientGUIListener)
107      */

108     public void init(Agent agent) {
109         this.agent = agent;
110         Thread JavaDoc t = new Thread JavaDoc() {
111             public void run() {
112                 doInit();
113                 eventLoop();
114             }
115         };
116         t.start();
117         synchronized (initLock) {
118             try {
119                 initLock.wait();
120             } catch (InterruptedException JavaDoc e) {
121             }
122         }
123
124     }
125
126     public Menu getMenu() {
127         return popupMenu;
128     }
129
130     public Agent getAgent() {
131         return agent;
132     }
133
134     public Display getDisplay() {
135         return display;
136     }
137
138     public Shell getShell() {
139         return shell;
140     }
141
142     protected void doInit() {
143         //
144
display = new Display();
145         shell = new Shell(display);
146
147         // Load the icons
148
icons = new Image[5];
149         icons[IDLE_ICON] = loadImage(SWTSystemTrayGUI.class, "/images/tray-idle.gif"); //$NON-NLS-1$
150
icons[TX_ICON] = loadImage(SWTSystemTrayGUI.class, "/images/tray-tx.gif"); //$NON-NLS-1$
151
icons[RX_ICON] = loadImage(SWTSystemTrayGUI.class, "/images/tray-rx.gif"); //$NON-NLS-1$
152
icons[TXRX_ICON] = loadImage(SWTSystemTrayGUI.class, "/images/tray-txrx.gif"); //$NON-NLS-1$
153
icons[DISCONNECTED_ICON] = loadImage(SWTSystemTrayGUI.class, "/images/tray-disconnecting.gif"); //$NON-NLS-1$
154

155         // Create the menu
156
popupMenu = new Menu(shell, SWT.POP_UP);
157
158         MenuItem open = new MenuItem(popupMenu, SWT.PUSH);
159         open.setText(Messages.getString("GUI.menu.openBrowser")); //$NON-NLS-1$
160
open.addSelectionListener(new SelectionListener() {
161             public void widgetDefaultSelected(SelectionEvent e) {
162             }
163
164             public void widgetSelected(SelectionEvent e) {
165                 openBrowser(null);
166             }
167         });
168
169         // #ifdef DEBUG
170
MenuItem console = new MenuItem(popupMenu, SWT.PUSH);
171         console.setText(Messages.getString("GUI.menu.debugConsole")); //$NON-NLS-1$
172
console.addSelectionListener(new SelectionListener() {
173             public void widgetDefaultSelected(SelectionEvent e) {
174             }
175
176             public void widgetSelected(SelectionEvent e) {
177                 getConsole().show();
178             }
179         });
180         // #endif
181
MenuItem ports = new MenuItem(popupMenu, SWT.PUSH);
182         ports.setText(Messages.getString("GUI.menu.tunnelMonitor")); //$NON-NLS-1$
183
ports.addSelectionListener(new SelectionListener() {
184             public void widgetDefaultSelected(SelectionEvent e) {
185             }
186
187             public void widgetSelected(SelectionEvent e) {
188                 getPortMonitor().setVisible(!getPortMonitor().isVisible());
189             }
190         });
191         MenuItem about = new MenuItem(popupMenu, SWT.PUSH);
192         about.setText(Messages.getString("GUI.menu.about")); //$NON-NLS-1$
193
about.addSelectionListener(new SelectionListener() {
194             public void widgetDefaultSelected(SelectionEvent e) {
195             }
196
197             public void widgetSelected(SelectionEvent e) {
198                 about();
199             }
200         });
201
202         // Create the menu items
203
new MenuItem(popupMenu, SWT.SEPARATOR);
204         MenuItem exit = new MenuItem(popupMenu, SWT.PUSH);
205         exit.setText(Messages.getString("GUI.menu.exit")); //$NON-NLS-1$
206
exit.addSelectionListener(new SelectionListener() {
207             public void widgetDefaultSelected(SelectionEvent e) {
208             }
209
210             public void widgetSelected(SelectionEvent e) {
211                 exit();
212             }
213         });
214
215         // Create the tray item
216
tray = display.getSystemTray();
217         if (tray == null) {
218             // #ifdef DEBUG
219
log.error("The system tray is not available");
220             // #endif
221
} else {
222             // Create the icon
223
trayItem = new TrayItem(tray, SWT.NONE);
224             trayItem.setToolTipText("SSL-Explorer Agent");
225             trayItem.addListener(SWT.Show, new Listener() {
226                 public void handleEvent(Event event) {
227                 }
228             });
229             trayItem.addListener(SWT.Hide, new Listener() {
230                 public void handleEvent(Event event) {
231                 }
232             });
233             trayItem.addListener(SWT.Selection, new Listener() {
234                 public void handleEvent(Event event) {
235                 }
236             });
237             trayItem.addListener(SWT.DefaultSelection, new Listener() {
238                 public void handleEvent(Event event) {
239                 }
240             });
241             trayItem.addListener(SWT.MenuDetect, new Listener() {
242                 public void handleEvent(Event event) {
243                     popupMenu.setVisible(true);
244                 }
245             });
246             trayItem.setImage(icons[IDLE_ICON]);
247         }
248     }
249
250     void about() {
251         final Image image = loadImage(SWTSystemTrayGUI.class, "/images/frame-agent.png");
252         SWTAboutDialog about = new SWTAboutDialog(shell,
253                         Messages.getString("About.close"),
254                         Messages.getString("About.title"),
255                         image,
256                         MessageFormat.format(Messages.getString("About.message"), new Object JavaDoc[] { agent.getServerVersion() }),
257                         Messages.getString("About.description"),
258                         Messages.getString("About.copyright"),
259                         Messages.getString("About.link"));
260
261         if (agent.getState() != Agent.STATE_DISCONNECTED) {
262
263             Composite shell = about.getAccessory();
264
265             Composite c = new Composite(shell, 0);
266             GridLayout gridLayout = new GridLayout();
267             c.setLayout(gridLayout);
268
269             Label host = new Label(c, SWT.WRAP);
270             host.setText(MessageFormat.format(Messages.getString("About.host"), new Object JavaDoc[] { agent.getSSLExplorerHost() }));
271             GridData data = new GridData();
272             data.horizontalAlignment = GridData.BEGINNING;
273             data.grabExcessHorizontalSpace = true;
274             host.setLayoutData(data);
275
276             Label port = new Label(c, SWT.WRAP);
277             port.setText(MessageFormat.format(Messages.getString("About.port"),
278                 new Object JavaDoc[] { String.valueOf(agent.getSSLExplorerPort()) }));
279             data = new GridData();
280             data.horizontalAlignment = GridData.BEGINNING;
281             data.grabExcessHorizontalSpace = true;
282             port.setLayoutData(data);
283
284             Label username = new Label(c, SWT.WRAP);
285             username.setText(MessageFormat.format(Messages.getString("About.username"), new Object JavaDoc[] { agent.getUsername() }));
286             data = new GridData();
287             data.horizontalAlignment = GridData.BEGINNING;
288             data.grabExcessHorizontalSpace = true;
289             username.setLayoutData(data);
290
291             Label serverVersion = new Label(c, SWT.WRAP);
292             serverVersion.setText(MessageFormat.format(Messages.getString("About.serverVersion"),
293                 new Object JavaDoc[] { agent.getServerVersion() }));
294             data = new GridData();
295             data.horizontalAlignment = GridData.BEGINNING;
296             data.grabExcessHorizontalSpace = true;
297             serverVersion.setLayoutData(data);
298
299             Label agentVersion = new Label(c, SWT.WRAP);
300             agentVersion.setText(MessageFormat.format(Messages.getString("About.agentVersion"),
301                 new Object JavaDoc[] { agent.getClientVersion() }));
302             data = new GridData();
303             data.horizontalAlignment = GridData.BEGINNING;
304             data.grabExcessHorizontalSpace = true;
305             agentVersion.setLayoutData(data);
306         }
307
308         about.open();
309     }
310
311     /*
312      * (non-Javadoc)
313      *
314      * @see com.sslexplorer.agent.client.AgentClientGUI#openBrowser(java.lang.String)
315      */

316     public void openBrowser(String JavaDoc path) {
317         try {
318             String JavaDoc browserPath = "https://" + agent.getSSLExplorerHost() + ":" + agent.getSSLExplorerPort() + //$NON-NLS-1$ //$NON-NLS-2$
319
(path == null ? "" : ("/" + path));
320             // #ifdef DEBUG
321
log.info("Opening browser to " + browserPath);
322             // #endif
323
BrowserLauncher.openURL(browserPath);
324         } catch (IOException JavaDoc ioe) {
325             // #ifdef DEBUG
326
log.error(ioe);
327             // #endif
328
}
329     }
330
331     void eventLoop() {
332         synchronized (initLock) {
333             initLock.notify();
334         }
335         while (true) {
336             if (!display.readAndDispatch())
337                 display.sleep();
338         }
339     }
340
341     /*
342      * (non-Javadoc)
343      *
344      * @see com.sslexplorer.vpn.client.VPNClientGUI#showIdle()
345      */

346     public void showIdle() {
347         setImage(icons[IDLE_ICON]);
348     }
349
350     /*
351      * (non-Javadoc)
352      *
353      * @see com.sslexplorer.vpn.client.VPNClientGUI#showDisconnected()
354      */

355     public void showDisconnected() {
356         setImage(icons[DISCONNECTED_ICON]);
357     }
358
359     /*
360      * (non-Javadoc)
361      *
362      * @see com.sslexplorer.vpn.client.VPNClientGUI#showTx()
363      */

364     public void showTx() {
365         setImage(icons[TX_ICON]);
366     }
367
368     /*
369      * (non-Javadoc)
370      *
371      * @see com.sslexplorer.vpn.client.VPNClientGUI#showRx()
372      */

373     public void showRx() {
374         setImage(icons[RX_ICON]);
375     }
376
377     /*
378      * (non-Javadoc)
379      *
380      * @see com.sslexplorer.vpn.client.VPNClientGUI#showTxRx()
381      */

382     public void showTxRx() {
383         setImage(icons[TXRX_ICON]);
384     }
385
386     void setImage(final Image image) {
387         display.asyncExec(new Runnable JavaDoc() {
388             public void run() {
389                 trayItem.setImage(image);
390             }
391         });
392     }
393
394     /*
395      * (non-Javadoc)
396      *
397      * @see com.sslexplorer.vpn.client.VPNClientGUI#setInfo(java.lang.String)
398      */

399     public void setInfo(final String JavaDoc info) {
400         display.asyncExec(new Runnable JavaDoc() {
401             public void run() {
402                 trayItem.setToolTipText(info);
403             }
404         });
405     }
406
407     protected Image loadImage(Class JavaDoc clazz, String JavaDoc path) {
408         InputStream JavaDoc stream = clazz.getResourceAsStream(path);
409         return stream == null ? null : new Image(display, stream);
410     }
411
412     public boolean confirm(final int dialogType, final String JavaDoc okText, final String JavaDoc cancelText, final String JavaDoc title,
413                             final String JavaDoc message) {
414         final List JavaDoc l = new ArrayList JavaDoc();
415         display.syncExec(new Runnable JavaDoc() {
416             public void run() {
417                 int type = SWT.ICON_QUESTION;
418                 if (dialogType == INFORMATION) {
419                     type = SWT.ICON_INFORMATION;
420                 } else if (dialogType == ERROR) {
421                     type = SWT.ICON_ERROR;
422                 } else if (dialogType == WARNING) {
423                     type = SWT.ICON_WARNING;
424                 }
425                 MessageBox messageBox = new MessageBox(shell, type | SWT.OK | (cancelText != null ? SWT.CANCEL : 0));
426                 messageBox.setText(title);
427                 messageBox.setMessage(message);
428                 int buttonID = messageBox.open();
429                 switch (buttonID) {
430                     case SWT.OK:
431                         l.add(Boolean.TRUE);
432                     default:
433                         l.add(Boolean.FALSE);
434                 }
435             }
436         });
437         return ((Boolean JavaDoc) l.get(0)).booleanValue();
438     }
439
440     /*
441      * (non-Javadoc)
442      *
443      * @see com.sslexplorer.agent.client.AgentClientGUI#error(java.lang.String,
444      * java.lang.String, java.lang.String, java.lang.String,
445      * java.lang.Throwable)
446      */

447     public boolean error(String JavaDoc okText, String JavaDoc cancelText, String JavaDoc title, String JavaDoc message, Throwable JavaDoc ex) {
448         return confirm(ERROR, okText, cancelText, title, message);
449     }
450
451     /*
452      * (non-Javadoc)
453      *
454      * @see com.sslexplorer.agent.client.AgentClientGUI#getConsole()
455      */

456     public synchronized Console getConsole() {
457         if (console == null) {
458             console = new SWTConsoleOutputStream("true".equals(System.getProperty("console.toSysOut", "false")) ? System.out : null, this); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
459
}
460         return console;
461     }
462
463     /*
464      * (non-Javadoc)
465      *
466      * @see com.sslexplorer.agent.client.AgentClientGUI#createTaskProgress(java.lang.String,
467      * java.lang.String, long, boolean)
468      */

469     public TaskProgress createTaskProgress(String JavaDoc message, String JavaDoc note, long maxValue, boolean allowCancel) {
470         return new SWTProgressDialog(this, (int) maxValue, allowCancel, message, note);
471     }
472
473     /*
474      * (non-Javadoc)
475      *
476      * @see com.sslexplorer.agent.client.AgentClientGUI#popup(com.sslexplorer.agent.client.AgentClientGUI.ActionCallback,
477      * java.lang.String, java.lang.String, java.lang.String, int)
478      */

479     public void popup(final ActionCallback callback, final String JavaDoc message, final String JavaDoc title, final String JavaDoc imageName,
480                         final int timeout) {
481         display.syncExec(new Runnable JavaDoc() {
482             public void run() {
483
484                 if (popupTimer != null) {
485                     popupTimer.setBalloon(null);
486                 }
487                 popupTimer = new PopupTimer();
488
489                 if (balloon != null && !balloon.getShell().isDisposed()) {
490                     balloon.setVisible(false);
491                 }
492                 balloon = new SWTBalloonWindow(display, SWT.ON_TOP | SWT.TITLE | SWT.CLOSE);
493                 balloon.setAutoLocation(SWT.BOTTOM | SWT.RIGHT);
494                 balloon.setLocation(56, 56);
495                 balloon.setAnchor(SWT.BOTTOM | SWT.RIGHT);
496                 balloon.setAutoAnchor(false);
497                 balloon.getContents().setLayout(new FillLayout());
498                 balloon.addListener(SWT.Selection, new Listener() {
499                     public void handleEvent(Event event) {
500                         // #ifdef DEBUG
501
log.debug("Balloon selected");
502                         // #endif
503
if (callback != null) {
504                             callback.actionPerformed();
505                         }
506                         balloon.close();
507                     }
508                 });
509                 messageLabel = new Label(balloon.getContents(), SWT.WRAP);
510                 messageLabel.setForeground(balloon.getShell().getForeground());
511                 messageLabel.setBackground(balloon.getShell().getBackground());
512                 balloon.addSelectionControl(messageLabel);
513                 balloon.setText(title);
514
515                 // balloon.setText(title);
516
messageLabel.setText(message == null ? "<No message supplied>" : message);
517                 messageLabel.setSize(messageLabel.computeSize(300, SWT.DEFAULT));
518                 Composite c = balloon.getContents();
519                 Point messageSize = messageLabel.getSize();
520                 Image image = imageName != null ? loadImage(SWTSystemTrayGUI.class, "/images/" + imageName + ".png") : null;
521                 if (image != null) {
522                     balloon.setImage(image);
523                     c.setSize(messageSize.x, messageSize.y);
524                 } else {
525                     c.setSize(messageSize);
526                 }
527                 if (!balloon.getShell().getVisible()) {
528                     balloon.setVisible(true);
529                 }
530                 if (timeout != 0) {
531                     popupTimer.setBalloon(balloon);
532                     display.timerExec(timeout == -1 ? DEFAULT_TIMEOUT : timeout, popupTimer);
533                 }
534             }
535         });
536     }
537
538     public PortMonitor getPortMonitor() {
539         if (portMonitor == null) {
540             createPortMonitor();
541         }
542         return portMonitor;
543     }
544
545     public boolean promptForCredentials(final boolean proxy, final HttpAuthenticator authenticator) {
546         return ((Boolean JavaDoc) SWTRunner.syncExec(display, new SWTRunner() {
547             public Object JavaDoc doRun() {
548                 return new Boolean JavaDoc(SWTAuthenticationDialog.promptForCredentials(proxy, shell, authenticator, null));
549             }
550
551         })).booleanValue();
552     }
553
554     public void dispose() {
555         shell.getDisplay().syncExec(new Runnable JavaDoc() {
556             public void run() {
557                 if (tray != null) {
558                     trayItem.dispose();
559                     tray.dispose();
560                 }
561                 getPortMonitor().dispose();
562                 getConsole().dispose();
563             }
564         });
565     }
566
567     public void addMenu(final String JavaDoc name) {
568
569         display.syncExec(new Runnable JavaDoc() {
570             public void run() {
571                 if (menuIdx == 0) {
572                     new MenuItem(popupMenu, SWT.SEPARATOR, 0);
573                 }
574                 MenuItem item = new MenuItem(popupMenu, SWT.CASCADE, menuIdx);
575                 menuIdx++;
576                 item.setText(name);
577                 Menu menu = new Menu(popupMenu);
578                 item.setMenu(menu);
579                 menuLookup.put(name, menu);
580                 menuItemLookup.put(name, item);
581             }
582         });
583     }
584
585     public void removeMenu(final String JavaDoc name) {
586
587         display.syncExec(new Runnable JavaDoc() {
588             public void run() {
589                 Menu menu = (Menu)menuLookup.get(name);
590                 MenuItem menuItem = (MenuItem)menuItemLookup.get(name);
591                 if(menu != null) {
592                     menu.dispose();
593                     menuItem.dispose();
594                     menuLookup.remove(name);
595                     menuItemLookup.remove(name);
596                 }
597             }
598         });
599     }
600     
601     public void clearMenu(final String JavaDoc name) {
602
603         display.syncExec(new Runnable JavaDoc() {
604             public void run() {
605                 Menu menu = (Menu)menuLookup.get(name);
606                 if(menu != null) {
607                     while(menu.getItemCount() > 0) {
608                         menu.getItem(0).dispose();
609                     }
610                 }
611             }
612         });
613     }
614     
615     public boolean isMenuExists(String JavaDoc name) {
616         return menuLookup.containsKey(name);
617     }
618     
619
620     public void addMenuItem(String JavaDoc name, final AgentAction action) {
621
622         // #ifdef DEBUG
623
log.debug("Adding menu item " + action.getAction() + " to " + name);
624         // #endif
625
final Menu parentMenu = name == null ? popupMenu : (Menu) menuLookup.get(name);
626         if (parentMenu == null) {
627             // #ifdef DEBUG
628
log.error("No parent menu item " + name + " for " + action.getAction());
629             // #endif
630
return;
631         }
632
633         display.syncExec(new Runnable JavaDoc() {
634             public void run() {
635                 MenuItem item = new MenuItem(parentMenu, SWT.PUSH);
636                 item.setText(action.getAction());
637                 item.addSelectionListener(new SelectionListener() {
638                     public void widgetDefaultSelected(SelectionEvent e) {
639                     }
640
641                     public void widgetSelected(SelectionEvent e) {
642                         action.actionPerformed();
643                     }
644                 });
645             }
646         });
647     }
648
649     public void addMenuSeperator(String JavaDoc name) {
650
651         final Menu parentMenu = name == null ? popupMenu : (Menu) menuLookup.get(name);
652         if (parentMenu == null)
653             return;
654         display.syncExec(new Runnable JavaDoc() {
655             public void run() {
656                 new MenuItem(parentMenu, SWT.SEPARATOR);
657             }
658         });
659
660     }
661
662     protected void createPortMonitor() {
663         display.syncExec(new Runnable JavaDoc() {
664             public void run() {
665                 portMonitor = new SWTPortMonitor(SWTSystemTrayGUI.this);
666             }
667         });
668     }
669
670     protected void exit() {
671         agent.disconnect();
672     }
673
674     class PopupTimer implements Runnable JavaDoc {
675
676         private SWTBalloonWindow balloon;
677
678         public void setBalloon(SWTBalloonWindow balloon) {
679             this.balloon = balloon;
680         }
681
682         public void run() {
683             display.syncExec(new Runnable JavaDoc() {
684                 public void run() {
685                     if (balloon != null && !balloon.getShell().isDisposed()) {
686                         balloon.setVisible(false);
687                     }
688                 }
689             });
690         }
691     }
692
693 }
Popular Tags