dcd0a1005995b8024f3db111ad526dec77060e80
[public/netxms.git] / webui / webapp / PerfView / src / org / netxms / ui / eclipse / perfview / views / HistoricalGraphView.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.perfview.views;
20
21 import java.io.UnsupportedEncodingException;
22 import java.net.URLDecoder;
23 import java.util.ArrayList;
24 import java.util.Date;
25 import java.util.List;
26 import org.eclipse.core.runtime.IProgressMonitor;
27 import org.eclipse.core.runtime.IStatus;
28 import org.eclipse.core.runtime.Status;
29 import org.eclipse.jface.action.Action;
30 import org.eclipse.jface.action.IMenuListener;
31 import org.eclipse.jface.action.IMenuManager;
32 import org.eclipse.jface.action.IToolBarManager;
33 import org.eclipse.jface.action.MenuManager;
34 import org.eclipse.jface.action.Separator;
35 import org.eclipse.jface.window.Window;
36 import org.eclipse.swt.SWT;
37 import org.eclipse.swt.widgets.Composite;
38 import org.eclipse.swt.widgets.Control;
39 import org.eclipse.swt.widgets.Menu;
40 import org.eclipse.swt.widgets.Widget;
41 import org.eclipse.ui.IActionBars;
42 import org.eclipse.ui.IMemento;
43 import org.eclipse.ui.IViewSite;
44 import org.eclipse.ui.PartInitException;
45 import org.eclipse.ui.internal.dialogs.PropertyDialog;
46 import org.eclipse.ui.part.ViewPart;
47 import org.netxms.client.AccessListElement;
48 import org.netxms.client.NXCException;
49 import org.netxms.client.NXCSession;
50 import org.netxms.client.constants.RCC;
51 import org.netxms.client.datacollection.ChartConfig;
52 import org.netxms.client.datacollection.ChartDciConfig;
53 import org.netxms.client.datacollection.DciData;
54 import org.netxms.client.datacollection.GraphItem;
55 import org.netxms.client.datacollection.GraphItemStyle;
56 import org.netxms.client.datacollection.GraphSettings;
57 import org.netxms.client.datacollection.GraphSettingsChangeListener;
58 import org.netxms.client.datacollection.Threshold;
59 import org.netxms.client.objects.AbstractObject;
60 import org.netxms.ui.eclipse.actions.RefreshAction;
61 import org.netxms.ui.eclipse.charts.api.ChartColor;
62 import org.netxms.ui.eclipse.charts.api.ChartFactory;
63 import org.netxms.ui.eclipse.charts.api.HistoricalDataChart;
64 import org.netxms.ui.eclipse.console.resources.SharedIcons;
65 import org.netxms.ui.eclipse.jobs.ConsoleJob;
66 import org.netxms.ui.eclipse.perfview.Activator;
67 import org.netxms.ui.eclipse.perfview.Messages;
68 import org.netxms.ui.eclipse.perfview.dialogs.SaveGraphDlg;
69 import org.netxms.ui.eclipse.shared.ConsoleSharedData;
70 import org.netxms.ui.eclipse.tools.MessageDialogHelper;
71 import org.netxms.ui.eclipse.tools.ViewRefreshController;
72
73 /**
74 * History graph view
75 */
76 @SuppressWarnings("restriction")
77 public class HistoricalGraphView extends ViewPart implements GraphSettingsChangeListener
78 {
79 public static final String ID = "org.netxms.ui.eclipse.perfview.views.HistoryGraph"; //$NON-NLS-1$
80 public static final String PREDEFINED_GRAPH_SUBID = "org.netxms.ui.eclipse.charts.predefinedGraph"; //$NON-NLS-1$
81
82 private static final int[] presetUnits = { GraphSettings.TIME_UNIT_MINUTE, GraphSettings.TIME_UNIT_MINUTE,
83 GraphSettings.TIME_UNIT_HOUR, GraphSettings.TIME_UNIT_HOUR, GraphSettings.TIME_UNIT_HOUR, GraphSettings.TIME_UNIT_HOUR,
84 GraphSettings.TIME_UNIT_DAY, GraphSettings.TIME_UNIT_DAY, GraphSettings.TIME_UNIT_DAY, GraphSettings.TIME_UNIT_DAY,
85 GraphSettings.TIME_UNIT_DAY, GraphSettings.TIME_UNIT_DAY };
86 private static final int[] presetRanges = { 10, 30, 1, 2, 4, 12, 1, 2, 5, 7, 31, 365 };
87 private static final String[] presetNames =
88 { Messages.get().HistoricalGraphView_Preset10min, Messages.get().HistoricalGraphView_Preset30min, Messages.get().HistoricalGraphView_Preset1hour, Messages.get().HistoricalGraphView_Preset2hours, Messages.get().HistoricalGraphView_Preset4hours, Messages.get().HistoricalGraphView_Preset12hours, Messages.get().HistoricalGraphView_Preset1day,
89 Messages.get().HistoricalGraphView_Preset2days, Messages.get().HistoricalGraphView_Preset5days, Messages.get().HistoricalGraphView_PresetWeek, Messages.get().HistoricalGraphView_PresetMonth, Messages.get().HistoricalGraphView_PresetYear };
90
91 private NXCSession session;
92 private HistoricalDataChart chart = null;
93 private boolean updateInProgress = false;
94 private ViewRefreshController refreshController;
95 private Composite chartParent = null;
96 private GraphSettings settings = new GraphSettings();
97 private boolean useMoreThanOneShoucrNode = false;
98
99 private Action actionRefresh;
100 private Action actionAutoRefresh;
101 private Action actionZoomIn;
102 private Action actionZoomOut;
103 private Action actionAdjustX;
104 private Action actionAdjustY;
105 private Action actionAdjustBoth;
106 private Action actionLogScale;
107 private Action actionStacked;
108 private Action actionAreaChart;
109 private Action actionTranslucent;
110 private Action actionShowLegend;
111 private Action actionExtendedLegend;
112 private Action actionLegendLeft;
113 private Action actionLegendRight;
114 private Action actionLegendTop;
115 private Action actionLegendBottom;
116 private Action actionProperties;
117 private Action actionSave;
118 private Action actionSaveAsTemplate;
119 private Action[] presetActions;
120 private Action actionSaveAsImage;
121
122 /*
123 * (non-Javadoc)
124 *
125 * @see org.eclipse.ui.part.ViewPart#init(org.eclipse.ui.IViewSite)
126 */
127 @Override
128 public void init(IViewSite site) throws PartInitException
129 {
130 super.init(site);
131
132 refreshController = new ViewRefreshController(this, -1, new Runnable() {
133 @Override
134 public void run()
135 {
136 if (((Widget)chart).isDisposed())
137 return;
138
139 updateChart();
140 }
141 });
142
143 session = (NXCSession)ConsoleSharedData.getSession();
144
145 settings.setTimeFrom(new Date(System.currentTimeMillis() - settings.getTimeRangeMillis()));
146 settings.setTimeTo(new Date(System.currentTimeMillis()));
147
148 // Extract DCI ids from view id
149 // (first field will be unique view id, so we skip it)
150 String id = site.getSecondaryId();
151 String[] fields = id.split("&"); //$NON-NLS-1$
152 if (!fields[0].equals(PREDEFINED_GRAPH_SUBID))
153 {
154 List<ChartDciConfig> items = new ArrayList<ChartDciConfig>();
155 for(int i = 1; i < fields.length; i++)
156 {
157 String[] subfields = fields[i].split("\\@"); //$NON-NLS-1$
158 if (subfields.length == 6) // item
159 {
160 try
161 {
162 ChartDciConfig dci = new ChartDciConfig();
163 dci.nodeId = Long.parseLong(subfields[0], 10);
164 dci.dciId = Long.parseLong(subfields[1], 10);
165 dci.name = URLDecoder.decode(subfields[5], "UTF-8"); //$NON-NLS-1$
166 dci.dciName = URLDecoder.decode(subfields[4], "UTF-8"); //$NON-NLS-1$
167 dci.dciDescription = URLDecoder.decode(subfields[5], "UTF-8"); //$NON-NLS-1$
168 items.add(dci);
169 }
170 catch(NumberFormatException e)
171 {
172 e.printStackTrace();
173 }
174 catch(UnsupportedEncodingException e)
175 {
176 e.printStackTrace();
177 }
178 }
179 else if (subfields.length == 8) // table
180 {
181 try
182 {
183 ChartDciConfig dci = new ChartDciConfig();
184 dci.type = ChartDciConfig.TABLE;
185 dci.nodeId = Long.parseLong(subfields[0], 10);
186 dci.dciId = Long.parseLong(subfields[1], 10);
187 dci.name = URLDecoder.decode(subfields[5], "UTF-8"); //$NON-NLS-1$
188 dci.dciName = URLDecoder.decode(subfields[5], "UTF-8"); //$NON-NLS-1$
189 dci.instance = URLDecoder.decode(subfields[6], "UTF-8"); //$NON-NLS-1$
190 dci.column = URLDecoder.decode(subfields[7], "UTF-8"); //$NON-NLS-1$
191 items.add(dci);
192 }
193 catch(NumberFormatException e)
194 {
195 e.printStackTrace();
196 }
197 catch(UnsupportedEncodingException e)
198 {
199 e.printStackTrace();
200 }
201 }
202 }
203
204 // Set view title to "host name: dci description" if we have only one DCI
205 if (items.size() == 1)
206 {
207 ChartDciConfig item = items.get(0);
208 AbstractObject object = session.findObjectById(item.nodeId);
209 if (object != null)
210 {
211 setPartName(object.getObjectName() + ": " + item.name); //$NON-NLS-1$
212 }
213 }
214 else if (items.size() > 1)
215 {
216 long nodeId = items.get(0).nodeId;
217 for(ChartDciConfig item : items)
218 if (item.nodeId != nodeId)
219 {
220 nodeId = -1;
221 break;
222 }
223 if (nodeId != -1)
224 {
225 // All DCIs from same node, set title to "host name"
226 AbstractObject object = session.findObjectById(nodeId);
227 if (object != null)
228 {
229 setPartName(String.format(Messages.get().HistoricalGraphView_PartName, object.getObjectName()));
230 }
231 }
232 }
233 settings.setTitle(getPartName());
234 settings.setDciList(items.toArray(new ChartDciConfig[items.size()]));
235 }
236 }
237
238 /*
239 * (non-Javadoc)
240 *
241 * @see org.eclipse.ui.part.ViewPart#init(org.eclipse.ui.IViewSite, org.eclipse.ui.IMemento)
242 */
243 @Override
244 public void init(IViewSite site, IMemento memento) throws PartInitException
245 {
246 init(site);
247
248 if (memento != null)
249 {
250 try
251 {
252 settings = GraphSettings.createFromXml(memento.getTextData());
253 }
254 catch(Exception e)
255 {
256 e.printStackTrace();
257 }
258 }
259 }
260
261 /*
262 * (non-Javadoc)
263 *
264 * @see org.eclipse.ui.part.ViewPart#saveState(org.eclipse.ui.IMemento)
265 */
266 @Override
267 public void saveState(IMemento memento)
268 {
269 try
270 {
271 memento.putTextData(settings.createXml());
272 }
273 catch(Exception e)
274 {
275 }
276 }
277
278 /**
279 * Initialize this view with predefined graph settings
280 *
281 * @param gs graph settings
282 */
283 public void initPredefinedGraph(GraphSettings gs)
284 {
285 settings = gs;
286 settings.addChangeListener(this);
287 configureGraphFromSettings();
288 }
289
290 /**
291 * Configure graph from graph settings
292 */
293 private void configureGraphFromSettings()
294 {
295 if (chart != null)
296 ((Widget)chart).dispose();
297 chart = ChartFactory.createLineChart(chartParent, SWT.NONE);
298 createPopupMenu();
299
300 // General settings
301 setPartName(settings.getTitle());
302 chart.setChartTitle(settings.getTitle());
303
304 // Chart visual settings
305 chart.setLogScaleEnabled(settings.isLogScale());
306 chart.setGridVisible(settings.isShowGrid());
307 chart.setLegendVisible(settings.isShowLegend());
308 chart.setLegendPosition(settings.getLegendPosition());
309 chart.setExtendedLegend(settings.isExtendedLegend());
310 chart.setStacked(settings.isStacked());
311 chart.setTranslucent(settings.isTranslucent());
312 chart.setLineWidth(settings.getLineWidth());
313 if(!settings.isAutoScale())
314 chart.setYAxisRange(settings.getMinYScaleValue(), settings.getMaxYScaleValue());
315 else
316 chart.modifyYBase(settings.modifyYBase());
317
318 // Data
319 final List<GraphItemStyle> styles = new ArrayList<GraphItemStyle>(settings.getDciList().length);
320 int index = 0;
321 int nodeId = 0;
322 for(ChartDciConfig dci : settings.getDciList())
323 {
324 nodeId |= dci.nodeId; //Check that all DCI's are form one node
325 final String name = settings.isShowHostNames() ? (session.getObjectName(dci.nodeId) + " - " + dci.getName()) : dci.getName(); //$NON-NLS-1$
326 chart.addParameter(new GraphItem(dci.nodeId, dci.dciId, 0, 0, Long.toString(dci.dciId), name, dci.getDisplayFormat()));
327 int color = dci.getColorAsInt();
328 if (color == -1)
329 color = ChartColor.getDefaultColor(index).getRGB();
330 styles.add(new GraphItemStyle(getDisplayType(dci), color, 2, dci.invertValues ? GraphItemStyle.INVERTED : 0));
331 index++;
332 }
333
334 //Check that all DCI's are form one node
335 if(index > 0)
336 useMoreThanOneShoucrNode = (nodeId != settings.getDciList()[0].nodeId);
337
338 chart.setItemStyles(styles);
339
340 if (settings.getTimeFrameType() == GraphSettings.TIME_FRAME_BACK_FROM_NOW)
341 {
342 settings.setTimeFrom(new Date(System.currentTimeMillis() - settings.getTimeRangeMillis()));
343 settings.setTimeTo(new Date(System.currentTimeMillis()));
344 }
345
346 getDataFromServer();
347
348 // Automatic refresh
349 actionAutoRefresh.setChecked(settings.isAutoRefresh());
350 refreshMenuSelection();
351 refreshController.setInterval(settings.isAutoRefresh() ? settings.getRefreshRate() : -1);
352 }
353
354 /**
355 * @param dci
356 * @return
357 */
358 private int getDisplayType(ChartDciConfig dci)
359 {
360 int type = dci.getDisplayType();
361 switch(type)
362 {
363 case ChartDciConfig.AREA:
364 return GraphItemStyle.AREA;
365 case ChartDciConfig.LINE:
366 return GraphItemStyle.LINE;
367 default:
368 return settings.isArea() ? GraphItemStyle.AREA : GraphItemStyle.LINE;
369 }
370 }
371
372 /*
373 * (non-Javadoc)
374 *
375 * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
376 */
377 @Override
378 public void createPartControl(Composite parent)
379 {
380 chartParent = parent;
381
382 createActions();
383 contributeToActionBars();
384
385 configureGraphFromSettings();
386 settings.addChangeListener(this);
387 }
388
389 /**
390 * Create pop-up menu
391 */
392 private void createPopupMenu()
393 {
394 // Create menu manager.
395 MenuManager menuMgr = new MenuManager();
396 menuMgr.setRemoveAllWhenShown(true);
397 menuMgr.addMenuListener(new IMenuListener() {
398 public void menuAboutToShow(IMenuManager mgr)
399 {
400 fillContextMenu(mgr);
401 }
402 });
403
404 // Create menu
405 Menu menu = menuMgr.createContextMenu((Control)chart);
406 ((Control)chart).setMenu(menu);
407 for(Control ch : ((Composite)chart).getChildren())
408 {
409 ch.setMenu(menu);
410 }
411 }
412
413 /**
414 * Get DCI data from server
415 */
416 private void getDataFromServer()
417 {
418 final ChartDciConfig[] dciList = settings.getDciList();
419
420 // Request data from server
421 ConsoleJob job = new ConsoleJob(Messages.get().HistoricalGraphView_JobName, this, Activator.PLUGIN_ID, Activator.PLUGIN_ID) {
422 private ChartDciConfig currentItem;
423
424 @Override
425 protected void runInternal(IProgressMonitor monitor) throws Exception
426 {
427 monitor.beginTask(getName(), dciList.length);
428 final DciData[] data = new DciData[dciList.length];
429 final Threshold[][] thresholds = new Threshold[dciList.length][];
430 for(int i = 0; i < dciList.length; i++)
431 {
432 currentItem = dciList[i];
433 if (currentItem.type == ChartDciConfig.ITEM)
434 {
435 data[i] = session.getCollectedData(currentItem.nodeId, currentItem.dciId, settings.getTimeFrom(),
436 settings.getTimeTo(), 0);
437 thresholds[i] = session.getThresholds(currentItem.nodeId, currentItem.dciId);
438 }
439 else
440 {
441 data[i] = session.getCollectedTableData(currentItem.nodeId, currentItem.dciId, currentItem.instance,
442 currentItem.column, settings.getTimeFrom(), settings.getTimeTo(), 0);
443 thresholds[i] = null;
444 }
445 monitor.worked(1);
446 }
447
448 runInUIThread(new Runnable() {
449 @Override
450 public void run()
451 {
452 if (!((Widget)chart).isDisposed())
453 {
454 chart.setTimeRange(settings.getTimeFrom(), settings.getTimeTo());
455 setChartData(data);
456 chart.clearErrors();
457 }
458 updateInProgress = false;
459 }
460 });
461 }
462
463 @Override
464 protected String getErrorMessage()
465 {
466 return String.format(Messages.get().HistoricalGraphView_JobError, session.getObjectName(currentItem.nodeId), currentItem.name);
467 }
468
469 @Override
470 protected void jobFailureHandler()
471 {
472 updateInProgress = false;
473 super.jobFailureHandler();
474 }
475
476 @Override
477 protected IStatus createFailureStatus(final Exception e)
478 {
479 runInUIThread(new Runnable() {
480 @Override
481 public void run()
482 {
483 chart.addError(getErrorMessage() + " (" + e.getLocalizedMessage() + ")"); //$NON-NLS-1$ //$NON-NLS-2$
484 }
485 });
486 return Status.OK_STATUS;
487 }
488 };
489 job.setUser(false);
490 job.start();
491 }
492
493 /*
494 * (non-Javadoc)
495 *
496 * @see org.eclipse.ui.part.WorkbenchPart#setFocus()
497 */
498 @Override
499 public void setFocus()
500 {
501 ((Composite)chart).setFocus();
502 }
503
504 /**
505 * Create actions
506 */
507 private void createActions()
508 {
509 actionRefresh = new RefreshAction(this) {
510 @Override
511 public void run()
512 {
513 updateChart();
514 }
515 };
516
517 actionProperties = new Action(Messages.get().HistoricalGraphView_Properties) {
518 @Override
519 public void run()
520 {
521 PropertyDialog dlg = PropertyDialog.createDialogOn(getSite().getShell(), null, settings);
522 if (dlg != null)
523 {
524 dlg.open();
525 configureGraphFromSettings();
526 refreshMenuSelection();
527 }
528 }
529 };
530
531 actionAutoRefresh = new Action(Messages.get().HistoricalGraphView_Autorefresh) {
532 @Override
533 public void run()
534 {
535 settings.setAutoRefresh(!settings.isAutoRefresh());
536 setChecked(settings.isAutoRefresh());
537 refreshController.setInterval(settings.isAutoRefresh() ? settings.getRefreshRate() : -1);
538 }
539 };
540 actionAutoRefresh.setChecked(settings.isAutoRefresh());
541
542 actionLogScale = new Action(Messages.get().HistoricalGraphView_LogScale) {
543 @Override
544 public void run()
545 {
546 try
547 {
548 chart.setLogScaleEnabled(!settings.isLogScale());
549 settings.setLogScale(!settings.isLogScale());
550 }
551 catch(IllegalStateException e)
552 {
553 MessageDialogHelper.openError(getSite().getShell(), Messages.get().HistoricalGraphView_Error,
554 String.format(Messages.get().HistoricalGraphView_LogScaleSwitchError, e.getLocalizedMessage()));
555 Activator.logError("Cannot change log scale mode", e); //$NON-NLS-1$
556 }
557 setChecked(settings.isLogScale());
558 }
559 };
560 actionLogScale.setChecked(settings.isLogScale());
561
562 actionZoomIn = new Action(Messages.get().HistoricalGraphView_ZoomIn) {
563 @Override
564 public void run()
565 {
566 chart.zoomIn();
567 }
568 };
569 actionZoomIn.setImageDescriptor(SharedIcons.ZOOM_IN);
570
571 actionZoomOut = new Action(Messages.get().HistoricalGraphView_ZoomOut) {
572 @Override
573 public void run()
574 {
575 chart.zoomOut();
576 }
577 };
578 actionZoomOut.setImageDescriptor(SharedIcons.ZOOM_OUT);
579
580 actionAdjustX = createAction(ActionType.ADJUST_X, chart);
581 actionAdjustY = createAction(ActionType.ADJUST_Y, chart);
582 actionAdjustBoth = createAction(ActionType.ADJUST_BOTH, chart);
583
584 actionShowLegend = new Action(Messages.get().HistoricalGraphView_ShowLegend) {
585 @Override
586 public void run()
587 {
588 settings.setShowLegend(actionShowLegend.isChecked());
589 chart.setLegendVisible(settings.isShowLegend());
590 }
591 };
592 actionShowLegend.setChecked(settings.isShowLegend());
593
594 actionExtendedLegend = new Action(Messages.get().HistoricalGraphView_ExtendedLegend) {
595 @Override
596 public void run()
597 {
598 settings.setExtendedLegend(actionExtendedLegend.isChecked());
599 chart.setExtendedLegend(settings.isExtendedLegend());
600 }
601 };
602 actionExtendedLegend.setChecked(settings.isExtendedLegend());
603
604 actionLegendLeft = new Action(Messages.get().HistoricalGraphView_PlaceOnLeft, Action.AS_RADIO_BUTTON) {
605 @Override
606 public void run()
607 {
608 settings.setLegendPosition(GraphSettings.POSITION_LEFT);
609 chart.setLegendPosition(settings.getLegendPosition());
610 }
611 };
612 actionLegendLeft.setChecked(settings.getLegendPosition() == GraphSettings.POSITION_LEFT);
613
614 actionLegendRight = new Action(Messages.get().HistoricalGraphView_PlaceOnRight, Action.AS_RADIO_BUTTON) {
615 @Override
616 public void run()
617 {
618 settings.setLegendPosition(GraphSettings.POSITION_RIGHT);
619 chart.setLegendPosition(settings.getLegendPosition());
620 }
621 };
622 actionLegendRight.setChecked(settings.getLegendPosition() == GraphSettings.POSITION_RIGHT);
623
624 actionLegendTop = new Action(Messages.get().HistoricalGraphView_PlaceOnTop, Action.AS_RADIO_BUTTON) {
625 @Override
626 public void run()
627 {
628 settings.setLegendPosition(GraphSettings.POSITION_TOP);
629 chart.setLegendPosition(settings.getLegendPosition());
630 }
631 };
632 actionLegendTop.setChecked(settings.getLegendPosition() == GraphSettings.POSITION_TOP);
633
634 actionLegendBottom = new Action(Messages.get().HistoricalGraphView_PlaceOnBottom, Action.AS_RADIO_BUTTON) {
635 @Override
636 public void run()
637 {
638 settings.setLegendPosition(GraphSettings.POSITION_BOTTOM);
639 chart.setLegendPosition(settings.getLegendPosition());
640 }
641 };
642 actionLegendBottom.setChecked(settings.getLegendPosition() == GraphSettings.POSITION_BOTTOM);
643
644 actionSave = new Action(Messages.get().HistoricalGraphView_Save, SharedIcons.SAVE) {
645 @Override
646 public void run()
647 {
648 String initalName = settings.getName().compareTo("noname") == 0 ? settings.getTitle() : settings.getName();
649 saveGraph(initalName, null, false, false);
650 }
651 };
652
653 //TODO: add check that graph uses only one node as source
654 actionSaveAsTemplate = new Action("Save as template", SharedIcons.SAVE_AS) {
655 @Override
656 public void run()
657 {
658 String initalName = settings.getName().compareTo("noname") == 0 ? settings.getTitle() : settings.getName();
659 saveGraph(initalName, null, false, true);
660 }
661 };
662
663 actionStacked = new Action(Messages.get().HistoricalGraphView_Stacked, Action.AS_CHECK_BOX) {
664 @Override
665 public void run()
666 {
667 settings.setStacked(actionStacked.isChecked());
668 configureGraphFromSettings();
669 }
670 };
671 actionStacked.setChecked(settings.isStacked());
672
673 actionTranslucent = new Action(Messages.get().HistoricalGraphView_Translucent, Action.AS_CHECK_BOX) {
674 @Override
675 public void run()
676 {
677 settings.setTranslucent(actionTranslucent.isChecked());
678 configureGraphFromSettings();
679 }
680 };
681 actionTranslucent.setChecked(settings.isTranslucent());
682
683 actionAreaChart = new Action("Area chart", Action.AS_CHECK_BOX) {
684 @Override
685 public void run()
686 {
687 settings.setArea(actionAreaChart.isChecked());
688 configureGraphFromSettings();
689 }
690 };
691 actionAreaChart.setChecked(settings.isArea());
692
693 presetActions = createPresetActions(new PresetHandler() {
694 @Override
695 public void onPresetSelected(int units, int range)
696 {
697 settings.setTimeUnits(units);
698 settings.setTimeRange(range);
699 updateChart();
700 }
701 });
702
703 actionSaveAsImage = new Action("Save as image", SharedIcons.SAVE_AS_IMAGE) {
704 @Override
705 public void run()
706 {
707 chart.saveAsImage();
708 }
709 };
710 }
711
712 /**
713 *
714 */
715 protected void refreshMenuSelection()
716 {
717 actionAutoRefresh.setChecked(settings.isAutoRefresh());
718 actionLogScale.setChecked(settings.isLogScale());
719 actionShowLegend.setChecked(settings.isShowLegend());
720 actionExtendedLegend.setChecked(settings.isExtendedLegend());
721 actionStacked.setChecked(settings.isStacked());
722 actionTranslucent.setChecked(settings.isTranslucent());
723 actionAreaChart.setChecked(settings.isArea());
724
725 actionLegendLeft.setChecked(settings.getLegendPosition() == GraphSettings.POSITION_LEFT);
726 actionLegendRight.setChecked(settings.getLegendPosition() == GraphSettings.POSITION_RIGHT);
727 actionLegendTop.setChecked(settings.getLegendPosition() == GraphSettings.POSITION_TOP);
728 actionLegendBottom.setChecked(settings.getLegendPosition() == GraphSettings.POSITION_BOTTOM);
729 }
730
731 /**
732 * Fill action bars
733 */
734 private void contributeToActionBars()
735 {
736 IActionBars bars = getViewSite().getActionBars();
737 fillLocalPullDown(bars.getMenuManager());
738 fillLocalToolBar(bars.getToolBarManager());
739 }
740
741 /**
742 * Fill local pull-down menu
743 *
744 * @param manager
745 */
746 private void fillLocalPullDown(IMenuManager manager)
747 {
748 MenuManager presets = new MenuManager(Messages.get().HistoricalGraphView_Presets);
749 for(int i = 0; i < presetActions.length; i++)
750 presets.add(presetActions[i]);
751
752 MenuManager legend = new MenuManager(Messages.get().HistoricalGraphView_Legend);
753 legend.add(actionShowLegend);
754 legend.add(actionExtendedLegend);
755 legend.add(new Separator());
756 legend.add(actionLegendLeft);
757 legend.add(actionLegendRight);
758 legend.add(actionLegendTop);
759 legend.add(actionLegendBottom);
760
761 manager.add(presets);
762 manager.add(new Separator());
763 manager.add(actionAdjustBoth);
764 manager.add(actionAdjustX);
765 manager.add(actionAdjustY);
766 manager.add(new Separator());
767 manager.add(actionZoomIn);
768 manager.add(actionZoomOut);
769 manager.add(new Separator());
770 manager.add(actionAreaChart);
771 manager.add(actionStacked);
772 manager.add(actionLogScale);
773 manager.add(actionTranslucent);
774 manager.add(actionAutoRefresh);
775 manager.add(legend);
776 manager.add(new Separator());
777 manager.add(actionRefresh);
778 manager.add(new Separator());
779 manager.add(actionSave);
780 manager.add(actionSaveAsTemplate);
781 manager.add(actionProperties);
782 }
783
784 /**
785 * Fill context menu
786 *
787 * @param manager
788 */
789 private void fillContextMenu(IMenuManager manager)
790 {
791 MenuManager presets = new MenuManager(Messages.get().HistoricalGraphView_Presets);
792 for(int i = 0; i < presetActions.length; i++)
793 presets.add(presetActions[i]);
794
795 MenuManager legend = new MenuManager(Messages.get().HistoricalGraphView_Legend);
796 legend.add(actionShowLegend);
797 legend.add(actionExtendedLegend);
798 legend.add(new Separator());
799 legend.add(actionLegendLeft);
800 legend.add(actionLegendRight);
801 legend.add(actionLegendTop);
802 legend.add(actionLegendBottom);
803
804 manager.add(presets);
805 manager.add(new Separator());
806 manager.add(actionAdjustBoth);
807 manager.add(actionAdjustX);
808 manager.add(actionAdjustY);
809 manager.add(new Separator());
810 manager.add(actionZoomIn);
811 manager.add(actionZoomOut);
812 manager.add(new Separator());
813 manager.add(actionAreaChart);
814 manager.add(actionStacked);
815 manager.add(actionLogScale);
816 manager.add(actionTranslucent);
817 manager.add(actionAutoRefresh);
818 manager.add(legend);
819 manager.add(new Separator());
820 manager.add(actionRefresh);
821 manager.add(new Separator());
822 manager.add(actionProperties);
823 }
824
825 /**
826 * Fill local tool bar
827 *
828 * @param manager
829 */
830 private void fillLocalToolBar(IToolBarManager manager)
831 {
832 manager.add(actionAdjustBoth);
833 manager.add(actionAdjustX);
834 manager.add(actionAdjustY);
835 manager.add(new Separator());
836 manager.add(actionZoomIn);
837 manager.add(actionZoomOut);
838 manager.add(new Separator());
839 manager.add(actionSave);
840 manager.add(actionSaveAsTemplate);
841 manager.add(actionSaveAsImage);
842 manager.add(new Separator());
843 manager.add(actionRefresh);
844 }
845
846 /**
847 * Set chart data
848 *
849 * @param data Retrieved DCI data
850 */
851 private void setChartData(final DciData[] data)
852 {
853 for(int i = 0; i < data.length; i++)
854 chart.updateParameter(i, data[i], false);
855 chart.refresh();
856 }
857
858 /**
859 * Update chart
860 */
861 private void updateChart()
862 {
863 if (updateInProgress)
864 return;
865
866 updateInProgress = true;
867 settings.setTimeFrom(new Date(System.currentTimeMillis() - settings.getTimeRangeMillis()));
868 settings.setTimeTo(new Date(System.currentTimeMillis()));
869 getDataFromServer();
870 }
871
872 /*
873 * (non-Javadoc)
874 *
875 * @see org.eclipse.ui.part.WorkbenchPart#dispose()
876 */
877 @Override
878 public void dispose()
879 {
880 refreshController.dispose();
881 super.dispose();
882 }
883
884 /*
885 * (non-Javadoc)
886 *
887 * @see
888 * org.netxms.client.datacollection.GraphSettingsChangeListener#onGraphSettingsChange(org.netxms.client.datacollection.GraphSettings
889 * )
890 */
891 @Override
892 public void onGraphSettingsChange(ChartConfig settings)
893 {
894 if (this.settings == settings)
895 configureGraphFromSettings();
896 }
897
898 /**
899 * Save this graph as predefined
900 */
901 private void saveGraph(String graphName, String errorMessage, final boolean canBeOverwritten, final boolean asTemplate)
902 {
903 if(asTemplate && useMoreThanOneShoucrNode)
904 {
905 String templateError = "More than one node is used for template creation.\nThis may cause undefined behaviour.";
906 errorMessage = errorMessage == null ? templateError : errorMessage+"\n\n" +templateError;
907 }
908 SaveGraphDlg dlg = new SaveGraphDlg(getSite().getShell(), graphName, errorMessage, canBeOverwritten);
909 int result = dlg.open();
910 if (result == Window.CANCEL)
911 return;
912
913 final GraphSettings gs = new GraphSettings(0, session.getUserId(), 0, new ArrayList<AccessListElement>(0));
914 gs.setName(dlg.getName());
915 gs.setConfig(settings);
916 if(asTemplate)
917 {
918 gs.setFlags(GraphSettings.GRAPH_FLAG_TEMPLATE);
919 }
920
921 if (result == SaveGraphDlg.OVERRIDE)
922 {
923 new ConsoleJob(Messages.get().HistoricalGraphView_SaveSettings, this, Activator.PLUGIN_ID, null) {
924 @Override
925 protected void runInternal(IProgressMonitor monitor) throws Exception
926 {
927 session.saveGraph(gs, canBeOverwritten);
928 }
929
930 @Override
931 protected String getErrorMessage()
932 {
933 return Messages.get().HistoricalGraphView_SaveSettingsError;
934 }
935 }.start();
936 }
937 else
938 {
939 new ConsoleJob(Messages.get().HistoricalGraphView_SaveSettings, this, Activator.PLUGIN_ID, null) {
940 @Override
941 protected void runInternal(IProgressMonitor monitor) throws Exception
942 {
943 try
944 {
945 session.saveGraph(gs, canBeOverwritten);
946 }
947 catch(NXCException e)
948 {
949 if (e.getErrorCode() == RCC.OBJECT_ALREADY_EXISTS)
950 {
951 runInUIThread(new Runnable() {
952
953 @Override
954 public void run()
955 {
956 saveGraph(gs.getName(), Messages.get().HistoricalGraphView_NameAlreadyExist, true, asTemplate);
957 }
958
959 });
960 }
961 else
962 {
963 if (e.getErrorCode() == RCC.ACCESS_DENIED)
964 {
965 runInUIThread(new Runnable() {
966
967 @Override
968 public void run()
969 {
970 saveGraph(gs.getName(), Messages.get().HistoricalGraphView_NameAlreadyExistNoOverwrite, false, asTemplate);
971 }
972
973 });
974 }
975 else
976 {
977 throw e;
978 }
979 }
980 }
981 }
982
983 @Override
984 protected String getErrorMessage()
985 {
986 return Messages.get().HistoricalGraphView_SaveError;
987 }
988 }.start();
989 }
990 updateChart();
991 }
992
993 /**
994 * Create preset actions
995 *
996 * @param handler
997 * @return
998 */
999 public static Action[] createPresetActions(final PresetHandler handler)
1000 {
1001 Action[] actions = new Action[presetRanges.length];
1002 for(int i = 0; i < presetRanges.length; i++)
1003 {
1004 final Integer presetIndex = i;
1005 actions[i] = new Action(String.format(Messages.get().HistoricalGraphView_Last, presetNames[i])) {
1006 @Override
1007 public void run()
1008 {
1009 handler.onPresetSelected(presetUnits[presetIndex], presetRanges[presetIndex]);
1010 }
1011 };
1012 }
1013 return actions;
1014 }
1015
1016 /**
1017 * Create action for chart
1018 *
1019 * @param type
1020 * @param chart
1021 * @return
1022 */
1023 public static Action createAction(ActionType type, final HistoricalDataChart chart)
1024 {
1025 Action action = null;
1026 switch(type)
1027 {
1028 case ADJUST_BOTH:
1029 action = new Action() {
1030 @Override
1031 public void run()
1032 {
1033 chart.adjustXAxis(false);
1034 chart.adjustYAxis(true);
1035 }
1036 };
1037 action.setText(Messages.get().HistoricalGraphView_Adjust);
1038 action.setImageDescriptor(Activator.getImageDescriptor("icons/adjust.png")); //$NON-NLS-1$
1039 break;
1040 case ADJUST_X:
1041 action = new Action() {
1042 @Override
1043 public void run()
1044 {
1045 chart.adjustXAxis(true);
1046 }
1047 };
1048 action.setText(Messages.get().HistoricalGraphView_AdjustX);
1049 action.setImageDescriptor(Activator.getImageDescriptor("icons/adjust_x.png")); //$NON-NLS-1$
1050 break;
1051 case ADJUST_Y:
1052 action = new Action() {
1053 @Override
1054 public void run()
1055 {
1056 chart.adjustYAxis(true);
1057 }
1058 };
1059 action.setText(Messages.get().HistoricalGraphView_AdjustY);
1060 action.setImageDescriptor(Activator.getImageDescriptor("icons/adjust_y.png")); //$NON-NLS-1$
1061 break;
1062 }
1063 return action;
1064 }
1065
1066 /**
1067 * Action types
1068 */
1069 public enum ActionType
1070 {
1071 ADJUST_X, ADJUST_Y, ADJUST_BOTH
1072 }
1073
1074 /**
1075 * Preset handler
1076 */
1077 public interface PresetHandler
1078 {
1079 /**
1080 * Called when new preset selected
1081 *
1082 * @param units
1083 * @param range
1084 */
1085 public void onPresetSelected(int units, int range);
1086 }
1087 }