package eu.jucy.gui; import java.util.Collections; import java.util.List; import java.util.concurrent.Semaphore; import logger.LoggerFactory; import org.apache.log4j.Logger; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener; import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent; import org.eclipse.jface.action.IStatusLineManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.ShellAdapter; import org.eclipse.swt.events.ShellEvent; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Tray; import org.eclipse.swt.widgets.TrayItem; import org.eclipse.ui.IPartListener; import org.eclipse.ui.IWorkbenchActionConstants; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PartInitException; import org.eclipse.ui.application.ActionBarAdvisor; import org.eclipse.ui.application.IActionBarConfigurer; import org.eclipse.ui.application.IWorkbenchWindowConfigurer; import org.eclipse.ui.application.WorkbenchWindowAdvisor; import org.eclipse.ui.menus.IMenuService; import org.eclipse.ui.plugin.AbstractUIPlugin; import eu.jucy.gui.IUCEditor.ITopicChangedListener; import eu.jucy.gui.texteditor.hub.HubEditor; import eu.jucy.gui.texteditor.hub.HubEditorInput; import eu.jucy.gui.texteditor.hub.RedirectReceivedProvider; import uc.DCClient; import uc.FavHub; import uc.IDCCControlListener; import uc.LanguageKeys; import uc.FavFolders.SharedDir; import uihelpers.IconManager; import uihelpers.SUIJob; public class ApplicationWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor { public static final String TrayMenuID = "eu.jucy.gui.TrayMenu"; private static final Logger logger = LoggerFactory.make(); private static DCClient dcc; private static Thread uiThread; private static volatile Job shutdownJob; private TrayItem trayItem; private Image trayImage; public static void waitForShutdownJob() { if (Thread.currentThread() == uiThread) { Display display = Display.getCurrent(); while (shutdownJob != null) { if (!display.readAndDispatch ()) display.sleep (); } } else { if (shutdownJob != null) { try { shutdownJob.join(); } catch (InterruptedException e) { e.printStackTrace(); } } } } /** * -> opens new HubEditors when ever a hub is created.. */ private IDCCControlListener dCCControlListener; /** * may only be called from ui thread * this returns the DCClient for which this WorkbenchWindow is responsible */ public static DCClient get() { if (Thread.currentThread() != uiThread) { throw new IllegalStateException("IllegalThread Access"); } return dcc; } public ApplicationWorkbenchWindowAdvisor(IWorkbenchWindowConfigurer configurer) { super(configurer); } public ActionBarAdvisor createActionBarAdvisor(IActionBarConfigurer configurer) { return new ApplicationActionBarAdvisor(configurer); } public void preWindowOpen() { uiThread = Thread.currentThread(); dcc = new DCClient(); IWorkbenchWindowConfigurer configurer = getWindowConfigurer(); configurer.setInitialSize(new Point(1024, 768)); configurer.setShowMenuBar(true); configurer.setShowCoolBar(true); configurer.setShowStatusLine(true); configurer.setShowProgressIndicator(false); configurer.setTitle(DCClient.LONGVERSION); } public void postWindowOpen() { super.postWindowOpen(); IWorkbenchWindow window = getWindowConfigurer().getWindow(); if (logger.isDebugEnabled()) { GUIPI.get().addPreferenceChangeListener(new IPreferenceChangeListener() { public void preferenceChange(PreferenceChangeEvent event) { String pref= event.getKey(); logger.debug("pref changed: "+pref); } }); } IStatusLineManager manager = getWindowConfigurer().getActionBarConfigurer().getStatusLineManager(); GuiAppender.get().initialize(manager); //handle tray icon trayItem = initTaskItem(window); if (trayItem != null) { hookMinimized(window); hookMenu(trayItem,window); } if (GUIPI.getBoolean(GUIPI.minimizeOnStart)) { GuiHelpers.executeCommand(window, EnlargeShellHandler.COMMAND_ID, Collections.singletonMap(EnlargeShellHandler.PARAM_MAXIMIZE ,Boolean.FALSE.toString())); } Dialog.setDefaultImage(trayImage); registerListeners(window); new Job(String.format(LanguageKeys.StartingJucy, DCClient.LONGVERSION)) { @Override protected IStatus run(IProgressMonitor monitor) { try { dcc.start(monitor); loadFileIcons(); } catch(Exception e) { logger.error(e, e); } return Status.OK_STATUS; } }.schedule(); // //check for updates.. // if (PI.getBoolean(PI.checkForUpdates) && // System.currentTimeMillis() - PI.getLong(PI.lastCheckForUpdates) > 24 * 3600 * 1000 && // !Platform.inDevelopmentMode()) { // //eu.jucy.gui.update.UpdateHandler.checkForUpdates(); // PI.put(PI.lastCheckForUpdates, System.currentTimeMillis()); // } UIThreadDeadLockChecker.start(); // new SUIJob() { // // @Override // public void run() { // Event event = Application.stored; // if (event != null) { // logger.error(event.toString()+" "+event.data+" "+event.getClass().getName()); // Application.stored = null; // } // schedule(500); // } // // }.schedule(1000); // logger.info(Display.getAppName()); } private void loadFileIcons() { List<SharedDir> loadeddirs = dcc.getFavFolders().getSharedDirs(); for (SharedDir sd: loadeddirs) { if (sd.getDirectory().isDirectory()) { IconManager.loadImageSources(sd.getDirectory()); } } } @Override public void postWindowClose() { dcc.unregister(dCCControlListener); dcc.getHashEngine().unregisterHashedListener(GuiAppender.get()); shutdownJob = new Job("Shutdown") { @Override protected IStatus run(IProgressMonitor monitor) { dcc.stop(true); shutdownJob = null; return Status.OK_STATUS; } }; shutdownJob.schedule(); super.postWindowClose(); } private void registerListeners(final IWorkbenchWindow window) { dcc.getHashEngine().registerHashedListener(GuiAppender.get()); dCCControlListener = new IDCCControlListener() { public void hubCreated(final FavHub fh, boolean showInUI,final Semaphore sem) { if (showInUI) { new SUIJob() { public void run() { try { window.getActivePage().openEditor( new HubEditorInput(fh), HubEditor.ID,true); } catch(PartInitException pie) { MessageDialog.openError(window.getShell(), "Error", "Error open hub:" + pie.getMessage()); } sem.release(); } }.schedule(); } else { sem.release(); } } @Override public void requireRestart() { window.getWorkbench().restart(); } }; dcc.register(dCCControlListener); //listener for setting topic string on the top of the window final ITopicChangedListener listener = new ITopicChangedListener() { public void topicChanged(IUCEditor editor) { String text = DCClient.LONGVERSION+" -["+editor.getTopic()+"]"; window.getShell().setText(text); } }; window.getPartService().addPartListener(new IPartListener() { public void partActivated(IWorkbenchPart part) { if (part instanceof IUCEditor) { IUCEditor editor = (IUCEditor)part; editor.registerTopicChangedListener(listener); editor.fireTopicChangedListeners(); editor.partActivated(); } } public void partBroughtToTop(IWorkbenchPart part) { partActivated(part); } public void partClosed(IWorkbenchPart part) {} public void partDeactivated(IWorkbenchPart part) { if (part instanceof IUCEditor) { IUCEditor editor = (IUCEditor)part; editor.unregisterTopicChangedListener(listener); deleteTopText(); } } private void deleteTopText() { String text = DCClient.LONGVERSION; window.getShell().setText(text); } public void partOpened(IWorkbenchPart part) {} }); RedirectReceivedProvider.init(window); } private void hookMinimized(final IWorkbenchWindow window) { trayItem.addSelectionListener(new SelectionAdapter() { long lastUsed; @Override public void widgetSelected(SelectionEvent e) { widgetDefaultSelected(e); } @Override public void widgetDefaultSelected(SelectionEvent e) { if (System.currentTimeMillis() - lastUsed < 500) { //no accidental multiple activations return; } //using ahead provided window! -> //problems in Linux due to not window available when minimized? Boolean maximize = window.getShell().getMinimized(); GuiHelpers.executeCommand(window, EnlargeShellHandler.COMMAND_ID, Collections.singletonMap(EnlargeShellHandler.PARAM_MAXIMIZE,maximize.toString())); // //using ahead provided window! -> // //problems in Linux due to not window available when minimized? // if (window.getShell().getMinimized()) { // IHandlerService ihs = (IHandlerService)window.getService(IHandlerService.class); // // try { // ihs.executeCommand(EnlargeShellHandler.COMMAND_ID, null); // } catch (Exception e1) { // logger.warn(e1, e1); // } // } else { // EnlargeShellHandler.mininmize(window); // } lastUsed = System.currentTimeMillis(); } }); window.getShell().addShellListener(new ShellAdapter() { public void shellIconified(ShellEvent e){ GuiHelpers.executeCommand(window, EnlargeShellHandler.COMMAND_ID, Collections.singletonMap(EnlargeShellHandler.PARAM_MAXIMIZE ,Boolean.FALSE.toString())); } }); } private void hookMenu(TrayItem trayItem,IWorkbenchWindow window) { Shell shell = new Shell(Display.getCurrent()); MenuManager manager = new MenuManager("TrayMenu",TrayMenuID); manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); IMenuService service = (IMenuService)window.getService(IMenuService.class); service.populateContributionManager(manager, "popup:"+TrayMenuID); final Menu menu = manager.createContextMenu(shell); //final Menu menu = new Menu(shell, SWT.POP_UP); trayItem.addListener(SWT.MenuDetect, new Listener() { public void handleEvent(Event event) { menu.setVisible(true); } }); } private TrayItem initTaskItem(IWorkbenchWindow window){ trayImage = AbstractUIPlugin.imageDescriptorFromPlugin( Application.PLUGIN_ID, IImageKeys.TRAYICON).createImage(); if (Platform.OS_MACOSX.equals(Platform.getOS())) { //MacOsX uses gray tray icons.. Image img = new Image(null,trayImage,SWT.IMAGE_GRAY); trayImage.dispose(); trayImage = img; } try { final Tray tray = window.getShell().getDisplay().getSystemTray(); if( tray == null ) { return null; } // tray.addListener(SWT.MouseHover, new Listener() { // @Override // public void handleEvent(Event event) { // logger.info("Event hover tray: "+event.detail); // } // }); TrayItem trayItem = new TrayItem(tray,SWT.NONE); trayItem.setImage(trayImage); trayItem.setToolTipText(DCClient.LONGVERSION+" - Direct Connect Client"); trayItem.setVisible(true); // trayItem.addMenuDetectListener(new MenuDetectListener() { // // @Override // public void menuDetected(MenuDetectEvent e) { // String data = new SimpleDateFormat().format(new Date()); // logger.info("MenuDetectEven: "+data); // trayItem.setToolTipText("time: "+data); // } // }); return trayItem; } catch(NoClassDefFoundError err) { if (Platform.OS_MACOSX.equals(Platform.getOS())) { logger.warn("Tray icon not loaded. Probably you are running a too old MacOSX version."); } else { logger.error(err, err); } } catch(UnsatisfiedLinkError err) { if (Platform.OS_MACOSX.equals(Platform.getOS())) { logger.warn("Tray icon not loaded. Probably you are running a too old MacOSX version."); } else { logger.error(err, err); } } return null; } public void dispose() { disposeTray(); } void disposeTray() { if (trayItem != null && !trayItem.isDisposed()) { trayItem.setVisible(false); trayImage.dispose(); trayItem.dispose(); } } } /* *add menu * Tray tray = display.getSystemTray(); if(tray != null) { TrayItem item = new TrayItem(tray, SWT.NONE); item.setImage(image);final Menu menu = new Menu(shell, SWT.POP_UP); MenuItem menuItem = new MenuItem(menu, SWT.PUSH); menuItem.setText("Button A"); menuItem = new MenuItem(menu, SWT.PUSH); menuItem.setText("Button B"); menuItem = new MenuItem(menu, SWT.PUSH); menuItem.setText("Show Tooltip"); item.addListener (SWT.MenuDetect, new Listener () { public void handleEvent (Event event) { menu.setVisible (true); } }); } Recent releases of SWT (post-M5) finally support balloons/tooltips through the tray icon. Balloons are quite common in platforms with tray icons, so this is a nice feature to finally have. To add a tooltip, simply use the TrayItem.setToolTip(ToolTip) method, and set the visibility of the tooltip to true when you want to show it. final ToolTip tip = new ToolTip(shell, SWT.BALLOON | SWT.ICON_INFORMATION); tip.setMessage("Balloon Message Goes Here!"); Tray tray = display.getSystemTray(); if (tray != null) { TrayItem item = new TrayItem(tray, SWT.NONE); item.setImage(image); tip.setText("Balloon Title goes here."); item.setToolTip(tip); final Menu menu = new Menu(shell, SWT.POP_UP); MenuItem menuItem = new MenuItem(menu, SWT.PUSH); menuItem.setText("Button A"); menuItem = new MenuItem(menu, SWT.PUSH); menuItem.setText("Button B"); menuItem = new MenuItem(menu, SWT.PUSH); menuItem.setText("Show Tooltip"); // Add tooltip visibility to menu item. menuItem.addListener (SWT.Selection, new Listener () { public void handleEvent (Event e) { tip.setVisible(true); } }); // Add menu detection listener to tray icon. item.addListener (SWT.MenuDetect, new Listener () { public void handleEvent (Event event) { menu.setVisible (true); } }); } */