31 import org.eclipse.swt.events.MouseEvent; |
31 import org.eclipse.swt.events.MouseEvent; |
32 import org.eclipse.swt.events.SelectionAdapter; |
32 import org.eclipse.swt.events.SelectionAdapter; |
33 import org.eclipse.swt.events.SelectionEvent; |
33 import org.eclipse.swt.events.SelectionEvent; |
34 import org.eclipse.swt.graphics.Image; |
34 import org.eclipse.swt.graphics.Image; |
35 import org.eclipse.swt.graphics.Point; |
35 import org.eclipse.swt.graphics.Point; |
|
36 import org.eclipse.swt.graphics.Rectangle; |
36 import org.eclipse.swt.widgets.Composite; |
37 import org.eclipse.swt.widgets.Composite; |
37 import org.eclipse.swt.widgets.Control; |
38 import org.eclipse.swt.widgets.Control; |
38 import org.eclipse.swt.widgets.Display; |
39 import org.eclipse.swt.widgets.Display; |
39 import org.eclipse.swt.widgets.Menu; |
40 import org.eclipse.swt.widgets.Menu; |
40 import org.eclipse.swt.widgets.MenuItem; |
41 import org.eclipse.swt.widgets.MenuItem; |
41 import org.eclipse.swt.widgets.Shell; |
42 import org.eclipse.swt.widgets.Shell; |
|
43 import org.eclipse.swt.widgets.ToolBar; |
|
44 import org.eclipse.swt.widgets.ToolItem; |
42 import org.eclipse.swt.widgets.ToolTip; |
45 import org.eclipse.swt.widgets.ToolTip; |
43 import org.eclipse.ui.IWorkbench; |
46 import org.eclipse.ui.IWorkbench; |
44 import org.eclipse.ui.IWorkbenchWindow; |
47 import org.eclipse.ui.IWorkbenchWindow; |
45 import org.eclipse.ui.PartInitException; |
48 import org.eclipse.ui.PartInitException; |
46 import org.eclipse.ui.PlatformUI; |
49 import org.eclipse.ui.PlatformUI; |
|
50 import org.eclipse.ui.menus.CommandContributionItem; |
47 import org.eclipse.ui.menus.WorkbenchWindowControlContribution; |
51 import org.eclipse.ui.menus.WorkbenchWindowControlContribution; |
48 |
52 |
49 import com.nokia.carbide.remoteconnections.Messages; |
53 import com.nokia.carbide.remoteconnections.Messages; |
50 import com.nokia.carbide.remoteconnections.RemoteConnectionsActivator; |
54 import com.nokia.carbide.remoteconnections.RemoteConnectionsActivator; |
51 import com.nokia.carbide.remoteconnections.interfaces.IConnectedService; |
55 import com.nokia.carbide.remoteconnections.interfaces.IConnectedService; |
64 import com.nokia.cpp.internal.api.utils.ui.WorkbenchUtils; |
68 import com.nokia.cpp.internal.api.utils.ui.WorkbenchUtils; |
65 |
69 |
66 |
70 |
67 /** |
71 /** |
68 * This widget appears in the Eclipse trim and allows the user to select the |
72 * This widget appears in the Eclipse trim and allows the user to select the |
69 * "default" device connection and also see its status at a glance. |
73 * "default" device connection and also see its status at a glance. |
|
74 * <p> |
|
75 * Note: the UI for this control should behave similarly to that of the News Reader |
|
76 * trim. Due to the way we're modifying the icon and the state dynamically |
|
77 * for this contribution, they can't be implemented the same way, however. |
70 */ |
78 */ |
71 @SuppressWarnings("deprecation") |
79 @SuppressWarnings("deprecation") |
72 public class ConnectionStatusSelectorContribution extends WorkbenchWindowControlContribution { |
80 public class ConnectionStatusSelectorContribution extends WorkbenchWindowControlContribution { |
73 |
81 |
|
82 /** |
|
83 * This is a portion of the ICommand id used for the icon in the |
|
84 * widget. Keep this in sync with the extension point! |
|
85 */ |
|
86 private static final String OPEN_REMOTE_CONNECTIONS_VIEW_COMMAND_SUFFIX = "openRemoteConnectionsView"; |
74 private Composite container; |
87 private Composite container; |
75 private CLabel connectionInfo; |
88 private CLabel connectionInfo; |
|
89 private ToolItem connectionIcon; |
76 private IConnectionsManager manager; |
90 private IConnectionsManager manager; |
77 private IConnection defaultConnection; |
91 private IConnection defaultConnection; |
78 private ListenerBlock listenerBlock; |
92 private ListenerBlock listenerBlock; |
79 private ToolTip tooltip; |
93 private ToolTip tooltip; |
|
94 private MouseAdapter toolbarListener; |
80 |
95 |
81 /** |
96 /** |
82 * Contains all the listeners. In most cases we just recreate the contribution status item. |
97 * Contains all the listeners. In most cases we just recreate the contribution status item. |
83 */ |
98 */ |
84 class ListenerBlock implements IConnectionListener, IConnectionsManagerListener, IStatusChangedListener, IConnectionStatusChangedListener { |
99 class ListenerBlock implements IConnectionListener, IConnectionsManagerListener, IStatusChangedListener, IConnectionStatusChangedListener { |
86 /* (non-Javadoc) |
101 /* (non-Javadoc) |
87 * @see com.nokia.carbide.remoteconnections.interfaces.IConnectionsManager.IConnectionListener#connectionAdded(com.nokia.carbide.remoteconnections.interfaces.IConnection) |
102 * @see com.nokia.carbide.remoteconnections.interfaces.IConnectionsManager.IConnectionListener#connectionAdded(com.nokia.carbide.remoteconnections.interfaces.IConnection) |
88 */ |
103 */ |
89 public void connectionAdded(IConnection connection) { |
104 public void connectionAdded(IConnection connection) { |
90 updateUI(); |
105 updateUI(); |
91 if (connection instanceof IConnection2 && ((IConnection2) connection).isDynamic()) |
106 boolean display = (connection instanceof IConnection2 && ((IConnection2) connection).isDynamic()); |
|
107 if (display) |
92 launchBubble(MessageFormat.format( |
108 launchBubble(MessageFormat.format( |
93 Messages.getString("ConnectionStatusSelectorContribution.AddedConnectionFormat"), //$NON-NLS-1$ |
109 Messages.getString("ConnectionStatusSelectorContribution.AddedConnectionFormat"), //$NON-NLS-1$ |
94 connection.getDisplayName())); |
110 connection.getDisplayName())); |
95 } |
111 } |
96 |
112 |
97 /* (non-Javadoc) |
113 /* (non-Javadoc) |
98 * @see com.nokia.carbide.remoteconnections.interfaces.IConnectionsManager.IConnectionListener#connectionRemoved(com.nokia.carbide.remoteconnections.interfaces.IConnection) |
114 * @see com.nokia.carbide.remoteconnections.interfaces.IConnectionsManager.IConnectionListener#connectionRemoved(com.nokia.carbide.remoteconnections.interfaces.IConnection) |
99 */ |
115 */ |
100 public void connectionRemoved(IConnection connection) { |
116 public void connectionRemoved(IConnection connection) { |
101 updateUI(); |
117 updateUI(); |
102 if (connection instanceof IConnection2 && ((IConnection2) connection).isDynamic()) |
118 boolean display = (connection instanceof IConnection2 && ((IConnection2) connection).isDynamic()); |
|
119 if (display) |
103 launchBubble(MessageFormat.format( |
120 launchBubble(MessageFormat.format( |
104 Messages.getString("ConnectionStatusSelectorContribution.RemovedConnectionFormat"), //$NON-NLS-1$ |
121 Messages.getString("ConnectionStatusSelectorContribution.RemovedConnectionFormat"), //$NON-NLS-1$ |
105 connection.getDisplayName())); |
122 connection.getDisplayName())); |
106 } |
123 } |
107 |
124 |
154 @Override |
171 @Override |
155 protected Control createControl(Composite parent) { |
172 protected Control createControl(Composite parent) { |
156 |
173 |
157 // This UI is recreated whenever the default connection changes. |
174 // This UI is recreated whenever the default connection changes. |
158 |
175 |
|
176 // This is gross. The normal parent of this is a toolbar, |
|
177 // but we cannot add arbitrary stuff to the toolbar besides |
|
178 // this control. (If you try, it will usually show up |
|
179 // out of order!) |
|
180 // |
|
181 // But we want to have a toolbar button for the connection icon |
|
182 // for which we can change the tooltip and image, and attach |
|
183 // a mouse listener responds to left and right clicking. |
|
184 // |
|
185 // In order to do this, we need to poke around in the widget tree |
|
186 // to find the expected Eclipse-generated toolitem. Unfortunately, |
|
187 // controlling all this ourselves is even uglier (I tried). |
|
188 |
|
189 final ToolBar toolbar; |
|
190 if (parent instanceof ToolBar) { |
|
191 toolbar = (ToolBar) parent; |
|
192 ToolItem[] items = toolbar.getItems(); |
|
193 for (ToolItem item : items) { |
|
194 Object data = item.getData(); |
|
195 if (data instanceof CommandContributionItem && |
|
196 ((CommandContributionItem) data).getId().contains(OPEN_REMOTE_CONNECTIONS_VIEW_COMMAND_SUFFIX)) { |
|
197 connectionIcon = item; |
|
198 break; |
|
199 } |
|
200 } |
|
201 } else { |
|
202 toolbar = null; |
|
203 } |
|
204 |
159 container = new Composite(parent, SWT.NONE); |
205 container = new Composite(parent, SWT.NONE); |
160 GridLayoutFactory.fillDefaults().margins(2, 0).applyTo(container); |
206 GridLayoutFactory.fillDefaults().margins(2, 0).applyTo(container); |
161 |
207 |
162 // Create a label for the trim. |
208 // Create a label for the trim, outside the toolbar. |
163 connectionInfo = new CLabel(container, SWT.FLAT); |
209 connectionInfo = new CLabel(container, SWT.NONE); |
164 GridDataFactory.fillDefaults().grab(false, true).applyTo(connectionInfo); |
210 GridDataFactory.fillDefaults().grab(false, true).applyTo(connectionInfo); |
165 |
211 |
166 String text = Messages.getString("ConnectionStatusSelectorContribution_NoDefaultConnectionMessage"); //$NON-NLS-1$ |
212 String text = Messages.getString("ConnectionStatusSelectorContribution_NoDefaultConnectionMessage"); //$NON-NLS-1$ |
167 defaultConnection = manager.getDefaultConnection(); |
213 defaultConnection = manager.getDefaultConnection(); |
168 if (defaultConnection != null) |
214 if (defaultConnection != null) |
172 |
218 |
173 attachListeners(); |
219 attachListeners(); |
174 |
220 |
175 updateConnectionStatus(getConnectionStatus(defaultConnection)); |
221 updateConnectionStatus(getConnectionStatus(defaultConnection)); |
176 |
222 |
177 connectionInfo.addMouseListener (new MouseAdapter() { |
223 |
178 public void mouseDown(MouseEvent event) { |
224 // Yuck, toolbars and items have a wonky UI. We need to do these events on the parent, |
179 Shell shell = connectionInfo.getShell(); |
225 // since the ToolItem itself is just an area inside the parent. (#getControl() is only for separators ?!) |
180 final Display display = shell.getDisplay(); |
226 |
181 |
227 // On icon: left click = open view, right click = menu |
182 final Menu menu = new Menu(shell, SWT.POP_UP); |
228 |
183 populateConnectionMenu(menu); |
229 if (toolbar != null) { |
184 |
230 if (toolbarListener != null) |
185 Point screenLoc = connectionInfo.toDisplay(event.x, event.y); |
231 toolbar.removeMouseListener(toolbarListener); |
186 menu.setLocation(screenLoc.x, screenLoc.y); |
232 |
187 menu.setVisible(true); |
233 toolbarListener = new MouseAdapter() { |
188 |
234 /* (non-Javadoc) |
189 while (!menu.isDisposed() && menu.isVisible()) { |
235 * @see org.eclipse.swt.events.MouseAdapter#mouseDown(org.eclipse.swt.events.MouseEvent) |
190 if (!display.readAndDispatch()) |
236 */ |
191 display.sleep(); |
237 @Override |
|
238 public void mouseDown(MouseEvent event) { |
|
239 ToolItem item = toolbar.getItem(new Point(event.x, event.y)); |
|
240 if (item == connectionIcon) { |
|
241 if (event.button == 1) { |
|
242 openConnectionsView(); |
|
243 } else if (event.button == 3) { |
|
244 Point screenLoc = toolbar.toDisplay(event.x, event.y); |
|
245 handleConnectionMenu(screenLoc); |
|
246 } |
|
247 } |
192 } |
248 } |
193 menu.dispose(); |
249 }; |
194 } |
250 toolbar.addMouseListener(toolbarListener); |
195 /* (non-Javadoc) |
251 |
196 * @see org.eclipse.swt.events.MouseAdapter#mouseDoubleClick(org.eclipse.swt.events.MouseEvent) |
252 // On label: left or right click = menu |
197 */ |
253 connectionInfo.addMouseListener(new MouseAdapter() { |
198 @Override |
254 public void mouseDown(MouseEvent event) { |
199 public void mouseDoubleClick(MouseEvent ev) { |
255 if (event.button == 1 || event.button == 3) { |
200 // NOTE: the menu usually comes up before double-click is seen |
256 Point screenLoc = toolbar.toDisplay(event.x, event.y); |
201 if (ev.button == 1) { |
257 handleConnectionMenu(screenLoc); |
202 openConnectionsView(); |
258 } |
203 } |
259 } |
204 } |
260 }); |
205 }); |
261 } |
206 |
262 |
207 RemoteConnectionsActivator.setHelp(container, "ConnectionStatusSelector"); //$NON-NLS-1$ |
263 RemoteConnectionsActivator.setHelp(container, "ConnectionStatusSelector"); //$NON-NLS-1$ |
208 return container; |
264 return container; |
|
265 } |
|
266 |
|
267 private void handleConnectionMenu(Point screenLoc) { |
|
268 Shell shell = connectionInfo.getParent().getShell(); |
|
269 final Display display = shell.getDisplay(); |
|
270 |
|
271 final Menu menu = new Menu(shell, SWT.POP_UP); |
|
272 populateConnectionMenu(menu); |
|
273 |
|
274 menu.setLocation(screenLoc.x, screenLoc.y); |
|
275 menu.setVisible(true); |
|
276 |
|
277 while (!menu.isDisposed() && menu.isVisible()) { |
|
278 if (!display.readAndDispatch()) |
|
279 display.sleep(); |
|
280 } |
|
281 menu.dispose(); |
|
282 |
|
283 } |
|
284 |
|
285 /** |
|
286 * @return |
|
287 */ |
|
288 protected void populateConnectionMenu(Menu menu) { |
|
289 // Display the connections with dynamic ones first, |
|
290 // then static ones, separated by a separator |
|
291 |
|
292 List<IConnection> dynamicConnections = new ArrayList<IConnection>(); |
|
293 List<IConnection> staticConnections = new ArrayList<IConnection>(); |
|
294 for (IConnection connection : RemoteConnectionsActivator.getConnectionsManager().getConnections()) { |
|
295 if (connection instanceof IConnection2 && ((IConnection2)connection).isDynamic()) |
|
296 dynamicConnections.add(connection); |
|
297 else |
|
298 staticConnections.add(connection); |
|
299 } |
|
300 |
|
301 |
|
302 Comparator<IConnection> connectionComparator = new Comparator<IConnection>() { |
|
303 public int compare(IConnection o1, IConnection o2) { |
|
304 return o1.getDisplayName().compareToIgnoreCase(o2.getDisplayName()); |
|
305 } |
|
306 }; |
|
307 Collections.sort(dynamicConnections, connectionComparator); |
|
308 Collections.sort(staticConnections, connectionComparator); |
|
309 |
|
310 MenuItem label = new MenuItem(menu, SWT.NONE); |
|
311 label.setEnabled(false); |
|
312 |
|
313 int number = 1; |
|
314 if (dynamicConnections.size() + staticConnections.size() == 0) { |
|
315 label.setText(Messages.getString("ConnectionStatusSelectorContribution.NoConnectionsDefinedOrDetected")); //$NON-NLS-1$ |
|
316 } else { |
|
317 label.setText(Messages.getString("ConnectionStatusSelectorContribution_SelectTheDefaultConnectionMessage")); //$NON-NLS-1$ |
|
318 |
|
319 for (IConnection connection : dynamicConnections) { |
|
320 createConnectionMenuItem(menu, connection, defaultConnection, number++); |
|
321 } |
|
322 |
|
323 new MenuItem(menu, SWT.SEPARATOR); |
|
324 |
|
325 for (IConnection connection : staticConnections) { |
|
326 createConnectionMenuItem(menu, connection, defaultConnection, number++); |
|
327 } |
|
328 } |
|
329 |
|
330 new MenuItem(menu, SWT.SEPARATOR); |
|
331 |
|
332 MenuItem openView = new MenuItem(menu, SWT.PUSH); |
|
333 openView.setText(Messages.getString("ConnectionStatusSelectorContribution.OpenRemoteConnectionsView")); //$NON-NLS-1$ |
|
334 openView.addSelectionListener(new SelectionAdapter() { |
|
335 @Override |
|
336 public void widgetSelected(SelectionEvent e) { |
|
337 openConnectionsView(); |
|
338 } |
|
339 }); |
|
340 } |
|
341 |
|
342 /** |
|
343 * @param menu |
|
344 * @param connection |
|
345 * @param defaultConnection |
|
346 */ |
|
347 private MenuItem createConnectionMenuItem(Menu menu, |
|
348 final IConnection connection, |
|
349 IConnection defaultConnection, |
|
350 int number) { |
|
351 MenuItem item = new MenuItem(menu, SWT.CHECK); |
|
352 |
|
353 boolean isDefault = false; |
|
354 isDefault = connection.equals(defaultConnection); |
|
355 |
|
356 item.setSelection(isDefault); |
|
357 |
|
358 item.setText("&" + number + " - " + connection.getDisplayName()); |
|
359 |
|
360 item.addSelectionListener(new SelectionAdapter() { |
|
361 @Override |
|
362 public void widgetSelected(SelectionEvent e) { |
|
363 manager.setDefaultConnection(connection); |
|
364 } |
|
365 }); |
|
366 |
|
367 return item; |
209 } |
368 } |
210 |
369 |
211 private void attachListeners() { |
370 private void attachListeners() { |
212 manager.addConnectionListener(listenerBlock); |
371 manager.addConnectionListener(listenerBlock); |
213 Registry.instance().addConnectionStoreChangedListener(listenerBlock); |
372 Registry.instance().addConnectionStoreChangedListener(listenerBlock); |
297 return ((IConnection2) connection).getStatus(); |
462 return ((IConnection2) connection).getStatus(); |
298 } |
463 } |
299 } |
464 } |
300 |
465 |
301 /** |
466 /** |
302 * @return |
|
303 */ |
|
304 protected void populateConnectionMenu(Menu menu) { |
|
305 // Display the connections with dynamic ones first, |
|
306 // then static ones, separated by a separator |
|
307 |
|
308 List<IConnection> dynamicConnections = new ArrayList<IConnection>(); |
|
309 List<IConnection> staticConnections = new ArrayList<IConnection>(); |
|
310 for (IConnection connection : RemoteConnectionsActivator.getConnectionsManager().getConnections()) { |
|
311 if (connection instanceof IConnection2 && ((IConnection2)connection).isDynamic()) |
|
312 dynamicConnections.add(connection); |
|
313 else |
|
314 staticConnections.add(connection); |
|
315 } |
|
316 |
|
317 |
|
318 Comparator<IConnection> connectionComparator = new Comparator<IConnection>() { |
|
319 public int compare(IConnection o1, IConnection o2) { |
|
320 return o1.getDisplayName().compareToIgnoreCase(o2.getDisplayName()); |
|
321 } |
|
322 }; |
|
323 Collections.sort(dynamicConnections, connectionComparator); |
|
324 Collections.sort(staticConnections, connectionComparator); |
|
325 |
|
326 MenuItem label = new MenuItem(menu, SWT.NONE); |
|
327 label.setEnabled(false); |
|
328 |
|
329 if (dynamicConnections.size() + staticConnections.size() == 0) { |
|
330 label.setText(Messages.getString("ConnectionStatusSelectorContribution.NoConnectionsDefinedOrDetected")); //$NON-NLS-1$ |
|
331 } else { |
|
332 label.setText(Messages.getString("ConnectionStatusSelectorContribution_SelectTheDefaultConnectionMessage")); //$NON-NLS-1$ |
|
333 |
|
334 for (IConnection connection : dynamicConnections) { |
|
335 createConnectionMenuItem(menu, connection, defaultConnection); |
|
336 } |
|
337 |
|
338 new MenuItem(menu, SWT.SEPARATOR); |
|
339 |
|
340 for (IConnection connection : staticConnections) { |
|
341 createConnectionMenuItem(menu, connection, defaultConnection); |
|
342 } |
|
343 } |
|
344 |
|
345 new MenuItem(menu, SWT.SEPARATOR); |
|
346 |
|
347 MenuItem openView = new MenuItem(menu, SWT.PUSH); |
|
348 openView.setText(Messages.getString("ConnectionStatusSelectorContribution.OpenRemoteConnectionsView")); //$NON-NLS-1$ |
|
349 openView.addSelectionListener(new SelectionAdapter() { |
|
350 @Override |
|
351 public void widgetSelected(SelectionEvent e) { |
|
352 openConnectionsView(); |
|
353 } |
|
354 }); |
|
355 } |
|
356 |
|
357 /** |
|
358 * @param menu |
|
359 * @param connection |
|
360 * @param defaultConnection |
|
361 */ |
|
362 private MenuItem createConnectionMenuItem(Menu menu, final IConnection connection, IConnection defaultConnection) { |
|
363 MenuItem item = new MenuItem(menu, SWT.CHECK); |
|
364 |
|
365 boolean isDefault = false; |
|
366 isDefault = connection.equals(defaultConnection); |
|
367 |
|
368 item.setSelection(isDefault); |
|
369 |
|
370 item.setText(connection.getDisplayName()); |
|
371 |
|
372 item.addSelectionListener(new SelectionAdapter() { |
|
373 @Override |
|
374 public void widgetSelected(SelectionEvent e) { |
|
375 manager.setDefaultConnection(connection); |
|
376 } |
|
377 }); |
|
378 |
|
379 return item; |
|
380 } |
|
381 |
|
382 /** |
|
383 * @param status |
467 * @param status |
384 */ |
468 */ |
385 private void updateConnectionStatus(final IConnectionStatus status) { |
469 private void updateConnectionStatus(final IConnectionStatus status) { |
386 Display.getDefault().syncExec(new Runnable() { |
470 Display.getDefault().syncExec(new Runnable() { |
387 public void run() { |
471 public void run() { |
388 if (connectionInfo.isDisposed()) |
472 if (connectionIcon == null || connectionIcon.isDisposed()) |
389 return; |
473 return; |
390 |
474 |
391 Image statusImage; |
475 Image statusImage; |
392 if (status != null) |
476 if (status != null) |
393 statusImage = ConnectionUIUtils.getConnectionStatusImage(status); |
477 statusImage = ConnectionUIUtils.getConnectionStatusImage(status); |
394 else |
478 else |
395 statusImage = ConnectionUIUtils.getConnectionImage(defaultConnection); |
479 statusImage = ConnectionUIUtils.getConnectionImage(defaultConnection); |
396 |
480 |
397 connectionInfo.setImage(statusImage); |
481 connectionIcon.setImage(statusImage); |
398 connectionInfo.setToolTipText(createConnectionStatusTooltip(defaultConnection, status)); |
482 String tip = createConnectionStatusTooltip(defaultConnection, status); |
|
483 connectionInfo.setToolTipText(tip); |
|
484 |
|
485 String preamble = "Click to open the Remote Connections View.\n\n"; |
|
486 connectionIcon.setToolTipText(preamble + tip); |
399 } |
487 } |
400 }); |
488 }); |
401 |
489 |
402 } |
490 } |
403 |
491 |