e4b5a7d7ca2e79066477f39dabc058357d89cf30
[public/netxms.git] / webui / webapp / 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.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
127 tabFolder.addSelectionListener(new SelectionListener() {
128 @Override
129 public void widgetSelected(SelectionEvent e)
130 {
131 ObjectTab tab = null;
132 if (e.item != null)
133 {
134 tab = (ObjectTab)((CTabItem)e.item).getData();
135 tab.selected();
136 selectionProvider.setSelectionProviderDelegate(tab.getSelectionProvider());
137 }
138 if (sourceProvider != null)
139 sourceProvider.updateProperty(SourceProvider.ACTIVE_TAB, tab);
140 }
141
142 @Override
143 public void widgetDefaultSelected(SelectionEvent e)
144 {
145 widgetSelected(e);
146 }
147 });
148
149 tabs = new ArrayList<ObjectTab>();
150 addTabs();
151
152 selectionListener = new ISelectionListener() {
153 @Override
154 public void selectionChanged(IWorkbenchPart part, ISelection selection)
155 {
156 if ((part.getSite().getId().equals("org.netxms.ui.eclipse.view.navigation.objectbrowser")) && //$NON-NLS-1$
157 (selection instanceof IStructuredSelection))
158 {
159 if (selection.isEmpty())
160 {
161 setObject(null);
162 }
163 else
164 {
165 Object object = ((IStructuredSelection)selection).getFirstElement();
166 if (object instanceof AbstractObject)
167 {
168 setObject((AbstractObject)object);
169 }
170 }
171 }
172 }
173 };
174 selectionService.addPostSelectionListener(selectionListener);
175
176 createActions();
177 contributeToActionBars();
178
179 selectionProvider = new IntermediateSelectionProvider();
180 getSite().setSelectionProvider(selectionProvider);
181
182 final NXCSession session = ConsoleSharedData.getSession();
183 sessionListener = new SessionListener() {
184 @Override
185 public void notificationHandler(SessionNotification n)
186 {
187 if ((n.getCode() == SessionNotification.OBJECT_CHANGED) && (objectId == n.getSubCode()))
188 {
189 final AbstractObject object = (AbstractObject)n.getObject();
190 getSite().getShell().getDisplay().asyncExec(new Runnable() {
191 @Override
192 public void run()
193 {
194 onObjectUpdate(object);
195 }
196 });
197 }
198 }
199 };
200 session.addListener(sessionListener);
201
202 CommandBridge.getInstance().registerCommand("TabbedObjectView/selectTab", new Command() { //$NON-NLS-1$
203 @Override
204 public Object execute(String name, Object arg)
205 {
206 if (arg instanceof String)
207 selectTab((String)arg);
208 return null;
209 }
210 });
211
212 CommandBridge.getInstance().registerCommand("TabbedObjectView/changeObject", new Command() { //$NON-NLS-1$
213 @Override
214 public Object execute(String name, Object arg)
215 {
216 if (arg instanceof Long)
217 setObject(session.findObjectById((Long)arg));
218 return null;
219 }
220 });
221 }
222
223 /**
224 * Create actions
225 */
226 private void createActions()
227 {
228 actionRefresh = new RefreshAction() {
229 @Override
230 public void run()
231 {
232 refreshCurrentTab();
233 }
234 };
235 }
236
237 /**
238 * Fill action bars
239 */
240 private void contributeToActionBars()
241 {
242 IActionBars bars = getViewSite().getActionBars();
243 fillLocalPullDown(bars.getMenuManager());
244 fillLocalToolBar(bars.getToolBarManager());
245 }
246
247 /**
248 * Fill local pull-down menu
249 * @param manager
250 */
251 private void fillLocalPullDown(IMenuManager manager)
252 {
253 manager.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS));
254 manager.add(new Separator());
255 manager.add(actionRefresh);
256 }
257
258 /**
259 * Fill local tool bar
260 * @param manager
261 */
262 private void fillLocalToolBar(IToolBarManager manager)
263 {
264 manager.add(actionRefresh);
265 }
266
267 /**
268 * Refresh current tab
269 */
270 private void refreshCurrentTab()
271 {
272 CTabItem item = tabFolder.getSelection();
273 if (item != null)
274 ((ObjectTab)item.getData()).refresh();
275 }
276 /**
277 * Notify visible tabs about object update
278 *
279 * @param object New object
280 */
281 private void onObjectUpdate(AbstractObject object)
282 {
283 header.setText(object.getObjectName());
284 for(final ObjectTab tab : tabs)
285 {
286 if (tab.isVisible())
287 tab.currentObjectUpdated(object);
288 }
289 }
290
291 /**
292 * Set new active object
293 *
294 * @param object New object
295 */
296 public void setObject(final AbstractObject object)
297 {
298 // Prevent multiple calls to setObjectInternal
299 if (objectId == getObjectId(object))
300 return;
301 objectId = getObjectId(object);
302
303 // Current focus event may not be finished yet, so we have
304 // to wait for any outstanding events and only then start
305 // changing tabs. Otherwise runtime exception will be thrown.
306 final Display display = getSite().getShell().getDisplay();
307 display.asyncExec(new Runnable() {
308 @Override
309 public void run()
310 {
311 while(display.readAndDispatch()); // wait for events to finish before continue
312 if (objectId != getObjectId(object))
313 return; // already received next object change
314 setObjectInternal(object);
315 }
316 });
317 }
318
319 /**
320 * @param object
321 * @return
322 */
323 private static long getObjectId(AbstractObject object)
324 {
325 return (object != null) ? object.getObjectId() : 0;
326 }
327
328 /**
329 * Set new active object - internal implementation
330 *
331 * @param object New object
332 */
333 private void setObjectInternal(AbstractObject object)
334 {
335 Control focusControl = Display.getCurrent().getFocusControl();
336 if (object != null)
337 {
338 header.setText(object.getObjectName());
339 for(final ObjectTab tab : tabs)
340 {
341 if (tab.showForObject(object) && !WorkbenchActivityHelper.filterItem(tab))
342 {
343 tab.show();
344 tab.changeObject(object);
345 }
346 else
347 {
348 tab.hide();
349 tab.changeObject(null);
350 }
351 }
352
353 if ((objectId == 0) || (tabFolder.getSelection() == null))
354 {
355 try
356 {
357 tabFolder.setSelection(0);
358 ObjectTab tab = (ObjectTab)tabFolder.getItem(0).getData();
359 tab.selected();
360 selectionProvider.setSelectionProviderDelegate(tab.getSelectionProvider());
361 }
362 catch(IllegalArgumentException e)
363 {
364 }
365 }
366 objectId = (object != null) ? object.getObjectId() : 0;
367 }
368 else
369 {
370 for(final ObjectTab tab : tabs)
371 {
372 tab.hide();
373 tab.changeObject(null);
374 }
375 objectId = 0;
376 header.setText(""); //$NON-NLS-1$
377 }
378 if (focusControl != null)
379 focusControl.setFocus();
380 }
381
382 /* (non-Javadoc)
383 * @see org.eclipse.ui.part.WorkbenchPart#setFocus()
384 */
385 @Override
386 public void setFocus()
387 {
388 tabFolder.setFocus();
389 CTabItem item = tabFolder.getSelection();
390 if (item != null)
391 ((ObjectTab)item.getData()).selected();
392 }
393
394 /**
395 * Add all tabs
396 */
397 private void addTabs()
398 {
399 // Read all registered extensions and create tabs
400 final IExtensionRegistry reg = Platform.getExtensionRegistry();
401 IConfigurationElement[] elements = reg.getConfigurationElementsFor("org.netxms.ui.eclipse.objectview.tabs"); //$NON-NLS-1$
402 for(int i = 0; i < elements.length; i++)
403 {
404 try
405 {
406 final ObjectTab tab = (ObjectTab)elements[i].createExecutableExtension("class"); //$NON-NLS-1$
407 tab.configure(elements[i], this);
408 tabs.add(tab);
409 }
410 catch(CoreException e)
411 {
412 Activator.log("Exception when instantiating object tab", e); //$NON-NLS-1$
413 }
414 }
415
416 // Sort tabs by appearance order
417 Collections.sort(tabs, new Comparator<ObjectTab>() {
418 @Override
419 public int compare(ObjectTab arg0, ObjectTab arg1)
420 {
421 return arg0.getOrder() - arg1.getOrder();
422 }
423 });
424
425 // Create widgets for all tabs
426 for(final ObjectTab tab : tabs)
427 {
428 tab.create(tabFolder);
429 }
430 }
431
432 /**
433 * Select tab with given ID
434 *
435 * @param tabId
436 */
437 public void selectTab(String tabId)
438 {
439 for(int i = 0; i < tabFolder.getItemCount(); i++)
440 {
441 CTabItem item = tabFolder.getItem(i);
442 ObjectTab tab = (ObjectTab)item.getData();
443 if (tab.getLocalId().equals(tabId))
444 {
445 tabFolder.setSelection(i);
446 tab.selected();
447 selectionProvider.setSelectionProviderDelegate(tab.getSelectionProvider());
448 break;
449 }
450 }
451 }
452
453 /* (non-Javadoc)
454 * @see org.eclipse.ui.part.WorkbenchPart#dispose()
455 */
456 @Override
457 public void dispose()
458 {
459 ConsoleSharedData.getSession().removeListener(sessionListener);
460 CommandBridge.getInstance().unregisterCommand("TabbedObjectView/selectTab"); //$NON-NLS-1$
461 CommandBridge.getInstance().unregisterCommand("TabbedObjectView/changeObject"); //$NON-NLS-1$
462 ConsoleSharedData.getSession().removeListener(sessionListener);
463 if (sourceProvider != null)
464 sourceProvider.updateProperty(SourceProvider.ACTIVE_TAB, null);
465 getSite().setSelectionProvider(null);
466 if ((selectionService != null) && (selectionListener != null))
467 selectionService.removePostSelectionListener(selectionListener);
468 for(final ObjectTab tab : tabs)
469 {
470 tab.dispose();
471 }
472 headerFont.dispose();
473 super.dispose();
474 }
475 }