Java tutorial
/* * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * This component and the accompanying materials are made available * under the terms of the License "Eclipse Public License v1.0" * which accompanies this distribution, and is available * at the URL "http://www.eclipse.org/legal/epl-v10.html". * * Initial Contributors: * Nokia Corporation - initial contribution. * * Contributors: * * Description: * */ package com.nokia.carbide.remoteconnections.internal.ui; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import org.eclipse.jface.action.IContributionManager; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.GridLayoutFactory; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.CLabel; import org.eclipse.swt.events.MouseAdapter; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.MenuItem; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.ToolBar; import org.eclipse.swt.widgets.ToolItem; import org.eclipse.swt.widgets.ToolTip; import org.eclipse.ui.IViewPart; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.menus.CommandContributionItem; import org.eclipse.ui.menus.WorkbenchWindowControlContribution; import com.nokia.carbide.remoteconnections.Messages; import com.nokia.carbide.remoteconnections.RemoteConnectionsActivator; import com.nokia.carbide.remoteconnections.interfaces.IConnection; import com.nokia.carbide.remoteconnections.interfaces.IConnectionsManager; import com.nokia.carbide.remoteconnections.interfaces.IConnectionsManager.IConnectionListener; import com.nokia.carbide.remoteconnections.interfaces.IConnectionsManager.IConnectionsManagerListener; import com.nokia.carbide.remoteconnections.internal.api.IConnection2; import com.nokia.carbide.remoteconnections.internal.api.IConnection2.IConnectionStatus; import com.nokia.carbide.remoteconnections.internal.api.IConnection2.IConnectionStatusChangedListener; import com.nokia.carbide.remoteconnections.internal.registry.Registry; import com.nokia.carbide.remoteconnections.view.ConnectionsView; import com.nokia.cpp.internal.api.utils.core.TextUtils; import com.nokia.cpp.internal.api.utils.ui.WorkbenchUtils; /** * This widget appears in the Eclipse trim and allows the user to select the * "current" device connection and also see its status at a glance. * <p> * Note: the UI for this control should behave similarly to that of the News Reader * trim. Due to the way we're modifying the icon and the state dynamically * for this contribution, they can't be implemented the same way, however. */ @SuppressWarnings("deprecation") public class ConnectionStatusSelectorContribution extends WorkbenchWindowControlContribution { /** * This is the id on the command in the toolbar contribution associated with this * widget. Keep this in sync with the extension point! */ private static final String OPEN_REMOTE_CONNECTIONS_VIEW_COMMAND_ID = "openRemoteConnectionsView"; //$NON-NLS-1$ private Composite container; private CLabel connectionInfo; private ToolItem connectionIcon; private IConnectionsManager manager; private IConnection currentConnection; private ListenerBlock listenerBlock; private ToolTip tooltip; private MouseAdapter toolbarListener; private ToolBar toolbar; /** * Contains all the listeners. In most cases we just recreate the contribution status item. */ class ListenerBlock implements IConnectionListener, IConnectionsManagerListener, IConnectionStatusChangedListener { /* (non-Javadoc) * @see com.nokia.carbide.remoteconnections.interfaces.IConnectionsManager.IConnectionListener#connectionAdded(com.nokia.carbide.remoteconnections.interfaces.IConnection) */ public void connectionAdded(IConnection connection) { updateUI(); boolean display = (connection instanceof IConnection2 && ((IConnection2) connection).isDynamic()); if (display) launchBubble(MessageFormat.format( Messages.getString("ConnectionStatusSelectorContribution.AddedConnectionFormat"), //$NON-NLS-1$ connection.getDisplayName())); } /* (non-Javadoc) * @see com.nokia.carbide.remoteconnections.interfaces.IConnectionsManager.IConnectionListener#connectionRemoved(com.nokia.carbide.remoteconnections.interfaces.IConnection) */ public void connectionRemoved(IConnection connection) { updateUI(); boolean display = (connection instanceof IConnection2 && ((IConnection2) connection).isDynamic()); if (display) launchBubble(MessageFormat.format( Messages.getString("ConnectionStatusSelectorContribution.RemovedConnectionFormat"), //$NON-NLS-1$ connection.getDisplayName())); } /* (non-Javadoc) * @see com.nokia.carbide.remoteconnections.interfaces.IConnectionsManager.IConnectionListener#currentConnectionSet(com.nokia.carbide.remoteconnections.interfaces.IConnection) */ public void currentConnectionSet(IConnection connection) { updateUI(); } /* (non-Javadoc) * @see com.nokia.carbide.remoteconnections.interfaces.IConnectionsManager.IConnectionsManagerListener#connectionStoreChanged() */ public void connectionStoreChanged() { updateUI(); } /* (non-Javadoc) * @see com.nokia.carbide.remoteconnections.interfaces.IConnectionsManager.IConnectionsManagerListener#displayChanged() */ public void displayChanged() { updateUI(); } /* (non-Javadoc) * @see com.nokia.carbide.remoteconnections.internal.api.IConnection2.IConnectionStatusChangedListener#statusChanged(com.nokia.carbide.remoteconnections.internal.api.IConnection2.IConnectionStatus) */ public void statusChanged(IConnectionStatus status) { updateConnectionStatus(status); } } public ConnectionStatusSelectorContribution() { manager = RemoteConnectionsActivator.getConnectionsManager(); listenerBlock = new ListenerBlock(); } /* * (non-Javadoc) * @see org.eclipse.jface.action.ControlContribution#createControl(org.eclipse.swt.widgets.Composite) */ @Override protected Control createControl(Composite parent) { // This UI is recreated whenever the current connection changes. removeListeners(); // This is gross. The normal parent of this is a toolbar, // but we cannot add arbitrary stuff to the toolbar besides // this control. (If you try, it will usually show up // out of order!) // // But we want to have a toolbar button for the connection icon // for which we can change the tooltip and image, and attach // a mouse listener responds to left and right clicking. // // In order to do this, we need to poke around in the widget tree // to find the expected Eclipse-generated toolitem. Unfortunately, // controlling all this ourselves is even uglier (I tried). if (parent instanceof ToolBar) { toolbar = (ToolBar) parent; ToolItem[] items = toolbar.getItems(); for (ToolItem item : items) { Object data = item.getData(); if (data instanceof CommandContributionItem && ((CommandContributionItem) data).getId() .contains(OPEN_REMOTE_CONNECTIONS_VIEW_COMMAND_ID)) { connectionIcon = item; break; } } } else { toolbar = null; } container = new Composite(parent, SWT.NONE); GridLayoutFactory.fillDefaults().margins(2, 0).applyTo(container); // Create a label for the trim, outside the toolbar. connectionInfo = new CLabel(container, SWT.NONE); GridDataFactory.fillDefaults().grab(false, true).applyTo(connectionInfo); String text = Messages.getString("ConnectionStatusSelectorContribution_NoCurrentConnectionMessage"); //$NON-NLS-1$ currentConnection = manager.getCurrentConnection(); if (currentConnection != null) text = currentConnection.getDisplayName(); connectionInfo.setText(text); attachListeners(); updateConnectionStatus(getConnectionStatus(currentConnection)); // Yuck, toolbars and items have a wonky UI. We need to do these events on the parent, // since the ToolItem itself is just an area inside the parent. (#getControl() is only for separators ?!) // On icon: left click = open view, right click = menu if (toolbar != null) { if (toolbarListener != null) toolbar.removeMouseListener(toolbarListener); toolbarListener = new MouseAdapter() { /* (non-Javadoc) * @see org.eclipse.swt.events.MouseAdapter#mouseDown(org.eclipse.swt.events.MouseEvent) */ @Override public void mouseDown(MouseEvent event) { ToolItem item = toolbar.getItem(new Point(event.x, event.y)); if (item == connectionIcon) { if (event.button == 1) { openConnectionsView(); } else if (event.button == 3) { Point screenLoc = toolbar.toDisplay(event.x, event.y); handleConnectionMenu(screenLoc); } } } }; toolbar.addMouseListener(toolbarListener); // On label: left or right click = menu connectionInfo.addMouseListener(new MouseAdapter() { public void mouseDown(MouseEvent event) { if (event.button == 1 || event.button == 3) { Point screenLoc = toolbar.toDisplay(event.x, event.y); handleConnectionMenu(screenLoc); } } }); } RemoteConnectionsActivator.setHelp(container, "ConnectionStatusSelector"); //$NON-NLS-1$ return container; } private void handleConnectionMenu(Point screenLoc) { Shell shell = connectionInfo.getParent().getShell(); final Display display = shell.getDisplay(); final Menu menu = new Menu(shell, SWT.POP_UP); populateConnectionMenu(menu); menu.setLocation(screenLoc.x, screenLoc.y); menu.setVisible(true); while (!menu.isDisposed() && menu.isVisible()) { if (!display.readAndDispatch()) display.sleep(); } menu.dispose(); } /** * @return */ protected void populateConnectionMenu(Menu menu) { // Display the connections with dynamic ones first, // then static ones, separated by a separator List<IConnection> dynamicConnections = new ArrayList<IConnection>(); List<IConnection> staticConnections = new ArrayList<IConnection>(); for (IConnection connection : RemoteConnectionsActivator.getConnectionsManager().getConnections()) { if (connection instanceof IConnection2 && ((IConnection2) connection).isDynamic()) dynamicConnections.add(connection); else staticConnections.add(connection); } Comparator<IConnection> connectionComparator = new Comparator<IConnection>() { public int compare(IConnection o1, IConnection o2) { return o1.getDisplayName().compareToIgnoreCase(o2.getDisplayName()); } }; Collections.sort(dynamicConnections, connectionComparator); Collections.sort(staticConnections, connectionComparator); MenuItem label = new MenuItem(menu, SWT.NONE); label.setEnabled(false); int number = 1; if (dynamicConnections.size() + staticConnections.size() == 0) { label.setText( Messages.getString("ConnectionStatusSelectorContribution.NoConnectionsDefinedOrDetected")); //$NON-NLS-1$ } else { label.setText( Messages.getString("ConnectionStatusSelectorContribution_SelectTheCurrentConnectionMessage")); //$NON-NLS-1$ for (IConnection connection : dynamicConnections) { createConnectionMenuItem(menu, connection, currentConnection, number++); } if (!staticConnections.isEmpty()) new MenuItem(menu, SWT.SEPARATOR); for (IConnection connection : staticConnections) { createConnectionMenuItem(menu, connection, currentConnection, number++); } } new MenuItem(menu, SWT.SEPARATOR); MenuItem openView = new MenuItem(menu, SWT.PUSH); openView.setText(Messages.getString("ConnectionStatusSelectorContribution.OpenRemoteConnectionsView")); //$NON-NLS-1$ openView.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { openConnectionsView(); } }); new MenuItem(menu, SWT.SEPARATOR); final MenuItem toggleServicesTestingItem = new MenuItem(menu, SWT.CHECK); toggleServicesTestingItem .setText(Messages.getString("ConnectionStatusSelectorContribution.TestServicesMenuLabel")); //$NON-NLS-1$ toggleServicesTestingItem.setSelection(RemoteConnectionsActivator.getDefault().getShouldTestServices()); toggleServicesTestingItem.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { boolean state = !RemoteConnectionsActivator.getDefault().getShouldTestServices(); RemoteConnectionsActivator.getDefault().setShouldTestServices(state); toggleServicesTestingItem.setSelection(state); } }); } /** * @param menu * @param connection * @param currentConnection */ private MenuItem createConnectionMenuItem(Menu menu, final IConnection connection, IConnection currentConnection, int number) { MenuItem item = new MenuItem(menu, SWT.CHECK); boolean isCurrent = false; isCurrent = connection.equals(currentConnection); item.setSelection(isCurrent); item.setText(MessageFormat.format("&{0} - {1}", number, connection.getDisplayName())); //$NON-NLS-1$ item.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { manager.setCurrentConnection(connection); } }); return item; } private void attachListeners() { manager.addConnectionListener(listenerBlock); Registry.instance().addConnectionStoreChangedListener(listenerBlock); if (currentConnection != null) { if (currentConnection instanceof IConnection2) { ((IConnection2) currentConnection).addStatusChangedListener(listenerBlock); } } } private void removeListeners() { if (currentConnection != null) { if (currentConnection instanceof IConnection2) { ((IConnection2) currentConnection).removeStatusChangedListener(listenerBlock); } } manager.removeConnectionListener(listenerBlock); Registry.instance().removeConnectionStoreChangedListener(listenerBlock); } /* * (non-Javadoc) * @see org.eclipse.jface.action.ContributionItem#dispose() */ public void dispose() { removeListeners(); if (connectionIcon != null) connectionIcon.dispose(); if (toolbarListener != null && !toolbar.isDisposed()) toolbar.removeMouseListener(toolbarListener); if (connectionInfo != null) connectionInfo.dispose(); super.dispose(); } /** * @param ev */ protected void openConnectionsView() { try { IViewPart view = WorkbenchUtils.getView(ConnectionsView.VIEW_ID); if (currentConnection != null && view instanceof ConnectionsView) { ((ConnectionsView) view).setSelectedConnection(currentConnection); } } catch (PartInitException e) { RemoteConnectionsActivator.logError(e); } } /** * @param currentConnection * @param status * @return */ private String createConnectionStatusTooltip(IConnection currentConnection, IConnectionStatus status) { if (currentConnection == null) { return Messages.getString("ConnectionStatusSelectorContribution.NoDynamicOrManualConnectionsTooltip"); //$NON-NLS-1$ } String statusString = null; if (status != null) { statusString = createStatusString(status); } if (TextUtils.isEmpty(statusString)) { // fallback string; the status should not be empty if (ConnectionUIUtils.isSomeServiceInUse(currentConnection)) statusString = Messages.getString("ConnectionStatusSelectorContribution.InUse"); //$NON-NLS-1$ else statusString = Messages.getString("ConnectionStatusSelectorContribution.NotInUse"); //$NON-NLS-1$ } return MessageFormat.format( Messages.getString("ConnectionStatusSelectorContribution.ConnectionStatusFormat"), //$NON-NLS-1$ currentConnection.getDisplayName(), statusString); } private String createStatusString(IConnectionStatus status) { String shortDescription = status.getShortDescription(); if (shortDescription == null || shortDescription.length() == 0) return ""; //$NON-NLS-1$ String pattern = Messages.getString("ConnectionStatusSelectorContribution.StatusFormat"); //$NON-NLS-1$ if (shortDescription != null) shortDescription = shortDescription.toLowerCase(); return MessageFormat.format(pattern, shortDescription, status.getLongDescription()); } /** * Get the image representing the connection status. * @param connection * @return Image, to be disposed */ private IConnectionStatus getConnectionStatus(IConnection connection) { if (!(connection instanceof IConnection2)) { return null; } else { return ((IConnection2) connection).getStatus(); } } /** * @param status */ private void updateConnectionStatus(final IConnectionStatus status) { Display.getDefault().asyncExec(new Runnable() { public void run() { if (connectionIcon == null || connectionIcon.isDisposed()) return; Image statusImage; if (status != null) statusImage = ConnectionUIUtils.getConnectionStatusImage(status); else statusImage = ConnectionUIUtils.getConnectionImage(currentConnection); connectionIcon.setImage(statusImage); String tip = createConnectionStatusTooltip(currentConnection, status); connectionInfo.setToolTipText(tip); String preamble = Messages .getString("ConnectionStatusSelectorContribution.IconTooltipPrefixMessage"); //$NON-NLS-1$ connectionIcon.setToolTipText(preamble + tip); } }); } /** * */ private void updateUI() { // perform update in UI thread final IWorkbench workbench = PlatformUI.getWorkbench(); workbench.getDisplay().asyncExec(new Runnable() { public void run() { IWorkbenchWindow window = workbench.getActiveWorkbenchWindow(); if (window != null) { update(); } } }); } /* * (non-Javadoc) * @see org.eclipse.jface.action.ContributionItem#isDynamic() */ @Override public boolean isDynamic() { return true; } /* * (non-Javadoc) * @see org.eclipse.jface.action.ContributionItem#update() */ @Override public void update() { IContributionManager parent = getParent(); if (parent != null) parent.update(true); } /** * Show a status bubble for important changes. * @param string */ public void launchBubble(final String string) { Display.getDefault().asyncExec(new Runnable() { public void run() { if (tooltip != null) tooltip.dispose(); if (connectionInfo == null || connectionInfo.isDisposed()) return; tooltip = new ToolTip(connectionInfo.getParent().getShell(), SWT.BALLOON | SWT.ICON_INFORMATION); tooltip.setMessage(string); Rectangle bounds = connectionInfo.getBounds(); Point center = new Point(bounds.x + bounds.width / 2, bounds.y + bounds.height); Point location = connectionInfo.getParent().toDisplay(center); //System.out.println(connectionInfo.hashCode() + ": " + connectionInfo.getLocation() + " : " + location); tooltip.setLocation(location); tooltip.setVisible(true); } }); } }