fa1b94c98362389ff1ba4bbb52989961a0271d9e
[public/netxms.git] / src / java / netxms-eclipse / NetworkMaps / src / org / netxms / ui / eclipse / networkmaps / views / NetworkMap.java
1 /**
2 * NetXMS - open source network management system
3 * Copyright (C) 2003-2010 Victor Kirhenshtein
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
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 License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 package org.netxms.ui.eclipse.networkmaps.views;
20
21 import java.util.ArrayList;
22 import java.util.Comparator;
23 import java.util.HashSet;
24 import java.util.Iterator;
25 import java.util.List;
26 import java.util.Set;
27
28 import org.eclipse.core.runtime.IProgressMonitor;
29 import org.eclipse.core.runtime.IStatus;
30 import org.eclipse.core.runtime.Status;
31 import org.eclipse.jface.action.Action;
32 import org.eclipse.jface.action.GroupMarker;
33 import org.eclipse.jface.action.IContributionItem;
34 import org.eclipse.jface.action.IMenuListener;
35 import org.eclipse.jface.action.IMenuManager;
36 import org.eclipse.jface.action.IToolBarManager;
37 import org.eclipse.jface.action.MenuManager;
38 import org.eclipse.jface.action.Separator;
39 import org.eclipse.jface.viewers.ISelection;
40 import org.eclipse.jface.viewers.ISelectionChangedListener;
41 import org.eclipse.jface.viewers.ISelectionProvider;
42 import org.eclipse.jface.viewers.IStructuredSelection;
43 import org.eclipse.jface.viewers.SelectionChangedEvent;
44 import org.eclipse.jface.viewers.StructuredSelection;
45 import org.eclipse.swt.SWT;
46 import org.eclipse.swt.layout.FillLayout;
47 import org.eclipse.swt.widgets.Composite;
48 import org.eclipse.swt.widgets.Menu;
49 import org.eclipse.ui.IActionBars;
50 import org.eclipse.ui.IViewSite;
51 import org.eclipse.ui.IWorkbenchActionConstants;
52 import org.eclipse.ui.PartInitException;
53 import org.eclipse.ui.dialogs.PropertyDialogAction;
54 import org.eclipse.ui.part.ViewPart;
55 import org.eclipse.ui.progress.UIJob;
56 import org.eclipse.zest.core.viewers.AbstractZoomableViewer;
57 import org.eclipse.zest.core.viewers.IZoomableWorkbenchPart;
58 import org.eclipse.zest.layouts.LayoutAlgorithm;
59 import org.eclipse.zest.layouts.LayoutStyles;
60 import org.eclipse.zest.layouts.algorithms.CompositeLayoutAlgorithm;
61 import org.eclipse.zest.layouts.algorithms.HorizontalTreeLayoutAlgorithm;
62 import org.eclipse.zest.layouts.algorithms.RadialLayoutAlgorithm;
63 import org.eclipse.zest.layouts.algorithms.SpringLayoutAlgorithm;
64 import org.eclipse.zest.layouts.algorithms.TreeLayoutAlgorithm;
65 import org.netxms.api.client.SessionListener;
66 import org.netxms.api.client.SessionNotification;
67 import org.netxms.client.NXCNotification;
68 import org.netxms.client.NXCSession;
69 import org.netxms.client.maps.NetworkMapPage;
70 import org.netxms.client.maps.elements.NetworkMapObject;
71 import org.netxms.client.objects.GenericObject;
72 import org.netxms.ui.eclipse.actions.RefreshAction;
73 import org.netxms.ui.eclipse.networkmaps.algorithms.SparseTree;
74 import org.netxms.ui.eclipse.networkmaps.views.helpers.ExtendedGraphViewer;
75 import org.netxms.ui.eclipse.networkmaps.views.helpers.MapContentProvider;
76 import org.netxms.ui.eclipse.networkmaps.views.helpers.MapLabelProvider;
77 import org.netxms.ui.eclipse.shared.IActionConstants;
78 import org.netxms.ui.eclipse.shared.ConsoleSharedData;
79 import org.netxms.ui.eclipse.shared.SharedIcons;
80
81 /**
82 * Base class for network map views
83 *
84 */
85 public abstract class NetworkMap extends ViewPart implements ISelectionProvider, IZoomableWorkbenchPart
86 {
87 protected static final int LAYOUT_MANUAL = -1;
88 protected static final int LAYOUT_SPRING = 0;
89 protected static final int LAYOUT_RADIAL = 1;
90 protected static final int LAYOUT_HTREE = 2;
91 protected static final int LAYOUT_VTREE = 3;
92 protected static final int LAYOUT_SPARSE_VTREE = 4;
93
94 private static final String[] layoutAlgorithmNames =
95 { "&Spring", "&Radial", "&Horizontal tree", "&Vertical tree", "S&parse vertical tree" };
96
97 protected NXCSession session;
98 protected GenericObject rootObject;
99 protected NetworkMapPage mapPage;
100 protected ExtendedGraphViewer viewer;
101 protected SessionListener sessionListener;
102 protected MapLabelProvider labelProvider;
103 protected int layoutAlgorithm = LAYOUT_SPRING;
104
105 private RefreshAction actionRefresh;
106 private Action actionShowStatusIcon;
107 private Action actionShowStatusBackground;
108 private Action actionShowStatusFrame;
109 private Action actionZoomIn;
110 private Action actionZoomOut;
111 private Action[] actionZoomTo;
112 private Action[] actionSetAlgorithm;
113
114 private IStructuredSelection currentSelection = new StructuredSelection(new Object[0]);
115 private Set<ISelectionChangedListener> selectionListeners = new HashSet<ISelectionChangedListener>();
116
117 /* (non-Javadoc)
118 * @see org.eclipse.ui.part.ViewPart#init(org.eclipse.ui.IViewSite)
119 */
120 @Override
121 public void init(IViewSite site) throws PartInitException
122 {
123 super.init(site);
124
125 session = (NXCSession)ConsoleSharedData.getSession();
126 rootObject = session.findObjectById(Long.parseLong(site.getSecondaryId()));
127
128 buildMapPage();
129 }
130
131 /**
132 * Build map page containing data to display. Should be implemented
133 * in derived classes.
134 */
135 protected abstract void buildMapPage();
136
137 /* (non-Javadoc)
138 * @see org.eclipse.ui.part.ViewPart#createPartControl(org.eclipse.swt.widgets.Composite)
139 */
140 @Override
141 public void createPartControl(Composite parent)
142 {
143 FillLayout layout = new FillLayout();
144 parent.setLayout(layout);
145
146 viewer = new ExtendedGraphViewer(parent, SWT.NONE);
147 viewer.setContentProvider(new MapContentProvider());
148 labelProvider = new MapLabelProvider(viewer);
149 viewer.setLabelProvider(labelProvider);
150 viewer.setLayoutAlgorithm(new SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING));
151 viewer.setInput(mapPage);
152
153 getSite().setSelectionProvider(this);
154 viewer.addSelectionChangedListener(new ISelectionChangedListener() {
155 @Override
156 public void selectionChanged(SelectionChangedEvent e)
157 {
158 currentSelection = transformSelection(e.getSelection());
159 if (selectionListeners.isEmpty())
160 return;
161
162 SelectionChangedEvent event = new SelectionChangedEvent(NetworkMap.this, currentSelection);
163 for(ISelectionChangedListener l : selectionListeners)
164 {
165 l.selectionChanged(event);
166 }
167 }
168 });
169
170 createActions();
171 contributeToActionBars();
172 createPopupMenu();
173
174 sessionListener = new SessionListener() {
175 @Override
176 public void notificationHandler(SessionNotification n)
177 {
178 if (n.getCode() == NXCNotification.OBJECT_CHANGED)
179 onObjectChange((GenericObject)n.getObject());
180 }
181 };
182 session.addListener(sessionListener);
183 }
184
185 /**
186 * Do full map refresh
187 */
188 private void refreshMap()
189 {
190 buildMapPage();
191 viewer.setInput(mapPage);
192 }
193
194 /**
195 * Replace current map page with new one
196 *
197 * @param page new map page
198 */
199 protected void replaceMapPage(final NetworkMapPage page)
200 {
201 new UIJob("Replace map page") {
202 @Override
203 public IStatus runInUIThread(IProgressMonitor monitor)
204 {
205 mapPage = page;
206 viewer.setInput(mapPage);
207 return Status.OK_STATUS;
208 }
209 }.schedule();
210 }
211
212 /**
213 * Set layout algorithm for map
214 * @param alg
215 */
216 @SuppressWarnings("rawtypes")
217 protected void setLayoutAlgorithm(int alg)
218 {
219 switch(alg)
220 {
221 case LAYOUT_SPRING:
222 viewer.setLayoutAlgorithm(new SpringLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true);
223 break;
224 case LAYOUT_RADIAL:
225 viewer.setLayoutAlgorithm(new RadialLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true);
226 break;
227 case LAYOUT_HTREE:
228 viewer.setLayoutAlgorithm(new HorizontalTreeLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true);
229 break;
230 case LAYOUT_VTREE:
231 viewer.setLayoutAlgorithm(new TreeLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true);
232 break;
233 case LAYOUT_SPARSE_VTREE:
234 TreeLayoutAlgorithm mainLayoutAlgorithm = new TreeLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING);
235 mainLayoutAlgorithm.setComparator(new Comparator() {
236 @Override
237 public int compare(Object arg0, Object arg1)
238 {
239 return arg0.toString().compareToIgnoreCase(arg1.toString());
240 }
241 });
242 viewer.setLayoutAlgorithm(new CompositeLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING,
243 new LayoutAlgorithm[] { mainLayoutAlgorithm,
244 new SparseTree(LayoutStyles.NO_LAYOUT_NODE_RESIZING) }));
245 break;
246 }
247
248 actionSetAlgorithm[layoutAlgorithm].setChecked(false);
249 layoutAlgorithm = alg;
250 actionSetAlgorithm[layoutAlgorithm].setChecked(true);
251 }
252
253 /**
254 * Create actions
255 */
256 protected void createActions()
257 {
258 actionRefresh = new RefreshAction() {
259 @Override
260 public void run()
261 {
262 refreshMap();
263 }
264 };
265
266 actionShowStatusBackground = new Action("Show status &background", Action.AS_CHECK_BOX) {
267 @Override
268 public void run()
269 {
270 labelProvider.setShowStatusBackground(!labelProvider.isShowStatusBackground());
271 setChecked(labelProvider.isShowStatusBackground());
272 viewer.refresh();
273 }
274 };
275 actionShowStatusBackground.setChecked(labelProvider.isShowStatusBackground());
276
277 actionShowStatusIcon = new Action("Show status &icon", Action.AS_CHECK_BOX) {
278 @Override
279 public void run()
280 {
281 labelProvider.setShowStatusIcons(!labelProvider.isShowStatusIcons());
282 setChecked(labelProvider.isShowStatusIcons());
283 viewer.refresh();
284 }
285 };
286 actionShowStatusIcon.setChecked(labelProvider.isShowStatusIcons());
287
288 actionShowStatusFrame = new Action("Show status &frame", Action.AS_CHECK_BOX) {
289 @Override
290 public void run()
291 {
292 labelProvider.setShowStatusFrame(!labelProvider.isShowStatusFrame());
293 setChecked(labelProvider.isShowStatusFrame());
294 viewer.refresh();
295 }
296 };
297 actionShowStatusFrame.setChecked(labelProvider.isShowStatusFrame());
298
299 actionZoomIn = new Action("Zoom &in") {
300 @Override
301 public void run()
302 {
303 viewer.zoomIn();
304 }
305 };
306 actionZoomIn.setImageDescriptor(SharedIcons.ZOOM_IN);
307
308 actionZoomOut = new Action("Zoom &out") {
309 @Override
310 public void run()
311 {
312 viewer.zoomOut();
313 }
314 };
315 actionZoomOut.setImageDescriptor(SharedIcons.ZOOM_OUT);
316
317 actionZoomTo = viewer.createZoomActions();
318
319 actionSetAlgorithm = new Action[layoutAlgorithmNames.length];
320 for(int i = 0; i < layoutAlgorithmNames.length; i++)
321 {
322 final int alg = i;
323 actionSetAlgorithm[i] = new Action(layoutAlgorithmNames[i], Action.AS_RADIO_BUTTON) {
324 @Override
325 public void run()
326 {
327 setLayoutAlgorithm(alg);
328 }
329 };
330 actionSetAlgorithm[i].setChecked(layoutAlgorithm == i);
331 }
332 }
333
334 /**
335 * Create "Layout" submenu
336 * @return
337 */
338 protected IContributionItem createLayoutSubmenu()
339 {
340 MenuManager layout = new MenuManager("&Layout");
341 for(int i = 0; i < actionSetAlgorithm.length; i++)
342 layout.add(actionSetAlgorithm[i]);
343 return layout;
344 }
345
346 /**
347 * Fill action bars
348 */
349 private void contributeToActionBars()
350 {
351 IActionBars bars = getViewSite().getActionBars();
352 fillLocalPullDown(bars.getMenuManager());
353 fillLocalToolBar(bars.getToolBarManager());
354 }
355
356 /**
357 * Fill local pull-down menu
358 * @param manager
359 */
360 protected void fillLocalPullDown(IMenuManager manager)
361 {
362 MenuManager zoom = new MenuManager("&Zoom");
363 for(int i = 0; i < actionZoomTo.length; i++)
364 zoom.add(actionZoomTo[i]);
365
366 manager.add(actionShowStatusBackground);
367 manager.add(actionShowStatusIcon);
368 manager.add(actionShowStatusFrame);
369 manager.add(new Separator());
370 manager.add(createLayoutSubmenu());
371 manager.add(zoom);
372 manager.add(new Separator());
373 manager.add(actionRefresh);
374 }
375
376 /**
377 * Fill local tool bar
378 * @param manager
379 */
380 protected void fillLocalToolBar(IToolBarManager manager)
381 {
382 manager.add(actionZoomIn);
383 manager.add(actionZoomOut);
384 manager.add(new Separator());
385 manager.add(actionRefresh);
386 }
387
388 /**
389 * Create popup menu for map
390 */
391 private void createPopupMenu()
392 {
393 // Create menu manager.
394 MenuManager menuMgr = new MenuManager();
395 menuMgr.setRemoveAllWhenShown(true);
396 menuMgr.addMenuListener(new IMenuListener()
397 {
398 public void menuAboutToShow(IMenuManager mgr)
399 {
400 if (currentSelection.isEmpty())
401 fillMapContextMenu(mgr);
402 else
403 fillObjectContextMenu(mgr);
404 }
405 });
406
407 // Create menu.
408 Menu menu = menuMgr.createContextMenu(viewer.getControl());
409 viewer.getControl().setMenu(menu);
410
411 // Register menu for extension.
412 getSite().registerContextMenu(menuMgr, this);
413 }
414
415 /**
416 * Fill context menu for map object
417 * @param mgr Menu manager
418 */
419 protected void fillObjectContextMenu(IMenuManager mgr)
420 {
421 mgr.add(new GroupMarker(IActionConstants.MB_OBJECT_CREATION));
422 mgr.add(new Separator());
423 mgr.add(new GroupMarker(IActionConstants.MB_OBJECT_MANAGEMENT));
424 mgr.add(new Separator());
425 mgr.add(new GroupMarker(IActionConstants.MB_OBJECT_BINDING));
426 mgr.add(new Separator());
427 mgr.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS));
428 mgr.add(new Separator());
429 mgr.add(new GroupMarker(IActionConstants.MB_DATA_COLLECTION));
430 mgr.add(new Separator());
431 mgr.add(new GroupMarker(IActionConstants.MB_PROPERTIES));
432 mgr.add(new PropertyDialogAction(getSite(), this));
433 }
434
435 /**
436 * Fill context menu for map view
437 * @param mgr Menu manager
438 */
439 protected void fillMapContextMenu(IMenuManager manager)
440 {
441 MenuManager zoom = new MenuManager("&Zoom");
442 for(int i = 0; i < actionZoomTo.length; i++)
443 zoom.add(actionZoomTo[i]);
444
445 manager.add(actionShowStatusBackground);
446 manager.add(actionShowStatusIcon);
447 manager.add(actionShowStatusFrame);
448 manager.add(new Separator());
449 manager.add(createLayoutSubmenu());
450 manager.add(zoom);
451 manager.add(new Separator());
452 manager.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS));
453 manager.add(new Separator());
454 manager.add(actionRefresh);
455 }
456
457 /**
458 * Called by session listener when NetXMS object was changed.
459 *
460 * @param object changed NetXMS object
461 */
462 protected void onObjectChange(final GenericObject object)
463 {
464 new UIJob("Refresh map") {
465 @Override
466 public IStatus runInUIThread(IProgressMonitor monitor)
467 {
468 NetworkMapObject element = mapPage.findObjectElement(object.getObjectId());
469 if (element != null)
470 viewer.refresh(element, true);
471 if (object.getObjectId() == rootObject.getObjectId())
472 rootObject = object;
473 return Status.OK_STATUS;
474 }
475 }.schedule();
476 }
477
478 /* (non-Javadoc)
479 * @see org.eclipse.ui.part.WorkbenchPart#setFocus()
480 */
481 @Override
482 public void setFocus()
483 {
484 viewer.getControl().setFocus();
485 }
486
487 /* (non-Javadoc)
488 * @see org.eclipse.ui.part.WorkbenchPart#dispose()
489 */
490 @Override
491 public void dispose()
492 {
493 if (sessionListener != null)
494 session.removeListener(sessionListener);
495 super.dispose();
496 }
497
498 /* (non-Javadoc)
499 * @see org.eclipse.jface.viewers.ISelectionProvider#addSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener)
500 */
501 @Override
502 public void addSelectionChangedListener(ISelectionChangedListener listener)
503 {
504 selectionListeners.add(listener);
505 }
506
507 /**
508 * Transform viewer's selection to form usable by another plugins by extracting
509 * NetXMS objects from map elements.
510 *
511 * @param viewerSelection viewer's selection
512 * @return selection containing only NetXMS objects
513 */
514 @SuppressWarnings("rawtypes")
515 private IStructuredSelection transformSelection(ISelection viewerSelection)
516 {
517 IStructuredSelection selection = (IStructuredSelection)viewerSelection;
518 if (selection.isEmpty())
519 return selection;
520
521 List<GenericObject> objects = new ArrayList<GenericObject>();
522 Iterator it = selection.iterator();
523 while(it.hasNext())
524 {
525 Object element = it.next();
526 if (element instanceof NetworkMapObject)
527 {
528 GenericObject object = session.findObjectById(((NetworkMapObject)element).getObjectId());
529 if (object != null)
530 objects.add(object);
531 }
532 }
533
534 return new StructuredSelection(objects.toArray());
535 }
536
537 /* (non-Javadoc)
538 * @see org.eclipse.jface.viewers.ISelectionProvider#getSelection()
539 */
540 @Override
541 public ISelection getSelection()
542 {
543 //return transformSelection((IStructuredSelection)viewer.getSelection());
544 return currentSelection;
545 }
546
547 /* (non-Javadoc)
548 * @see org.eclipse.jface.viewers.ISelectionProvider#removeSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener)
549 */
550 @Override
551 public void removeSelectionChangedListener(ISelectionChangedListener listener)
552 {
553 selectionListeners.remove(listener);
554 }
555
556 /* (non-Javadoc)
557 * @see org.eclipse.jface.viewers.ISelectionProvider#setSelection(org.eclipse.jface.viewers.ISelection)
558 */
559 @Override
560 public void setSelection(ISelection selection)
561 {
562 }
563
564 /* (non-Javadoc)
565 * @see org.eclipse.zest.core.viewers.IZoomableWorkbenchPart#getZoomableViewer()
566 */
567 @Override
568 public AbstractZoomableViewer getZoomableViewer()
569 {
570 return viewer;
571 }
572 }