56ba186b8b7995c31c481bb06779150b0e1329e3
[public/netxms.git] / src / java / netxms-eclipse / ObjectView / src / org / netxms / ui / eclipse / objectview / views / TabbedObjectView.java
1 /**
2 * NetXMS - open source network management system
3 * Copyright (C) 2003-2015 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.objectview.views;
20
21 import java.util.ArrayList;
22 import java.util.Collections;
23 import java.util.Comparator;
24 import java.util.List;
25 import org.eclipse.core.runtime.CoreException;
26 import org.eclipse.core.runtime.IConfigurationElement;
27 import org.eclipse.core.runtime.IExtensionRegistry;
28 import org.eclipse.core.runtime.Platform;
29 import org.eclipse.jface.action.Action;
30 import org.eclipse.jface.action.GroupMarker;
31 import org.eclipse.jface.action.IMenuManager;
32 import org.eclipse.jface.action.IToolBarManager;
33 import org.eclipse.jface.action.Separator;
34 import org.eclipse.jface.viewers.ISelection;
35 import org.eclipse.jface.viewers.IStructuredSelection;
36 import org.eclipse.swt.SWT;
37 import org.eclipse.swt.custom.CLabel;
38 import org.eclipse.swt.custom.CTabFolder;
39 import org.eclipse.swt.custom.CTabItem;
40 import org.eclipse.swt.events.SelectionEvent;
41 import org.eclipse.swt.events.SelectionListener;
42 import org.eclipse.swt.graphics.Font;
43 import org.eclipse.swt.layout.GridData;
44 import org.eclipse.swt.layout.GridLayout;
45 import org.eclipse.swt.widgets.Composite;
46 import org.eclipse.swt.widgets.Control;
47 import org.eclipse.swt.widgets.Display;
48 import org.eclipse.ui.IActionBars;
49 import org.eclipse.ui.ISelectionListener;
50 import org.eclipse.ui.ISelectionService;
51 import org.eclipse.ui.IViewSite;
52 import org.eclipse.ui.IWorkbenchActionConstants;
53 import org.eclipse.ui.IWorkbenchPart;
54 import org.eclipse.ui.PartInitException;
55 import org.eclipse.ui.activities.WorkbenchActivityHelper;
56 import org.eclipse.ui.part.ViewPart;
57 import org.netxms.client.NXCSession;
58 import org.netxms.client.SessionListener;
59 import org.netxms.client.SessionNotification;
60 import org.netxms.client.objects.AbstractObject;
61 import org.netxms.ui.eclipse.actions.RefreshAction;
62 import org.netxms.ui.eclipse.console.resources.SharedColors;
63 import org.netxms.ui.eclipse.objectview.Activator;
64 import org.netxms.ui.eclipse.objectview.SourceProvider;
65 import org.netxms.ui.eclipse.objectview.objecttabs.ObjectTab;
66 import org.netxms.ui.eclipse.shared.ConsoleSharedData;
67 import org.netxms.ui.eclipse.tools.Command;
68 import org.netxms.ui.eclipse.tools.CommandBridge;
69 import org.netxms.ui.eclipse.tools.FontTools;
70 import org.netxms.ui.eclipse.tools.IntermediateSelectionProvider;
71
72 /**
73 * Tabbed view of currently selected object
74 */
75 public class TabbedObjectView extends ViewPart
76 {
77 public static final String ID = "org.netxms.ui.eclipse.objectview.view.tabbed_object_view"; //$NON-NLS-1$
78
79 private static final String[] HEADER_FONTS = { "Verdana", "DejaVu Sans", "Liberation Sans", "Arial" };
80
81 private CLabel header;
82 private CTabFolder tabFolder;
83 private Font headerFont;
84 private List<ObjectTab> tabs;
85 private ISelectionService selectionService = null;
86 private ISelectionListener selectionListener = null;
87 private IntermediateSelectionProvider selectionProvider;
88 private SessionListener sessionListener = null;
89 private Action actionRefresh;
90 private SourceProvider sourceProvider = null;
91 private long objectId = 0;
92
93 /* (non-Javadoc)
94 * @see org.eclipse.ui.part.ViewPart#init(org.eclipse.ui.IViewSite)
95 */
96 @Override
97 public void init(IViewSite site) throws PartInitException
98 {
99 super.init(site);
100 sourceProvider = SourceProvider.getInstance();
101 selectionService = getSite().getWorkbenchWindow().getSelectionService();
102 }
103
104 /* (non-Javadoc)
105 * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
106 */
107 @Override
108 public void createPartControl(Composite parent)
109 {
110 GridLayout layout = new GridLayout();
111 layout.marginHeight = 0;
112 layout.marginWidth = 0;
113 layout.verticalSpacing = 0;
114 parent.setLayout(layout);
115
116 headerFont = FontTools.createFont(HEADER_FONTS, +3, SWT.BOLD);
117
118 header = new CLabel(parent, SWT.BORDER);
119 header.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
120 header.setFont(headerFont);
121 header.setBackground(SharedColors.getColor(SharedColors.OBJECT_TAB_HEADER_BACKGROUND, parent.getDisplay()));
122 header.setForeground(SharedColors.getColor(SharedColors.OBJECT_TAB_HEADER, parent.getDisplay()));
123
124 tabFolder = new CTabFolder(parent, SWT.TOP | SWT.FLAT | SWT.MULTI);
125 tabFolder.setUnselectedImageVisible(true);
126 tabFolder.setSimple(true);
127 tabFolder.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
128 tabFolder.addSelectionListener(new SelectionListener() {
129 @Override
130 public void widgetSelected(SelectionEvent e)
131 {
132 ObjectTab tab = null;
133 if (e.item != null)
134 {
135 tab = (ObjectTab)((CTabItem)e.item).getData();
136 tab.selected();
137 selectionProvider.setSelectionProviderDelegate(tab.getSelectionProvider());
138 }
139 if (sourceProvider != null)
140 sourceProvider.updateProperty(SourceProvider.ACTIVE_TAB, tab);
141 }
142
143 @Override
144 public void widgetDefaultSelected(SelectionEvent e)
145 {
146 widgetSelected(e);
147 }
148 });
149
150 tabs = new ArrayList<ObjectTab>();
151 addTabs();
152
153 selectionListener = new ISelectionListener() {
154 @Override
155 public void selectionChanged(IWorkbenchPart part, ISelection selection)
156 {
157 if ((part.getSite().getId().equals("org.netxms.ui.eclipse.view.navigation.objectbrowser")) && //$NON-NLS-1$
158 (selection instanceof IStructuredSelection))
159 {
160 if (selection.isEmpty())
161 {
162 setObject(null);
163 }
164 else
165 {
166 Object object = ((IStructuredSelection)selection).getFirstElement();
167 if (object instanceof AbstractObject)
168 {
169 setObject((AbstractObject)object);
170 }
171 }
172 }
173 }
174 };
175 selectionService.addPostSelectionListener(selectionListener);
176
177 createActions();
178 contributeToActionBars();
179
180 selectionProvider = new IntermediateSelectionProvider();
181 getSite().setSelectionProvider(selectionProvider);
182
183 final NXCSession session = ConsoleSharedData.getSession();
184 sessionListener = new SessionListener() {
185 @Override
186 public void notificationHandler(SessionNotification n)
187 {
188 if ((n.getCode() == SessionNotification.OBJECT_CHANGED) && (objectId == n.getSubCode()))
189 {
190 final AbstractObject object = (AbstractObject)n.getObject();
191 getSite().getShell().getDisplay().asyncExec(new Runnable() {
192 @Override
193 public void run()
194 {
195 onObjectUpdate(object);
196 }
197 });
198 }
199 }
200 };
201 session.addListener(sessionListener);
202
203 CommandBridge.getInstance().registerCommand("TabbedObjectView/selectTab", new Command() { //$NON-NLS-1$
204 @Override
205 public Object execute(String name, Object arg)
206 {
207 if (arg instanceof String)
208 selectTab((String)arg);
209 return null;
210 }
211 });
212
213 CommandBridge.getInstance().registerCommand("TabbedObjectView/changeObject", new Command() { //$NON-NLS-1$
214 @Override
215 public Object execute(String name, Object arg)
216 {
217 if (arg instanceof Long)
218 setObject(session.findObjectById((Long)arg));
219 return null;
220 }
221 });
222 }
223
224 /**
225 * Create actions
226 */
227 private void createActions()
228 {
229 actionRefresh = new RefreshAction() {
230 @Override
231 public void run()
232 {
233 refreshCurrentTab();
234 }
235 };
236 }
237
238 /**
239 * Fill action bars
240 */
241 private void contributeToActionBars()
242 {
243 IActionBars bars = getViewSite().getActionBars();
244 fillLocalPullDown(bars.getMenuManager());
245 fillLocalToolBar(bars.getToolBarManager());
246 }
247
248 /**
249 * Fill local pull-down menu
250 * @param manager
251 */
252 private void fillLocalPullDown(IMenuManager manager)
253 {
254 manager.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS));
255 manager.add(new Separator());
256 manager.add(actionRefresh);
257 }
258
259 /**
260 * Fill local tool bar
261 * @param manager
262 */
263 private void fillLocalToolBar(IToolBarManager manager)
264 {
265 manager.add(actionRefresh);
266 }
267
268 /**
269 * Refresh current tab
270 */
271 private void refreshCurrentTab()
272 {
273 CTabItem item = tabFolder.getSelection();
274 if (item != null)
275 ((ObjectTab)item.getData()).refresh();
276 }
277 /**
278 * Notify visible tabs about object update
279 *
280 * @param object New object
281 */
282 private void onObjectUpdate(AbstractObject object)
283 {
284 header.setText(object.getObjectName());
285 for(final ObjectTab tab : tabs)
286 {
287 if (tab.isVisible())
288 tab.currentObjectUpdated(object);
289 }
290 }
291
292 /**
293 * Set new active object
294 *
295 * @param object New object
296 */
297 public void setObject(final AbstractObject object)
298 {
299 // Prevent multiple calls to setObjectInternal
300 if (objectId == getObjectId(object))
301 return;
302 objectId = getObjectId(object);
303
304 // Current focus event may not be finished yet, so we have
305 // to wait for any outstanding events and only then start
306 // changing tabs. Otherwise runtime exception will be thrown.
307 final Display display = getSite().getShell().getDisplay();
308 display.asyncExec(new Runnable() {
309 @Override
310 public void run()
311 {
312 while(display.readAndDispatch()); // wait for events to finish before continue
313 if (objectId != getObjectId(object))
314 return; // already received next object change
315 setObjectInternal(object);
316 }
317 });
318 }
319
320 /**
321 * @param object
322 * @return
323 */
324 private static long getObjectId(AbstractObject object)
325 {
326 return (object != null) ? object.getObjectId() : 0;
327 }
328
329 /**
330 * Set new active object - internal implementation
331 *
332 * @param object New object
333 */
334 private void setObjectInternal(AbstractObject object)
335 {
336 Control focusControl = Display.getCurrent().getFocusControl();
337 if (object != null)
338 {
339 header.setText(object.getObjectName());
340 for(final ObjectTab tab : tabs)
341 {
342 if (tab.showForObject(object) && !WorkbenchActivityHelper.filterItem(tab))
343 {
344 tab.show();
345 tab.changeObject(object);
346 }
347 else
348 {
349 tab.hide();
350 tab.changeObject(null);
351 }
352 }
353
354 if ((objectId == 0) || (tabFolder.getSelection() == null))
355 {
356 try
357 {
358 tabFolder.setSelection(0);
359 ObjectTab tab = (ObjectTab)tabFolder.getItem(0).getData();
360 tab.selected();
361 selectionProvider.setSelectionProviderDelegate(tab.getSelectionProvider());
362 }
363 catch(IllegalArgumentException e)
364 {
365 }
366 }
367 objectId = (object != null) ? object.getObjectId() : 0;
368 }
369 else
370 {
371 for(final ObjectTab tab : tabs)
372 {
373 tab.hide();
374 tab.changeObject(null);
375 }
376 objectId = 0;
377 header.setText(""); //$NON-NLS-1$
378 }
379 if (focusControl != null)
380 focusControl.setFocus();
381 }
382
383 /* (non-Javadoc)
384 * @see org.eclipse.ui.part.WorkbenchPart#setFocus()
385 */
386 @Override
387 public void setFocus()
388 {
389 tabFolder.setFocus();
390 CTabItem item = tabFolder.getSelection();
391 if (item != null)
392 ((ObjectTab)item.getData()).selected();
393 }
394
395 /**
396 * Add all tabs
397 */
398 private void addTabs()
399 {
400 // Read all registered extensions and create tabs
401 final IExtensionRegistry reg = Platform.getExtensionRegistry();
402 IConfigurationElement[] elements = reg.getConfigurationElementsFor("org.netxms.ui.eclipse.objectview.tabs"); //$NON-NLS-1$
403 for(int i = 0; i < elements.length; i++)
404 {
405 try
406 {
407 final ObjectTab tab = (ObjectTab)elements[i].createExecutableExtension("class"); //$NON-NLS-1$
408 tab.configure(elements[i], this);
409 tabs.add(tab);
410 }
411 catch(CoreException e)
412 {
413 Activator.log("Exception when instantiating object tab", e); //$NON-NLS-1$
414 }
415 }
416
417 // Sort tabs by appearance order
418 Collections.sort(tabs, new Comparator<ObjectTab>() {
419 @Override
420 public int compare(ObjectTab arg0, ObjectTab arg1)
421 {
422 return arg0.getOrder() - arg1.getOrder();
423 }
424 });
425
426 // Create widgets for all tabs
427 for(final ObjectTab tab : tabs)
428 {
429 tab.create(tabFolder);
430 }
431 }
432
433 /**
434 * Select tab with given ID
435 *
436 * @param tabId
437 */
438 public void selectTab(String tabId)
439 {
440 for(int i = 0; i < tabFolder.getItemCount(); i++)
441 {
442 CTabItem item = tabFolder.getItem(i);
443 ObjectTab tab = (ObjectTab)item.getData();
444 if (tab.getLocalId().equals(tabId))
445 {
446 tabFolder.setSelection(i);
447 tab.selected();
448 selectionProvider.setSelectionProviderDelegate(tab.getSelectionProvider());
449 break;
450 }
451 }
452 }
453
454 /* (non-Javadoc)
455 * @see org.eclipse.ui.part.WorkbenchPart#dispose()
456 */
457 @Override
458 public void dispose()
459 {
460 ConsoleSharedData.getSession().removeListener(sessionListener);
461 CommandBridge.getInstance().unregisterCommand("TabbedObjectView/selectTab"); //$NON-NLS-1$
462 CommandBridge.getInstance().unregisterCommand("TabbedObjectView/changeObject"); //$NON-NLS-1$
463 ConsoleSharedData.getSession().removeListener(sessionListener);
464 if (sourceProvider != null)
465 sourceProvider.updateProperty(SourceProvider.ACTIVE_TAB, null);
466 getSite().setSelectionProvider(null);
467 if ((selectionService != null) && (selectionListener != null))
468 selectionService.removePostSelectionListener(selectionListener);
469 for(final ObjectTab tab : tabs)
470 {
471 tab.dispose();
472 }
473 headerFont.dispose();
474 super.dispose();
475 }
476 }