From: Francois Chouinard Date: Fri, 22 Jul 2011 15:49:28 +0000 (-0400) Subject: Refactor the Histogram View (Bug352885) X-Git-Url: http://drtracing.org/?a=commitdiff_plain;h=c392540b8698a11f37fe36d2950200a10a65c1c1;p=deliverable%2Ftracecompass.git Refactor the Histogram View (Bug352885) --- diff --git a/org.eclipse.linuxtools.lttng.ui.tests/src/org/eclipse/linuxtools/lttng/ui/tests/histogram/HistogramDataModelTest.java b/org.eclipse.linuxtools.lttng.ui.tests/src/org/eclipse/linuxtools/lttng/ui/tests/histogram/HistogramDataModelTest.java new file mode 100644 index 0000000000..7384e74a2f --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui.tests/src/org/eclipse/linuxtools/lttng/ui/tests/histogram/HistogramDataModelTest.java @@ -0,0 +1,389 @@ +/******************************************************************************* + * Copyright (c) 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Francois Chouinard - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.linuxtools.lttng.ui.tests.histogram; + +import static org.junit.Assert.assertTrue; + +import org.eclipse.linuxtools.lttng.ui.views.histogram.HistogramDataModel; +import org.eclipse.linuxtools.lttng.ui.views.histogram.HistogramScaledData; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * HistogramDataModelTest + *

+ * Unit tests for the HistogramDataModel class. + */ +public class HistogramDataModelTest { + + // ------------------------------------------------------------------------ + // Test data + // ------------------------------------------------------------------------ + + // ------------------------------------------------------------------------ + // Housekeeping + // ------------------------------------------------------------------------ + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + // ------------------------------------------------------------------------ + // Tests + // ------------------------------------------------------------------------ + + /** + * Test method for + * {@link org.eclipse.linuxtools.tmf.HistogramDataModel.views.histogram.TmfHistogramDataModel#HistogramDataModel()} + * . + */ + @Test + public void testHistogramDataModel() { + HistogramDataModel model = new HistogramDataModel(); + assertTrue(model.getNbBuckets() == HistogramDataModel.DEFAULT_NUMBER_OF_BUCKETS); + assertTrue(model.getNbEvents() == 0); + assertTrue(model.getBucketDuration() == 1); + assertTrue(model.getStartTime() == 0); + assertTrue(model.getEndTime() == 0); + assertTrue(model.getTimeLimit() == HistogramDataModel.DEFAULT_NUMBER_OF_BUCKETS); + } + + /** + * Test method for + * {@link org.eclipse.linuxtools.tmf.HistogramDataModel.views.histogram.TmfHistogramDataModel#HistogramDataModel(int)} + * . + */ + @Test + public void testHistogramDataModelInt() { + final int nbBuckets = 5 * 1000; + HistogramDataModel model = new HistogramDataModel(nbBuckets); + assertTrue(model.getNbEvents() == 0); + assertTrue(model.getNbBuckets() == nbBuckets); + assertTrue(model.getBucketDuration() == 1); + assertTrue(model.getStartTime() == 0); + assertTrue(model.getEndTime() == 0); + assertTrue(model.getTimeLimit() == nbBuckets); + } + + /** + * Test methods for + * {@link org.eclipse.linuxtools.tmf.HistogramDataModel.views.histogram.TmfHistogramDataModel#countEvent(long)} + * . + */ + @Test + public void testClear() { + final int nbBuckets = 100; + HistogramDataModel model = new HistogramDataModel(nbBuckets); + model.countEvent(-1); + + assertTrue(model.getNbEvents() == 0); + assertTrue(model.getNbBuckets() == nbBuckets); + assertTrue(model.getBucketDuration() == 1); + assertTrue(model.getStartTime() == 0); + assertTrue(model.getEndTime() == 0); + assertTrue(model.getTimeLimit() == nbBuckets); + } + + /** + * Test methods for + * {@link org.eclipse.linuxtools.tmf.HistogramDataModel.views.histogram.TmfHistogramDataModel#countEvent(long)} + * . + */ + @Test + public void testCountEvent_0() { + final int nbBuckets = 100; + HistogramDataModel model = new HistogramDataModel(nbBuckets); + model.countEvent(-1); + + assertTrue(model.getNbEvents() == 0); + assertTrue(model.getNbBuckets() == nbBuckets); + assertTrue(model.getBucketDuration() == 1); + assertTrue(model.getStartTime() == 0); + assertTrue(model.getEndTime() == 0); + assertTrue(model.getTimeLimit() == nbBuckets); + } + + @Test + public void testCountEvent_1() { + final int nbBuckets = 100; + final int maxHeight = 10; + + HistogramDataModel model = new HistogramDataModel(nbBuckets); + + HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight); + for (int i = 0; i < result.fData.length; i++) { + assertTrue(result.fData[i] == 0); + } + + assertTrue(model.getNbEvents() == 0); + assertTrue(model.getNbBuckets() == nbBuckets); + assertTrue(model.getBucketDuration() == 1); + assertTrue(model.getStartTime() == 0); + assertTrue(model.getEndTime() == 0); + assertTrue(model.getTimeLimit() == nbBuckets); + } + + @Test + public void testCountEvent_2() { + final int nbBuckets = 100; + final int maxHeight = 10; + + HistogramDataModel model = new HistogramDataModel(nbBuckets); + model.countEvent(1); + + HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight); + assertTrue(result.fData[0] == 1); + for (int i = 1; i < result.fData.length; i++) { + assertTrue(result.fData[i] == 0); + } + + assertTrue(model.getNbEvents() == 1); + assertTrue(model.getNbBuckets() == nbBuckets); + assertTrue(model.getBucketDuration() == 1); + assertTrue(model.getStartTime() == 1); + assertTrue(model.getEndTime() == 1); + assertTrue(model.getTimeLimit() == nbBuckets + 1); + } + + @Test + public void testCountEvent_3() { + final int nbBuckets = 100; + final int maxHeight = 10; + + HistogramDataModel model = new HistogramDataModel(nbBuckets); + for (int i = 0; i < nbBuckets; i++) { + model.countEvent(i); + } + + HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight); + for (int i = 0; i < result.fData.length; i++) { + assertTrue(result.fData[i] == 1); + } + + assertTrue(model.getNbEvents() == nbBuckets); + assertTrue(model.getNbBuckets() == nbBuckets); + assertTrue(model.getBucketDuration() == 1); + assertTrue(model.getStartTime() == 0); + assertTrue(model.getEndTime() == nbBuckets - 1); + assertTrue(model.getTimeLimit() == nbBuckets); + } + + @Test + public void testCountEvent_4() { + final int nbBuckets = 100; + final int maxHeight = 10; + + HistogramDataModel model = new HistogramDataModel(nbBuckets); + for (int i = 0; i < nbBuckets; i++) { + model.countEvent(i); + model.countEvent(i); + } + + HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight); + for (int i = 0; i < result.fData.length; i++) { + assertTrue(result.fData[i] == 2); + } + + assertTrue(model.getNbEvents() == 2 * nbBuckets); + assertTrue(model.getNbBuckets() == nbBuckets); + assertTrue(model.getBucketDuration() == 1); + assertTrue(model.getStartTime() == 0); + assertTrue(model.getEndTime() == nbBuckets - 1); + assertTrue(model.getTimeLimit() == nbBuckets); + } + + @Test + public void testCountEvent_5() { + final int nbBuckets = 100; + final int startTime = 25; + final int maxHeight = 10; + + HistogramDataModel model = new HistogramDataModel(nbBuckets); + for (int i = startTime; i < startTime + nbBuckets; i++) { + model.countEvent(i); + } + + HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight); + for (int i = 0; i < result.fData.length; i++) { + assertTrue(result.fData[i] == 1); + } + + assertTrue(model.getNbEvents() == nbBuckets); + assertTrue(model.getNbBuckets() == nbBuckets); + assertTrue(model.getBucketDuration() == 1); + assertTrue(model.getStartTime() == startTime); + assertTrue(model.getEndTime() == startTime + nbBuckets - 1); + assertTrue(model.getTimeLimit() == startTime + nbBuckets); + } + + /** + * Test method for + * {@link org.eclipse.linuxtools.tmf.HistogramDataModel.views.histogram.TmfHistogramDataModel#scaleTo(int,int)} + * . + */ + @Test + public void testScaleTo_1() { + final int nbBuckets = 10; + final int maxHeight = 10; + final int nbEvents = nbBuckets / 2; + final int[] expectedResult = new int[] { 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 }; + + HistogramDataModel model = new HistogramDataModel(nbBuckets); + for (int i = 0; i < nbEvents; i++) { + model.countEvent(i); + } + + HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight); + for (int i = 0; i < result.fData.length; i++) { + assertTrue(result.fData[i] == expectedResult[i]); + } + + assertTrue(model.getNbEvents() == nbEvents); + assertTrue(model.getNbBuckets() == nbBuckets); + assertTrue(model.getBucketDuration() == 1); + assertTrue(model.getStartTime() == 0); + assertTrue(model.getEndTime() == nbEvents - 1); + assertTrue(model.getTimeLimit() == nbBuckets); + } + + @Test + public void testScaleTo_2() { + final int nbBuckets = 10; + final int maxHeight = 10; + final int nbEvents = nbBuckets; + final int[] expectedResult = new int[] { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; + + HistogramDataModel model = new HistogramDataModel(nbBuckets); + for (int i = 0; i < nbEvents; i++) { + model.countEvent(i); + } + + HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight); + for (int i = 0; i < result.fData.length; i++) { + assertTrue(result.fData[i] == expectedResult[i]); + } + + assertTrue(model.getNbEvents() == nbEvents); + assertTrue(model.getNbBuckets() == nbBuckets); + assertTrue(model.getBucketDuration() == 1); + assertTrue(model.getStartTime() == 0); + assertTrue(model.getEndTime() == nbEvents - 1); + assertTrue(model.getTimeLimit() == nbBuckets); + } + + @Test + public void testScaleTo_3() { + final int nbBuckets = 10; + final int maxHeight = 10; + final int nbEvents = 2 * nbBuckets; + final int[] expectedResult = new int[] { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }; + + HistogramDataModel model = new HistogramDataModel(nbBuckets); + for (int i = 0; i < nbEvents; i++) { + model.countEvent(i); + } + + HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight); + for (int i = 0; i < result.fData.length; i++) { + assertTrue(result.fData[i] == expectedResult[i]); + } + + assertTrue(model.getNbEvents() == nbEvents); + assertTrue(model.getNbBuckets() == nbBuckets); + assertTrue(model.getBucketDuration() == 2); + assertTrue(model.getStartTime() == 0); + assertTrue(model.getEndTime() == nbEvents - 1); + assertTrue(model.getTimeLimit() == 2 * nbBuckets); + } + + @Test + public void testScaleTo_4() { + final int nbBuckets = 10; + final int maxHeight = 10; + final int nbEvents = 3 * nbBuckets; + final int[] expectedResult = new int[] { 4, 4, 4, 4, 4, 4, 4, 2, 0, 0 }; + + HistogramDataModel model = new HistogramDataModel(nbBuckets); + for (int i = 0; i < nbEvents; i++) { + model.countEvent(i); + } + + HistogramScaledData result = model.scaleTo(nbBuckets, maxHeight); + for (int i = 0; i < result.fData.length; i++) { + assertTrue(result.fData[i] == expectedResult[i]); + } + + assertTrue(model.getNbEvents() == nbEvents); + assertTrue(model.getNbBuckets() == nbBuckets); + assertTrue(model.getBucketDuration() == 4); + assertTrue(model.getStartTime() == 0); + assertTrue(model.getEndTime() == nbEvents - 1); + assertTrue(model.getTimeLimit() == 4 * nbBuckets); + } + + @Test + public void testScaleTo_5() { + final int nbBuckets = 100; + final int maxHeight = 20; + final int nbEvents = 2 * nbBuckets; + final int[] expectedResult = new int[] { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20 }; + + HistogramDataModel model = new HistogramDataModel(nbBuckets); + for (int i = 0; i < nbEvents; i++) { + model.countEvent(i); + } + + HistogramScaledData result = model.scaleTo(10, maxHeight); + for (int i = 0; i < result.fData.length; i++) { + assertTrue(result.fData[i] == expectedResult[i]); + } + + assertTrue(model.getNbEvents() == nbEvents); + assertTrue(model.getNbBuckets() == nbBuckets); + assertTrue(model.getBucketDuration() == 2); + assertTrue(model.getStartTime() == 0); + assertTrue(model.getEndTime() == nbEvents - 1); + assertTrue(model.getTimeLimit() == 2 * nbBuckets); + } + + @Test + public void testScaleTo_6() { + final int nbBuckets = 100; + final int maxHeight = 24; + final int nbEvents = 2 * nbBuckets + 1; + final int[] expectedResult = new int[] { 24, 24, 24, 24, 24, 24, 24, 24, 9, 0 }; + + HistogramDataModel model = new HistogramDataModel(nbBuckets); + for (int i = 0; i < nbEvents; i++) { + model.countEvent(i); + } + + HistogramScaledData result = model.scaleTo(10, maxHeight); + for (int i = 0; i < result.fData.length; i++) { + assertTrue(result.fData[i] == expectedResult[i]); + } + + assertTrue(model.getNbEvents() == nbEvents); + assertTrue(model.getNbBuckets() == nbBuckets); + assertTrue(model.getBucketDuration() == 4); + assertTrue(model.getStartTime() == 0); + assertTrue(model.getEndTime() == nbEvents - 1); + assertTrue(model.getTimeLimit() == 4 * nbBuckets); + } + +} diff --git a/org.eclipse.linuxtools.lttng.ui/META-INF/MANIFEST.MF b/org.eclipse.linuxtools.lttng.ui/META-INF/MANIFEST.MF index 48a739faed..a9ddff0518 100644 --- a/org.eclipse.linuxtools.lttng.ui/META-INF/MANIFEST.MF +++ b/org.eclipse.linuxtools.lttng.ui/META-INF/MANIFEST.MF @@ -22,3 +22,33 @@ Require-Bundle: org.eclipse.ui, Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Bundle-ActivationPolicy: lazy Bundle-Localization: plugin +Export-Package: org.eclipse.linuxtools.lttng.ui;x-friends:="org.eclipse.linuxtools.lttng.ui.tests", + org.eclipse.linuxtools.lttng.ui.model.trange;x-friends:="org.eclipse.linuxtools.lttng.ui.tests", + org.eclipse.linuxtools.lttng.ui.tracecontrol;x-friends:="org.eclipse.linuxtools.lttng.ui.tests", + org.eclipse.linuxtools.lttng.ui.tracecontrol.actions;x-friends:="org.eclipse.linuxtools.lttng.ui.tests", + org.eclipse.linuxtools.lttng.ui.tracecontrol.connectorservice;x-friends:="org.eclipse.linuxtools.lttng.ui.tests", + org.eclipse.linuxtools.lttng.ui.tracecontrol.dialogs;x-friends:="org.eclipse.linuxtools.lttng.ui.tests", + org.eclipse.linuxtools.lttng.ui.tracecontrol.model;x-friends:="org.eclipse.linuxtools.lttng.ui.tests", + org.eclipse.linuxtools.lttng.ui.tracecontrol.model.config;x-friends:="org.eclipse.linuxtools.lttng.ui.tests", + org.eclipse.linuxtools.lttng.ui.tracecontrol.subsystems;x-friends:="org.eclipse.linuxtools.lttng.ui.tests", + org.eclipse.linuxtools.lttng.ui.tracecontrol.utility;x-friends:="org.eclipse.linuxtools.lttng.ui.tests", + org.eclipse.linuxtools.lttng.ui.tracecontrol.wizards;x-friends:="org.eclipse.linuxtools.lttng.ui.tests", + org.eclipse.linuxtools.lttng.ui.views;x-friends:="org.eclipse.linuxtools.lttng.ui.tests", + org.eclipse.linuxtools.lttng.ui.views.common;x-friends:="org.eclipse.linuxtools.lttng.ui.tests", + org.eclipse.linuxtools.lttng.ui.views.control;x-friends:="org.eclipse.linuxtools.lttng.ui.tests", + org.eclipse.linuxtools.lttng.ui.views.controlflow;x-friends:="org.eclipse.linuxtools.lttng.ui.tests", + org.eclipse.linuxtools.lttng.ui.views.controlflow.evProcessor;x-friends:="org.eclipse.linuxtools.lttng.ui.tests", + org.eclipse.linuxtools.lttng.ui.views.controlflow.model;x-friends:="org.eclipse.linuxtools.lttng.ui.tests", + org.eclipse.linuxtools.lttng.ui.views.events;x-friends:="org.eclipse.linuxtools.lttng.ui.tests", + org.eclipse.linuxtools.lttng.ui.views.histogram;x-friends:="org.eclipse.linuxtools.lttng.ui.tests", + org.eclipse.linuxtools.lttng.ui.views.project;x-friends:="org.eclipse.linuxtools.lttng.ui.tests", + org.eclipse.linuxtools.lttng.ui.views.project.dialogs;x-friends:="org.eclipse.linuxtools.lttng.ui.tests", + org.eclipse.linuxtools.lttng.ui.views.project.handlers;x-friends:="org.eclipse.linuxtools.lttng.ui.tests", + org.eclipse.linuxtools.lttng.ui.views.project.model;x-friends:="org.eclipse.linuxtools.lttng.ui.tests", + org.eclipse.linuxtools.lttng.ui.views.resources;x-friends:="org.eclipse.linuxtools.lttng.ui.tests", + org.eclipse.linuxtools.lttng.ui.views.resources.evProcessor;x-friends:="org.eclipse.linuxtools.lttng.ui.tests", + org.eclipse.linuxtools.lttng.ui.views.resources.model;x-friends:="org.eclipse.linuxtools.lttng.ui.tests", + org.eclipse.linuxtools.lttng.ui.views.statistics;x-friends:="org.eclipse.linuxtools.lttng.ui.tests", + org.eclipse.linuxtools.lttng.ui.views.statistics.evProcessor;x-friends:="org.eclipse.linuxtools.lttng.ui.tests", + org.eclipse.linuxtools.lttng.ui.views.statistics.model;x-friends:="org.eclipse.linuxtools.lttng.ui.tests", + org.eclipse.linuxtools.lttng.ui.views.timeframe;x-friends:="org.eclipse.linuxtools.lttng.ui.tests" diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/LTTngUILogger.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/LTTngUILogger.java new file mode 100644 index 0000000000..e6e163f056 --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/LTTngUILogger.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Francois Chouinard - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.linuxtools.lttng.ui; + +/** + * LTTngUILogger + *

+ * A logging utility + */ +public class LTTngUILogger { + + public static void logInfo(String message) { + LTTngUiPlugin.getDefault().getLogger().logInfo(message); + } + + public static void logWarning(String message) { + LTTngUiPlugin.getDefault().getLogger().logWarning(message); + } + + public static void logError(Throwable exception) { + logError("Unexpected exception", exception); //$NON-NLS-1$ + } + + public static void logError(String message, Throwable exception) { + LTTngUiPlugin.getDefault().getLogger().logError(message, exception); + } + +} diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/ChildrenHistogramCanvas.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/ChildrenHistogramCanvas.java deleted file mode 100644 index 23ba8adff6..0000000000 --- a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/ChildrenHistogramCanvas.java +++ /dev/null @@ -1,78 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009 Ericsson - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v1.0 which - * accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * William Bourque - Initial API and implementation - * - * Modifications: - * 2010-06-20 Yuriy Vashchuk - Histogram optimisations. - * 2010-07-16 Yuriy Vashchuk - Base Histogram class simplification. - *******************************************************************************/ -package org.eclipse.linuxtools.lttng.ui.views.histogram; - -import org.eclipse.swt.widgets.Composite; - -/** - * ChildrenHistogramCanvas - *

- * Extended implementation of the HistogramCanvas. - *

- * This canvas goal is to display the "SelectionWindow" in details. - */ -public class ChildrenHistogramCanvas extends HistogramCanvas { - - private HistogramCanvasPaintListener paintListener = null; - private HistogramCanvasControlListener controlListener = null; - - /** - * ChildrenHistogramCanvas constructor.

- * Same as HistogramCanvas, but receive a parent HistogramView that we can call from here. - * - * @param parent Composite control which will be the parent of the new instance (cannot be null) - * @param Style the style of control to construct - */ - public ChildrenHistogramCanvas(HistogramView histogramView, Composite parent, int style) { - super(histogramView, parent, style); - - // 2010-06-20 Yuriy: Moved from parent class - createAndAddPaintListener(); - createAndAddControlListener(); - } - - /* - * Create a histogram paint listener and bind it to this canvas.

- * - * Note : This one is a bit particular, as it is made to draw content that is of a power of 2. - * The default one draw content that is relative to the real pixels size. - */ - private void createAndAddPaintListener() { - paintListener = new HistogramCanvasPaintListener(this); - this.addPaintListener( paintListener ); - } - - /* - * Create a histogram control listener and bind it to this canvas.

- * - * @see org.eclipse.linuxtools.lttng.ui.views.histogram.HistogramCanvasControlListener - */ - private void createAndAddControlListener() { - controlListener = new HistogramCanvasControlListener(this); - this.addControlListener(controlListener); - } - - /** - * Notify the parent HistogramView that we have updated information.

- * This is intended to be called at the end of the request when we know we have up-to-date information. - */ - @Override - public void notifyParentUpdatedInformation() { - if(getHistogramView() != null) { - getHistogramView().updateSelectedWindowInformation(); - } - } -} diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/FullTraceHistogram.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/FullTraceHistogram.java new file mode 100644 index 0000000000..9cebbd4bbd --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/FullTraceHistogram.java @@ -0,0 +1,193 @@ +/******************************************************************************* + * Copyright (c) 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Francois Chouinard - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.linuxtools.lttng.ui.views.histogram; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseMoveListener; +import org.eclipse.swt.events.PaintEvent; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; + +/** + * FullTraceHistogram + *

+ * A histogram that displays the full trace. + *

+ * It also features a selected range window that can be dragged and zoomed. + */ +public class FullTraceHistogram extends Histogram implements MouseMoveListener { + + // ------------------------------------------------------------------------ + // Constants + // ------------------------------------------------------------------------ + + // Histogram colors + private final Color fTimeRangeColor = new Color(Display.getCurrent(), 255, 128, 0); + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + + private final HistogramZoom fZoom; + + private long fRangeStartTime; + private long fRangeDuration; + + // ------------------------------------------------------------------------ + // Construction + // ------------------------------------------------------------------------ + + public FullTraceHistogram(HistogramView view, Composite parent) { + super(view, parent); + fZoom = new HistogramZoom(this, fCanvas, getStartTime(), getTimeLimit()); + fCanvas.addMouseMoveListener(this); + } + + @Override + public void dispose() { + fTimeRangeColor.dispose(); + super.dispose(); + } + + // ------------------------------------------------------------------------ + // Operations + // ------------------------------------------------------------------------ + + public void setTimeRange(long startTime, long duration) { + fRangeStartTime = startTime; + fRangeDuration = duration; + fZoom.setFullRange(getStartTime(), getEndTime()); + fZoom.setNewRange(fRangeStartTime, fRangeDuration); + refresh(); + } + + @Override + public void updateTimeRange(long startTime, long endTime) { + ((HistogramView) fParentView).updateTimeRange(startTime, endTime); + } + + // ------------------------------------------------------------------------ + // MouseListener + // ------------------------------------------------------------------------ + + private boolean fMouseDown; + private int fStartPosition; + + @Override + public void mouseDown(MouseEvent event) { + // Check if we are outside the time range; if so, just set the current + // event + long timestamp = getTimestamp(event.x); + if (timestamp < fZoom.getStartTime() || timestamp > fZoom.getEndTime()) { + super.mouseDown(event); + return; + } + + // Otherwise start moving the range window + fMouseDown = true; + fStartPosition = event.x; + } + + @Override + public void mouseUp(MouseEvent event) { + if (fMouseDown) { + fMouseDown = false; + ((HistogramView) fParentView).updateTimeRange(fRangeStartTime, fRangeStartTime + fZoom.getDuration()); + } + } + + // ------------------------------------------------------------------------ + // MouseMoveListener + // ------------------------------------------------------------------------ + + @Override + public void mouseMove(MouseEvent event) { + if (fMouseDown) { + int nbBuckets = event.x - fStartPosition; + long delta = nbBuckets * fScaledData.fBucketDuration; + long newStart = fZoom.getStartTime() + delta; + if (newStart < getStartTime()) + newStart = getStartTime(); + long newEnd = newStart + fZoom.getDuration(); + if (newEnd > getEndTime()) { + newEnd = getEndTime(); + newStart = newEnd - fZoom.getDuration(); + } + fRangeStartTime = newStart; + refresh(); + } + } + + // ------------------------------------------------------------------------ + // PaintListener + // ------------------------------------------------------------------------ + + @Override + public void paintControl(PaintEvent event) { + super.paintControl(event); + + Image image = (Image) fCanvas.getData(IMAGE_KEY); + assert image != null; + + Image rangeRectangleImage = new Image(image.getDevice(), image, SWT.IMAGE_COPY); + GC rangeWindowGC = new GC(rangeRectangleImage); + + if (fRangeStartTime != 0) { + drawTimeRangeWindow(rangeWindowGC, rangeRectangleImage); + } + + // Draws the buffer image onto the canvas. + event.gc.drawImage(rangeRectangleImage, 0, 0); + + rangeWindowGC.dispose(); + rangeRectangleImage.dispose(); + } + + private void drawTimeRangeWindow(GC imageGC, Image image) { + + // Map times to histogram coordinates + long bucketSpan = fScaledData.fBucketDuration; + int rangeWidth = (int) (fRangeDuration / bucketSpan); + + int left = (int) ((fRangeStartTime - fDataModel.getStartTime()) / bucketSpan); + int right = left + rangeWidth; + int center = (left + right) / 2; + int height = fCanvas.getSize().y - 2; + + // Draw the selection window + imageGC.setForeground(fTimeRangeColor); + imageGC.setLineWidth(1); + imageGC.setLineStyle(SWT.LINE_SOLID); + imageGC.drawRoundRectangle(left, 0, rangeWidth, height - 1, 15, 15); + + // Fill the selection window + imageGC.setBackground(fTimeRangeColor); + imageGC.setAlpha(35); + imageGC.fillRoundRectangle(left + 1, 1, rangeWidth - 1, height - 2, 15, 15); + imageGC.setAlpha(255); + + // Draw the cross hair + imageGC.setForeground(fTimeRangeColor); + imageGC.setLineWidth(1); + imageGC.setLineStyle(SWT.LINE_SOLID); + + int chHalfWidth = ((rangeWidth < 60) ? rangeWidth * 2 / 3 : 40) / 2; + imageGC.drawLine(center - chHalfWidth, height / 2, center + chHalfWidth, height / 2); + imageGC.drawLine(center, height / 2 - chHalfWidth, center, height / 2 + chHalfWidth); + } + +} diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/Histogram.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/Histogram.java new file mode 100644 index 0000000000..fc604583c7 --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/Histogram.java @@ -0,0 +1,575 @@ +/******************************************************************************* + * Copyright (c) 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Francois Chouinard - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.linuxtools.lttng.ui.views.histogram; + +import org.eclipse.linuxtools.tmf.ui.views.TmfView; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ControlEvent; +import org.eclipse.swt.events.ControlListener; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.KeyListener; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.events.MouseTrackListener; +import org.eclipse.swt.events.PaintEvent; +import org.eclipse.swt.events.PaintListener; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.FontData; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Canvas; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Text; + +/** + * Histogram + *

+ * Re-usable histogram widget with the following features: + *

+ * The widget also has 2 'markers' to identify: + * + * Clicking on the histogram will select the current event at the mouse + * location. + *

+ * Once the histogram is selected, there is some limited keyboard support: + *

+ * Finally, when the mouse hovers over the histogram, a tool tip showing the + * following information about the corresponding histogram bar time range: + * + */ +public abstract class Histogram implements ControlListener, PaintListener, KeyListener, MouseListener, MouseTrackListener { + + // ------------------------------------------------------------------------ + // Constants + // ------------------------------------------------------------------------ + + // Histogram refresh frequency + private final static int REFRESH_FREQUENCY = HistogramDataModel.DEFAULT_NUMBER_OF_BUCKETS; + + // Histogram colors + private final Color fBackgroundColor = Display.getCurrent().getSystemColor(SWT.COLOR_WHITE); + private final Color fCurrentEventColor = Display.getCurrent().getSystemColor(SWT.COLOR_RED); + private final Color fLastEventColor = Display.getCurrent().getSystemColor(SWT.COLOR_DARK_RED); + private final Color fHistoBarColor = new Color(Display.getDefault(), 74, 112, 139); + + // Timestamp scale (nanosecond) + public static final byte TIME_SCALE = -9; + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + + // Owner view + protected TmfView fParentView; + + // Histogram text fields + private Text fMaxNbEventsText; + private Text fMinNbEventsText; + private Text fTimeRangeStartText; + private Text fTimeRangeEndText; + + // Histogram drawing area + protected Canvas fCanvas; + + // Data model + protected final HistogramDataModel fDataModel; + protected HistogramScaledData fScaledData; + + protected long fCurrentEventTime = 0; + + // ------------------------------------------------------------------------ + // Construction + // ------------------------------------------------------------------------ + + public Histogram(TmfView view, Composite parent) { + fParentView = view; + + createWidget(parent); + fDataModel = new HistogramDataModel(); + clear(); + + fCanvas.addControlListener(this); + fCanvas.addPaintListener(this); + fCanvas.addKeyListener(this); + fCanvas.addMouseListener(this); + fCanvas.addMouseTrackListener(this); + } + + public void dispose() { + fHistoBarColor.dispose(); + } + + private void createWidget(Composite parent) { + + final Color labelColor = parent.getDisplay().getSystemColor(SWT.COLOR_TITLE_INACTIVE_BACKGROUND); + final Font fFont = adjustFont(parent); + + final int initalWidth = 10; + + // -------------------------------------------------------------------- + // Define the histogram + // -------------------------------------------------------------------- + + GridLayout gridLayout = new GridLayout(); + gridLayout.numColumns = 3; + gridLayout.marginHeight = 0; + gridLayout.marginWidth = 0; + gridLayout.marginTop = 0; + gridLayout.horizontalSpacing = 0; + gridLayout.verticalSpacing = 0; + gridLayout.marginLeft = 0; + gridLayout.marginRight = 0; + Composite composite = new Composite(parent, SWT.FILL); + composite.setLayout(gridLayout); + + // Use all the horizontal space + GridData gridData = new GridData(); + gridData.horizontalAlignment = SWT.FILL; + gridData.verticalAlignment = SWT.FILL; + gridData.grabExcessHorizontalSpace = true; + composite.setLayoutData(gridData); + + // Y-axis max event + gridData = new GridData(); + gridData.horizontalAlignment = SWT.RIGHT; + gridData.verticalAlignment = SWT.TOP; + fMaxNbEventsText = new Text(composite, SWT.READ_ONLY | SWT.RIGHT); + fMaxNbEventsText.setFont(fFont); + fMaxNbEventsText.setBackground(labelColor); + fMaxNbEventsText.setEditable(false); + fMaxNbEventsText.setText("0"); //$NON-NLS-1$ + fMaxNbEventsText.setLayoutData(gridData); + + // Histogram itself + gridData = new GridData(); + gridData.horizontalSpan = 2; + gridData.verticalSpan = 2; + gridData.horizontalAlignment = SWT.FILL; + gridData.verticalAlignment = SWT.FILL; + gridData.grabExcessHorizontalSpace = true; + fCanvas = new Canvas(composite, SWT.BORDER | SWT.DOUBLE_BUFFERED); + fCanvas.setLayoutData(gridData); + + // Y-axis min event (always 0...) + gridData = new GridData(); + gridData.horizontalAlignment = SWT.RIGHT; + gridData.verticalAlignment = SWT.BOTTOM; + fMinNbEventsText = new Text(composite, SWT.READ_ONLY | SWT.RIGHT); + fMinNbEventsText.setFont(fFont); + fMinNbEventsText.setBackground(labelColor); + fMinNbEventsText.setEditable(false); + fMinNbEventsText.setText("0"); //$NON-NLS-1$ + fMinNbEventsText.setLayoutData(gridData); + + // Dummy cell + gridData = new GridData(initalWidth, SWT.DEFAULT); + gridData.horizontalAlignment = SWT.RIGHT; + gridData.verticalAlignment = SWT.BOTTOM; + Text dummyText = new Text(composite, SWT.READ_ONLY); + dummyText.setFont(fFont); + dummyText.setBackground(labelColor); + dummyText.setEditable(false); + dummyText.setText(""); //$NON-NLS-1$ + dummyText.setLayoutData(gridData); + + // Window range start time + gridData = new GridData(); + gridData.horizontalAlignment = SWT.LEFT; + gridData.verticalAlignment = SWT.BOTTOM; + fTimeRangeStartText = new Text(composite, SWT.READ_ONLY); + fTimeRangeStartText.setFont(fFont); + fTimeRangeStartText.setBackground(labelColor); + fTimeRangeStartText.setText(HistogramUtils.nanosecondsToString(0)); + fTimeRangeStartText.setLayoutData(gridData); + + // Window range end time + gridData = new GridData(); + gridData.horizontalAlignment = SWT.RIGHT; + gridData.verticalAlignment = SWT.BOTTOM; + fTimeRangeEndText = new Text(composite, SWT.READ_ONLY); + fTimeRangeEndText.setFont(fFont); + fTimeRangeEndText.setBackground(labelColor); + fTimeRangeEndText.setText(HistogramUtils.nanosecondsToString(0)); + fTimeRangeEndText.setLayoutData(gridData); + } + + private Font adjustFont(Composite composite) { + // Reduce font size for a more pleasing rendering + int fontSizeAdjustment = -2; + Font font = composite.getFont(); + FontData fontData = font.getFontData()[0]; + return new Font(font.getDevice(), fontData.getName(), fontData.getHeight() + fontSizeAdjustment, fontData.getStyle()); + } + + // ------------------------------------------------------------------------ + // Accessors + // ------------------------------------------------------------------------ + + public long getStartTime() { + return fDataModel.getStartTime(); + } + + public long getEndTime() { + return fDataModel.getEndTime(); + } + + public long getTimeLimit() { + return fDataModel.getTimeLimit(); + } + + // ------------------------------------------------------------------------ + // Operations + // ------------------------------------------------------------------------ + + public abstract void updateTimeRange(long startTime, long endTime); + + /** + * Clear the histogram and reset the data + */ + public void clear() { + fDataModel.clear(); + fScaledData = null; + refresh(); + } + + /** + * Increase the histogram bucket corresponding to [timestamp] + * + * @param timestamp + */ + public void countEvent(long timestamp) { + fDataModel.countEvent(timestamp); + if (fDataModel.getNbEvents() % REFRESH_FREQUENCY == 0) { + refresh(); + refresh(); + } + } + + /** + * Sets the current event time and refresh the display + * + * @param timestamp + */ + public void setCurrentEvent(long timestamp) { + fCurrentEventTime = timestamp; + fDataModel.setCurrentEvent(timestamp); + refresh(); + } + + /** + * Computes the timestamp of the bucket at [offset] + * + * @param offset offset from the left on the histogram + * @return the start timestamp of the corresponding bucket + */ + public synchronized long getTimestamp(int offset) { + assert offset > 0 && offset < fScaledData.fWidth; + try { + return fDataModel.getStartTime() + fScaledData.fBucketDuration * offset; + } catch (Exception e) { + return 0; // TODO: Fix that racing condition (NPE) + } + } + + /** + * Computes the offset of the timestamp in the histogram + * + * @param timestamp the timestamp + * @return the offset of the corresponding bucket (-1 if invalid) + */ + public synchronized int getOffset(long timestamp) { + if (timestamp < fDataModel.getStartTime() || timestamp > fDataModel.getEndTime()) + return -1; + return (int) ((timestamp - fDataModel.getStartTime()) / fScaledData.fBucketDuration); + } + + /** + * Move the currently selected bar cursor to a non-empty bucket. + * + * @param keyCode the SWT key code + */ + protected void moveCursor(int keyCode) { + + if (fScaledData.fCurrentBucket == HistogramScaledData.OUT_OF_RANGE_BUCKET) + return; + + int index; + switch (keyCode) { + + case SWT.HOME: + index = 0; + while (index < fScaledData.fLastBucket && fScaledData.fData[index] == 0) + index++; + if (index < fScaledData.fLastBucket) + fScaledData.fCurrentBucket = index; + break; + + case SWT.ARROW_RIGHT: + index = fScaledData.fCurrentBucket + 1; + while (index < fScaledData.fWidth && fScaledData.fData[index] == 0) + index++; + if (index < fScaledData.fLastBucket) + fScaledData.fCurrentBucket = index; + break; + + case SWT.END: + index = fScaledData.fLastBucket; + while (index >= 0 && fScaledData.fData[index] == 0) + index--; + if (index >= 0) + fScaledData.fCurrentBucket = index; + break; + + case SWT.ARROW_LEFT: + index = fScaledData.fCurrentBucket - 1; + while (index >= 0 && fScaledData.fData[index] == 0) + index--; + if (index >= 0) + fScaledData.fCurrentBucket = index; + break; + + default: + return; + } + + updateCurrentEventTime(); + } + + /** + * Refresh the histogram display + */ + protected void refresh() { + if (!fCanvas.isDisposed() && fCanvas.getDisplay() != null) { + fCanvas.getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + if (!fCanvas.isDisposed()) { + // Retrieve and normalize the data + int canvasWidth = fCanvas.getBounds().width; + int canvasHeight = fCanvas.getBounds().height; + fDataModel.setCurrentEvent(fCurrentEventTime); + fScaledData = fDataModel.scaleTo(canvasWidth, canvasHeight); + // If there's no data, just get out + if (fScaledData.fData[0] == 0) + return; + // Display histogram and update X-,Y-axis labels + fCanvas.redraw(); + fTimeRangeStartText.setText(HistogramUtils.nanosecondsToString(fDataModel.getStartTime())); + fTimeRangeEndText.setText(HistogramUtils.nanosecondsToString(fDataModel.getEndTime())); + if (fDataModel.getStartTime() > 0) { + fMaxNbEventsText.setText(Long.toString(fScaledData.fMaxValue)); + } + // The Y-axis area might need to be re-sized + fMaxNbEventsText.getParent().layout(); + } + } + }); + } + } + + // ------------------------------------------------------------------------ + // Helper functions + // ------------------------------------------------------------------------ + + private void updateCurrentEventTime() { + long bucketStartTime = getTimestamp(fScaledData.fCurrentBucket); + ((HistogramView) fParentView).updateCurrentEventTime(bucketStartTime); + } + + // ------------------------------------------------------------------------ + // PaintListener + // ------------------------------------------------------------------------ + + protected final String IMAGE_KEY = "double-buffer-image"; //$NON-NLS-1$ + + @Override + public void paintControl(PaintEvent event) { + + // Get the geometry + int canvasWidth = fCanvas.getBounds().width; + int canvasHeight = fCanvas.getBounds().height; + + // Make sure we have something to draw upon + if (canvasWidth <= 0 || canvasHeight <= 0) + return; + + // Retrieve image; re-create only if necessary + Image image = (Image) fCanvas.getData(IMAGE_KEY); + if (image == null || image.getBounds().width != canvasWidth || image.getBounds().height != canvasHeight) { + image = new Image(event.display, canvasWidth, canvasHeight); + fCanvas.setData(IMAGE_KEY, image); + } + + // Draw the histogram on its canvas + GC imageGC = new GC(image); + formatImage(imageGC, image); + event.gc.drawImage(image, 0, 0); + imageGC.dispose(); + } + + private void formatImage(GC imageGC, Image image) { + + if (fScaledData == null) + return; + + HistogramScaledData scaledData = new HistogramScaledData(fScaledData); + + try { + // Get drawing boundaries + int width = image.getBounds().width; + int height = image.getBounds().height; + + // Clear the drawing area + imageGC.setBackground(fBackgroundColor); + imageGC.fillRectangle(0, 0, image.getBounds().width + 1, image.getBounds().height + 1); + + // Draw the histogram bars + imageGC.setBackground(fHistoBarColor); + int limit = width < scaledData.fWidth ? width : scaledData.fWidth; + for (int i = 1; i < limit; i++) { + int value = (int) (scaledData.fData[i] * scaledData.fScalingFactor); + imageGC.fillRectangle(i, height - value, 1, value); + } + + // Draw the current event bar + int currentBucket = scaledData.fCurrentBucket; + if (currentBucket >= 0 && currentBucket < limit) { + drawDelimiter(imageGC, fCurrentEventColor, height, currentBucket); + } + + // Add a dashed line as a delimiter (at the right of the last bar) + int lastEventIndex = limit - 1; + while (lastEventIndex >= 0 && scaledData.fData[lastEventIndex] == 0) + lastEventIndex--; + lastEventIndex += (lastEventIndex < limit - 1) ? 1 : 0; + drawDelimiter(imageGC, fLastEventColor, height, lastEventIndex); + } catch (Exception e) { + // Do nothing + } + } + + private void drawDelimiter(GC imageGC, Color color, int height, int index) { + imageGC.setBackground(color); + int dash = height / 4; + imageGC.fillRectangle(index, 0 * dash, 1, dash - 1); + imageGC.fillRectangle(index, 1 * dash, 1, dash - 1); + imageGC.fillRectangle(index, 2 * dash, 1, dash - 1); + imageGC.fillRectangle(index, 3 * dash, 1, height - 3 * dash); + } + + // ------------------------------------------------------------------------ + // KeyListener + // ------------------------------------------------------------------------ + + @Override + public void keyPressed(KeyEvent event) { + moveCursor(event.keyCode); + } + + @Override + public void keyReleased(KeyEvent event) { + } + + // ------------------------------------------------------------------------ + // MouseListener + // ------------------------------------------------------------------------ + + @Override + public void mouseDoubleClick(MouseEvent event) { + } + + @Override + public void mouseDown(MouseEvent event) { + if (fDataModel.getNbEvents() > 0 && fScaledData.fLastBucket >= event.x) { + fScaledData.fCurrentBucket = event.x; + updateCurrentEventTime(); + } + } + + @Override + public void mouseUp(MouseEvent event) { + } + + // ------------------------------------------------------------------------ + // MouseTrackListener + // ------------------------------------------------------------------------ + + @Override + public void mouseEnter(MouseEvent event) { + } + + @Override + public void mouseExit(MouseEvent event) { + } + + @Override + public void mouseHover(MouseEvent event) { + if (fDataModel.getNbEvents() > 0 && fScaledData.fLastBucket >= event.x) { + String tooltip = formatToolTipLabel(event.x); + fCanvas.setToolTipText(tooltip); + } + } + + private String formatToolTipLabel(int index) { + long startTime = fDataModel.getStartTime() + fScaledData.fCurrentBucket * fScaledData.fBucketDuration; + long endTime = startTime + fScaledData.fBucketDuration; + int nbEvents = fScaledData.fData[index]; + + StringBuffer buffer = new StringBuffer(); + buffer.append("Range = ["); //$NON-NLS-1$ + buffer.append(HistogramUtils.nanosecondsToString(startTime)); + buffer.append(","); //$NON-NLS-1$ + buffer.append(HistogramUtils.nanosecondsToString(endTime)); + buffer.append(")\n"); //$NON-NLS-1$ + buffer.append("Event count = "); //$NON-NLS-1$ + buffer.append(nbEvents); + return buffer.toString(); + } + + // ------------------------------------------------------------------------ + // ControlListener + // ------------------------------------------------------------------------ + + @Override + public void controlMoved(ControlEvent event) { + refresh(); + } + + @Override + public void controlResized(ControlEvent event) { + refresh(); + } + +} diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramCanvas.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramCanvas.java deleted file mode 100644 index eaf22e08f9..0000000000 --- a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramCanvas.java +++ /dev/null @@ -1,459 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009 Ericsson - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v1.0 which - * accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * William Bourque - Initial API and implementation - * - * Modifications: - * 2010-06-20 Yuriy Vashchuk - Histogram optimisations. - * 2010-07-16 Yuriy Vashchuk - Histogram class simplification. - * Selection Window related methods has been - * implemented in Parent Histogram. - *******************************************************************************/ -package org.eclipse.linuxtools.lttng.ui.views.histogram; - -import org.eclipse.swt.SWT; -import org.eclipse.swt.widgets.Canvas; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Display; - -/** - * HistogramCanvas - *

- * Canvas implementation aimed to draw histograms. - *

- * This canvas goal is to display certain "HistogramContent" onto an histogram.

- * Several method exist to extend it so it should suit most needs. - */ -public class HistogramCanvas extends Canvas -{ - private static HistogramView histogramView = null; - - protected AsyncCanvasRedrawer canvasRedrawer = null; - protected HistogramContent histogramContent = null; - -/* - // 2010-07-16 Yuriy: Moved to child classes. - protected HistogramCanvasPaintListener paintListener = null; - protected HistogramCanvasMouseListener mouseListener = null; - protected HistogramCanvasKeyListener keyListener = null; - protected HistogramCanvasControlListener controlListener = null; -*/ - protected HistogramCanvasFocusListener focusListener = null; - -/* - // 2010-07-16 Yuriy: Moved to parent histogram class. - protected HistogramSelectedWindow currentWindow = null; -*/ - - /** - * HistogramCanvas constructor - * - * @param parent Composite control which will be the parent of the new instance (cannot be null) - * @param Style the style of control to construct - */ - public HistogramCanvas(HistogramView histogramView, Composite parent, int style) { - super(parent, style | SWT.DOUBLE_BUFFERED); - HistogramCanvas.histogramView = histogramView; - addNeededListeners(); - -/* - // 2010-06-20 Yuriy: Moved to parent hitogram class. - // New selected window, not visible by default - createNewSelectedWindow(0L); -*/ - } - - /* - * Create the needed "event listeners" and hook them to the Canvas. - */ - - protected void addNeededListeners() { - createAndAddCanvasRedrawer(); - createAndAddFocusListener(); - -/* - // 2010-06-20 Yuriy: Moved to derived classes. - createAndAddPaintListener(); - createAndAddMouseListener(); - createAndAddKeyListener(); - createAndAddControlListener(); -*/ - } - - /* - * Create a canvas redrawer and bind it to this canvas.

- * - * Note : AsyncCanvasRedrawer is an internal class - * This is used to redraw the canvas from a different thread - * without^H^H^H with less danger. - */ - protected void createAndAddCanvasRedrawer() { - canvasRedrawer = new AsyncCanvasRedrawer(this); - } - - /* - * Create a histogram paint listener and bind it to this canvas.

- * - * @see org.eclipse.linuxtools.lttng.ui.views.histogram.HistogramCanvasPaintListener - */ -/* - // 2010-07-16 Yuriy: Moved to derived classes. - protected void createAndAddPaintListener() { - paintListener = new HistogramCanvasPaintListener(this); - this.addPaintListener( paintListener ); - } -*/ - /* - * Create a histogram mouse listener and bind it to this canvas.

- * Note : this mouse listener handle the mouse, the move and the wheel at once. - * - * @see org.eclipse.linuxtools.lttng.ui.views.histogram.HistogramCanvasMouseListener - */ -/* - // 2010-07-16 Yuriy: Moved to parent histogram class - protected void createAndAddMouseListener() { - mouseListener = new HistogramCanvasMouseListener(this); - this.addMouseListener(mouseListener); - this.addMouseMoveListener(mouseListener); - this.addMouseWheelListener(mouseListener); - } -*/ - - /* - * Create a histogram key listener and bind it to this canvas.

- * - * @see org.eclipse.linuxtools.lttng.ui.views.histogram.HistogramCanvasKeyListener - */ -/* - // 2010-07-16 Yuriy: Moved to parent histogram class - protected void createAndAddKeyListener() { - keyListener = new HistogramCanvasKeyListener(this); - this.addKeyListener(keyListener); - } -*/ - /* - * Create a histogram focus listener and bind it to this canvas.

- * - * @see org.eclipse.linuxtools.lttng.ui.views.histogram.HistogramCanvasFocusListener - */ - protected void createAndAddFocusListener() { - focusListener = new HistogramCanvasFocusListener(this); - this.addFocusListener(focusListener); - } - - /* - * Create a histogram control listener and bind it to this canvas.

- * - * @see org.eclipse.linuxtools.lttng.ui.views.histogram.HistogramCanvasControlListener - */ -/* - // 2010-07-16 Yuriy: Moved to derived classes. - protected void createAndAddControlListener() { - controlListener = new HistogramCanvasControlListener(this); - this.addControlListener(controlListener); - } -*/ - /** - * Create a new HistogramContent for this HistogramCanvas

- * A new empty content will then be created. - * - * IMPORTANT NOTE : Canvas size, bar width and bar height need to be known at this point, as these dimension are used to create a content - * of the correct size. - * - * @param canvasSize Size of the parent canvas. - * @param widthPerBar Width of the histogram "bars" - * @param barsHeight Height of the histogram "bars" - * @param maxBarsDifferenceToAverage Factor used to "chop" bars that are too tall. Set to something big (100.0?) if not needed. - */ - public void createNewHistogramContent(int canvasSize, int widthPerBar, int barsHeight, double maxBarsDifferenceToAverage) { - histogramContent = new HistogramContent( canvasSize / widthPerBar, canvasSize, widthPerBar, barsHeight, maxBarsDifferenceToAverage); - } - - /** - * Create a new selection window of the size (time width) given.

- * The window initial position is at X = 0. - * The window is created hidden, it won't be draw unless it is set to visible.

- * - * @param windowTimeDuration Time width (in nanosecond) of the window. - */ -/* - // 2010-07-16 Yuriy: Moved to parent histogram class. - public void createNewSelectedWindow(long windowTimeDuration) { - currentWindow = new HistogramSelectedWindow(histogramContent); - - currentWindow.setWindowTimeWidth(windowTimeDuration); - currentWindow.setWindowXPositionCenter(0); - } -*/ - public HistogramContent getHistogramContent() { - return histogramContent; - } - - /** - * Getter for the selection window

- * - * @return the current selection window - * - * @see org.eclipse.linuxtools.lttng.ui.views.histogram.HistogramSelectedWindow - */ -/* - // 2010-07-16 Yuriy: Moved to parent histogram class. - public HistogramSelectedWindow getCurrentWindow() { - return currentWindow; - } -*/ - - /** - * Getter for the selection window width

- * - * @return Time width (in nanosecond) of the selection window. - */ -/* - // 2010-07-16 Yuriy: Moved to parent histogram class. - public long getSelectedWindowSize() { - return currentWindow.getWindowTimeWidth(); - } -*/ - - /** - * Setter for the selection window width

- * The window size will be ajusted if it does not respect one of these constraints : - * - The window size cannot be smaller than a single histogram content interval.

- * - The window size cannot be larger than twice the histogram content complete time interval.

- * - * @param newSelectedWindowSize New time width (in nanosecond) of the selection window. - */ -/* - // 2010-07-16 Yuriy: Moved to parent histogram class. - public void setSelectedWindowSize(long newSelectedWindowSize) { - - if ( newSelectedWindowSize <= 0 ) { - newSelectedWindowSize = 1L; - } - else if ( newSelectedWindowSize > (2*histogramContent.getCompleteTimeInterval()) ) { - newSelectedWindowSize = (2*histogramContent.getCompleteTimeInterval()); - } - - currentWindow.setWindowTimeWidth(newSelectedWindowSize); - } -*/ - /** - * Method to call the "Asynchronous redrawer" for this canvas

- * This allow safe redraw from different threads. - * - */ - public void redrawAsynchronously() { - // Create a new redrawer in case it doesn't exist yet (we never know with thread!) - if ( canvasRedrawer == null ) { - canvasRedrawer = new AsyncCanvasRedrawer(this); - } - - canvasRedrawer.asynchronousRedraw(); - } - - /** - * Method to call the "Asynchronous NotifyParentSelectionWindowChanged" for this canvas

- * This allow safe update UI objects from different threads. - * - */ -/* - // 2010-07-16 Yuriy: Moved to parent histogram class. - public void notifyParentSelectionWindowChangedAsynchronously() { - // Create a new redrawer in case it doesn't exist yet (we never know with thread!) - if ( canvasRedrawer == null ) { - canvasRedrawer = new AsyncCanvasRedrawer(this); - } - - canvasRedrawer.asynchronousNotifyParentSelectionWindowChanged(); - } -*/ - - /** - * Method to call the "Asynchronous NotifyParentUpdatedInformation" for this canvas

- * This allow safe redraw from different threads. - * - */ - public void notifyParentUpdatedInformationAsynchronously() { - // Create a new redrawer in case it doesn't exist yet (we never know with thread!) - if ( canvasRedrawer == null ) { - canvasRedrawer = new AsyncCanvasRedrawer(this); - } - - canvasRedrawer.asynchronousNotifyParentUpdatedInformation(); - } - - /** - * Function that is called when the selection window is moved.

- * Note: Given position should be relative to the previous (centered) absolute position. - * - * METHOD INTENDED TO BE EXTENDED - * - * @param newRelativeXPosition New position relative to the last known absolute position. - */ -/* - // 2010-07-16 Yuriy: Moved to parent histogram class. - public void moveWindow(int newRelativeXPosition) { - // Nothing : function is a place holder - } -*/ - - /** - * Function that is called when the selection window is re-centered.

- * Note: Given position should be absolute to the window and need to be the selection window center. - * - * METHOD INTENDED TO BE EXTENDED - * - * @param newRelativeXPosition New absolute position. - */ -/* - // 2010-07-16 Yuriy: Moved to parent histogram class. - public void setWindowCenterPosition(int newAbsoluteXPosition) { - // Nothing : function is a place holder - } -*/ - - /** - * Function that is called when the selection window size (time width) changed by an absolute time.

- * Note: Given time should be in nanoseconds, positive. - * - * METHOD INTENDED TO BE EXTENDED - * - * @param newTime New absoulte time (in nanoseconds) to apply to the window. - */ -/* -/* - // 2010-07-16 Yuriy: Moved to parent histogram class. - public void resizeWindowByAbsoluteTime(long newTime) { - // Nothing : function is a place holder - } -*/ - /** - * Function that is called to tell the parent that the selection window changed.

- * - * METHOD INTENDED TO BE EXTENDED - * - */ -/* - // 2010-07-16 Yuriy: Moved to parent histogram class. - public void notifyParentSelectionWindowChanged() { - // Nothing : function is a place holder - } -*/ - /** - * Function that is called to tell the parent that some information changed.

- * - * METHOD INTENDED TO BE EXTENDED - * - */ - public void notifyParentUpdatedInformation() { - // Nothing : function is a place holder - } - - /** - * Getter for View - * - * @return view instance - * - */ - public static HistogramView getHistogramView() { - return histogramView; - } - - /** - * Setter for View - * - * @param histogramView reference to object - */ - public static void setHistogramView(HistogramView histogramView) { - HistogramCanvas.histogramView = histogramView; - } -} - - -/** - * AsyncCanvasRedrawer Inner Class - *

- * Asynchronous redrawer for the HistogramCanvas - *

- * This class role is to call method that update the UI on asynchronously. - * This should prevent any "invalid thread access" exception when trying to update UI from a different thread. - */ -class AsyncCanvasRedrawer { - - private HistogramCanvas parentCanvas = null; - - /** - * AsyncCanvasRedrawer constructor. - * - * @param newCanvas Related histogram canvas. - */ - public AsyncCanvasRedrawer(HistogramCanvas newCanvas) { - parentCanvas = newCanvas; - } - - /** - * Function to redraw the related canvas asynchonously.

- * - * Basically, it just run "canvas.redraw()" in asyncExec. - * - */ - public void asynchronousRedraw() { - if ((parentCanvas != null) && (!parentCanvas.isDisposed())) { - Display display = parentCanvas.getDisplay(); - display.asyncExec(new Runnable() { - @Override - public void run() { - if ((parentCanvas != null) && (!parentCanvas.isDisposed())) { - parentCanvas.redraw(); - } - } - }); - } - } - - /** - * Function to asynchronously notify the parent of the related canvas that the window changed.

- * - * Basically, it just run "notifyParentSelectionWindowChanged()" in asyncExec. - * - */ -/* - // 2010-07-16 Yuriy: Moved to parent histogram class. - public void asynchronousNotifyParentSelectionWindowChanged() { - if(parentCanvas != null) { - Display display = parentCanvas.getDisplay(); - display.asyncExec(new Runnable() { - public void run() { - parentCanvas.notifyParentSelectionWindowChanged(); - } - }); - } - } -*/ - - /** - * Function to asynchonously notify the parent of the related canvas that information changed.

- * - * Basically, it just run "notifyParentUpdatedInformation()" in asyncExec. - * - */ - public void asynchronousNotifyParentUpdatedInformation() { - if((parentCanvas != null) && (!parentCanvas.isDisposed())) { - Display display = parentCanvas.getDisplay(); - display.asyncExec(new Runnable() { - @Override - public void run() { - if((parentCanvas != null) && (!parentCanvas.isDisposed())) { - parentCanvas.notifyParentUpdatedInformation(); - } - } - }); - } - } -} diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramCanvasControlListener.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramCanvasControlListener.java deleted file mode 100644 index 4da176b2b2..0000000000 --- a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramCanvasControlListener.java +++ /dev/null @@ -1,72 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2010 Ericsson - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v1.0 which - * accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Modifications: - * 2010-07-16 Yuriy Vashchuk - Base class simplification - *******************************************************************************/ - -package org.eclipse.linuxtools.lttng.ui.views.histogram; - -import org.eclipse.swt.events.ControlEvent; -import org.eclipse.swt.events.ControlListener; - -/** - * HistogramCanvasControlListener - *

- * Implementation of a ControlListener for the need of the HistogramCanvas - *

- */ -public class HistogramCanvasControlListener implements ControlListener { - - private HistogramCanvas ourCanvas = null; - - /** - * HistogramCanvasControlListener default constructor - */ - public HistogramCanvasControlListener() { - } - - /** - * HistogramCanvasControlListener constructor - * - * @param newCanvas Related canvas - */ - public HistogramCanvasControlListener(HistogramCanvas newCanvas) { - ourCanvas = newCanvas; - } - - - /** - * Method called when the canvas is moved.

- * - * Just redraw the canvas... - * - * @param event The controle event generated by the move. - */ - @Override - public void controlMoved(ControlEvent event) { - if (ourCanvas != null) - ourCanvas.redraw(); - } - - /** - * Method called when the canvas is resized.

- * - * We need to tell the content that the canvas size changed - * - * @param event The control event generated by the resize. - */ - @Override - public void controlResized(ControlEvent event) { - - if ( (ourCanvas != null) && (ourCanvas.getHistogramContent() != null) ) { - // Set the new canvas size - ourCanvas.getHistogramContent().setCanvasWindowSize(ourCanvas.getSize().x); - } - } -} diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramCanvasFocusListener.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramCanvasFocusListener.java deleted file mode 100644 index 2451ba406c..0000000000 --- a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramCanvasFocusListener.java +++ /dev/null @@ -1,63 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009 Ericsson - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v1.0 which - * accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * William Bourque - Initial API and implementation - * - * Modifications: - * 2010-07-16 Yuriy Vashchuk - Heritage corrections. - *******************************************************************************/ -package org.eclipse.linuxtools.lttng.ui.views.histogram; - -import org.eclipse.swt.events.FocusEvent; -import org.eclipse.swt.events.FocusListener; - -/** - * HistogramCanvasFocusListener - *

- * Implementation of a FocusListener for the need of the HistogramCanvas - *

- */ -public class HistogramCanvasFocusListener implements FocusListener { - - private HistogramCanvas ourCanvas = null; - - /** - * HistogramCanvasFocusListener constructor - * - * @param newCanvas Related canvas - */ - public HistogramCanvasFocusListener(HistogramCanvas newCanvas) { - ourCanvas = newCanvas; - } - - /** - * Function that is called when the canvas get focus.

- * - * Redraw the screen to make sure everything is sane. - * - * @param event The focus event generated. - */ - @Override - public void focusGained(FocusEvent event) { - ourCanvas.redrawAsynchronously(); - } - - /** - * Function that is called when the canvas loose focus.

- * - * Doesn't do anything yet... - * - * @param event The focus event generated. - */ - @Override - public void focusLost(FocusEvent event) { - // Nothing to do yet - } - -} diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramCanvasKeyListener.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramCanvasKeyListener.java deleted file mode 100644 index 4461011705..0000000000 --- a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramCanvasKeyListener.java +++ /dev/null @@ -1,97 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009 Ericsson - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v1.0 which - * accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * William Bourque - Initial API and implementation - *******************************************************************************/ -package org.eclipse.linuxtools.lttng.ui.views.histogram; - -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.KeyEvent; -import org.eclipse.swt.events.KeyListener; - -/** - * HistogramCanvasKeyListener - *

- * Implementation of a KeyListener for the need of the HistogramCanvas - *

- */ -public class HistogramCanvasKeyListener implements KeyListener -{ - private ParentHistogramCanvas parentCanvas = null; - private boolean isShiftPressed = false; - - /** - * HistogramCanvasKeyListener constructor - * - * @param newCanvas Related canvas - */ - public HistogramCanvasKeyListener(ParentHistogramCanvas newCanvas) { - parentCanvas = newCanvas; - } - - /** - * Function that is called when a key is pressed.

- * Possible actions : - * - Left arrow : move the selection window left.

- * - Right arrow : move the selection window right.

- * - Shift : turn on "fast move" mode.

- * - * @param event The KeyEvent generated when the key was pressed. - */ - @Override - public void keyPressed(KeyEvent event) { - switch (event.keyCode) { - case SWT.SHIFT: - isShiftPressed = true; - break; - case SWT.ARROW_LEFT: - moveWindowPosition(HistogramConstant.BASIC_DISPLACEMENT_FACTOR * -1); - break; - case SWT.ARROW_RIGHT: - moveWindowPosition(HistogramConstant.BASIC_DISPLACEMENT_FACTOR); - break; - default: - break; - } - } - - /** - * Function that is called when a key is released.

- * Possible actions : - * - Shift : turn off "fast move" mode. - * - * @param event The KeyEvent generated when the key was pressed. - */ - @Override - public void keyReleased(KeyEvent event) { - switch (event.keyCode) { - case SWT.SHIFT: - isShiftPressed = false; - break; - default: - break; - } - } - - /** - * Function to move the window position of a given displacemnt.

- * - * @param displacementFactor The basic displacement to perform (positive or negative value) - */ - public void moveWindowPosition(int displacementFactor) { - - // If we are in "fast move mode", multiply the basic displacement by a factor - if ( isShiftPressed == true ) { - displacementFactor = (int)((double)displacementFactor * HistogramConstant.FAST_DISPLACEMENT_MULTIPLE); - } - - parentCanvas.moveWindow(displacementFactor); - } - -} diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramCanvasMouseListener.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramCanvasMouseListener.java deleted file mode 100644 index d9e8ec1232..0000000000 --- a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramCanvasMouseListener.java +++ /dev/null @@ -1,284 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009 Ericsson - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v1.0 which - * accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * William Bourque - Initial API and implementation - * - * Modifications: - * 2010-06-20 Yuriy Vashchuk - Selection "red square" window optimisation. - * Null pointer exception correction. - *******************************************************************************/ -package org.eclipse.linuxtools.lttng.ui.views.histogram; - -import org.eclipse.swt.events.MouseEvent; -import org.eclipse.swt.events.MouseListener; -import org.eclipse.swt.events.MouseMoveListener; -import org.eclipse.swt.events.MouseWheelListener; - -/** - * HistogramCanvasMouseListener - *

- * Implementation of a MouseListener for the need of the HistogramCanvas - *

- */ -public class HistogramCanvasMouseListener implements MouseMoveListener, MouseListener, MouseWheelListener -{ - private DelayedMouseScroll mouseScrollListener = null; - private ParentHistogramCanvas parentCanvas = null; - private int oldWindowXPositionCenter = 0; - - private boolean isWindowMoving = false; - - /** - * HistogramCanvasMouseListener constructor - * - * @param newCanvas Related canvas - */ - public HistogramCanvasMouseListener(ParentHistogramCanvas newCanvas) { - parentCanvas = newCanvas; - } - - /** - * Function called when the mouse is moved.

- * If the mouse button is clicked, we will move the selection window. - * - * @param event The generated mouse event when the mouse moved. - */ - @Override - public void mouseMove(MouseEvent event) { - if ( parentCanvas.getHistogramContent() != null && isWindowMoving == true ) { - - parentCanvas.setWindowCenterPosition(event.x); - } - } - - /** - * Function called when the mouse buttons are clicked.

- * If the button is the first one (left button), turn on the "move window" mode - * - * @param event The generated mouse event when the mouse button was pressed. - */ - @Override - public void mouseDown(MouseEvent event) { - if ( parentCanvas.getHistogramContent() != null && event.button == 1) { - isWindowMoving = true; - - oldWindowXPositionCenter = parentCanvas.getCurrentWindow().getWindowXPositionCenter(); - parentCanvas.setWindowCenterPosition(event.x); - } - } - - /** - * Function called when the mouse buttons are released.

- * If the button is the first one (left button), turn off the "move window" mode - * - * @param event The generated mouse event when the mouse button was released. - */ - @Override - public void mouseUp(MouseEvent event) { - if ( parentCanvas.getHistogramContent() != null && event.button == 1) { - isWindowMoving = false; - - if( oldWindowXPositionCenter != parentCanvas.getCurrentWindow().getWindowXPositionCenter()) { - parentCanvas.notifyParentSelectionWindowChangedAsynchronously(); - } - } - } - - /** - * Function called when the mouse perform a double-click.

- * Don't do anything yet... - * - * @param event The generated mouse event when the mouse double-click was issued. - */ - @Override - public void mouseDoubleClick(MouseEvent event) { -// System.out.println("mouseDoubleClick"); - } - - /** - * Function called when the mouse scroll button is used.

- * Start a "ScrollListener" that will wait for more scroll clicks as they are asynchonous. - * After a certain delay, the parent canvas will get notified. - * - * @param event The generated mouse event when the mouse scroll was spinned. - */ - @Override - public void mouseScrolled(MouseEvent event) { - - // Start a scrollListener if none exist yet and start its thread - // Otherwise, we will just notify the one that is currenly alive... - // Badly timed event could happen while the thread is dying but we can live with loss scroll events, I believe. - if ( mouseScrollListener == null ) { - mouseScrollListener = new DelayedMouseScroll(this, HistogramConstant.FULL_WAIT_MS_TIME_BETWEEN_MOUSE_SCROLL, HistogramConstant.INTERVAL_WAIT_MS_TIME_BETWEEN_POLL ); - mouseScrollListener.start(); - } - - // *** NOTE *** - // We need to refer to the "count" to know if the scroll is done backward or forward. - // Positive count mean it is done backward (from the wall in the direction of the hand) - // Negative count mean it is done backward (from the hand in the direction of the wall) - if ( event.count > 0) { - mouseScrollListener.incrementMouseScroll(); - } - else { - mouseScrollListener.decrementMouseScroll(); - } - } - - /** - * This will calculate the correct zoom time and call the canvas to resize its selection window. - * - * @param nbMouseScroll - * @return new window timerange - */ - public long receiveMouseScrollCount(int nbMouseScroll) { - - double ajustedTime = 0; - long selectedWindowSize = parentCanvas.getSelectedWindowSize(); - - // If we received Negative scroll event, ZoomOut by ZOOM_OUT_FACTOR * the number of scroll events received. - if ( nbMouseScroll < 0 ) { - ajustedTime = (double)selectedWindowSize * HistogramConstant.ZOOM_OUT_FACTOR; - ajustedTime = ajustedTime * Math.abs(nbMouseScroll); - ajustedTime = selectedWindowSize + ajustedTime; - } - // If we received Positive scroll event, ZoomIn by ZOOM_IN_FACTOR * the number of scroll events received. - else { - if(selectedWindowSize > 2) { - ajustedTime = (double)selectedWindowSize * HistogramConstant.ZOOM_IN_FACTOR; - ajustedTime = ajustedTime * Math.abs(nbMouseScroll); - ajustedTime = selectedWindowSize - ajustedTime; - } - } - - return (long)ajustedTime; - - } - - /** - * Function that will be called at the end of the "wait time" for scroll events.

- * This will calculate the correct zoom time and call the canvas to resize its selection window. - * - * @param nbMouseScroll - */ - public void receiveMouseScrollCountWithNotification(int nbMouseScroll) { - - if(parentCanvas.getHistogramContent() != null) { - - mouseScrollListener = null; - - // Resize the canvas selection window - parentCanvas.resizeWindowByAbsoluteTime( receiveMouseScrollCount(nbMouseScroll) ); - } - } - - /** - * Function that will be called on mouse scroll.

- * This will calculate the correct zoom time and call the canvas to resize its selection window. - * - * @param nbMouseScroll - */ - public void receiveMouseScrollCountWithoutNotification(int nbMouseScroll) { - if(parentCanvas.getHistogramContent() != null) { - - // Resize the canvas selection window - parentCanvas.resizeWindowByAbsoluteTimeWithoutNotification( receiveMouseScrollCount(nbMouseScroll) ); - } - } - -} - -/** - * DelayedMouseScroll Inner Class - *

- * Asynchronous "Mouse Scroll Listener" - *

- * This class role is to wait for mouse scroll and count them during a certain delay.

- * Once the time is up, it will notify the mouse listener of the number of scroll events received.

- * - * Note that a new scroll event received will reset the wait timer. - */ -class DelayedMouseScroll extends Thread { - - private HistogramCanvasMouseListener mouseListener = null; - - private long waitTimeBetweenScroll = 0; - private long waitTimeBetweenCheck = 0; - - private long lastScrollTime = 0L; - private int nbScrollClick = 0; - - /** - * Constructor of the DelayedMouseScroll listener.

- * Object will be initialized but start() need to be called for it start listening for scroll. - * - * @param newListener The parent mouse listener - * @param newWaitFullTime The time to wait for scroll events - * @param newWaitBeforeCheck The delay between polling for scroll events - */ - public DelayedMouseScroll(HistogramCanvasMouseListener newListener, long newWaitFullTime, long newWaitBeforePoll) { - - mouseListener = newListener; - - // Get the current system time. - // This will be used to determine since how long we wait for click - lastScrollTime = System.currentTimeMillis(); - - waitTimeBetweenScroll = newWaitFullTime; - waitTimeBetweenCheck = newWaitBeforePoll; - } - - /** - * Increment the counter for the number of scroll events received.

- * This is intended to be called by the MouseListener. - * - * Note : A new scroll event receive will reset the wait timer. - */ - public void incrementMouseScroll() { - // Reset the wait timer - lastScrollTime = System.currentTimeMillis(); - nbScrollClick++; - mouseListener.receiveMouseScrollCountWithoutNotification(nbScrollClick); - } - - /** - * Decrement the counter for the number of scroll events received.

- * This is intended to be called by the MouseListener. - * - * Note : A new scroll event receive will reset the wait timer. - */ - public void decrementMouseScroll() { - // Reset the wait timer - lastScrollTime = System.currentTimeMillis(); - nbScrollClick--; - mouseListener.receiveMouseScrollCountWithoutNotification(nbScrollClick); - } - - /** - * Threaded execution method.

- * This is the real "wait" method that will wait for mouse scroll events.

- * - * The function will wake every "waitTimeBetweenCheck" to check if we exhausted the timer.

- * So, the "longest" we could wait after the last event is "waitTimeBetweenScroll" + "waitTimeBetweenCheck" - * - */ - @Override - public void run() { - // Check if we waited more than "waitTimeBetweenScroll" - while ( (System.currentTimeMillis() - lastScrollTime) < waitTimeBetweenScroll ) { - try { - Thread.sleep(waitTimeBetweenCheck); - } - catch (Exception e) { } - } - - // Tell the mouse listener the number of click received - mouseListener.receiveMouseScrollCountWithNotification(nbScrollClick); - } -} diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramCanvasPaintListener.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramCanvasPaintListener.java deleted file mode 100644 index f94ce74285..0000000000 --- a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramCanvasPaintListener.java +++ /dev/null @@ -1,180 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009 Ericsson - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v1.0 which - * accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * William Bourque - Initial API and implementation - * - * Modifications: - * 2010-07-16 Yuriy Vashchuk - Heritage corrections. Redraw bug correction. - * Double Buffering implementation. - *******************************************************************************/ -package org.eclipse.linuxtools.lttng.ui.views.histogram; - -import org.eclipse.swt.events.PaintEvent; -import org.eclipse.swt.events.PaintListener; - -import org.eclipse.swt.graphics.Color; -import org.eclipse.swt.graphics.GC; -import org.eclipse.swt.graphics.Image; - -/** - * HistogramCanvasPaintListener - *

- * Implementation of a PaintListener for the need of the HistogramCanvas - *

- */ -public class HistogramCanvasPaintListener implements PaintListener -{ - private static ChildrenHistogramCanvas childrenCanvas = null; - protected boolean isFinished = false; - - /** - * HistogramCanvasPaintListener default constructor - */ - public HistogramCanvasPaintListener() { - } - - /** - * HistogramCanvasPaintListener constructor - * - * @param parentCanvas Related canvas - */ - public HistogramCanvasPaintListener(ChildrenHistogramCanvas newCanvas) { - childrenCanvas = newCanvas; - } - - /** - * Function called when the canvas need to redraw.

- * - * @param event The generated paint event when redraw is called. - */ - private final String DATA_KEY = "double-buffer-image"; //$NON-NLS-1$ - @Override - public void paintControl(PaintEvent event) { - - if (childrenCanvas.getSize().x > 0 && childrenCanvas.getSize().y > 0) { - Image image = (Image) childrenCanvas.getData(DATA_KEY); - - // Creates new image only absolutely necessary. - if (image == null - || image.getBounds().width != childrenCanvas.getBounds().width - || image.getBounds().height != childrenCanvas.getBounds().height) { - - image = new Image( - event.display, - childrenCanvas.getBounds().width, - childrenCanvas.getBounds().height - ); - - childrenCanvas.setData(DATA_KEY, image); - } - - // Initializes the graphics context of the image. - GC imageGC = new GC(image); - - // First clear the whole canvas to have a clean section where to draw - clearDrawingSection(imageGC, image, childrenCanvas); - - // If the content is null or has rady to draw we quit the function here - if ( (childrenCanvas.getHistogramContent() != null) - && (childrenCanvas.getHistogramContent().getReadyUpToPosition() != 0) ) { - - // Call the function that draw the bars -// if (!isFinished) { - drawHistogram(imageGC, image); -// } - - // Pinpoint a position if set - if (childrenCanvas.getHistogramContent().getSelectedEventTimeInWindow() > 0 ) { - drawSelectedEventInWindow(imageGC, image); - } - - // Draws the buffer image onto the canvas. - event.gc.drawImage(image, 0, 0); - } - - imageGC.dispose(); - } - } - - /** - * Clear the drawing section of the canvas

- * This paint the whole background in EMPTY_BACKGROUND_COLOR, so we have something clean to draw on. - * - * @param imageGC GC content. - * @param image Image content. - * @param ourCanvas Canvas to clean. - */ - public void clearDrawingSection(GC imageGC, Image image, HistogramCanvas ourCanvas) { - // Fills background. - imageGC.setBackground(ourCanvas.getDisplay().getSystemColor(HistogramConstant.EMPTY_BACKGROUND_COLOR)); - imageGC.fillRectangle(0, 0, image.getBounds().width + 1, image.getBounds().height + 1); - } - - // *** VERIFY *** - // Is it good to put this synchronized? - // - /** - * Draw the histogram bars in the canvas.

- * Use existing elements in HistogramContent to draw bars on the cancas; - * the element table in content need to be populated and have consistent value. - * - * @param imageGC GC content. - * @param image image content. - */ - public synchronized void drawHistogram(GC imageGC, Image image) { - - // This will be the bottom color for all the bars that wil be draw below. - imageGC.setBackground( new Color( imageGC.getDevice(), 74, 112, 139) ); - - // *** NOTE *** - // Y Position in a canvas is REVERSED, so "0" is on top of the screen and "MAX" is on bottom. - // Not very instinctive, isn't it? - - // Draw a bar from the left (pos X=0) until the pos=(NbBars*barWidth). If space is left, it will be blanked after. - for ( int x = 0; x < childrenCanvas.getHistogramContent().getReadyUpToPosition(); x++) { - imageGC.fillRectangle( - childrenCanvas.getHistogramContent().getBarsWidth() * x, - image.getBounds().height - childrenCanvas.getHistogramContent().getElementByIndex(x).intervalHeight, - childrenCanvas.getHistogramContent().getBarsWidth(), - childrenCanvas.getHistogramContent().getElementByIndex(x).intervalHeight - ); - } - - } - - /** - * Draw a certain event selected in the window.

- * - * @param imageGC GC content. - * @param image image content. - */ - public synchronized void drawSelectedEventInWindow(GC imageGC, Image image) { - - final HistogramContent tmpContent = childrenCanvas.getHistogramContent(); - final int tmpBarWidth = tmpContent.getBarsWidth(); - final int position = tmpContent.getClosestXPositionFromTimestamp(tmpContent.getSelectedEventTimeInWindow()); - - // This will be the color for all the bars that will be draw below. - imageGC.setForeground(childrenCanvas.getDisplay().getSystemColor(HistogramConstant.SELECTED_EVENT_COLOR)); - imageGC.setLineWidth(HistogramConstant.SELECTION_LINE_WIDTH); - imageGC.drawLine( - tmpBarWidth * position, - 0, - tmpBarWidth * position, - image.getBounds().height - ); - } - - /** - * @param isFinished the flag value - */ - public void setIsFinished(boolean isFinished) { - this.isFinished = isFinished; - } -} diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramConstant.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramConstant.java deleted file mode 100644 index 051dcddb1a..0000000000 --- a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramConstant.java +++ /dev/null @@ -1,172 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009 Ericsson - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v1.0 which - * accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * William Bourque - Initial API and implementation - *******************************************************************************/ -package org.eclipse.linuxtools.lttng.ui.views.histogram; - -import org.eclipse.linuxtools.lttng.LttngConstants; -import org.eclipse.swt.SWT; -import org.eclipse.swt.graphics.GC; -import org.eclipse.swt.widgets.Composite; - -/** - * HistogramConstant - *

- * Empty interface class to hold the different constants needed by the histogram. - *

- */ -public abstract class HistogramConstant { - - // Constants relative to requests -// public final static int MAX_EVENTS_PER_READ = LttngConstants.DEFAULT_BLOCK_SIZE; - public final static int REDRAW_EVERY_NB_EVENTS = 20000; - public final static Boolean SKIP_EMPTY_INTERVALS_WHEN_CALCULATING_AVERAGE = true; - - - // Constant relative to the content - public final static double DEFAULT_DIFFERENCE_TO_AVERAGE = 1000.0; - - - - // Constants relative to zoom. Factors need to be a percentage ( 0 < factors < 1 ) - public final static double ZOOM_IN_FACTOR = 0.1; - public final static double ZOOM_OUT_FACTOR = 0.1; - - - // Constants relative to wait time while listening for scroll events - // "FULL" is time to wait to stop "to count" mouse scroll click events - // "INTERVAL" is time to wait between polling for scroll click events - public final static long FULL_WAIT_MS_TIME_BETWEEN_MOUSE_SCROLL = 1000L; - public final static long INTERVAL_WAIT_MS_TIME_BETWEEN_POLL = 100L; - - - // Constants relative to the displacement in the trace - // Factor represent a number of HistogramContent interval - // Multiple is the factor to multiply to basic during "fast" displacement - public final static int BASIC_DISPLACEMENT_FACTOR = 1; - public final static double FAST_DISPLACEMENT_MULTIPLE = 10.0; - - - // Constants relative to the drawing of the Histogram - // Colors for the histogram. Background should be the same as the background in use - public final static int EMPTY_BACKGROUND_COLOR = SWT.COLOR_WHITE; - public final static int SELECTED_EVENT_COLOR = SWT.COLOR_RED; - - // Dimension for the line of the "Selection Window" - public final static int MINIMUM_WINDOW_WIDTH = 3; - public final static int SELECTION_LINE_WIDTH = 1; - public final static int SELECTION_CROSSHAIR_WIDTH = 1; - - - /** - * Method to format a long representing nanosecond into a proper String.

- * The returned String will always be like "0.000000000", missing decimal will be added. - * - * @param nanosecTime This time to format - * - * @return The formatted string - */ - public static String formatNanoSecondsTime(long nanosecTime) { - String returnedTime = Long.toString(nanosecTime); - - // If our number has over 9 digits, just add a dot after the ninth digits - if ( returnedTime.length() > 9 ) { - returnedTime = returnedTime.substring(0, returnedTime.length() - 9 ) + "." + returnedTime.substring( returnedTime.length() - 9 ); //$NON-NLS-1$ - } - // Otherwise, patch missing decimal with 0 - else { - int curSize = returnedTime.length(); - for (int l=0; (curSize+l)< 9; l++) { - returnedTime = "0" + returnedTime; //$NON-NLS-1$ - } - returnedTime = "0." + returnedTime; //$NON-NLS-1$ - } - - return returnedTime; - } - - /** - * Convert a String representing nanoseconds into a valid long.

- * This can handle number like "0.5", "0.123456789" as well as plain number like "12".

- * - * Note : This function ALWAYS return a number, if conversion failed, 0 will be returned.

- * - * @param timeString The string to convert - * - * @return The converted nanoseconds time as long - */ - public static long convertStringToNanoseconds( String timeString ) { - long returnedNumber = 0L; - - try { - // Avoid simple commat/dot mistake - timeString = timeString.replace(",", "."); //$NON-NLS-1$ //$NON-NLS-2$ - - // If we have a dot, we have a decimal number to convert - int dotPosition = timeString.indexOf("."); //$NON-NLS-1$ - - // If the user begun the line with a dot, we add a zero - if ( dotPosition == 0 ) { - timeString = "0" + timeString; //$NON-NLS-1$ - dotPosition = 1; - } - - // If we found a dot, verify that we have 9 digits - if ( dotPosition != -1 ) { - int decimalNumber = (timeString.length() - dotPosition -1); - - // If we have less than 9 digits, we fill with 0 - if ( decimalNumber <= 9 ) { - StringBuffer strBuffer = new StringBuffer(timeString); - for ( int nbDec=decimalNumber; nbDec<9; nbDec++) { - strBuffer.append("0"); //$NON-NLS-1$ - } - timeString = strBuffer.toString(); - } - // We have OVER 9 digits, skip the useless part - else { - timeString = timeString.substring(dotPosition, 9); - } - } - - // Conversion into decimal seconds - double dblMaxTimerange = Double.parseDouble(timeString); - // Conversion into nanoseconds - returnedNumber = (long)(dblMaxTimerange * 1000000000.0); - } - catch (NumberFormatException e) { - System.out.println("Warning : Could not convert string into nanoseconds (convertStringToLong)"); //$NON-NLS-1$ - } - - return returnedNumber; - } - - /** - * Calculate the correcte width of a String.

- * Useful to set a control to its maximum size; since the size depends on characters, - * this will calculate the correct sum... should be platform independant (we hope). - * - * @param parent Parent control we will use as a reference. Could be any composite. - * @param text The Text to measure the size from - * - * @return The size calculated. - */ - public static int getTextSizeInControl(Composite parent, String text) { - GC graphicContext = new GC(parent); - int textSize = 0; - for ( int pos=0; posHistogramContent - *

- * This class hold the content that will be used to draw the Histograms. - *

- */ -public class HistogramContent { - - // Start and end time of the content - private long startTime = 0L; - private long endTime = 0L; - - // Some information about the content - // Most of them are required to calculate position and/or draw - // Make sure they stay consistent! - private long elementsTimeInterval = 1L; - private double heightFactor = 100.0; - private long heighestEventCount = 0L; - private int maxHeight = 0; - private int canvasWindowSize = 0; - private int barsWidth = 0; - - // This value is used to calculate at which point we should "cut" bar that are too tall. - // Default value is large enought so that no bar should be cut - private double maxDifferenceToAverage = HistogramConstant.DEFAULT_DIFFERENCE_TO_AVERAGE; - // This is a factor we might apply on the max difference to average, as example if we concatenate interval together - private double maxDifferenceFactor = 1.0; - - // By default we will only consider element up to this position - private int readyUpToPosition = 0; - - // The average number of events in the content - // Note : this IS needed to draw - private int averageNumberOfEvents = 0; - - // This is to draw the selected event of the TMF framework in another color - // Set the 0 to ignore - private long selectedEventTimeInWindow = -1L; - - // The table that hold the elements - private HistogramElement[] elementTable; - - - /** - * Default constructor for the HistogramContent. - * - * @param tableSize The size ofthe element table that will be created. - * @param newCanvasSize The full size of the canvas. Used for positionning; need to be consistent with canvas. - * @param newMaxHeight The maximum height of a bar, usually same as the height of the canvas. - */ - public HistogramContent(int tableSize, int newCanvasSize, int newBarWidth, int newMaxHeight) { - this(tableSize, newCanvasSize, newBarWidth, newMaxHeight, HistogramConstant.DEFAULT_DIFFERENCE_TO_AVERAGE); - } - - /** - * Default constructor for the HistogramContent. - * - * @param tableSize The size ofthe element table that will be created. - * @param newCanvasSize The full size of the canvas. Used for positionning; need to be consistent with canvas. - * @param newMaxHeight The maximum height of a bar, usually same as the height of the canvas. - * @param newDiffToAverage This value at which point we "cut" bar that are too tall. - */ - public HistogramContent(int tableSize, int newCanvasSize, int newBarWidth, int newMaxHeight, double newDiffToAverage) { - canvasWindowSize = newCanvasSize; - barsWidth = newBarWidth; - maxHeight = newMaxHeight; - maxDifferenceToAverage = newDiffToAverage; - - // Create a new element table from the above value - // The table will not get initialized until resetTable() is called. - createNewTable(tableSize); - } - - /** - * Create a new table to hold the content element.

- * Note that the table is not initialized (and so unusable) until resetTable() is called. - * - * @param newTableSize The size (number of element) of the table. - */ - public void createNewTable(int newTableSize) { - elementTable = new HistogramElement[newTableSize]; - - for ( int x=0; x - */ - public void clearContentData() { - startTime = 0L; - endTime = 0L; - - elementsTimeInterval = 1L; - heightFactor = 100.0; - heighestEventCount = 0L; - - readyUpToPosition = 0; - } - - /** - * Reset the data in the elements table.

- * NOTE : For this to be consistent and usuable, "startTime", "endTime" and "intervalTime" need to be set already. - */ - public void resetTable() { - for ( int x=0; x - * Start and EndTime will be used to calculate elementsTimeInterval.

- * - * @param newStartTime The new start time to use - * @param newEndTime The new stop time to use - */ - public void resetTable(long newStartTime, long newEndTime) { - resetTable(newStartTime, newEndTime, elementsTimeInterval); - } - - /** - * Reset the data in the elements table.

- * elementsTimeInterval will be set to the one give, use this for fixed interval.

- * - * @param newStartTime The new start time to use - * @param newEndTime The new stop time to use - * @param newTimeInterval The new time interval to use - */ - public void resetTable(long newStartTime, long newEndTime, long newTimeInterval) { - - startTime = newStartTime; - endTime = newEndTime; - recalculateElementsTimeInterval(newStartTime, newEndTime); - - for ( int x=0; x - * NOTE : Unlike reset, this does not recalculate the content, - * so it should be done either by hand or by calling reset table after. - */ - public void clearTable() { - for ( int x=0; x - */ - @SuppressWarnings("nls") - public void printTable() { - for ( int x=0; x " + elementTable[x].intervalNbEvents + ":" + elementTable[x].intervalHeight + " (" + elementTable[x].firstIntervalTimestamp + ")"); - } - } - - /** - * Getter for the timestamp of the selected event in the window.

- * - * @return The time of the event. - */ - public long getSelectedEventTimeInWindow() { - return selectedEventTimeInWindow; - } - - /** - * Setter for the timestamp of the selected event in the window.

- * - * This allow to pinpoint a certain event or position in the window. - * Set to 0 or lower to ignore. - * - * @param newPosition The new event time. - */ - public void setSelectedEventTimeInWindow(long newTime) { - this.selectedEventTimeInWindow = newTime; - } - - /** - * Get an element in the table by its index.

- * Null is returned if the index is out of range.

- * Note that you can get an element past "readyUpToPosition", the index is NOT tested against it. - * - * @param index The index of the element (0 < index < nbElement) - * - * @return The element found or null if the index is wrong. - */ - public HistogramElement getElementByIndex(int index) { - HistogramElement returnedElement = null; - - if ( (index >= 0) && (index < elementTable.length) ) { - returnedElement = elementTable[index]; - } - - return returnedElement; - } - - /** - * Return the closest element to a X position on the canvas.

- * Note : canvasWindowSize need to be set correctly here, otherwise unexpected element might be returned.

- *

- * NOTE : This ALWAYS return an element; - * If calculation lead outside the table, the first or the last element will be returned. - * - * @param position The X position we are looking at (0 < pos < canvasWidth) - * - * @return The closest element found. - */ - public HistogramElement getClosestElementFromXPosition(int position) { - - int index = (int)Math.round((double)elementTable.length * ((double)position / (double)canvasWindowSize) ); - - // If we are out of bound, return the closest border (first or last element) - if ( index < 0) { - index = 0; - } - else if ( index >= elementTable.length ) { - index = (elementTable.length -1); - } - - return elementTable[index]; - } - - /** - * Return the closest element's timestamp to a X position on the canvas.

- * Note : canvasWindowSize need to be set correctly here, otherwise unexpected timestamp might be returned.

- *

- * NOTE : This ALWAYS return a timestamp; - * If calculation lead outside the table, the first or the last timestamp will be returned. - * - * @param position The X position we are looking at (0 < pos < canvasWidth) - * - * @return The closest timestamp found. - */ - public long getClosestTimestampFromXPosition(int position) { - return getClosestElementFromXPosition(position).firstIntervalTimestamp; - } - - /** - * Return the X position (relative to the canvas) of a certain element.

- * Note : canvasWindowSize need to be set correctly here, otherwise unexpected element might be returned.

- * - * NOTE : This ALWAYS return an element; - * If calculation lead outside the table, the first or the last element will be returned. - * - * @param targetElement The element we are looking to find the position - * - * @return The closest found element. - */ - public int getXPositionFromElement(HistogramElement targetElement) { - return (int)Math.round( ((double)targetElement.index / (double)elementTable.length)*(double)canvasWindowSize ); - } - - /** - * Return the closest element to a timestamp (long) given.

- * Note : startTime and intervalTime need to be set correctly here, otherwise unexpected element might be returned.

- *

- * NOTE : This ALWAYS return an element; - * If calculation lead outside the table, the first or the last element will be returned. - * - * @param timestamp The timestamp (in nanosecond, as long) of the element we are looking for (startTime < timestamp < endTime) - * - * @return The closest element found. - */ - public HistogramElement getClosestElementFromTimestamp(long timestamp) { - int index = (int)Math.round( (double)(timestamp - startTime)/(double)elementsTimeInterval ); - - // If we are out of bound, return the closest border (first or last element) - if ( index < 0) { - index = 0; - } - else if ( index >= elementTable.length ) { - index = (elementTable.length -1); - } - - return elementTable[index]; - } - - /** - * Return the closest X position to a timestamp (long) given.

- * Note : startTime and intervalTime need to be set correctly here, otherwise unexpected position might be returned.

- *

- * NOTE : This ALWAYS return a position; - * If calculation lead outside the table, the first or the last position will be returned. - * - * @param timestamp The timestamp (in nanosecond, as long) of the element we are looking for (startTime < timestamp < endTime) - * - * @return The closest position found. - */ - public int getClosestXPositionFromTimestamp(long timestamp) { - return getXPositionFromElement(getClosestElementFromTimestamp(timestamp)); - } - - /** - * Return the closest element to an element and a time interval to this element.

- * The time interval can be negative or positive (before or after the element). - * - * Note : IntervalTime and StartTime need to be set correctly here, otherwise unexpected result might be returned.

- * - * @param targetElement The element we compare the interval with. - * @param intervalToElement Time negative or positive time interval (in nanosecond) to this element. - * - * @return The closest found element, or null if given data are wrong. - */ - public HistogramElement getClosestElementByElementAndTimeInterval(HistogramElement targetElement, long intervalToElement) { - - // Get the timestamp of the target element - // This should always be valid as long the table is initialized - long elementTime = targetElement.firstIntervalTimestamp; - elementTime = elementTime + intervalToElement; - - return getClosestElementFromTimestamp(elementTime); - } - - /** - * Return the closest element to an element's timestamp (as long) and a time interval to this element.

- * The time interval can be negative or positive (before or after the element). - * - * Note : IntervalTime and StartTime need to be set correctly here, otherwise unexpected result might be returned.

- * - * @param timestamp The timestamp (in nanoseconds, as long) of the element we want to compare from. - * @param intervalToElement Time negative or positive time interval (in nanosecond) to this element. - * - * @return The closest found element, or null if given data are wrong. - */ - public int getClosestElementByTimestampAndTimeInterval(long timestamp, long intervalToElement) { - HistogramElement targetElement = getClosestElementFromTimestamp(timestamp); - HistogramElement newElement = getClosestElementByElementAndTimeInterval(targetElement, intervalToElement); - - return getXPositionFromElement(newElement); - } - - /** - * Return the closest element to an element's position and a time interval to this element.

- * The time interval can be negative or positive (before or after the element). - * - * Note : IntervalTime and StartTime need to be set correctly here, otherwise unexpected result might be returned.

- * - * @param targetPosition The position (relative to the canvas) of the element we want to compare from. - * @param intervalToElement Time negative or positive time interval (in nanosecond) to this element. - * - * @return The closest found element, or null if given data are wrong. - */ - public int getXPositionByPositionAndTimeInterval(int targetPosition, long intervalToElement) { - HistogramElement targetElement = getClosestElementFromXPosition(targetPosition); - HistogramElement newElement = getClosestElementByElementAndTimeInterval(targetElement, intervalToElement); - - return getXPositionFromElement(newElement); - } - - /** - * Getter for the number of element.

- * The same as the value of tableSize given at construction. - * - * @return The number of element in the elements table. - */ - public int getNbElement() { - return elementTable.length; - } - - /** - * Getter for the average number of events by interval in the content.

- * - * Note : Might be set externally (instead of calculated internally), so consistency with the content is not guarantee. - * - * @return Average number of events we currently use in - */ - public int getAverageNumberOfEvents() { - return averageNumberOfEvents; - } - - /** - * Setter for averageNumberOfEvents.

- * - * Note : this is used in some drawing calculation so make sure this number make sense. - * Note : you might want to call recalculateEventHeight() if you change this. - * - * @param newAverageNumberOfEvents The new average number of events to use. - */ - public void setAverageNumberOfEvents(int newAverageNumberOfEvents) { - this.averageNumberOfEvents = newAverageNumberOfEvents; - } - - /** - * Recalculate the average number of events by time interval.

- * - * Note : This run over all the element so this is quite cpu intensive, use with care. - */ - public void recalculateAverageNumberOfEvents() { - - int nbInterval = 0; - int totalNbEvents = 0; - - // Go over the element up to readyUpToPosition (further position might not be ready) - for ( int x=0; x 0 ) { - nbInterval++; - } - } - else { - nbInterval++; - } - - totalNbEvents += elementTable[x].intervalNbEvents; - } - // Calculate the average here - averageNumberOfEvents = (int)Math.round((double)totalNbEvents / (double)nbInterval); - } - - /** - * Getter for the start time of the content.

- * - * @return The start time we currently use. - */ - public long getStartTime() { - return startTime; - } - - /** - * Setter for the start time of the content.

- * Note : You probably want to call "resetTable()" if you change this, otherwise data might be inconsistent. - * - * @param newStartTime the new start time - */ - public void setStartTime(long newStartTime) { - this.startTime = newStartTime; - } - - - /** - * Getter for the end time of the content.

- * - * @return The end time we currently use. - */ - public long getEndTime() { - return endTime; - } - - /** - * Setter for the end time of the content.

- * Note : You probably want to call "resetTable()" if you change this, otherwise data might be inconsistent. - * - * @param newStartTime the new end time - */ - public void setEndTime(long newEndTime) { - this.endTime = newEndTime; - } - - /** - * Getter for the complete time interval of the content.

- * Note : This return "endTime" minus "startTime", unlike getReadyTimeInterval() it won't check the actual time of elements. - * - * @return The complete time interval - */ - public long getCompleteTimeInterval() { - return ( endTime - startTime ); - } - - /** - * Getter for the time interval for the element between first and readyUpToPosition

- * Note : This return element[readyPosition].time - element[first].time , not the full interval like getCompleteTimeInterval() - * - * @return The time interval of the position that are ready. - */ - public long getReadyTimeInterval() { - return ( elementTable[readyUpToPosition].firstIntervalTimestamp - elementTable[0].firstIntervalTimestamp ); - } - - /** - * Getter for the height factor of the bar.

- * Note : height = "nb events in interval" * heightFactor - * - * @return Height factor currently used. - */ - public double getHeightFactor() { - return heightFactor; - } - - /** - * Recalculate the height factor of the element table.

- * Assume values of "maxHeight", "heighestEventCount" or "averageNumberOfEvents" are set correctly. - */ - public void recalculateHeightFactor() { - // Recalculate the new HeightFactor for the element; - // the highest bar will get "maxHeight" and other bar a fraction of it. - double diffToConsider = (maxDifferenceToAverage * maxDifferenceFactor * (double)barsWidth); - - if ( heighestEventCount > (long)(diffToConsider * (double)averageNumberOfEvents) ) { - heightFactor = (double)maxHeight/( diffToConsider * (double)averageNumberOfEvents); - } - else { - heightFactor = (double)maxHeight/(double)heighestEventCount; - } - } - - /** - * Recalculate the height of each bar in the elements table.

- * This assume "heightFactor" is already set correctly.

- * - * NOTE : if "maxHeight", "heighestEventCount" or "averageNumberOfEvents" changes, - * recalculateHeightFactor() should be recalled. - */ - public void recalculateEventHeight() { - // Recalculate the height of the bars up to "readyUpToPosition" - for ( int x=0; x - * Unlike recalculateEventHeight(), this only recalculate for the given range, not the whole table. - * - */ - public void recalculateEventHeightInInterval(int startPosition, int stopPosition) { - // Basic error checking on start : should be bigger than 0 - if ( startPosition < 0 ) { - startPosition = 0; - } - - // Basic error checking on start : should be smaller than length - 1 - if ( stopPosition >= elementTable.length) { - stopPosition = (elementTable.length-1); - } - - // Recalculate the height of the bars from startPosition to stopPosition - for ( int x=startPosition; x - * This is used for the positionnal calculation so should be consistent with the real canvas size. - * - * @return Size of the canvas we currently use. - */ - public int getCanvasWindowSize() { - return canvasWindowSize; - } - - /** - * Set a new full size of the canvas.

- * This is used for the positionnal calculation so should be consistent with the real canvas size. - * - * @param newSize New canvas size; - */ - public void setCanvasWindowSize(int newSize) { - canvasWindowSize = newSize; - } - - /** - * Getter for the heighest event count recorded so far for an interval.

- * - * Note : Might be set externally (instead of calculated internally), so consistency with the content is not guarantee. - * - * @return Current heighestEventCount - */ - public long getHeighestEventCount() { - return heighestEventCount; - } - - /** - * Setter for setHeighestEventCount.

- * - * Note : this is used in some drawing calculation so make sure this number make sense. - * Note : you might want to call recalculateEventHeight() if you change this. - * - * @param newHeighestEventCount Heighest event count for a single interval. - */ - public void setHeighestEventCount(long newHeighestEventCount) { - this.heighestEventCount = newHeighestEventCount; - } - - /** - * Recalculate the heightest event count for a single time interval.

- * - * Note : This run over all the element so this is quite cpu intensive, use with care. - */ - public void recalculateHeighestEventCount() { - // Go over the element up to readyUpToPosition (further position might not be ready) - for ( int x=0; x heighestEventCount ) { - this.heighestEventCount = elementTable[x].intervalNbEvents; - } - } - } - - /** - * Getter for the max height of a bar in the content.

- * - * @return maximum height for a bar we currently use. - */ - public int getMaxHeight() { - return maxHeight; - } - - /** - * Setter for maxHeight.

- * - * Note : this is used in some drawing calculation so make sure this number make sense. - * Note : you might want to call recalculateEventHeight() if you change this. - * - * @param maxHeight The new maximum height for a bar to use. - */ - public void setMaxHeight(int maxHeight) { - this.maxHeight = maxHeight; - } - - /** - * Getter for the max difference to the average height a bar can have.

- * This determine at which point a bar too tall is "cut". Set a very large value (like 1000.0) to ignore. - * - * @return maximum difference to the average we currently use. - */ - public double getMaxDifferenceToAverage() { - return maxDifferenceToAverage; - } - - /** - * Setter for the max difference to the average height a bar can have.

- * This determine at which point a bar too tall is "cut". Set a very large value (like 1000.0) to ignore. - * - * Note : this is used in some drawing calculation so make sure this number make sense. - * Note : you might want to call recalculateEventHeight() if you change this. - * - * @param newDiffToAverage The new maximum difference to the average to use. - */ - public void setMaxDifferenceToAverage(double newDiffToAverage) { - maxDifferenceToAverage = newDiffToAverage; - } - - - /** - * Getter for a factor applied to the max difference to the average height a bar can have.

- * This is muliplied to maxDifferenceToAverage. Set to value 1.0 to ignore. - * - * Note : this is useful if you concatenate some intervals to gether but want the average to be consistent - * - * @return maximum difference to the average we currently use. - */ - public double getMaxDifferenceToAverageFactor() { - return maxDifferenceFactor; - } - - /** - * Setter for a factor applied to the max difference to the average height a bar can have.

- * - * Note : this is used in some drawing calculation so make sure this number make sense. - * Note : you might want to call recalculateEventHeight() if you change this. - * Note : setting to 0 will cause bar to have a zero size... use 1.0 to desactivate - * - * @param newFactor The new factor to use. - */ - public void setMaxDifferenceToAverageFactor(double newFactor) { - maxDifferenceFactor = newFactor; - } - - - /** - * Getter for the interval time of each interval.

- * This is usually "(EndTime - StartTime) / NbElement" - * - * @return Currently used interval time. - */ - public long getElementsTimeInterval() { - return elementsTimeInterval; - } - - - /** - * Setter for the interval time of each interval.

- * - * Note : this is used in some drawing calculation so make sure this number make sense. - * Note : you migth want to call resetTable() to to fill the element's table again if you change this. - * - * @return New interval time. - */ - public void setElementsTimeInterval(long newInterval) { - this.elementsTimeInterval = newInterval; - } - - - /** - * Calculate the correct time interval of each element from the given time.

- * - * @return The complete time interval - */ - public void recalculateElementsTimeInterval(long startTime, long endTime) { - long tmpInterval = (long)Math.ceil((double)(endTime - startTime)/ (double)getNbElement()); - - if ( tmpInterval <= 0 ) { - tmpInterval = 1L; - } - - this.elementsTimeInterval = tmpInterval; - } - - - /** - * Getter for readyUpToPosition.

- * This should tell to which point the content is filled, calculated and ready to use. - * - * @return Last position processed so far. - */ - public int getReadyUpToPosition() { - return readyUpToPosition; - } - - /** - * Setter for readyUpToPosition.

- * Set a new point (position) up to where the content is filled, calculated and ready to use. - * - * @param newReadyUpToPosition The new position to use. - */ - public void setReadyUpToPosition(int newReadyUpToPosition) { - this.readyUpToPosition = newReadyUpToPosition; - } - - /** - * Getter for the bar width.

- * This is needed by the paint listener usually. - * - * @return current bars width; - */ - public int getBarsWidth() { - return barsWidth; - } - - /** - * Setter for the bar width.

- * Setting this to 0 will hide all the bar in the histogram. - * - * @param newBarsWidth new bars width; - */ - public void setBarsWidth(int newBarsWidth) { - this.barsWidth = newBarsWidth; - } - -} diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramCurrentTimeControl.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramCurrentTimeControl.java new file mode 100644 index 0000000000..bbdd3f135a --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramCurrentTimeControl.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright (c) 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Francois Chouinard - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.linuxtools.lttng.ui.views.histogram; + +import org.eclipse.swt.widgets.Composite; + +/** + * HistogramCurrentTimeControl + *

+ * This control provides a group containing a text control. + */ +public class HistogramCurrentTimeControl extends HistogramTextControl { + + // ------------------------------------------------------------------------ + // Construction + // ------------------------------------------------------------------------ + + public HistogramCurrentTimeControl(HistogramView parentView, Composite parent, int textStyle, int groupStyle) { + this(parentView, parent, textStyle, groupStyle, "", HistogramUtils.nanosecondsToString(0L)); //$NON-NLS-1$ + } + + public HistogramCurrentTimeControl(HistogramView parentView, Composite parent, int textStyle, int groupStyle, String groupValue, String textValue) { + super(parentView, parent, textStyle, groupStyle, groupValue, textValue); + } + + // ------------------------------------------------------------------------ + // Operations + // ------------------------------------------------------------------------ + + @Override + protected void updateValue() { + String stringValue = fTextValue.getText(); + long value = HistogramUtils.stringToNanoseconds(stringValue); + + if (getValue() != value) { + setValue(value); + fParentView.updateCurrentEventTime(value); + } + } + +} diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramDataModel.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramDataModel.java new file mode 100644 index 0000000000..5c70e3d332 --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramDataModel.java @@ -0,0 +1,269 @@ +/******************************************************************************* + * Copyright (c) 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Francois Chouinard - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.linuxtools.lttng.ui.views.histogram; + +import java.util.Arrays; + +import org.eclipse.linuxtools.lttng.exceptions.EventOutOfSequenceException; +import org.eclipse.linuxtools.lttng.ui.LTTngUILogger; +import org.eclipse.linuxtools.lttng.ui.views.histogram.HistogramScaledData; + +/** + * HistogramDataModel + *

+ * Histogram-independent data model with the following characteristics: + *

+ * Initially, the bucket durations is set to 1ns. As the events are read, they + * are tallied (using countEvent()) in the appropriate bucket (relative + * to the basetime). + *

+ * Eventually, an event will have a timestamp that exceeds the timespan + * high end (determined by n, the number of buckets, and d, the + * bucket duration). At this point, the histogram needs to be compacted. This is + * done by simply merging adjacent buckets by pair, in effect doubling the + * timespan (timespan' = n * d', where d' = + * 2d). This compaction happens as needed as the trace is read. + *

+ * The mapping from the model to the UI is performed by the scaleTo() + * method. By keeping the number of buckets n relatively large with + * respect to to the number of pixels in the actual histogram, we should achieve + * a nice result when visualizing the histogram. + *

+ * TODO: Add filter support for more refined event counting (e.g. by trace, + * event type, etc.) + *

+ * TODO: Cut-off eccentric values? + * TODO: Support for going back in time? + */ +public class HistogramDataModel { + + // ------------------------------------------------------------------------ + // Constants + // ------------------------------------------------------------------------ + + // The default number of buckets + public static final int DEFAULT_NUMBER_OF_BUCKETS = 16 * 1000; + +// // The ratio where an eccentric value will be truncated +// private static final int MAX_TO_AVERAGE_CUTOFF_RATIO = 5; + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + + // Bucket management + private final int fNbBuckets; + private final long[] fBuckets; + private long fBucketDuration; + private long fNbEvents; + private int fLastBucket; + + // Timestamps + private long fFirstEventTime; + private long fLastEventTime; + private long fCurrentEventTime; + private long fTimeLimit; + + // ------------------------------------------------------------------------ + // Constructors + // ------------------------------------------------------------------------ + + public HistogramDataModel() { + this(DEFAULT_NUMBER_OF_BUCKETS); + } + + public HistogramDataModel(int nbBuckets) { + fNbBuckets = nbBuckets; + fBuckets = new long[nbBuckets]; + clear(); + } + + public HistogramDataModel(HistogramDataModel other) { + fNbBuckets = other.fNbBuckets; + fBuckets = Arrays.copyOf(other.fBuckets, fNbBuckets); + fBucketDuration = other.fBucketDuration; + fNbEvents = other.fNbEvents; + fLastBucket = other.fLastBucket; + fFirstEventTime = other.fFirstEventTime; + fLastEventTime = other.fLastEventTime; + fCurrentEventTime = other.fCurrentEventTime; + fTimeLimit = other.fTimeLimit; + } + + // ------------------------------------------------------------------------ + // Accessors + // ------------------------------------------------------------------------ + + public long getNbEvents() { + return fNbEvents; + } + + public int getNbBuckets() { + return fNbBuckets; + } + + public long getBucketDuration() { + return fBucketDuration; + } + + public long getStartTime() { + return fFirstEventTime; + } + + public long getEndTime() { + return fLastEventTime; + } + + public long getCurrentEventTime() { + return fCurrentEventTime; + } + + public long getTimeLimit() { + return fTimeLimit; + } + + // ------------------------------------------------------------------------ + // Operations + // ------------------------------------------------------------------------ + + /** + * Clear the histogram model. + */ + public void clear() { + Arrays.fill(fBuckets, 0); + fNbEvents = 0; + fFirstEventTime = 0; + fLastEventTime = 0; + fCurrentEventTime = 0; + fLastBucket = 0; + fBucketDuration = 1; // 1ns + updateEndTime(); + } + + /** + * Sets the current event time + * + * @param timestamp + */ + public void setCurrentEvent(long timestamp) { + fCurrentEventTime = timestamp; + } + + /** + * Add event to the correct bucket, compacting the if needed. + * + * @param timestamp the timestamp of the event to count + */ + public void countEvent(long timestamp) { + // Set the start/end time if not already done + if (fLastBucket == 0 && fBuckets[0] == 0 && timestamp > 0) { + fFirstEventTime = timestamp; + updateEndTime(); + } + if (fLastEventTime < timestamp) { + fLastEventTime = timestamp; + } + + // Compact as needed + while (timestamp >= fTimeLimit) { + mergeBuckets(); + } + + // Validate + if (timestamp < fFirstEventTime) { + String message = "Out of order timestamp. Going back in time?"; //$NON-NLS-1$ + EventOutOfSequenceException exception = new EventOutOfSequenceException(message); + LTTngUILogger.logError(message, exception); + return; + } + + // Increment the right bucket + int index = (int) ((timestamp - fFirstEventTime) / fBucketDuration); + fBuckets[index]++; + fNbEvents++; + if (fLastBucket < index) + fLastBucket = index; + } + + /** + * Scale the model data to the width and height requested. + * + * @param width + * @param height + * @return the result array of size [width] and where the highest value + * doesn't exceed [height] + */ + public HistogramScaledData scaleTo(int width, int height) { + // Basic validation + assert width > 0 && height > 0; + + // The result structure + HistogramScaledData result = new HistogramScaledData(width, height); + + // Scale horizontally + int bucketsPerBar = fLastBucket / width + 1; + result.fBucketDuration = bucketsPerBar * fBucketDuration; + for (int i = 0; i < width; i++) { + int count = 0; + for (int j = i * bucketsPerBar; j < (i + 1) * bucketsPerBar; j++) { + if (fNbBuckets <= j) + break; + count += fBuckets[j]; + } + result.fData[i] = count; + result.fLastBucket = i; + if (result.fMaxValue < count) + result.fMaxValue = count; + } + + // Scale vertically + if (result.fMaxValue > 0) { + result.fScalingFactor = (double) height / result.fMaxValue; + } + + // Set the current event index in the scaled histogram + if (fCurrentEventTime >= fFirstEventTime && fCurrentEventTime <= fLastEventTime) + result.fCurrentBucket = (int) ((fCurrentEventTime - fFirstEventTime) / fBucketDuration) / bucketsPerBar; + else + result.fCurrentBucket = HistogramScaledData.OUT_OF_RANGE_BUCKET; + + return result; + } + + // ------------------------------------------------------------------------ + // Helper functions + // ------------------------------------------------------------------------ + + private void updateEndTime() { + fTimeLimit = fFirstEventTime + fNbBuckets * fBucketDuration; + } + + private void mergeBuckets() { + for (int i = 0; i < fNbBuckets / 2; i++) { + fBuckets[i] = fBuckets[2 * i] + fBuckets[2 * i + 1]; + } + Arrays.fill(fBuckets, fNbBuckets / 2, fNbBuckets, 0); + fBucketDuration *= 2; + updateEndTime(); + fLastBucket = fNbBuckets / 2 - 1; + } + +} diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramElement.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramElement.java deleted file mode 100644 index eb907d4a9c..0000000000 --- a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramElement.java +++ /dev/null @@ -1,27 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009 Ericsson - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v1.0 which - * accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * William Bourque - Initial API and implementation - *******************************************************************************/ -package org.eclipse.linuxtools.lttng.ui.views.histogram; - -/** - * HistogramElement - *

- * This is used by the content to keep its data. - * It would be a struct if such a thing would exist in java. - *

- * Each "element" should represent a certain time interval - */ -public class HistogramElement { - public int index = 0; // Position of the element in the table (table index, obviously) - public long firstIntervalTimestamp = 0L; // The first timestamp recorded for this interval - public long intervalNbEvents = 0L; // Number of events recorded in this interval - public int intervalHeight = 0; // Height (in the canvas) of this element. Should be smaller than the canvas height. -} diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramRequest.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramRequest.java index 8990950c5f..7375f99a88 100644 --- a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramRequest.java +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramRequest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009 Ericsson + * Copyright (c) 2009, 2011 Ericsson * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v1.0 which @@ -8,10 +8,10 @@ * * Contributors: * William Bourque - Initial API and implementation - * - * Modifications: - * 2010-07-16 Yuriy Vashchuk - Heritage correction. + * Yuriy Vashchuk - Heritage correction. + * Francois Chouinard - Cleanup and refactoring *******************************************************************************/ + package org.eclipse.linuxtools.lttng.ui.views.histogram; import org.eclipse.linuxtools.lttng.LttngConstants; @@ -23,246 +23,51 @@ import org.eclipse.linuxtools.tmf.request.TmfEventRequest; /** * HistogramRequest *

- * Request class, to perform a request to TMF for the histograms. - *

*/ public class HistogramRequest extends TmfEventRequest { -/* - private HistogramContent histogramContent = null; -*/ - - private int lastInterval = 0; - private long lastRangeTime = 0L; - private long nbEventsInInterval = 0L; - - private int nbIntervalNotEmpty = 1; - private int nbEventRead = 0; - - private int lastDrawPosition = 0; - - private HistogramCanvas parentCanvas = null; - - private boolean isCompleted = false; - - /** - * Constructor for HistogramRequest.

- * Prepare the request in TMF and reset the histogram content. - * - * @param range Range of the request. - * @param nbRequested Nb events requested. Can be "Infinity" for all. - * @param newParentCanvas HistogramCanvas related to the request. - * @param timeInterval Time interval to consider (i.e. : 1 interval is 1 bar in the histogram) - * - * @see org.eclipse.linuxtools.tmf.request.TmfEventRequest - */ - public HistogramRequest(TmfTimeRange range, int nbRequested, HistogramCanvas newParentCanvas, long timeInterval, ITmfDataRequest.ExecutionType execType) { - super((Class)LttngEvent.class, range, nbRequested, LttngConstants.DEFAULT_BLOCK_SIZE, execType); - - setIsCompleted(false); - - // *** FIXME *** - // This does not work! The request won't be processed or the number of events returned is wrong! - // We cannot use this ! - //super((Class)dataType, range); - - parentCanvas = newParentCanvas; - - // Reset the content of the HistogramContent... the given data better be valid or this will fail. - parentCanvas.getHistogramContent().clearContentData(); - parentCanvas.getHistogramContent().resetTable(range.getStartTime().getValue(), range.getEndTime().getValue(), timeInterval); - - lastRangeTime = range.getStartTime().getValue(); - - // Notify the UI even before the request started, so we set the timestamp already. - parentCanvas.notifyParentUpdatedInformationAsynchronously(); + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + + private final Histogram fHistogram; + + // ------------------------------------------------------------------------ + // Constructor + // ------------------------------------------------------------------------ + + public HistogramRequest(Histogram histogram, TmfTimeRange range, int nbEvents, ITmfDataRequest.ExecutionType execType) { + super(LttngEvent.class, range, nbEvents, LttngConstants.DEFAULT_BLOCK_SIZE, execType); + fHistogram = histogram; + } + + public HistogramRequest(Histogram histogram, TmfTimeRange range, ITmfDataRequest.ExecutionType execType) { + this(histogram, range, ALL_DATA, execType); } - - /** - * HandleData function : will be called by TMF each time a new event is receive for the request.

- * Calculation for the content is done here. - */ -// @Override -// public void handleData() { -// LttngEvent[] result = getData(); -// LttngEvent event = (result.length > 0) ? result[0] : null; - - @Override - public void handleData(LttngEvent event) { - super.handleData(event); - // *** FIXME *** - // *** EVIL BUG *** - // The request by timerange only does not work! (see constructor above) - // However, the request with number of events will loop until it reach its number or EOF - // We have to filter out ourself the extra useless events! - // + // ------------------------------------------------------------------------ + // TmfEventRequest + // ------------------------------------------------------------------------ + + @Override + public void handleData(LttngEvent event) { + super.handleData(event); if (event != null) { - -// Tracer.trace("Hst: " + event.getTimestamp()); - - // This check is linked to the evil fix mentionned above - if ( ( event.getTimestamp().getValue() >= parentCanvas.getHistogramContent().getStartTime() ) && - ( event.getTimestamp().getValue() <= parentCanvas.getHistogramContent().getEndTime() ) ) - { - - // Distance (in time) between this event and the last one we read - long distance = ( event.getTimestamp().getValue() - lastRangeTime ); - - // Check if we changed of interval (the distance is higher than the interval time) - if ( distance > parentCanvas.getHistogramContent().getElementsTimeInterval() ) { - - parentCanvas.getHistogramContent().getElementByIndex(lastInterval).intervalNbEvents = nbEventsInInterval; - lastRangeTime = event.getTimestamp().getValue(); - - // * NOTE * - // We can skip several interval at once, so we need to find what was our interval now - lastInterval = (int)((lastRangeTime - parentCanvas.getHistogramContent().getStartTime()) / parentCanvas.getHistogramContent().getElementsTimeInterval() ); - - // *** HACK *** - // Because of the threads, weird phenomenons seem to happen here, like a position after the - // element range because another request was issued. - // This enforce the position but may result in slightly inconsistent result (i.e. a weird misplaced bar sometime). - if ( lastInterval < 0 ) { - lastInterval = 0; - } - else if ( lastInterval >= parentCanvas.getHistogramContent().getNbElement() ) { - lastInterval = (parentCanvas.getHistogramContent().getNbElement()-1); - } - - // * NOTE * - // We save the time we have here. This mean only the FIRST time read in an interval will be saved. - parentCanvas.getHistogramContent().getElementByIndex(lastInterval).firstIntervalTimestamp = lastRangeTime; - parentCanvas.getHistogramContent().setReadyUpToPosition(lastInterval); - - nbIntervalNotEmpty++; - nbEventsInInterval = 1L; - } - // We are still in the same interval, just keep counting - else { - nbEventsInInterval++; - } - - if ( nbEventsInInterval > parentCanvas.getHistogramContent().getHeighestEventCount() ) { - parentCanvas.getHistogramContent().setHeighestEventCount(nbEventsInInterval); - } - nbEventRead++; - - // Call an asynchronous redraw every REDRAW_EVERY_NB_EVENTS events - // That way we don't need to wait until to end to have something on the screen - if ( nbEventRead % HistogramConstant.REDRAW_EVERY_NB_EVENTS == 0 ) { - redrawAsyncronously(); - } - } - } - // We got a null event! This mean we reach the end of the request. - // Save the last interval we had, so we won't miss the very last events at the end. - else { - // Save the last events - parentCanvas.getHistogramContent().getElementByIndex(lastInterval).intervalNbEvents = nbEventsInInterval; - // We reached the end of the request, so assume we fill up the content as well - parentCanvas.getHistogramContent().setReadyUpToPosition(parentCanvas.getHistogramContent().getNbElement()); - - // If the interval wasn't null, count this as a "non empty" interval - if (nbEventsInInterval > 0) { - nbIntervalNotEmpty++; - } + long timestamp = event.getTimestamp().getValue(); + fHistogram.countEvent(timestamp); } } - - /** - * Function that is called when the request completed (successful or not).

- * Update information and redraw the screen. - */ + @Override public void handleCompleted() { - setIsCompleted(true); - parentCanvas.notifyParentUpdatedInformationAsynchronously(); - redrawAsyncronously(); - super.handleCompleted(); -// System.out.println(System.currentTimeMillis() + ": HistogramView (" + ((getExecType() == ExecutionType.LONG) ? "long" : "short") + ") completed"); + fHistogram.refresh(); + super.handleCompleted(); } - -// /** -// * Function that is called when the request completed successfully.

-// */ -// @Override -// public void handleSuccess() { -// // Nothing different from completed. -// } - -// /** -// * Function that is called when the request completed in failure.

-// */ -// @Override -// public void handleFailure() { -// // Nothing different from cancel. -// } - - /** - * Function that is called when the request was cancelled.

- * Redraw and set the requestCompleted flag to true; - */ + @Override public void handleCancel() { - redrawAsyncronously(); - super.handleCancel(); - } - - /** - * Update the HistogramContent with the latest information.

- * This will perform some calculation that might be a bit harsh so it should'nt be called too often. - */ - public void updateEventsInfo() { - // *** Note *** - // The average number of event is calculated while skipping empty interval if asked - int averageNumberOfEvents = 0; - if ( HistogramConstant.SKIP_EMPTY_INTERVALS_WHEN_CALCULATING_AVERAGE ) { - averageNumberOfEvents = (int)Math.ceil((double)nbEventRead / (double)nbIntervalNotEmpty); - } - else { - averageNumberOfEvents = (int)Math.ceil((double)nbEventRead / (double)parentCanvas.getHistogramContent().getNbElement()); - } - - parentCanvas.getHistogramContent().setAverageNumberOfEvents(averageNumberOfEvents); - - // It is possible that the height factor didn't change; - // If not, we only need to redraw the updated section, no the whole content - // Save the actual height, recalculate the height and check if there was any changes - double previousHeightFactor = parentCanvas.getHistogramContent().getHeightFactor(); - parentCanvas.getHistogramContent().recalculateHeightFactor(); - if ( parentCanvas.getHistogramContent().getHeightFactor() != previousHeightFactor ) { - parentCanvas.getHistogramContent().recalculateEventHeight(); - } - else { - parentCanvas.getHistogramContent().recalculateEventHeightInInterval(lastDrawPosition, parentCanvas.getHistogramContent().getReadyUpToPosition()); - } - - lastDrawPosition = parentCanvas.getHistogramContent().getReadyUpToPosition(); + fHistogram.refresh(); + super.handleCancel(); } - - /** - * Perform an asynchonous redraw of the screen. - */ - public void redrawAsyncronously() { - updateEventsInfo(); - // Canvas redraw is already asynchronous - parentCanvas.redrawAsynchronously(); - } - - /** - * Getter for isCompleted variable - * @return true if the request is completed - */ - public boolean getIsCompleted() { - return isCompleted; - } - /** - * Setter for isCompleted variable - * @param isCompleted value to set the completed flag - */ - public void setIsCompleted(boolean isCompleted) { - this.isCompleted = isCompleted; - } - } diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramScaledData.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramScaledData.java new file mode 100644 index 0000000000..8260b4fb59 --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramScaledData.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright (c) 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Francois Chouinard - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.linuxtools.lttng.ui.views.histogram; + +import java.util.Arrays; + +/** + * HistogramScaledData + *

+ * Convenience class/struct for scaled histogram data. + */ +public class HistogramScaledData { + + // ------------------------------------------------------------------------ + // Constants + // ------------------------------------------------------------------------ + + public static final int OUT_OF_RANGE_BUCKET = -1; + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + + public int fWidth; + public int fHeight; + public int[] fData; + public long fBucketDuration; + public long fMaxValue; + public int fCurrentBucket; + public int fLastBucket; + public double fScalingFactor; + + // ------------------------------------------------------------------------ + // Constructor + // ------------------------------------------------------------------------ + + public HistogramScaledData(int width, int height) { + fWidth = width; + fHeight = height; + fData = new int[width]; + Arrays.fill(fData, 0); + fBucketDuration = 1; + fMaxValue = 0; + fCurrentBucket = 0; + fLastBucket = 0; + fScalingFactor = 1; + } + + public HistogramScaledData(HistogramScaledData other) { + fWidth = other.fWidth; + fHeight = other.fHeight; + fData = Arrays.copyOf(other.fData, fWidth); + fBucketDuration = other.fBucketDuration; + fMaxValue = other.fMaxValue; + fCurrentBucket = other.fCurrentBucket; + fLastBucket = other.fLastBucket; + fScalingFactor = other.fScalingFactor; + } + +} \ No newline at end of file diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramSelectedWindow.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramSelectedWindow.java deleted file mode 100644 index cd8abadd2b..0000000000 --- a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramSelectedWindow.java +++ /dev/null @@ -1,211 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009 Ericsson - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v1.0 which - * accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * William Bourque - Initial API and implementation - * - * Modifications: - * 2010-07-16 Yuriy Vashchuk - Heritage correction and selection window - * optimisations. - *******************************************************************************/ -package org.eclipse.linuxtools.lttng.ui.views.histogram; - -/** - * HistogramSelectedWindow - *

- * Selection window represent the selected section of the trace in the HistogramCanvas. - *

- * The selected window have 3 important attributes : - *

- * The dimension are then deduced from the first 2 values. - * This mean the window is always a perfectly symetrical rectangle. - */ -public class HistogramSelectedWindow { - - private long timestampOfLeftPosition = 0; - private long timestampOfCenterPosition = 0; - private long timestampOfRightPosition = 0; - private long windowTimeWidth = 0L; - private int windowXPositionLeft = 0; - private int windowXPositionCenter = 0; - private int windowXPositionRight = 0; - private Boolean isSelectedWindowVisible = false; - - /** - * Default constructor for HistogramSelectedWindow.

- * Position and TimeWidth are set to given value. - * - * @param newTraceContent HistogramContent to read window's data from - * @param centralPosition Central X Position of the selection window in the canvas (0 to canvasWidth) - * @param newWindowWidth Time width (size) of the window. (0 or greater) - */ - public HistogramSelectedWindow(HistogramContent newTraceContent, long timestampOfLeftPosition, long newWindowWidth) { - if(newTraceContent != null) { - setWindowTimeWidth(newWindowWidth); - setTimestampOfLeftPosition(timestampOfLeftPosition); - setTimestampOfRightPosition(timestampOfLeftPosition + newWindowWidth); - setTimestampOfCenterPosition(timestampOfLeftPosition + newWindowWidth / 2); - } - } - - /** - * Getter for the window visibility.

- * - * @return true if the window is visible (will be draw), false otherwise - */ - public boolean getSelectedWindowVisible() { - return isSelectedWindowVisible; - } - - /** - * Setter for the window visibility.

- * True means the window will be draw, false that it will be hidden. - * - * @param newIsSelectedWindowVisible The visibility value - */ - public void setSelectedWindowVisible(Boolean newIsSelectedWindowVisible) { - this.isSelectedWindowVisible = newIsSelectedWindowVisible; - } - - - /** - * Getter for the window time width (size) - * - * @return Window time width (size) - */ - public long getWindowTimeWidth() { - return windowTimeWidth; - } - - /** - * Setter for the window time width (size).

- * Width need to be a time (in nanoseconds) that's coherent to the data we are looking at. - * - * @param newWindowTimeWidth The new time width - */ - public void setWindowTimeWidth(long newWindowTimeWidth) { - this.windowTimeWidth = newWindowTimeWidth; - } - - /** - * Getter for the timestamp of left border of the window.

- * Compute the timestamp from the HistogramContent data; may return 0 if the content data are wrong. - * - * @return The left timestamp of the window, or 0 if it cannot compute it. - */ - public long getTimestampOfLeftPosition() { - return timestampOfLeftPosition; - } - - /** - * Setter for the timestamp of left border of the window.

- * @param timestampOfLeftPosition The left timestamp of the window. - */ - public void setTimestampOfLeftPosition(long timestampOfLeftPosition) { - this.timestampOfLeftPosition = timestampOfLeftPosition; - } - - /** - * Getter for the timestamp of the center of the window.

- * Compute the timestamp from the HistogramContent data; may return 0 if the content data are wrong. - * - * @return The center timestamp of the window, or 0 if it cannot compute it. - */ - public long getTimestampOfCenterPosition() { - return timestampOfCenterPosition; - } - - /** - * Setter for the timestamp of center border of the window.

- */ - public void setTimestampOfCenterPosition(long timestampOfCenterPosition) { - this.timestampOfCenterPosition = timestampOfCenterPosition; - } - - /** - * Setter for the timestamp of center border of the window.

- */ - public void setTimestampOfLeftCenterRightPositions(long timestampOfCenterPosition) { - this.timestampOfLeftPosition = timestampOfCenterPosition - windowTimeWidth / 2; - this.timestampOfCenterPosition = timestampOfCenterPosition; - this.timestampOfRightPosition = timestampOfCenterPosition + windowTimeWidth / 2; - } - - /** - * Getter for the timestamp of right border of the window.

- * Compute the timestamp from the HistogramContent data; may return 0 if the content data are wrong. - * - * @return The right timestamp of the window, or 0 if it cannot compute it. - */ - public long getTimestampOfRightPosition() { - return timestampOfRightPosition; - } - - /** - * Setter for the timestamp of right border of the window.

- * @param timestampOfRightPosition The right timestamp of the window. - */ - public void setTimestampOfRightPosition(long timestampOfRightPosition) { - this.timestampOfRightPosition = timestampOfRightPosition; - } - - /** - * Getter for the coordinate of left border of the window.

- * - * @return The left coordinate. - */ - public int getWindowXPositionLeft() { - return windowXPositionLeft; - } - - /** - * Setter for the coordinate of left border of the window.

- * @param windowXPositionLeft The left coordinate of the window. - */ - public void setWindowXPositionLeft(int windowXPositionLeft) { - this.windowXPositionLeft = windowXPositionLeft; - } - - /** - * Getter for the coordinate of center border of the window.

- * - * @return The center coordinate. - */ - public int getWindowXPositionCenter() { - return windowXPositionCenter; - } - - /** - * Setter for the coordinate of center of the window.

- * @param windowXPositionCenter The center coordinate of the window. - */ - public void setWindowXPositionCenter(int windowXPositionCenter) { - this.windowXPositionCenter = windowXPositionCenter; - } - - /** - * Getter for the coordinate of right border of the window.

- * - * @return The right coordinate. - */ - public int getWindowXPositionRight() { - return windowXPositionRight; - } - - /** - * Setter for the coordinate of right border of the window.

- * @param windowXPositionRight The right coordinate of the window. - */ - public void setWindowXPositionRight(int windowXPositionRight) { - this.windowXPositionRight = windowXPositionRight; - } -} diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramTextControl.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramTextControl.java new file mode 100644 index 0000000000..009fa29f3f --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramTextControl.java @@ -0,0 +1,199 @@ +/******************************************************************************* + * Copyright (c) 2009, 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Wiliam Bourque - Adapted from SpinnerGroup (in TimeFrameView) + * Francois Chouinard - Cleanup and refactoring + *******************************************************************************/ + +package org.eclipse.linuxtools.lttng.ui.views.histogram; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.FocusEvent; +import org.eclipse.swt.events.FocusListener; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.KeyListener; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.FontData; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Text; + +/** + * HistogramTextControl + *

+ * This control provides a group containing a text control. + */ +public abstract class HistogramTextControl implements FocusListener, KeyListener { + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + + protected final HistogramView fParentView; + private final Composite fParent; + + // Controls + private final Group fGroup; + protected final Text fTextValue; + private long fValue; + + // ------------------------------------------------------------------------ + // Constructors + // ------------------------------------------------------------------------ + + public HistogramTextControl(HistogramView parentView, Composite parent, int textStyle, int groupStyle) { + this(parentView, parent, textStyle, groupStyle, "", HistogramUtils.nanosecondsToString(0L)); //$NON-NLS-1$ + } + + public HistogramTextControl(HistogramView parentView, Composite parent, int textStyle, int groupStyle, String groupValue, String textValue) { + + fParentView = parentView; + fParent = parent; + + // -------------------------------------------------------------------- + // Reduce font size for a more pleasing rendering + // -------------------------------------------------------------------- + + final int fontSizeAdjustment = -1; + final Font font = parent.getFont(); + final FontData fontData = font.getFontData()[0]; + final Font adjustedFont = new Font(font.getDevice(), fontData.getName(), fontData.getHeight() + fontSizeAdjustment, fontData.getStyle()); + + // -------------------------------------------------------------------- + // Pre-compute the size of the control + // -------------------------------------------------------------------- + + final String longestStringValue = "." + Long.MAX_VALUE; //$NON-NLS-1$ + final int maxChars = longestStringValue.length(); + final int textBoxSize = HistogramUtils.getTextSizeInControl(parent, longestStringValue); + + // -------------------------------------------------------------------- + // Create the group + // -------------------------------------------------------------------- + + // Re-used layout variables + GridLayout gridLayout; + GridData gridData; + + // Group control + gridLayout = new GridLayout(1, false); + gridLayout.horizontalSpacing = 0; + gridLayout.verticalSpacing = 0; + fGroup = new Group(fParent, groupStyle); + fGroup.setText(groupValue); + fGroup.setFont(adjustedFont); + fGroup.setLayout(gridLayout); + + // Group control + gridData = new GridData(SWT.LEFT, SWT.CENTER, true, false); + gridData.horizontalIndent = 0; + gridData.verticalIndent = 0; + gridData.minimumWidth = textBoxSize; + fTextValue = new Text(fGroup, textStyle); + fTextValue.setTextLimit(maxChars); + fTextValue.setText(textValue); + fTextValue.setFont(adjustedFont); + fTextValue.setLayoutData(gridData); + + // -------------------------------------------------------------------- + // Add listeners + // -------------------------------------------------------------------- + + fTextValue.addFocusListener(this); + fTextValue.addKeyListener(this); + } + + // ------------------------------------------------------------------------ + // Accessors + // ------------------------------------------------------------------------ + + // State + public boolean isDisposed() { + return fGroup.isDisposed(); + } + + // ------------------------------------------------------------------------ + // Operations + // ------------------------------------------------------------------------ + + protected abstract void updateValue(); + + // LayoutData + public void setLayoutData(GridData layoutData) { + fGroup.setLayoutData(layoutData); + } + + // Time value + public void setValue(String timeString) { + long timeValue = HistogramUtils.stringToNanoseconds(timeString); + setValue(timeValue); + } + + public void setValue(final long time) { + // If this is the UI thread, process now + Display display = Display.getCurrent(); + if (display != null) { + fValue = time; + fTextValue.setText(HistogramUtils.nanosecondsToString(time)); + return; + } + + // Call "recursively" from the UI thread + if (!isDisposed()) { + Display.getDefault().asyncExec(new Runnable() { + @Override + public void run() { + if (!isDisposed()) { + setValue(time); + } + } + }); + } + } + + public long getValue() { + return fValue; + } + + // ------------------------------------------------------------------------ + // FocusListener + // ------------------------------------------------------------------------ + + @Override + public void focusGained(FocusEvent event) { + } + + @Override + public void focusLost(FocusEvent event) { + updateValue(); + } + + // ------------------------------------------------------------------------ + // KeyListener + // ------------------------------------------------------------------------ + + @Override + public void keyPressed(KeyEvent event) { + switch (event.keyCode) { + case SWT.CR: + updateValue(); + break; + default: + break; + } + } + + @Override + public void keyReleased(KeyEvent e) { + } + +} diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramTimeRangeControl.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramTimeRangeControl.java new file mode 100644 index 0000000000..b12c25df88 --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramTimeRangeControl.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Francois Chouinard - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.linuxtools.lttng.ui.views.histogram; + +import org.eclipse.swt.widgets.Composite; + +/** + * HistogramTimeRangeControl + *

+ * This control provides a group containing a text control. + */ +public class HistogramTimeRangeControl extends HistogramTextControl { + + // ------------------------------------------------------------------------ + // Construction + // ------------------------------------------------------------------------ + + public HistogramTimeRangeControl(HistogramView parentView, Composite parent, int textStyle, int groupStyle) { + this(parentView, parent, textStyle, groupStyle, "", HistogramUtils.nanosecondsToString(0L)); //$NON-NLS-1$ + } + + public HistogramTimeRangeControl(HistogramView parentView, Composite parent, int textStyle, int groupStyle, String groupValue, String textValue) { + super(parentView, parent, textStyle, groupStyle, groupValue, textValue); + } + + // ------------------------------------------------------------------------ + // Operations + // ------------------------------------------------------------------------ + + @Override + protected void updateValue() { + String stringValue = fTextValue.getText(); + long value = HistogramUtils.stringToNanoseconds(stringValue); + + if (getValue() != value) { + fParentView.updateTimeRange(value); + } + } + +} diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramUtils.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramUtils.java new file mode 100644 index 0000000000..a5b9d53dea --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramUtils.java @@ -0,0 +1,126 @@ +/******************************************************************************* + * Copyright (c) 2009, 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * William Bourque - Initial API and implementation + * Francois Chouinard - Cleanup and refactoring + *******************************************************************************/ + +package org.eclipse.linuxtools.lttng.ui.views.histogram; + +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.widgets.Composite; + +/** + * HistogramUtils + *

+ * Bunch of conversion utilities. + *

+ */ +public abstract class HistogramUtils { + + // ------------------------------------------------------------------------ + // Operations + // ------------------------------------------------------------------------ + + /** + * Format a long representing nanoseconds into a string of the form + * "[seconds].[nanoseconds]" with the appropriate zero-padding. + *

+ * + * @param ns the timestamp in nanoseconds + * @return the formatted string + */ + public static String nanosecondsToString(long ns) { + ns = Math.abs(ns); + String time = Long.toString(ns); + + int length = time.length(); + if (time.length() > 9) { + // Just insert the decimal dot + time = time.substring(0, length - 9) + "." + time.substring(length - 9); //$NON-NLS-1$ + return time; + } + + // Zero-pad the value + for (int i = length; i < 9; i++) { + time = "0" + time; //$NON-NLS-1$ + } + time = "0." + time; //$NON-NLS-1$ + return time; + } + + /** + * Convert a string representing a time to the corresponding long. + *

+ * + * @param time the string to convert + * @return the corresponding nanoseconds value + */ + public static long stringToNanoseconds(String time) { + + long result = 0L; + StringBuffer buffer = new StringBuffer(time); + + try { + int dot = buffer.indexOf("."); //$NON-NLS-1$ + + // Prepend a "." if none was found (assume ns) + if (dot == -1) { + buffer.insert(0, "."); //$NON-NLS-1$ + dot = 0; + } + + // Zero-pad the string for nanoseconds + for (int i = buffer.length() - dot - 1; i < 9; i++) + buffer.append("0"); //$NON-NLS-1$ + + // Remove the extra decimals if present + int nbDecimals = buffer.substring(dot + 1).length(); + if (nbDecimals > 9) + buffer.delete(buffer.substring(0, dot + 1 + 9).length(), buffer.length()); + + // Do the conversion + long seconds = (dot > 0) ? Long.parseLong(buffer.substring(0, dot)) : 0; + seconds = Math.abs(seconds); + long nanosecs = Long.parseLong(buffer.substring(dot + 1)); + result = seconds * 1000000000 + nanosecs; + + } catch (NumberFormatException e) { + // TODO: Find something interesting to say + } + + return result; + } + + /** + * Calculate the width of a String. + *

+ * + * @param parent The control used as reference + * @param text The Text to measure + * + * @return The result size + */ + public static int getTextSizeInControl(Composite parent, String text) { + + GC controlGC = new GC(parent); + + int textSize = 0; + for (int pos = 0; pos < text.length(); pos++) { + textSize += controlGC.getAdvanceWidth(text.charAt(pos)); + } + // Add an extra space + textSize += controlGC.getAdvanceWidth(' '); + + controlGC.dispose(); + + return textSize; + } + +} diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramView.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramView.java index 7d30f4c832..9bbb86f348 100644 --- a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramView.java +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramView.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009 Ericsson + * Copyright (c) 2009, 2010, 2011 Ericsson * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v1.0 which @@ -8,1146 +8,431 @@ * * Contributors: * William Bourque - Initial API and implementation - * - * Modifications: - * 2010-06-10 Yuriy Vashchuk - GUI reorganisation, simplification and some - * related code improvements. - * 2010-06-20 Yuriy Vashchuk - Histograms optimisation. - * 2010-07-16 Yuriy Vashchuk - Histogram Canvas Heritage correction + * Yuriy Vashchuk - GUI reorganisation, simplification and some related code improvements. + * Yuriy Vashchuk - Histograms optimisation. + * Yuriy Vashchuk - Histogram Canvas Heritage correction + * Francois Chouinard - Cleanup and refactoring *******************************************************************************/ package org.eclipse.linuxtools.lttng.ui.views.histogram; import org.eclipse.linuxtools.lttng.event.LttngEvent; -import org.eclipse.linuxtools.lttng.event.LttngTimestamp; import org.eclipse.linuxtools.tmf.event.TmfTimeRange; import org.eclipse.linuxtools.tmf.event.TmfTimestamp; import org.eclipse.linuxtools.tmf.experiment.TmfExperiment; -import org.eclipse.linuxtools.tmf.request.ITmfDataRequest; import org.eclipse.linuxtools.tmf.request.ITmfDataRequest.ExecutionType; import org.eclipse.linuxtools.tmf.signal.TmfExperimentSelectedSignal; import org.eclipse.linuxtools.tmf.signal.TmfRangeSynchSignal; import org.eclipse.linuxtools.tmf.signal.TmfSignalHandler; +import org.eclipse.linuxtools.tmf.signal.TmfSignalManager; import org.eclipse.linuxtools.tmf.signal.TmfTimeSynchSignal; import org.eclipse.linuxtools.tmf.trace.ITmfTrace; import org.eclipse.linuxtools.tmf.ui.views.TmfView; import org.eclipse.swt.SWT; -import org.eclipse.swt.events.ControlEvent; -import org.eclipse.swt.events.ControlListener; -import org.eclipse.swt.graphics.Font; -import org.eclipse.swt.graphics.FontData; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Text; /** * HistogramView *

- * View that contain an visual approach to the window that control the request. - * This is intended to replace the TimeFrameView + * The purpose of this view is to provide graphical time distribution statistics + * about the experiment/trace events. *

- * This view is composed of 2 canvas, one for the whole experiment and one for the selected window in the experiment. - * It also contain a certain number of controls to print or change informations about the experiment. + * The view is composed of two histograms and two controls: + *

+ * The histograms x-axis show their respective time range. */ -public class HistogramView extends TmfView implements ControlListener { - - // *** TODO *** - // Here is what's left to do in this view - // - // 1- Make sure the interval time is small enough on very big trace (bug 311930) - // The interval time of the content is dynamically assigned from the screen width and trace duration. - // However, on very big trace (more than 1 hour), we could end up with time interval that are > 1 seconds, - // which is not very precise. - // An algorithm need to be implemented to make sure we "increase" the number of interval in the content if - // their precision is getting too bad. - // - // 2- Make sure all control are thread safe (bug 309348) - // Right now, all the basic controls (i.e. Text and Label) are sensible to "Thread Access Exception" if - // updated from different threads; we need to carefully decide when/where to redraw them. - // This is a real problem since there is a lot of thread going on in this view. - // All basic control should be subclassed to offer "Asynchronous" functions. - // - // 3- Implement a "preferences view" for the HistogramView (bug 311935) - // There is a lot of adjustable preferences in the view, however there is no way to adjust them right now - // at run time. There should be a view of some kind of "menu" to allow the user to change them while executing. - // Most of the pertinent values are in HistogramConstant.java or in this file. - +public class HistogramView extends TmfView { + + // ------------------------------------------------------------------------ + // Constants + // ------------------------------------------------------------------------ + + // The view ID as defined in plugin.xml public static final String ID = "org.eclipse.linuxtools.lttng.ui.views.histogram"; //$NON-NLS-1$ - - // "Minimum" screen width size. On smaller screen, we will apply several space saving technique - private static final int SCREEN_SMALL_IF_SMALLER_THAN = 1600; - -/* - // 2010-06-20 Yuriy: We will use the dynamic height. - // Size of the "full trace" canvas - private static final int FULL_TRACE_CANVAS_HEIGHT = 25; -*/ - private static final int FULL_TRACE_BAR_WIDTH = 1; - private static final double FULL_TRACE_DIFFERENCE_TO_AVERAGE = 1.5; - - // Size of the "Selected Window" canvas -/* - // 2010-06-20 Yuriy - private static final int SELECTED_WINDOW_CANVAS_WIDTH = 300; - private static final int SMALL_SELECTED_WINDOW_CANVAS_WIDTH = 200; - private static final int SELECTED_WINDOW_CANVAS_HEIGHT = 60; -*/ - private static final int SELECTED_WINDOW_BAR_WIDTH = 1; - private static final double SELECTED_WINDOW_DIFFERENCE_TO_AVERAGE = 10.0; - - // For the two "events" label (Max and Min number of events in the selection), we force a width - // This will prevent the control from moving horizontally if the number of events in the selection varies - private static final int NB_EVENTS_FIXED_WIDTH = 50; - - // The "small font" height used to display time will be "default font" minus this constant - private static final int SMALL_FONT_MODIFIER = 2; - private static final int VERY_SMALL_FONT_MODIFIER = 4; - - // *** TODO *** - // This need to be changed as soon the framework implement a "window" -// private static long DEFAULT_WINDOW_SIZE = (10L * 100 * 1000 * 1000); // 1sec - private static long DEFAULT_WINDOW_SIZE = (1L * 100 * 1000 * 1000); // .1sec - - // The last experiment received/used by the view - private TmfExperiment lastUsedExperiment = null; - - // Parent of the view - private Composite parent = null; - - // Request and canvas for the "full trace" part - private HistogramRequest dataBackgroundFullRequest = null; - private static ParentHistogramCanvas fullExperimentCanvas = null; - - // Request and canvas for the "selected window" - private HistogramRequest selectedWindowRequest = null; - private static ChildrenHistogramCanvas selectedWindowCanvas = null; - - // Content of the timeTextGroup - // Since the user can modify them with erroneous value, - // we will keep track of the value internally - private long currentEventTime = 0L; - - // *** All the UI control below - // - // NOTE : All textboxes will be READ_ONLY. - // So the user will be able to select/copy the value in them but not to change it - private Text txtExperimentStartTime = null; - private Text txtExperimentStopTime = null; - - private Text txtWindowStartTime = null; - private Text txtWindowStopTime = null; - private Text txtWindowMaxNbEvents = null; - private Text txtWindowMinNbEvents = null; - - // We move the time label to header from TimeTextGroup.java - private static final String WINDOW_TIMESPAN_LABEL_TEXT = Messages.HistogramView_windowSpanLabel; - private static final String WINDOW_CENTER_TIME_LABEL_TEXT = Messages.HistogramView_windowCenterLabel; - private static final String CURRENT_EVENT_TIME_LABEL_TEXT = Messages.HistogramView_currentEventLabel; - private TimeTextGroup ntgWindowTimeSpan = null; - private TimeTextGroup ntgWindowCenterTime = null; - private TimeTextGroup ntgCurrentEventTime = null; - - /** - * Default constructor of the view - */ - public HistogramView() { - super(ID); - } - - /** - * Create the UI controls of this view - * - * @param parent The composite parent of this view - */ - @Override - public void createPartControl(Composite newParent) { - // Save the parent - parent = newParent; - - // Default font - Font font = parent.getFont(); - FontData tmpFontData = font.getFontData()[0]; - - - Font smallFont = null; - int nbEventWidth = -1; - int selectedCanvasWidth = -1; - boolean doesTimeTextGroupNeedAdjustment = false; - - // Calculate if we need "small screen" fixes - if ( parent.getDisplay().getBounds().width < SCREEN_SMALL_IF_SMALLER_THAN ) { - - // A lot smaller font for timestamp - smallFont = new Font(font.getDevice(), tmpFontData.getName(), tmpFontData.getHeight() - VERY_SMALL_FONT_MODIFIER, tmpFontData.getStyle()); - -/* - // 2010-06-20 Yuriy - // Smaller selection window canvas - selectedCanvasWidth = SMALL_SELECTED_WINDOW_CANVAS_WIDTH; -*/ - // Smaller event number text field - nbEventWidth = NB_EVENTS_FIXED_WIDTH/2; - - // Tell the text group to ajust - doesTimeTextGroupNeedAdjustment = true; - - } else { - - // Slightly smaller font for timestamp - smallFont = new Font(font.getDevice(), tmpFontData.getName(), tmpFontData.getHeight() - SMALL_FONT_MODIFIER, tmpFontData.getStyle()); - // Usual size for selected window and event number text field - nbEventWidth = NB_EVENTS_FIXED_WIDTH; -/* - // 2010-06-20 Yuriy - selectedCanvasWidth = SELECTED_WINDOW_CANVAS_WIDTH; -*/ - // No ajustement needed by the text group - doesTimeTextGroupNeedAdjustment = false; - - } - - - ///////////////////////////////////////////////////////////////////////////////////// - // Layout for the whole view, other elements will be in a child composite of this one - // Contains : - // Composite layoutSelectionWindow - // Composite layoutTimesSpinner - // Composite layoutExperimentHistogram - ///////////////////////////////////////////////////////////////////////////////////// - Composite layoutFullView = new Composite(parent, SWT.FILL); - GridLayout gridFullView = new GridLayout(); - gridFullView.numColumns = 2; - gridFullView.horizontalSpacing = 0; - gridFullView.verticalSpacing = 0; - gridFullView.marginHeight = 0; - gridFullView.marginWidth = 0; - layoutFullView.setLayout(gridFullView); - - - ///////////////////////////////////////////////////////////////////////////////////// - // Layout that contain the time spinners - // Contains : - // NanosecTextGroup ntgCurrentEventTime - // NanosecTextGroup ntgTimeRangeWindow - // NanosecTextGroup ntgCurrentWindowTime - ///////////////////////////////////////////////////////////////////////////////////// - Composite layoutTimeSpinners = new Composite(layoutFullView, SWT.NONE); - GridLayout gridTimesSpinner = new GridLayout(); - gridTimesSpinner.numColumns = 3; - gridTimesSpinner.marginHeight = 0; - gridTimesSpinner.marginWidth = 0; - gridTimesSpinner.horizontalSpacing = 5; - gridTimesSpinner.verticalSpacing = 0; - gridTimesSpinner.makeColumnsEqualWidth = true; - gridTimesSpinner.marginLeft = 5; - gridTimesSpinner.marginRight = 5; - layoutTimeSpinners.setLayout(gridTimesSpinner); - - GridData gridDataCurrentEvent = new GridData(); - gridDataCurrentEvent.horizontalAlignment = SWT.LEFT; - gridDataCurrentEvent.verticalAlignment = SWT.CENTER; - ntgCurrentEventTime = new TimeTextGroup(this, layoutTimeSpinners, SWT.BORDER, SWT.BORDER, CURRENT_EVENT_TIME_LABEL_TEXT, HistogramConstant.formatNanoSecondsTime(0L), doesTimeTextGroupNeedAdjustment); - ntgCurrentEventTime.setLayoutData(gridDataCurrentEvent); - - GridData gridDataTimeSpan = new GridData(); - gridDataTimeSpan.horizontalAlignment = SWT.CENTER; - gridDataTimeSpan.verticalAlignment = SWT.CENTER; - ntgWindowTimeSpan = new TimeTextGroup(this, layoutTimeSpinners, SWT.BORDER, SWT.BORDER, WINDOW_TIMESPAN_LABEL_TEXT, HistogramConstant.formatNanoSecondsTime(0L), doesTimeTextGroupNeedAdjustment); - ntgWindowTimeSpan.setLayoutData(gridDataTimeSpan); - - GridData gridDataWindowCenter = new GridData(); - gridDataWindowCenter.horizontalAlignment = SWT.RIGHT; - gridDataWindowCenter.verticalAlignment = SWT.CENTER; - ntgWindowCenterTime = new TimeTextGroup(this, layoutTimeSpinners, SWT.BORDER, SWT.BORDER, WINDOW_CENTER_TIME_LABEL_TEXT, HistogramConstant.formatNanoSecondsTime(0L), doesTimeTextGroupNeedAdjustment); - ntgWindowCenterTime.setLayoutData(gridDataWindowCenter); - - - ///////////////////////////////////////////////////////////////////////////////////// - // Layout that contain the SelectionWindow - // Contains : - // Label txtWindowStartTime - // Label txtWindowStopTime - // Label txtWindowMaxNbEvents - // Label txtWindowMinNbEvents - // ChildrenHistogramCanvas selectedWindowCanvas - ///////////////////////////////////////////////////////////////////////////////////// - Composite layoutSelectionWindow = new Composite(layoutFullView, SWT.FILL); - GridLayout gridSelectionWindow = new GridLayout(); - gridSelectionWindow.numColumns = 3; - gridSelectionWindow.marginHeight = 0; - gridSelectionWindow.marginWidth = 2; - gridSelectionWindow.marginTop = 5; - gridSelectionWindow.horizontalSpacing = 0; - gridSelectionWindow.verticalSpacing = 0; - layoutSelectionWindow.setLayout(gridSelectionWindow); - - GridData gridDataSelectionWindow = new GridData(); - gridDataSelectionWindow.horizontalAlignment = SWT.FILL; - gridDataSelectionWindow.verticalAlignment = SWT.FILL; - layoutSelectionWindow.setLayoutData(gridDataSelectionWindow); - - GridData gridDataSelectionWindowCanvas = new GridData(); - gridDataSelectionWindowCanvas.horizontalSpan = 2; - gridDataSelectionWindowCanvas.verticalSpan = 2; - gridDataSelectionWindowCanvas.horizontalAlignment = SWT.FILL; - gridDataSelectionWindowCanvas.grabExcessHorizontalSpace = true; - gridDataSelectionWindowCanvas.verticalAlignment = SWT.FILL; -/* - // 2010-06-20 Yuriy - gridDataSelectionWindowCanvas.heightHint = SELECTED_WINDOW_CANVAS_HEIGHT; - gridDataSelectionWindowCanvas.minimumHeight = SELECTED_WINDOW_CANVAS_HEIGHT; -*/ - gridDataSelectionWindowCanvas.widthHint = selectedCanvasWidth; - gridDataSelectionWindowCanvas.minimumWidth = selectedCanvasWidth; - selectedWindowCanvas = new ChildrenHistogramCanvas(this, layoutSelectionWindow, SWT.BORDER); - selectedWindowCanvas.setLayoutData(gridDataSelectionWindowCanvas); - - GridData gridDataWindowMaxEvents = new GridData(); - gridDataWindowMaxEvents.horizontalAlignment = SWT.RIGHT; - gridDataWindowMaxEvents.verticalAlignment = SWT.TOP; - // Force a width, to avoid the control to enlarge if the number of events change - gridDataWindowMaxEvents.minimumWidth = nbEventWidth; - txtWindowMaxNbEvents = new Text(layoutSelectionWindow, SWT.READ_ONLY); - txtWindowMaxNbEvents.setFont(smallFont); - txtWindowMaxNbEvents.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_TITLE_INACTIVE_BACKGROUND)); - txtWindowMaxNbEvents.setEditable(false); - txtWindowMaxNbEvents.setText("0"); //$NON-NLS-1$ - txtWindowMaxNbEvents.setLayoutData(gridDataWindowMaxEvents); - - GridData gridDataWindowMinEvents = new GridData(); - gridDataWindowMinEvents.horizontalAlignment = SWT.RIGHT; - gridDataWindowMinEvents.verticalAlignment = SWT.BOTTOM; - // Force a width, to avoid the control to enlarge if the number of events change - gridDataWindowMinEvents.minimumWidth = nbEventWidth; - txtWindowMinNbEvents = new Text(layoutSelectionWindow, SWT.READ_ONLY); - txtWindowMinNbEvents.setFont(smallFont); - txtWindowMinNbEvents.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_TITLE_INACTIVE_BACKGROUND)); - txtWindowMinNbEvents.setEditable(false); - txtWindowMinNbEvents.setText("0"); //$NON-NLS-1$ - txtWindowMinNbEvents.setLayoutData(gridDataWindowMinEvents); - - GridData gridDataWindowStart = new GridData(); - gridDataWindowStart.horizontalAlignment = SWT.LEFT; - gridDataWindowStart.verticalAlignment = SWT.BOTTOM; - txtWindowStartTime = new Text(layoutSelectionWindow, SWT.READ_ONLY); - txtWindowStartTime.setFont(smallFont); - txtWindowStartTime.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_TITLE_INACTIVE_BACKGROUND)); - txtWindowStartTime.setEditable(false); - txtWindowStartTime.setText("0.000000000"); //$NON-NLS-1$ - txtWindowStartTime.setLayoutData(gridDataWindowStart); - - GridData gridDataWindowStop = new GridData(); - gridDataWindowStop.horizontalAlignment = SWT.RIGHT; - gridDataWindowStop.verticalAlignment = SWT.BOTTOM; - txtWindowStopTime = new Text(layoutSelectionWindow, SWT.READ_ONLY); - txtWindowStopTime.setFont(smallFont); - txtWindowStopTime.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_TITLE_INACTIVE_BACKGROUND)); - txtWindowStopTime.setEditable(false); - txtWindowStopTime.setText("0.000000000"); //$NON-NLS-1$ - txtWindowStopTime.setLayoutData(gridDataWindowStop); - - -/* - // 2010-06-10 Yuriy: NOT NEEDED AFTER GUI IMPROVEMENTS. WORK FINE WITOUT THIS HACK - // *** HACK *** - // To align properly AND to make sure the canvas size is fixed, we NEED to make sure all "section" of the - // gridlayout are taken (and if possible of a fixed size). - // However, SWT is VERY VERY DUMB and won't consider griddata that contain no control. - // Since there will be missing a section, the SelectedWindowCanvas + NbEventsText will take 3 spaces, but - // startTimeText + stopTimeText will take only 2 (as if empty the other griddata of 1 will get ignored). - // StopTime will then take over the missing space; I want to align "stopTime" right on the end of canvas, so - // the added space to stop time would make it being aligned improperly - // So I NEED the empty griddata to be considered! - // Visually : - // |---------------|---------------|-----------| - // |SelectionCanvas SelectionCanvas|NbEventText| - // |SelectionCanvas SelectionCanvas|NbEventText| - // |---------------|---------------|-----------| - // |StartTime | StopTime| ??? | - // |---------------|---------------|-----------| - // - // So since SWT will only consider griddata with control, - // I need to create a totally useless control in the ??? section. - // That's ugly, useless and it is generally a bad practice. - // - // *** SUB-HACK *** - // Other interesting fact about SWT : the way it draws (Fill/Expand control in grid) will change if - // the control is a Text or a Label. - // A Label here will be "pushed" by startTime/stopTime Text and won't fill the full space as NbEventText. - // A Text here will NOT be "pushed" and would give a nice visual output. - // (NB : No, I am NOT kidding, try it for yourself!) - // - // Soooooo I guess I will use a Text here. Way to go SWT! - // Downside is that disabled textbox has a slightly different color (even if you force it yourself) so if I want - // to make the text "invisible", I have to keep it enabled (but read only), so it can be clicked on. - // - // Label uselessControlToByPassSWTStupidBug = new Label(layoutSelectionWindow, SWT.BORDER); // WON'T align correctly!!! - //GridData gridDataSpacer = new GridData(SWT.FILL, SWT.TOP, true, true, 1, 1); - GridData gridDataSpacer = new GridData(); - gridDataWindowStop.horizontalAlignment = SWT.FILL; - gridDataWindowStop.verticalAlignment = SWT.TOP; - gridDataSpacer.minimumWidth = nbEventWidth; - Text uselessControlToByPassSWTStupidBug = new Text(layoutSelectionWindow, SWT.READ_ONLY); // WILL align correctly!!! - uselessControlToByPassSWTStupidBug.setEditable(false); - uselessControlToByPassSWTStupidBug.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_TITLE_INACTIVE_BACKGROUND)); - uselessControlToByPassSWTStupidBug.setLayoutData(gridDataSpacer); -*/ - - - ///////////////////////////////////////////////////////////////////////////////////// - // Layout that contain the complete experiment histogram and related controls. - // Contains : - // ParentHistogramCanvas fullExperimentCanvas - // Text txtExperimentStartTime - // Text txtExperimentStopTime - ///////////////////////////////////////////////////////////////////////////////////// - Composite layoutExperimentHistogram = new Composite(layoutFullView, SWT.FILL); - - GridLayout gridExperimentHistogram = new GridLayout(); - gridExperimentHistogram.numColumns = 2; - gridExperimentHistogram.marginHeight = 0; - gridExperimentHistogram.marginWidth = 0; - gridExperimentHistogram.horizontalSpacing = 0; - gridExperimentHistogram.verticalSpacing = 0; - gridExperimentHistogram.marginLeft = 5; - gridExperimentHistogram.marginRight = 5; - layoutExperimentHistogram.setLayout(gridExperimentHistogram); - -/* - // 2010-06-10 Yuriy: NOT NEEDED AFTER GUI IMPROVEMENTS - GridData gridDataExperimentHistogram = new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1); - layoutExperimentHistogram.setLayoutData(gridDataExperimentHistogram); -*/ - - // *** Everything related to the experiment canvas is below - GridData gridDataExperimentCanvas = new GridData(); - gridDataExperimentCanvas.horizontalSpan = 2; - gridDataExperimentCanvas.horizontalAlignment = SWT.FILL; - gridDataExperimentCanvas.grabExcessHorizontalSpace = true; - gridDataExperimentCanvas.verticalAlignment = SWT.FILL; - gridDataExperimentCanvas.grabExcessVerticalSpace = true; -/* - // 2010-06-20 Yuriy: We use the dynamic height. - gridDataExperimentCanvas.heightHint = FULL_TRACE_CANVAS_HEIGHT; - gridDataExperimentCanvas.minimumHeight = FULL_TRACE_CANVAS_HEIGHT; -*/ - fullExperimentCanvas = new ParentHistogramCanvas(this, layoutExperimentHistogram, SWT.BORDER); - fullExperimentCanvas.setLayoutData(gridDataExperimentCanvas); - layoutExperimentHistogram.setLayoutData(gridDataExperimentCanvas); - - GridData gridDataExperimentStart = new GridData(); - gridDataExperimentStart.horizontalAlignment = SWT.LEFT; - gridDataExperimentStart.verticalAlignment = SWT.BOTTOM; - txtExperimentStartTime = new Text(layoutExperimentHistogram, SWT.READ_ONLY); - txtExperimentStartTime.setFont(smallFont); - txtExperimentStartTime.setText("0.000000000"); //$NON-NLS-1$ - txtExperimentStartTime.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_TITLE_INACTIVE_BACKGROUND)); - txtExperimentStartTime.setEditable(false); - txtExperimentStartTime.setLayoutData(gridDataExperimentStart); - - GridData gridDataExperimentStop = new GridData(); - gridDataExperimentStop.horizontalAlignment = SWT.RIGHT; - gridDataExperimentStop.verticalAlignment = SWT.BOTTOM; - txtExperimentStopTime = new Text(layoutExperimentHistogram, SWT.READ_ONLY); - txtExperimentStopTime.setFont(smallFont); - txtExperimentStopTime.setText("0.000000000"); //$NON-NLS-1$ - txtExperimentStopTime.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_TITLE_INACTIVE_BACKGROUND)); - txtExperimentStopTime.setEditable(false); - txtExperimentStopTime.setLayoutData(gridDataExperimentStop); - } - - // *** FIXME *** - // This is mainly used because of a because in the "experimentSelected()" notification, we shouldn't need this - /** - * Method called when the view receive the focus.

- * If ExperimentSelected didn't send us a request yet, get the current Experiment and fire requests - */ - @SuppressWarnings("unchecked") - @Override - public void setFocus() { - // WARNING : This does not seem to be thread safe - TmfExperiment tmpExperiment = (TmfExperiment)TmfExperiment.getCurrentExperiment(); - - if ( (dataBackgroundFullRequest == null) && (tmpExperiment != null) ) { - createCanvasAndRequests(tmpExperiment); - } - - // Call a redraw for everything - parent.redraw(); - } - - /** - * Method called when the user select (double-click on) an experiment.

- * We will create the needed canvas and fire the requests. - * - * @param signal Signal received from the framework. Contain the experiment. - */ + + // The initial window span (in nanoseconds) + public static long INITIAL_WINDOW_SPAN = (1L * 100 * 1000 * 1000); // .1sec + + // Time scale + private final byte TIME_SCALE = Histogram.TIME_SCALE; + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + + // Parent widget + private Composite fParent; + + // The current experiment + private TmfExperiment fCurrentExperiment; + + // Current timestamp/time window + private long fExperimentStartTime; + private long fExperimentEndTime; + private long fWindowStartTime; + private long fWindowEndTime; + private long fWindowSpan = INITIAL_WINDOW_SPAN; + private long fCurrentTimestamp; + + // Time controls + private HistogramTextControl fCurrentEventTimeControl; + private HistogramTextControl fTimeSpanControl; + + // Histogram/request for the full trace range + private static FullTraceHistogram fFullTraceHistogram; + private HistogramRequest fFullTraceRequest; + + // Histogram/request for the selected time range + private static TimeRangeHistogram fTimeRangeHistogram; + private HistogramRequest fTimeRangeRequest; + + // ------------------------------------------------------------------------ + // Constructor + // ------------------------------------------------------------------------ + + public HistogramView() { + super(ID); + } + + public void dispose() { + fFullTraceHistogram.dispose(); + fTimeRangeHistogram.dispose(); + } + + // ------------------------------------------------------------------------ + // TmfView + // ------------------------------------------------------------------------ + + @Override @SuppressWarnings("unchecked") - @TmfSignalHandler - public void experimentSelected(TmfExperimentSelectedSignal signal) { - TmfExperiment tmpExperiment = (TmfExperiment)signal.getExperiment(); - createCanvasAndRequests(tmpExperiment); + public void createPartControl(Composite parent) { + + fParent = parent; + + // Control labels + final String currentEventLabel = Messages.HistogramView_currentEventLabel; + final String windowSpanLabel = Messages.HistogramView_windowSpanLabel; + + // -------------------------------------------------------------------- + // Set the HistogramView layout + // -------------------------------------------------------------------- + + Composite viewComposite = new Composite(fParent, SWT.FILL); + GridLayout gridLayout = new GridLayout(); + gridLayout.numColumns = 2; + gridLayout.horizontalSpacing = 5; + gridLayout.verticalSpacing = 0; + gridLayout.marginHeight = 0; + gridLayout.marginWidth = 0; + viewComposite.setLayout(gridLayout); + + // Use all available space + GridData gridData = new GridData(); + gridData.horizontalAlignment = SWT.FILL; + gridData.verticalAlignment = SWT.FILL; + gridData.grabExcessHorizontalSpace = true; + viewComposite.setLayoutData(gridData); + + // -------------------------------------------------------------------- + // Time controls + // -------------------------------------------------------------------- + + Composite controlsComposite = new Composite(viewComposite, SWT.FILL); + gridLayout = new GridLayout(); + gridLayout.numColumns = 2; + gridLayout.marginHeight = 0; + gridLayout.marginWidth = 0; + gridLayout.horizontalSpacing = 5; + gridLayout.verticalSpacing = 0; + gridLayout.makeColumnsEqualWidth = true; + gridLayout.marginLeft = 5; + gridLayout.marginRight = 5; + controlsComposite.setLayout(gridLayout); + + // Current event time control + gridData = new GridData(); + gridData.horizontalAlignment = SWT.CENTER; + gridData.verticalAlignment = SWT.CENTER; + fCurrentEventTimeControl = new HistogramCurrentTimeControl(this, controlsComposite, SWT.BORDER, SWT.BORDER, currentEventLabel, + HistogramUtils.nanosecondsToString(0L)); + fCurrentEventTimeControl.setLayoutData(gridData); + + // Window span time control + gridData = new GridData(); + gridData.horizontalAlignment = SWT.CENTER; + gridData.verticalAlignment = SWT.CENTER; + fTimeSpanControl = new HistogramTimeRangeControl(this, controlsComposite, SWT.BORDER, SWT.BORDER, windowSpanLabel, + HistogramUtils.nanosecondsToString(0L)); + fTimeSpanControl.setLayoutData(gridData); + + // -------------------------------------------------------------------- + // Time range histogram + // -------------------------------------------------------------------- + + Composite timeRangeComposite = new Composite(viewComposite, SWT.FILL); + gridLayout = new GridLayout(); + gridLayout.numColumns = 1; + gridLayout.marginHeight = 0; + gridLayout.marginWidth = 0; + gridLayout.marginTop = 5; + gridLayout.horizontalSpacing = 0; + gridLayout.verticalSpacing = 0; + gridLayout.marginLeft = 5; + gridLayout.marginRight = 5; + timeRangeComposite.setLayout(gridLayout); + + // Use remaining horizontal space + gridData = new GridData(); + gridData.horizontalAlignment = SWT.FILL; + gridData.verticalAlignment = SWT.FILL; + gridData.grabExcessHorizontalSpace = true; + timeRangeComposite.setLayoutData(gridData); + + // Histogram + fTimeRangeHistogram = new TimeRangeHistogram(this, timeRangeComposite); + + // -------------------------------------------------------------------- + // Full range histogram + // -------------------------------------------------------------------- + + Composite fullRangeComposite = new Composite(viewComposite, SWT.FILL); + gridLayout = new GridLayout(); + gridLayout.numColumns = 1; + gridLayout.marginHeight = 0; + gridLayout.marginWidth = 0; + gridLayout.marginTop = 5; + gridLayout.horizontalSpacing = 0; + gridLayout.verticalSpacing = 0; + gridLayout.marginLeft = 5; + gridLayout.marginRight = 5; + fullRangeComposite.setLayout(gridLayout); + + // Use remaining horizontal space + gridData = new GridData(); + gridData.horizontalAlignment = SWT.FILL; + gridData.verticalAlignment = SWT.FILL; + gridData.horizontalSpan = 2; + gridData.grabExcessHorizontalSpace = true; + fullRangeComposite.setLayoutData(gridData); + + // Histogram + fFullTraceHistogram = new FullTraceHistogram(this, fullRangeComposite); + + // Load the experiment if present + fCurrentExperiment = (TmfExperiment) TmfExperiment.getCurrentExperiment(); + if (fCurrentExperiment != null) + loadExperiment(); } - - - // *** VERIFY *** - // Not sure what this should do since I don't know when it will be called - // Let's do the same thing as experimentSelected for now - // - /** - * Method called when an experiment is updated (??).

- * ...for now, do nothing, as udating an experiment running in the background might cause crash - * - * @param signal Signal received from the framework. Contain the experiment. - */ -/* + + @Override @SuppressWarnings("unchecked") - @TmfSignalHandler - public void experimentUpdated(TmfExperimentUpdatedSignal signal) { - - TmfExperiment tmpExperiment = (TmfExperiment)signal.getExperiment(); - - // Make sure the UI object are sane - resetControlsContent(); - - // Redraw the canvas right away to have something "clean" as soon as we can - fullExperimentCanvas.redraw(); - selectedWindowCanvas.redraw(); - - // Recreate the request - createCanvasAndRequests(tmpExperiment); + public void setFocus() { + TmfExperiment experiment = (TmfExperiment) TmfExperiment.getCurrentExperiment(); + if ((experiment != null) && (experiment != fCurrentExperiment)) { + fCurrentExperiment = experiment; + initializeHistograms(); + } + fParent.redraw(); } -*/ - - /** - * Method called when synchronization is active and that the user select an event. - * We update the current event timeTextGroup and move the selected window if needed. - * - * @param signal Signal received from the framework. Contain the event. - */ - @TmfSignalHandler - public void currentTimeUpdated(TmfTimeSynchSignal signal) { - // In case we received our own signal - if ( (signal != null) && (signal.getSource() != this) ) { - TmfTimestamp currentTime = signal.getCurrentTime(); - - // Update the current event controls - currentEventTime = currentTime.getValue(); - updateSelectedEventTime(); + + // ------------------------------------------------------------------------ + // Accessors + // ------------------------------------------------------------------------ + + public TmfTimeRange getTimeRange() { + return new TmfTimeRange(new TmfTimestamp(fWindowStartTime, TIME_SCALE), new TmfTimestamp(fWindowEndTime, TIME_SCALE)); + } + + // ------------------------------------------------------------------------ + // Operations + // ------------------------------------------------------------------------ + + public void updateCurrentEventTime(long newTime) { + if (fCurrentExperiment != null) { + TmfTimeRange timeRange = new TmfTimeRange(new TmfTimestamp(newTime, TIME_SCALE), TmfTimestamp.BigCrunch); + HistogramRequest request = new HistogramRequest(fTimeRangeHistogram, timeRange, 1, ExecutionType.FOREGROUND) { + @Override + public void handleData(LttngEvent event) { + if (event != null) { + TmfTimeSynchSignal signal = new TmfTimeSynchSignal(this, event.getTimestamp()); + TmfSignalManager.dispatchSignal(signal); + } + } + }; + fCurrentExperiment.sendRequest(request); + } + } + + public void updateTimeRange(long startTime, long endTime) { + if (fCurrentExperiment != null) { + // Build the new time range; keep the current time + TmfTimeRange timeRange = new TmfTimeRange(new TmfTimestamp(startTime, TIME_SCALE), new TmfTimestamp(endTime, TIME_SCALE)); + TmfTimestamp currentTime = new TmfTimestamp(fCurrentTimestamp, TIME_SCALE); - // If the given event is outside the selection window, recenter the window - if ( isGivenTimestampInSelectedWindow( currentEventTime ) == false) { - fullExperimentCanvas.setWindowCenterPosition(currentEventTime); - - // Notify control that the window changed - windowChangedNotification(); - // Send a broadcast to the framework about the window change - sendTmfRangeSynchSignalBroadcast(); - } - } + fTimeSpanControl.setValue(endTime - startTime); + + // Send the FW signal + TmfRangeSynchSignal signal = new TmfRangeSynchSignal(this, timeRange, currentTime); + TmfSignalManager.dispatchSignal(signal); + } + } + + public synchronized void updateTimeRange(long newDuration) { + if (fCurrentExperiment != null) { + long delta = newDuration - fWindowSpan; + long newStartTime = fWindowStartTime + delta / 2; + setNewRange(newStartTime, newDuration); + } + } + + private void setNewRange(long startTime, long duration) { + if (startTime < fExperimentStartTime) + startTime = fExperimentStartTime; + + long endTime = startTime + duration; + if (endTime > fExperimentEndTime) { + endTime = fExperimentEndTime; + if (endTime - duration > fExperimentStartTime) + startTime = endTime - duration; + else { + startTime = fExperimentStartTime; + } + } + updateTimeRange(startTime, endTime); } - + + // ------------------------------------------------------------------------ + // Signal handlers + // ------------------------------------------------------------------------ + @TmfSignalHandler - public void synchToTimeRange(TmfRangeSynchSignal signal) { - if ( (signal != null) ) { - if ( lastUsedExperiment != null ) { - long currentTime = signal.getCurrentTime().getValue(); - long windowStart = signal.getCurrentRange().getStartTime().getValue(); - long windowEnd = signal.getCurrentRange().getEndTime().getValue(); - long windowTimeWidth = (windowEnd - windowStart); - - // Recenter the window - fullExperimentCanvas.setSelectedWindowSize(windowTimeWidth); - fullExperimentCanvas.setWindowCenterPosition( fullExperimentCanvas.getHistogramContent().getClosestXPositionFromTimestamp(windowStart + (windowTimeWidth/2)) ); - - // *** HACK *** - // Views could send us incorrect current event value (event outside the current window) - // Here we make sure the value is sane, otherwise, we force it as the left border of the window - if ( isGivenTimestampInSelectedWindow( currentTime ) == false ) { - currentTime = windowStart; - } - currentEventTime = currentTime; - - // Notify control that the window changed - windowChangedNotification(); - - // Make sure we redraw the change - fullExperimentCanvas.redraw(); - } - } - } - - - /* - * Create the canvas needed and issue the requests - * - * @param newExperiment Experiment we will use for the request - */ - private void createCanvasAndRequests(TmfExperiment newExperiment) { - // Save the experiment we are about to use - lastUsedExperiment = newExperiment; - -// // Create a copy of the trace that will be use only by the full experiment request -// TmfExperiment experimentCopy = newExperiment.createTraceCopy(); - - // Create the content for the full experiment. - // This NEED to be created first, as we use it in the selectedWindowCanvas - fullExperimentCanvas.createNewHistogramContent( - fullExperimentCanvas.getSize().x, - FULL_TRACE_BAR_WIDTH, -/* - // 2010-06-20 Yuriy: We will use the dynamic height. - FULL_TRACE_CANVAS_HEIGHT -*/ - fullExperimentCanvas.getSize().y / 2, - FULL_TRACE_DIFFERENCE_TO_AVERAGE - ); - - TmfTimeRange timeRange = getExperimentTimeRange(newExperiment); - - // We will take the half of the full experiment length in case of bigger window size than the full experiment length - if(timeRange.getEndTime().getValue() - timeRange.getStartTime().getValue() > DEFAULT_WINDOW_SIZE ) { - fullExperimentCanvas.createNewSelectedWindow( - timeRange.getStartTime().getValue(), - DEFAULT_WINDOW_SIZE - ); - } else { - fullExperimentCanvas.createNewSelectedWindow( - timeRange.getStartTime().getValue(), - (timeRange.getEndTime().getValue() - timeRange.getStartTime().getValue() ) / 2 - ); - } - - currentEventTime = timeRange.getStartTime().getValue(); - - // Set the window of the fullTrace canvas visible. - fullExperimentCanvas.getCurrentWindow().setSelectedWindowVisible(true); - fullExperimentCanvas.getHistogramContent().resetTable(timeRange.getStartTime().getValue(), timeRange.getEndTime().getValue()); - - // Create the content for the selected window. - selectedWindowCanvas.createNewHistogramContent( - selectedWindowCanvas.getSize().x, - SELECTED_WINDOW_BAR_WIDTH, - selectedWindowCanvas.getSize().y, - SELECTED_WINDOW_DIFFERENCE_TO_AVERAGE - ); - selectedWindowCanvas.getHistogramContent().resetTable(fullExperimentCanvas.getCurrentWindow().getTimestampOfLeftPosition(), fullExperimentCanvas.getCurrentWindow().getTimestampOfRightPosition()); - - // Make sure the UI object are sane - resetControlsContent(); - - // Redraw the canvas right away to have something "clean" as soon as we can - if ( dataBackgroundFullRequest != null ) { - fullExperimentCanvas.redraw(); - selectedWindowCanvas.redraw(); - } - // Nullify the (possible) old request to be sure we start we something clean - // Note : this is very important for the order of the request below, - // see "TODO" in performSelectedWindowEventsRequest - dataBackgroundFullRequest = null; - selectedWindowRequest = null; - - // Perform both request. - // Order is important here, the small/synchronous request for the selection window should go first - performSelectedWindowEventsRequest(newExperiment); - performAllTraceEventsRequest(newExperiment); + @SuppressWarnings("unchecked") + public void experimentSelected(TmfExperimentSelectedSignal signal) { + assert (signal != null); + fCurrentExperiment = (TmfExperiment) signal.getExperiment(); + loadExperiment(); } - // Before completing its indexing, the experiment doesn't know start/end time. - // However, LTTng individual traces have this knowledge so we should ask them - // directly. - private TmfTimeRange getExperimentTimeRange(TmfExperiment experiment) { - // Before completing its indexing, the experiment doesn't know start/end time. - // However, LTTng individual traces have this knowledge so we should ask them - // directly. - TmfTimestamp startTime = TmfTimestamp.BigCrunch; - TmfTimestamp endTime = TmfTimestamp.BigBang; - for (ITmfTrace trace : experiment.getTraces()) { - TmfTimestamp traceStartTime = trace.getStartTime(); - if (traceStartTime.compareTo(startTime, true) < 0) - startTime = traceStartTime; - TmfTimestamp traceEndTime = trace.getEndTime(); - if (traceEndTime.compareTo(endTime, true) > 0) - endTime = traceEndTime; - } - TmfTimeRange tmpRange = new TmfTimeRange(startTime, endTime); - return tmpRange; + private void loadExperiment() { + fExperimentStartTime = fCurrentExperiment.getStartTime().getValue(); + fExperimentEndTime = fCurrentExperiment.getEndTime().getValue(); + fCurrentTimestamp = fExperimentStartTime; + initializeHistograms(); + fParent.redraw(); } - /** - * Perform a new request for the Selection window.

- * This assume the full experiment canvas has correct information about the selected window; - * we need the fullExperimentCanvas' HistogramContent to be created and a selection window to be set. - * - * @param experiment The experiment we will select from - */ - public void performSelectedWindowEventsRequest(TmfExperiment experiment) { - - if(fullExperimentCanvas != null) { - HistogramSelectedWindow curSelectedWindow = fullExperimentCanvas.getCurrentWindow(); - - TmfTimeRange timeRange = getExperimentTimeRange(experiment); - - // If no selection window exists, we will try to create one; - // however this will most likely fail as the content is probably not created either - if ( curSelectedWindow == null ) { - // We will take the half of the full experiment length in case of bigger window size than the full experiment length - if(timeRange.getEndTime().getValue() - timeRange.getStartTime().getValue() > DEFAULT_WINDOW_SIZE ) { - fullExperimentCanvas.createNewSelectedWindow( - timeRange.getStartTime().getValue(), - DEFAULT_WINDOW_SIZE - ); - } else { - fullExperimentCanvas.createNewSelectedWindow( - timeRange.getStartTime().getValue(), - (timeRange.getEndTime().getValue() - timeRange.getStartTime().getValue() ) / 2 - ); - } - curSelectedWindow = fullExperimentCanvas.getCurrentWindow(); - } - - // The request will go from the Left timestamp of the window to the Right timestamp - // This assume that out-of-bound value are handled by the SelectionWindow itself - LttngTimestamp ts1 = new LttngTimestamp( curSelectedWindow.getTimestampOfLeftPosition() ); - LttngTimestamp ts2 = new LttngTimestamp( curSelectedWindow.getTimestampOfRightPosition() ); - TmfTimeRange tmpRange = new TmfTimeRange(ts1, ts2); - - // Set a (dynamic) time interval - long intervalTime = ( (ts2.getValue() - ts1.getValue()) / selectedWindowCanvas.getHistogramContent().getNbElement() ); - - selectedWindowRequest = performRequest(experiment, selectedWindowCanvas, tmpRange, intervalTime, ExecutionType.FOREGROUND); - selectedWindowCanvas.redrawAsynchronously(); - } - +// @TmfSignalHandler +// @SuppressWarnings("unchecked") +// public void experimentUpdated(TmfExperimentUpdatedSignal signal) { +// fCurrentExperiment = (TmfExperiment) signal.getExperiment(); +// fFullRangeHistogramCanvas.redraw(); +// fTimespanHistogramCanvas.redraw(); +// createCanvasAndRequests(); +// } + + @TmfSignalHandler + public void currentTimeUpdated(TmfTimeSynchSignal signal) { + // Because this can't happen :-) + assert (signal != null); + + // Update the selected event time + TmfTimestamp currentTime = signal.getCurrentTime(); + fCurrentTimestamp = currentTime.getValue(); + + // Notify the relevant widgets + fFullTraceHistogram.setCurrentEvent(fCurrentTimestamp); + fTimeRangeHistogram.setCurrentEvent(fCurrentTimestamp); + fCurrentEventTimeControl.setValue(fCurrentTimestamp); } - - /** - * Perform a new request for the full experiment.

- * NOTE : this is very long, we need to implement a way to run this in parallel (see TODO) - * - * @param experiment The experiment we will select from - */ - public void performAllTraceEventsRequest(TmfExperiment experiment) { - // Create a new time range from "start" to "end" - // That way, we will get "everything" in the trace -// LttngTimestamp ts1 = new LttngTimestamp( experiment.getStartTime() ); -// LttngTimestamp ts2 = new LttngTimestamp( experiment.getEndTime() ); -// TmfTimeRange tmpRange = new TmfTimeRange(ts1, ts2); - - TmfTimeRange tmpRange = getExperimentTimeRange(experiment); - TmfTimestamp startTime = tmpRange.getStartTime(); - TmfTimestamp endTime = tmpRange.getEndTime(); - - // Set a (dynamic) time interval - long intervalTime = ( (endTime.getValue() - startTime.getValue()) / fullExperimentCanvas.getHistogramContent().getNbElement() ); - - // *** VERIFY *** - // This would enable "fixed interval" instead of dynamic one. - // ... we don't need it, do we? - // - // long intervalTime = ((long)(0.001 * (double)1000000000)); - - // *** TODO *** - // It would be interesting if there was a way to tell the framework to run the request "in parallel" here. - // Mean a completetly independant copy of the Expereiment would be done and we would proceed on that. - // - dataBackgroundFullRequest = performRequest(experiment, fullExperimentCanvas, tmpRange, intervalTime, ExecutionType.BACKGROUND); - - - fullExperimentCanvas.getCurrentWindow().setWindowXPositionLeft(fullExperimentCanvas.getHistogramContent().getClosestXPositionFromTimestamp(fullExperimentCanvas.getCurrentWindow().getTimestampOfLeftPosition())); - fullExperimentCanvas.getCurrentWindow().setWindowXPositionCenter(fullExperimentCanvas.getHistogramContent().getClosestXPositionFromTimestamp(fullExperimentCanvas.getCurrentWindow().getTimestampOfCenterPosition())); - fullExperimentCanvas.getCurrentWindow().setWindowXPositionRight(fullExperimentCanvas.getHistogramContent().getClosestXPositionFromTimestamp(fullExperimentCanvas.getCurrentWindow().getTimestampOfRightPosition())); - fullExperimentCanvas.redrawAsynchronously(); + @TmfSignalHandler + public void timeRangeUpdated(TmfRangeSynchSignal signal) { + // Because this can't happen :-) + assert (signal != null); + + if (fCurrentExperiment != null) { + // Update the time range + fWindowStartTime = signal.getCurrentRange().getStartTime().getValue(); + fWindowEndTime = signal.getCurrentRange().getEndTime().getValue(); + fWindowSpan = fWindowEndTime - fWindowStartTime; + + // Notify the relevant widgets + sendTimeRangeRequest(fWindowStartTime, fWindowEndTime); + fFullTraceHistogram.setTimeRange(fWindowStartTime, fWindowSpan); + fTimeSpanControl.setValue(fWindowSpan); + } } - - // *** VERIFY *** - // This function is synchronized, is it a good idea? - // Tis is done to make sure requests arrive somewhat in order, - // this is especially important when request are issued from different thread. - /** - * Create a new request from the given data and send it to the framework.

- * The request will be queued and processed later. - * - * @param experiment The experiment we will process the request on - * @param targetCanvas The canvas that will received the result - * @param newRange The range of the request - * @param newInterval The interval of time we use to store the result into the HistogramContent - */ - private synchronized HistogramRequest performRequest(TmfExperiment experiment, HistogramCanvas targetCanvas, TmfTimeRange newRange, long newInterval, ITmfDataRequest.ExecutionType execType) { - HistogramRequest returnedRequest = null; - - // *** FIXME *** - // EVIL BUG! - // We use int.MAX_VALUE because we want every events BUT we don't know the number inside the range. - // HOWEVER, this would cause the request to run forever (or until it reach the end of trace). - // Seeting an EndTime does not seems to stop the request - returnedRequest = new HistogramRequest(newRange, Integer.MAX_VALUE, targetCanvas, newInterval, execType ); + + // ------------------------------------------------------------------------ + // Helper functions + // ------------------------------------------------------------------------ + + private void initializeHistograms() { + updateExperimentTimeRange(fCurrentExperiment); + fTimeRangeHistogram.setFullRange(fExperimentStartTime, fExperimentEndTime); + fTimeRangeHistogram.setTimeRange(fExperimentStartTime, INITIAL_WINDOW_SPAN); + fTimeRangeHistogram.setCurrentEvent(fExperimentStartTime); + + fFullTraceHistogram.setTimeRange(fExperimentStartTime, INITIAL_WINDOW_SPAN); + fFullTraceHistogram.setCurrentEvent(fExperimentStartTime); + + fWindowStartTime = fExperimentStartTime; + fWindowSpan = INITIAL_WINDOW_SPAN; + fWindowEndTime = fWindowStartTime + fWindowSpan; - // Send the request to the framework : it will be queued and processed later - experiment.sendRequest(returnedRequest); + fCurrentEventTimeControl.setValue(fExperimentStartTime); + fTimeSpanControl.setValue(fWindowSpan); - return returnedRequest; + sendTimeRangeRequest(fExperimentStartTime, fExperimentStartTime + fWindowSpan); + sendFullRangeRequest(); } - - /** - * Function used to warn that the selection window changed.

- * This might be called because the window moved or because its size changed.

- * - * We will update the different control related to the selection window. - */ - public void windowChangedNotification() { - - if ( lastUsedExperiment != null ) { - // If a request is ongoing, try to stop it - if (selectedWindowRequest != null && !selectedWindowRequest.isCompleted()) { - selectedWindowRequest.cancel(); - } - - if(fullExperimentCanvas != null) { - // If the current event time is outside the new window, change the current event - // The new current event will be the one closest to the LEFT side of the new window - if ( isGivenTimestampInSelectedWindow(currentEventTime) == false ) { - currentEventChangeNotification( fullExperimentCanvas.getCurrentWindow().getTimestampOfLeftPosition() ); - } - } - - // Perform a new request to read data about the new window - performSelectedWindowEventsRequest(lastUsedExperiment); - } - } - - /** - * Function used to tell that the current event changed.

- * This might be called because the user changed the current event or - * because the last current event is now outside the selection window.

- * - * We update the related control and send a signal to notify other views of the new current event. - * - * @param newCurrentEventTime - */ - public void currentEventChangeNotification(long newCurrentEventTime) { - - // Notify other views in the framework - if (currentEventTime != newCurrentEventTime) { - currentEventTime = newCurrentEventTime; - - if ( currentEventTime < fullExperimentCanvas.getHistogramContent().getStartTime() ) { - currentEventTime = fullExperimentCanvas.getHistogramContent().getStartTime(); - } - - if ( currentEventTime > fullExperimentCanvas.getHistogramContent().getEndTime() ) { - currentEventTime = fullExperimentCanvas.getHistogramContent().getEndTime(); - } - - // Update the UI control - updateSelectedEventTime(); + + private void sendTimeRangeRequest(long startTime, long endTime) { + if (fTimeRangeRequest != null && !fTimeRangeRequest.isCompleted()) { + fTimeRangeRequest.cancel(); } + TmfTimestamp startTS = new TmfTimestamp(startTime, TIME_SCALE); + TmfTimestamp endTS = new TmfTimestamp(endTime, TIME_SCALE); + TmfTimeRange timeRange = new TmfTimeRange(startTS, endTS); + + fTimeRangeHistogram.clear(); + fTimeRangeHistogram.setTimeRange(startTime, endTime - startTime); + fTimeRangeRequest = new HistogramRequest(fTimeRangeHistogram, timeRange, ExecutionType.FOREGROUND); + fCurrentExperiment.sendRequest(fTimeRangeRequest); } - - public void sendTmfTimeSynchSignalBroadcast() { - -// System.out.println("sendTmfTimeSynchSignalBroadcast " + System.currentTimeMillis()); - - // Send a signal to the framework - LttngTimestamp tmpTimestamp = new LttngTimestamp(currentEventTime); - broadcast(new TmfTimeSynchSignal(this, tmpTimestamp)); - } - - /** - * Function used to tell that the timerange (window) changed.

- * This will most likely be called if the time window is resized. - * - * We send a signal to notify other views of the new timerange. - */ - public void sendTmfRangeSynchSignalBroadcast() { - - if (TmfExperiment.getCurrentExperiment() == null) - return; - - long startTime = fullExperimentCanvas.getCurrentWindow().getTimestampOfLeftPosition(); - if ( startTime < fullExperimentCanvas.getHistogramContent().getStartTime() ) { - startTime = fullExperimentCanvas.getHistogramContent().getStartTime(); - } - LttngTimestamp tmpStartTime = new LttngTimestamp(startTime); - - long endTime = fullExperimentCanvas.getCurrentWindow().getTimestampOfRightPosition(); - if ( endTime > fullExperimentCanvas.getHistogramContent().getEndTime() ) { - endTime = fullExperimentCanvas.getHistogramContent().getEndTime(); - } - LttngTimestamp tmpEndTime = new LttngTimestamp(endTime); - - TmfTimeRange tmpTimeRange = new TmfTimeRange(tmpStartTime, tmpEndTime); - LttngTimestamp tmpEventTime = new LttngTimestamp(currentEventTime); - - // Send a signal to the framework - broadcast(new TmfRangeSynchSignal(this, tmpTimeRange, tmpEventTime)); + + private void sendFullRangeRequest() { + if (fFullTraceRequest != null && !fFullTraceRequest.isCompleted()) { + fFullTraceRequest.cancel(); + } + fFullTraceHistogram.clear(); + TmfTimeRange timeRange = updateExperimentTimeRange(fCurrentExperiment); + fFullTraceRequest = new HistogramRequest(fFullTraceHistogram, timeRange, ExecutionType.BACKGROUND); + fCurrentExperiment.sendRequest(fFullTraceRequest); } - - /** - * Function that will be called when one of the time text group value is changed.

- * Since we don't (and can't unless we subclass them) know which one, we check them all. - */ - public void timeTextGroupChangeNotification() { - - if(ntgCurrentEventTime != null) { - // If the user changed the current event time, call the notification - long newCurrentTime = ntgCurrentEventTime.getValue(); - if ( newCurrentTime != currentEventTime ) { - currentEventChangeNotification( newCurrentTime ); - // Send a broadcast to the framework about the window change - sendTmfTimeSynchSignalBroadcast(); - } - } - - if(ntgWindowCenterTime != null && fullExperimentCanvas != null) { - // If the user changed the selected window time, recenter the window and call the notification - long newSelectedWindowTime = ntgWindowCenterTime.getValue(); - if ( newSelectedWindowTime != fullExperimentCanvas.getCurrentWindow().getTimestampOfCenterPosition() ) { - fullExperimentCanvas.setWindowCenterPosition(newSelectedWindowTime); - // Send a broadcast to the framework about the window change - sendTmfRangeSynchSignalBroadcast(); - } - } - - if(ntgWindowTimeSpan != null && fullExperimentCanvas != null) { - // If the user changed the selected window size, resize the window and call the notification - long newSelectedWindowTimeRange = ntgWindowTimeSpan.getValue(); - if ( newSelectedWindowTimeRange != fullExperimentCanvas.getCurrentWindow().getWindowTimeWidth() ) { - fullExperimentCanvas.resizeWindowByAbsoluteTime(newSelectedWindowTimeRange); - // Send a broadcast to the framework about the window change - sendTmfRangeSynchSignalBroadcast(); - } - } - + + private TmfTimeRange updateExperimentTimeRange(TmfExperiment experiment) { + TmfTimestamp startTime = TmfTimestamp.BigCrunch; + TmfTimestamp endTime = TmfTimestamp.BigBang; + for (ITmfTrace trace : experiment.getTraces()) { + TmfTimestamp traceStartTime = trace.getStartTime(); + if (traceStartTime.compareTo(startTime, true) < 0) + startTime = traceStartTime; + TmfTimestamp traceEndTime = trace.getEndTime(); + if (traceEndTime.compareTo(endTime, true) > 0) + endTime = traceEndTime; + } + fExperimentStartTime = startTime.getValue(); + fExperimentEndTime = endTime.getValue(); + + return new TmfTimeRange(startTime, endTime); } - - /** - * Getter for the last used experiment.

- * This might be different than the current experiment or even null. - * - * @return the last experiment we used in this view - */ - public TmfExperiment getLastUsedExperiment() { - return lastUsedExperiment; - } - - /** - * Check if a given timestamp is inside the selection window.

- * This assume fullExperimentCanvas contain a valid HistogramContent - * - * @param timestamp the timestamp to check - * - * @return if the time is inside the selection window or not - */ - public boolean isGivenTimestampInSelectedWindow(long timestamp) { - boolean returnedValue = true; - - // If the content is not set correctly, this will return weird (or even null) result - if ( (timestamp < fullExperimentCanvas.getCurrentWindow().getTimestampOfLeftPosition() ) || - (timestamp > fullExperimentCanvas.getCurrentWindow().getTimestampOfRightPosition() ) ) - { - returnedValue = false; - } - - return returnedValue; - } - - /** - * Reset the content of all Controls.

- * WARNING : Calls in there are not thread safe and can't be called from different thread than "main" - */ - public void resetControlsContent() { - - TmfExperiment tmpExperiment = getLastUsedExperiment(); - - // Use the previous Start and End time, or default if they are not available - String startTime = null; - String stopTime = null; - if ( tmpExperiment != null ) { - startTime = HistogramConstant.formatNanoSecondsTime( tmpExperiment.getStartTime().getValue() ); - stopTime = HistogramConstant.formatNanoSecondsTime( tmpExperiment.getEndTime().getValue() ); - } - else { - startTime = HistogramConstant.formatNanoSecondsTime( 0L ); - stopTime = HistogramConstant.formatNanoSecondsTime( 0L ); - } - - txtExperimentStartTime.setText( startTime ); - txtExperimentStopTime.setText( stopTime ); - txtExperimentStartTime.getParent().layout(); - - txtWindowMaxNbEvents.setText("" + 0); //$NON-NLS-1$ - txtWindowMinNbEvents.setText("" + 0); //$NON-NLS-1$ - txtWindowStartTime.setText( HistogramConstant.formatNanoSecondsTime( 0L ) ); - txtWindowStopTime.setText( HistogramConstant.formatNanoSecondsTime( 0L ) ); - txtWindowStartTime.getParent().layout(); - - ntgWindowCenterTime.setValue( HistogramConstant.formatNanoSecondsTime( 0L ) ); - ntgWindowTimeSpan.setValue( HistogramConstant.formatNanoSecondsTime( 0L ) ); - - // Using "startTime" here can avoid an useless TmfTimeSynchSignal here - // However it look ugly to have only this time - ntgCurrentEventTime.setValue( HistogramConstant.formatNanoSecondsTime( 0L ) ); - } - - /** - * Update the content of the controls related to the full experiment canvas

- * WARNING : Calls in there are not thread safe and can't be called from different thread than "main" - */ - public void updateFullExperimentInformation() { - - if(fullExperimentCanvas != null) { - String startTime = HistogramConstant.formatNanoSecondsTime( fullExperimentCanvas.getHistogramContent().getStartTime() ); - String stopTime = HistogramConstant.formatNanoSecondsTime( fullExperimentCanvas.getHistogramContent().getEndTime() ); - - txtExperimentStartTime.setText( startTime ); - txtExperimentStopTime.setText( stopTime ); - } - - // Take one of the parent and call its layout to update control size - // Since both control have the same parent, only one call is needed - txtExperimentStartTime.getParent().layout(); - - // Update the selected window, just in case - // This should give a better user experience and it is low cost - updateSelectedWindowInformation(); - } - - /** - * Update the content of the controls related to the selection window canvas

- * WARNING : Calls in there are not thread safe and can't be called from different thread than "main" - */ - public void updateSelectedWindowInformation() { - // Update the timestamp as well - updateSelectedWindowTimestamp(); - - if(selectedWindowCanvas != null) { - txtWindowMaxNbEvents.setText( Long.toString(selectedWindowCanvas.getHistogramContent().getHeighestEventCount()) ); - txtWindowMinNbEvents.setText(Long.toString(0)); - } - - // Refresh the layout - txtWindowMaxNbEvents.getParent().layout(); - } - - /** - * Update the content of the controls related to the timestamp of the selection window

- * WARNING : Calls in there are not thread safe and can't be called from different thread than "main" - */ - public void updateSelectedWindowTimestamp() { - - if(selectedWindowCanvas != null) { - String startTime = HistogramConstant.formatNanoSecondsTime( selectedWindowCanvas.getHistogramContent().getStartTime() ); - String stopTime = HistogramConstant.formatNanoSecondsTime( selectedWindowCanvas.getHistogramContent().getEndTime() ); - txtWindowStartTime.setText( startTime ); - txtWindowStopTime.setText( stopTime ); - } - - if(fullExperimentCanvas != null) { - ntgWindowCenterTime.setValue( fullExperimentCanvas.getCurrentWindow().getTimestampOfCenterPosition() ); - ntgWindowTimeSpan.setValue( fullExperimentCanvas.getCurrentWindow().getWindowTimeWidth() ); - - // If the current event time is outside the selection window, recenter our window - if ( isGivenTimestampInSelectedWindow(ntgCurrentEventTime.getValue()) == false ) { - currentEventChangeNotification( fullExperimentCanvas.getCurrentWindow().getTimestampOfCenterPosition() ); - } - } - - // Take one control in each group to call to refresh the layout - // Since both control have the same parent, only one call is needed - txtWindowStartTime.getParent().layout(); - ntgWindowCenterTime.getParent().layout(); - } - - /** - * Update the controls related current event.

- * The call here SHOULD be thread safe and can be call from any threads. - */ - public void updateSelectedEventTime() { - ntgCurrentEventTime.setValueAsynchronously(currentEventTime); -// sendTmfTimeSynchSignalBroadcast(); - // Tell the selection canvas which event is currently selected - // This give a nice graphic output - selectedWindowCanvas.getHistogramContent().setSelectedEventTimeInWindow(currentEventTime); - selectedWindowCanvas.redrawAsynchronously(); - } - - /** - * Method called when the view is moved.

- * - * Just redraw everything... - * - * @param event The control event generated by the move. - */ - @Override - public void controlMoved(ControlEvent event) { - parent.redraw(); - } - - /** - * Method called when the view is resized.

- * - * We will make sure that the size didn't change more than the content size.

- * Otherwise we need to perform a new request for the full experiment because we are missing data). - * - * @param event The control event generated by the resize. - */ - @Override - public void controlResized(ControlEvent event) { - - // Ouch! The screen enlarged (screen resolution changed?) so far that we miss content to fill the space. - if ( parent.getDisplay().getBounds().width > fullExperimentCanvas.getHistogramContent().getNbElement() ) { - if ( lastUsedExperiment != null ) { - createCanvasAndRequests(lastUsedExperiment); - } - } - - } - - /* - * Getter of FullExperimentCanvas - * - * @return FullExperimentCanvas object - */ - public static ParentHistogramCanvas getFullExperimentCanvas() { - return fullExperimentCanvas; - } - - /* - * Getter of SelectedWindowCanvas - * - * @return SelectedWindowCanvas object - */ - public static ChildrenHistogramCanvas getSelectedWindowCanvas() { - return selectedWindowCanvas; - } - - - /* - * Getter of DEFAULT_WINDOW_SIZE - * - * @return DEFAULT_WINDOW_SIZE value - */ - public static long getDEFAULT_WINDOW_SIZE() { - return DEFAULT_WINDOW_SIZE; - } - - /** - * Getter for dataBackgroundFullRequest variable - * @return the dataBackgroundFullRequest instance - */ - public HistogramRequest getDataBackgroundFullRequest() { - return dataBackgroundFullRequest; - } - - /** - * Getter for selectedWindowRequest variable - * @return the selectedWindowRequest instance - */ - public HistogramRequest getSelectedWindowRequest() { - return selectedWindowRequest; - } } diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramZoom.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramZoom.java new file mode 100644 index 0000000000..437fb160bf --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramZoom.java @@ -0,0 +1,222 @@ +/******************************************************************************* + * Copyright (c) 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Francois Chouinard - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.linuxtools.lttng.ui.views.histogram; + +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseWheelListener; +import org.eclipse.swt.widgets.Canvas; + +/** + * HistogramZoom + *

+ * TODO: Document me... + */ +public class HistogramZoom implements MouseWheelListener { + + // ------------------------------------------------------------------------ + // Constants + // ------------------------------------------------------------------------ + + private final static double ZOOM_FACTOR = 0.8; + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + + private final Histogram fHistogram; + private final Canvas fCanvas; + + private long fAbsoluteStartTime; + private long fAbsoluteEndTime; + private final long fMinWindowSize; + + private long fRangeStartTime; + private long fRangeDuration; + + private MouseScrollCounter fScrollCounter; + + // ------------------------------------------------------------------------ + // Construction + // ------------------------------------------------------------------------ + + public HistogramZoom(Histogram histogram, Canvas canvas, long start, long end) { + fHistogram = histogram; + fCanvas = canvas; + fAbsoluteStartTime = start; + fAbsoluteEndTime = end; + fMinWindowSize = fCanvas.getBounds().x; + + fRangeStartTime = fAbsoluteStartTime; + fRangeDuration = fAbsoluteStartTime + fMinWindowSize; + + canvas.addMouseWheelListener(this); + } + + // ------------------------------------------------------------------------ + // Accessors + // ------------------------------------------------------------------------ + + public long getStartTime() { + return fRangeStartTime; + } + + public long getEndTime() { + return fRangeStartTime + fRangeDuration; + } + + public long getDuration() { + return fRangeDuration; + } + + // ------------------------------------------------------------------------ + // Operations + // ------------------------------------------------------------------------ + + public synchronized void stop() { + if (fScrollCounter != null) { + fScrollCounter.interrupt(); + fScrollCounter = null; + } + } + + public void setFullRange(long startTime, long endTime) { + fAbsoluteStartTime = startTime; + fAbsoluteEndTime = endTime; + } + + public void setNewRange(long startTime, long duration) { + if (startTime < fAbsoluteStartTime) + startTime = fAbsoluteStartTime; + + long endTime = startTime + duration; + if (endTime > fAbsoluteEndTime) { + endTime = fAbsoluteEndTime; + if (endTime - duration > fAbsoluteStartTime) + startTime = endTime - duration; + else { + startTime = fAbsoluteStartTime; + } + } + + fRangeStartTime = startTime; + fRangeDuration = endTime - startTime; + } + + // ------------------------------------------------------------------------ + // MouseWheelListener + // ------------------------------------------------------------------------ + + private long fMouseTimestamp = 0; + + @Override + public synchronized void mouseScrolled(MouseEvent event) { + if (fScrollCounter == null) { + fScrollCounter = new MouseScrollCounter(this); + fScrollCounter.start(); + fMouseTimestamp = fHistogram.getTimestamp(event.x); + } + fScrollCounter.incrementMouseScroll(event.count); + } + + private synchronized void zoom(int nbClicks) { + // The job is finished + fScrollCounter = null; + + // Compute the new time range + long requestedRange = (nbClicks > 0) ? Math.round(ZOOM_FACTOR * fRangeDuration) : (long) Math.ceil(fRangeDuration * (1.0 / ZOOM_FACTOR)); + + // Perform a proportional zoom wrt the mouse position + double ratio = ((double) (fMouseTimestamp - fRangeStartTime)) / fRangeDuration; + long requestedStart = validateStart(fRangeStartTime + (long) ((fRangeDuration - requestedRange) * ratio)); + long requestedEnd = validateEnd(requestedStart, requestedStart + requestedRange); + requestedStart = validateStart(requestedEnd - requestedRange); + + fHistogram.updateTimeRange(requestedStart, requestedEnd); + } + + private long validateStart(long start) { + if (start < fAbsoluteStartTime) + start = fAbsoluteStartTime; + if (start > fAbsoluteEndTime) + start = fAbsoluteEndTime - fMinWindowSize; + return start; + } + + private long validateEnd(long start, long end) { + if (end > fAbsoluteEndTime) + end = fAbsoluteEndTime; + if (end < start + fMinWindowSize) + end = start + fMinWindowSize; + return end; + } + + // ------------------------------------------------------------------------ + // DelayedMouseScroll + // ------------------------------------------------------------------------ + + private class MouseScrollCounter extends Thread { + + // -------------------------------------------------------------------- + // Constants + // -------------------------------------------------------------------- + + private final static long QUIET_TIME = 100L; + private final static long POLLING_INTERVAL = 10L; + + // -------------------------------------------------------------------- + // Attributes + // -------------------------------------------------------------------- + + private HistogramZoom fZoom = null; + + private long fLastPoolTime = 0L; + private int nbScrollClick = 0; + + // -------------------------------------------------------------------- + // Construction + // -------------------------------------------------------------------- + + public MouseScrollCounter(HistogramZoom zoom) { + fZoom = zoom; + fLastPoolTime = System.currentTimeMillis(); + } + + // -------------------------------------------------------------------- + // Operation + // -------------------------------------------------------------------- + + public void incrementMouseScroll(int nbScrolls) { + fLastPoolTime = System.currentTimeMillis(); + nbScrollClick += nbScrolls; + } + + // -------------------------------------------------------------------- + // Thread + // -------------------------------------------------------------------- + + @Override + public void run() { + while ((System.currentTimeMillis() - fLastPoolTime) < QUIET_TIME) { + try { + Thread.sleep(POLLING_INTERVAL); + } catch (Exception e) { + return; + } + } + // Done waiting. Notify the histogram. + if (!isInterrupted()) + fZoom.zoom(nbScrollClick); + } + } + +} diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/Messages.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/Messages.java index 595b21f31c..719ef6299a 100644 --- a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/Messages.java +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/Messages.java @@ -1,17 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2009, 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * William Bourque - Initial API and implementation + * Francois Chouinard - Cleanup and refactoring + *******************************************************************************/ + package org.eclipse.linuxtools.lttng.ui.views.histogram; import org.eclipse.osgi.util.NLS; +/** + * Messages + *

+ */ public class Messages extends NLS { + + // ------------------------------------------------------------------------ + // Constants + // ------------------------------------------------------------------------ + private static final String BUNDLE_NAME = "org.eclipse.linuxtools.lttng.ui.views.histogram.messages"; //$NON-NLS-1$ + public static String HistogramView_currentEventLabel; - public static String HistogramView_windowCenterLabel; - public static String HistogramView_windowSpanLabel; - static { - // initialize resource bundle - NLS.initializeMessages(BUNDLE_NAME, Messages.class); - } - - private Messages() { - } + public static String HistogramView_windowSpanLabel; + + // ------------------------------------------------------------------------ + // Initializer + // ------------------------------------------------------------------------ + + static { + // initialize resource bundle + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + // ------------------------------------------------------------------------ + // Constructor + // ------------------------------------------------------------------------ + + private Messages() { + } + } diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/ParentHistogramCanvas.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/ParentHistogramCanvas.java deleted file mode 100644 index fb1246ae3f..0000000000 --- a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/ParentHistogramCanvas.java +++ /dev/null @@ -1,485 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009 Ericsson - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v1.0 which - * accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * William Bourque - Initial API and implementation - * - * Modifications: - * 2010-06-20 Yuriy Vashchuk - Histogram optimisations. - * 2010-07-16 Yuriy Vashchuk - Base Histogram class simplification. - * Selection Window related methods has been - * implemented here (Parent Histogram). - *******************************************************************************/ -package org.eclipse.linuxtools.lttng.ui.views.histogram; - -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Display; - -/** - * ParentHistogramCanvas - *

- * Extended implementation of the HistogramCanvas. - *

- * This canvas goal is to display the "Full experiment" histogram. - */ -public class ParentHistogramCanvas extends HistogramCanvas { - - private ParentHistogramCanvasPaintListener paintListener = null; - private HistogramCanvasMouseListener mouseListener = null; - private HistogramCanvasKeyListener keyListener = null; - private ParentHistogramCanvasControlListener controlListener = null; - - private HistogramSelectedWindow currentWindow = null; - - /** - * ParentHistogramCanvas constructor.

- * Same as HistogramCanvas, but receive a parent HistogramView that we can call from here. - * - * @param parent Composite control which will be the parent of the new instance (cannot be null) - * @param Style the style of control to construct - */ - public ParentHistogramCanvas(HistogramView histogramView, Composite parent, int style) { - super(histogramView, parent, style); - - // New selected window, not visible by default - if (histogramView !=null && HistogramView.getFullExperimentCanvas() != null) { - createNewSelectedWindow( - HistogramView.getFullExperimentCanvas().getHistogramContent().getStartTime() + HistogramView.getDEFAULT_WINDOW_SIZE() / 2, - HistogramView.getDEFAULT_WINDOW_SIZE() - ); - } - - // 2010-06-20 Yuriy: Moved from parent class - createAndAddPaintListener(); - createAndAddMouseListener(); - createAndAddKeyListener(); - createAndAddControlListener(); - } - - /** - * Create a new HistogramContent for this HistogramCanvas

- * A new empty canvas will then be created. - * - * IMPORTANT NOTE : This implementaton use the next power of 2 to the full screen resolution as the content size. - * This allow us to resize the canvas at low cost (i.e. : no need to reissue a full request) - * We need a "particular" paint listener that know about this. - * - * @param canvasSize Size of the parent canvas. - * @param widthPerBar Width of the histogram "bars" - * @param barsHeight Height of the histogram "bars" - * @param maxBarsDifferenceToAverage Factor used to "chop" bars that are too tall. Set to something big (100.0?) if not needed. - */ - @Override - public void createNewHistogramContent(int canvasSize, int widthPerBar, int barsHeight, double maxBarsDifferenceToAverage) { - - // *** FIXME *** - // Note there MIGHT be some unhandled case, like if the resolution of the screen change - // or if a new screen is plugged. - // Let's ignore them for now. - // - // The maximum size the canvas could ever had - int canvasMaxSize = getParent().getDisplay().getBounds().width; - - // Calculate the power of two superior to the max size - int exp = (int)Math.ceil( Math.log( (double)canvasMaxSize ) / Math.log(2.0) ); - int contentSize = (int)Math.pow(2, exp); - - // Create the content - histogramContent = new HistogramContent( contentSize, canvasSize, widthPerBar, barsHeight, maxBarsDifferenceToAverage); - - // We need to ajust the "maxDifferenceToAverageFactor" as the bars we draw might be slitghly larger than the value asked - // Each "interval" are concatenated when draw so the worst case should be : - // contentSize / (closest power of 2 to canvasMaxSize) - // Ex : if canvasSize is 1500 -> (2048 / 1024) == 2 so maxDiff should be twice larger - // - // Note : this is not perfect, if the screen is resized after we calculate this, the resulting output can be quite ugly - // For this reason, this will be recalculated in the paintListener as well. - double maxBarsDiffFactor = ((double)contentSize / Math.pow(2, exp-1)); - histogramContent.setMaxDifferenceToAverageFactor(maxBarsDiffFactor); - } - - - /* - * Create a histogram paint listener and bind it to this canvas.

- * - * Note : This one is a bit particular, as it is made to draw content that is of a power of 2. - * The default one draw content that is relative to the real pixels size. - */ - private void createAndAddPaintListener() { - paintListener = new ParentHistogramCanvasPaintListener(this); - this.addPaintListener( paintListener ); - } - - /* - * Create a histogram mouse listener and bind it to this canvas.

- * Note : this mouse listener handle the mouse, the move and the wheel at once. - * - * @see org.eclipse.linuxtools.lttng.ui.views.histogram.HistogramCanvasMouseListener - */ - private void createAndAddMouseListener() { - mouseListener = new HistogramCanvasMouseListener(this); - this.addMouseListener(mouseListener); - this.addMouseMoveListener(mouseListener); - this.addMouseWheelListener(mouseListener); - } - - /* - * Create a histogram key listener and bind it to this canvas.

- * - * @see org.eclipse.linuxtools.lttng.ui.views.histogram.HistogramCanvasKeyListener - */ - private void createAndAddKeyListener() { - keyListener = new HistogramCanvasKeyListener(this); - this.addKeyListener(keyListener); - } - - /* - * Create a histogram control listener and bind it to this canvas.

- * - * @see org.eclipse.linuxtools.lttng.ui.views.histogram.HistogramCanvasControlListener - */ - private void createAndAddControlListener() { - controlListener = new ParentHistogramCanvasControlListener(this); - this.addControlListener(controlListener); - } - - /** - * Create a new selection window of the size (time width) given.

- * The window initial position is at X = 0. - * The window is created hidden, it won't be draw unless it is set to visible.

- * - * @param windowTimeDuration Time width (in nanosecond) of the window. - */ - public void createNewSelectedWindow(long timestampOfLeftPosition, long windowTimeDuration) { - currentWindow = new HistogramSelectedWindow(histogramContent, timestampOfLeftPosition, windowTimeDuration); - } - - /** - * Getter for the selection window

- * - * @return the current selection window - * - * @see org.eclipse.linuxtools.lttng.ui.views.histogram.HistogramSelectedWindow - */ - public HistogramSelectedWindow getCurrentWindow() { - return currentWindow; - } - - /** - * Getter for the selection window width

- * - * @return Time width (in nanosecond) of the selection window. - */ - public long getSelectedWindowSize() { - return currentWindow.getWindowTimeWidth(); - } - - /** - * Setter for the selection window width

- * The window size will be ajusted if it does not respect one of these constraints : - * - The window size cannot be smaller than a single histogram content interval.

- * - The window size cannot be larger than twice the histogram content complete time interval.

- * - * @param newSelectedWindowSize New time width (in nanosecond) of the selection window. - */ - public void setSelectedWindowSize(long newSelectedWindowSize) { - - if ( newSelectedWindowSize <= 0 ) { - newSelectedWindowSize = 1L; - } - else if ( newSelectedWindowSize > (2*histogramContent.getCompleteTimeInterval()) ) { - newSelectedWindowSize = (2*histogramContent.getCompleteTimeInterval()); - } - - currentWindow.setWindowTimeWidth(newSelectedWindowSize); - } - - /** - * Function that is called when the selection window is moved.

- * Note: Given position should be relative to the previous (centered) absolute position.

- * - * Calculate the new position then re-center the window.

- * It will also notify the HistogramView that the window changed. - * - * @param newRelativeXPosition New position relative to the last known absolute position. - */ - public void moveWindow(int newRelativeXPosition) { - int absolutePosition = currentWindow.getWindowXPositionCenter() + newRelativeXPosition; - - setWindowCenterPosition(absolutePosition); - notifyParentSelectionWindowChangedAsynchronously(); - } - - /** - * Function that is called when the selection window is re-centered.

- * Note: Given position should be absolute to the window and need to be the selection window center.

- * - * Recenter the window and notify the HistogramView that the window changed. - * - * @param newRelativeXPosition New absolute position. - */ - public void setWindowCenterPosition(int newAbsoluteXPosition) { - - // We will check if the coordinate the same - if ( newAbsoluteXPosition != currentWindow.getWindowXPositionCenter() ) { - - long timestampOfLeftPosition = this.getHistogramContent().getClosestElementFromXPosition( newAbsoluteXPosition ).firstIntervalTimestamp - currentWindow.getWindowTimeWidth() / 2; - long timestampOfCenterPosition = 0; - long timestampOfRightPosition = 0; - - // Let's do the border verifications - if ( timestampOfLeftPosition < histogramContent.getStartTime() ) { - - timestampOfLeftPosition = histogramContent.getStartTime(); - timestampOfCenterPosition = timestampOfLeftPosition + currentWindow.getWindowTimeWidth() / 2; - timestampOfRightPosition = timestampOfLeftPosition + currentWindow.getWindowTimeWidth(); - - } else { - - timestampOfRightPosition = this.getHistogramContent().getClosestElementFromXPosition( newAbsoluteXPosition ).firstIntervalTimestamp + currentWindow.getWindowTimeWidth() / 2; - - if ( timestampOfRightPosition > histogramContent.getEndTime() ) { - - timestampOfRightPosition = histogramContent.getEndTime(); - timestampOfCenterPosition = timestampOfRightPosition - currentWindow.getWindowTimeWidth() / 2; - timestampOfLeftPosition = timestampOfRightPosition - currentWindow.getWindowTimeWidth(); - - } else { - - timestampOfCenterPosition = this.getHistogramContent().getClosestElementFromXPosition( newAbsoluteXPosition ).firstIntervalTimestamp; - - } - - } - - // We will do the update in case of different center timestamp - if( timestampOfCenterPosition != currentWindow.getTimestampOfCenterPosition() ) { - // Firstly we will setup new left, right and center timestamps - currentWindow.setTimestampOfLeftPosition( timestampOfLeftPosition ); - currentWindow.setTimestampOfCenterPosition( timestampOfCenterPosition ); - currentWindow.setTimestampOfRightPosition( timestampOfRightPosition ); - - // After we will update coordonates using timestamps already recalculated - currentWindow.setWindowXPositionLeft( histogramContent.getClosestXPositionFromTimestamp(timestampOfLeftPosition) ); - currentWindow.setWindowXPositionCenter( histogramContent.getClosestXPositionFromTimestamp(timestampOfCenterPosition) ); - currentWindow.setWindowXPositionRight( histogramContent.getClosestXPositionFromTimestamp(timestampOfRightPosition) ); - - redrawAsynchronously(); - } - } - } - - /** - * Function that is called when the selection window is re-centered.

- * Note: Given position should be timestamp in the experiment timerange

- * - * Recenter the window and notify the HistogramView that the window changed. - * - * @param timestampOfCenterPosition New timestamp of center position. - */ - public void setWindowCenterPosition(long timestampOfCenterPosition) { - - // We will check if the coordinate the same - if ( timestampOfCenterPosition != currentWindow.getTimestampOfCenterPosition() ) { - - long timestampOfLeft = timestampOfCenterPosition - currentWindow.getWindowTimeWidth() / 2; - long timestampOfCenter = 0; - long timestampOfRight = 0; - - int windowXPositionLeft = histogramContent.getClosestXPositionFromTimestamp(timestampOfLeft); - int windowXPositionCenter = 0; - int windowXPositionRight = 0; - - // Let's do the border verifications - if ( timestampOfLeft < histogramContent.getStartTime() ) { - - timestampOfLeft = histogramContent.getStartTime(); - timestampOfCenter = timestampOfLeft + currentWindow.getWindowTimeWidth() / 2; - timestampOfRight = timestampOfLeft + currentWindow.getWindowTimeWidth(); - - windowXPositionLeft = histogramContent.getClosestXPositionFromTimestamp(timestampOfLeft); - windowXPositionCenter = histogramContent.getClosestXPositionFromTimestamp(timestampOfCenter); - windowXPositionRight = histogramContent.getClosestXPositionFromTimestamp(timestampOfRight); - - } else { - - timestampOfRight = timestampOfCenterPosition + currentWindow.getWindowTimeWidth() / 2; - windowXPositionRight = histogramContent.getClosestXPositionFromTimestamp(timestampOfRight); - - if ( timestampOfRight > histogramContent.getEndTime() ) { - - timestampOfRight = histogramContent.getEndTime(); - timestampOfCenter = timestampOfRight - currentWindow.getWindowTimeWidth() / 2; - timestampOfLeft = timestampOfRight - currentWindow.getWindowTimeWidth(); - - windowXPositionLeft = histogramContent.getClosestXPositionFromTimestamp(timestampOfLeft); - windowXPositionCenter = histogramContent.getClosestXPositionFromTimestamp(timestampOfCenter); - windowXPositionRight = histogramContent.getClosestXPositionFromTimestamp(timestampOfRight); - - } else { - - timestampOfCenter = timestampOfCenterPosition; - windowXPositionCenter = histogramContent.getClosestXPositionFromTimestamp(timestampOfCenter); - - } - - } - - // Firstly we will setup new left, right and center timestamps - currentWindow.setTimestampOfLeftPosition( timestampOfLeft ); - currentWindow.setTimestampOfCenterPosition( timestampOfCenter ); - currentWindow.setTimestampOfRightPosition( timestampOfRight ); - - // We will do the update in case of different center timestamp - if( windowXPositionCenter != currentWindow.getWindowXPositionCenter() ) { - - // After we will update coordonates using timestamps already recalculated - currentWindow.setWindowXPositionLeft(windowXPositionLeft); - currentWindow.setWindowXPositionCenter(windowXPositionCenter); - currentWindow.setWindowXPositionRight(windowXPositionRight); - - redrawAsynchronously(); - } - } - } - - - /** - * Function that is called when the selection window size (time width) changed by an absolute time.

- * Note: Given time should be in nanoseconds, positive. - * - * Set the new window size and notify the HistogramView that the window changed. - * - * @param newTime New absoulte time (in nanoseconds) to apply to the window. - */ - public void resizeWindowByAbsoluteTime(long newTime) { - if ( newTime != getSelectedWindowSize() ) { - - resizeWindowByAbsoluteTimeWithoutNotification(newTime); - - notifyParentSelectionWindowChangedAsynchronously(); - } - } - - /** - * Function that is called when the selection window size (time width) changed by an absolute time.

- * Note: Given time should be in nanoseconds, positive. - * - * Set the new window size and notify the HistogramView that the window changed. - * - * @param newTime New absoulte time (in nanoseconds) to apply to the window. - */ - public void resizeWindowByAbsoluteTimeWithoutNotification(long newTime) { - - // We will change the size in case of delta (newTime) != 0 - if (newTime != 0 ) { - - if(newTime > getHistogramContent().getEndTime() - getHistogramContent().getStartTime()) { - newTime = getHistogramContent().getEndTime() - getHistogramContent().getStartTime(); - } - - setSelectedWindowSize(newTime); - - /* - // Yuriy: we can't use this function because we change the left and right coordinates. - setWindowCenterPosition(currentWindow.getWindowXPositionCenter()); - */ - - long timestampOfLeftPosition = currentWindow.getTimestampOfCenterPosition() - currentWindow.getWindowTimeWidth() / 2; - long timestampOfCenterPosition = currentWindow.getTimestampOfCenterPosition(); - long timestampOfRightPosition = 0; - - // Let's do the border verifications - if ( timestampOfLeftPosition < histogramContent.getStartTime() ) { - - timestampOfLeftPosition = histogramContent.getStartTime(); - timestampOfCenterPosition = timestampOfLeftPosition + currentWindow.getWindowTimeWidth() / 2; - timestampOfRightPosition = timestampOfLeftPosition + currentWindow.getWindowTimeWidth(); - - } else { - - timestampOfRightPosition = currentWindow.getTimestampOfCenterPosition() + currentWindow.getWindowTimeWidth() / 2; - - if ( timestampOfRightPosition > histogramContent.getEndTime() ) { - - timestampOfRightPosition = histogramContent.getEndTime(); - timestampOfCenterPosition = timestampOfRightPosition - currentWindow.getWindowTimeWidth() / 2; - timestampOfLeftPosition = timestampOfRightPosition - currentWindow.getWindowTimeWidth(); - - } - - } - - // Firstly we will setup new left, right and center timestamps - currentWindow.setTimestampOfLeftPosition( timestampOfLeftPosition ); - currentWindow.setTimestampOfCenterPosition( timestampOfCenterPosition ); - currentWindow.setTimestampOfRightPosition( timestampOfRightPosition ); - - // After we will update coordonates using timestamps already recalculated - currentWindow.setWindowXPositionLeft( histogramContent.getClosestXPositionFromTimestamp(timestampOfLeftPosition) ); - currentWindow.setWindowXPositionCenter( histogramContent.getClosestXPositionFromTimestamp(timestampOfCenterPosition) ); - currentWindow.setWindowXPositionRight( histogramContent.getClosestXPositionFromTimestamp(timestampOfRightPosition) ); - - redrawAsynchronously(); - } - } - - /** - * Notify the parent HistogramView that we have updated information.

- * This is intended to be called at the end of the request when we know we have up-to-date information. - */ - @Override - public void notifyParentUpdatedInformation() { - getHistogramView().updateFullExperimentInformation(); - } - - /** - * Notify the parent HistogramView that the SelectionWindow changed.

- * This is intended to be called when the window move or is resized. - */ - public void notifyParentSelectionWindowChanged() { - // Notify the parent view that something changed - getHistogramView().windowChangedNotification(); - // Send a broadcast to the framework about the window change - getHistogramView().sendTmfRangeSynchSignalBroadcast(); - } - - /** - * Method to call the "Asynchronous NotifyParentSelectionWindowChanged" for this canvas

- * This allow safe update UI objects from different threads. - * - */ - public void notifyParentSelectionWindowChangedAsynchronously() { - // Create a new redrawer in case it doesn't exist yet (we never know with thread!) - if ( canvasRedrawer == null ) { - canvasRedrawer = new AsyncCanvasRedrawer(this); - } - - asynchronousNotifyParentSelectionWindowChanged(); - } - - /** - * Function to asynchonously notify the parent of the related canvas that the window changed.

- * - * Basically, it just run "notifyParentSelectionWindowChanged()" in asyncExec. - * - */ - public void asynchronousNotifyParentSelectionWindowChanged() { - // Ignore update if widget is disposed - if (this.isDisposed()) return; - - Display display = this.getDisplay(); - display.asyncExec(new Runnable() { - @Override - public void run() { - if(!ParentHistogramCanvas.this.isDisposed()) - notifyParentSelectionWindowChanged(); - } - }); - } -} diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/ParentHistogramCanvasControlListener.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/ParentHistogramCanvasControlListener.java deleted file mode 100644 index ba5e4c6f56..0000000000 --- a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/ParentHistogramCanvasControlListener.java +++ /dev/null @@ -1,67 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009, 2010 Ericsson - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v1.0 which - * accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * 2010-06-20 Yuriy Vashchuk - Initial API and implementation - * - * Modifications: - * 2010-07-16 Yuriy Vashchuk - Base class simplification. - *******************************************************************************/ - -package org.eclipse.linuxtools.lttng.ui.views.histogram; - -import org.eclipse.swt.events.ControlEvent; - -/** - * ParentHistogramCanvasControlListener - *

- * Implementation of a ControlListener for the need of the ParentHistogramCanvas - *

- */ -public class ParentHistogramCanvasControlListener extends HistogramCanvasControlListener { - - private ParentHistogramCanvas ourCanvas = null; - - /** - * ParentHistogramCanvasControlListenerl constructor - * - * @param newCanvas Related canvas - */ - public ParentHistogramCanvasControlListener(ParentHistogramCanvas newCanvas) { - ourCanvas = newCanvas; - } - - - /** - * Method called when the canvas is resized.

- * - * We need to tell the content that the canvas size changed and to recenter the windows - * - * @param event The control event generated by the resize. - */ - @Override - public void controlResized(ControlEvent event) { - - if ( (ourCanvas != null) && (ourCanvas.getHistogramContent() != null) ) { - int newSize = ourCanvas.getSize().x; - int oldSize = ourCanvas.getHistogramContent().getCanvasWindowSize(); - - // Set the new canvas size - ourCanvas.getHistogramContent().setCanvasWindowSize(newSize); - - // Try to recenter to window at the same place it was - // Note : this is a best hope approach and is not intended to be precise; - // the idea is to avoid issuing a (maybe) long request fo the selection window; - // There WILL be slight discrepancy between the "window values" (timestamp, etc...) showed - // and what it really points to. The user should reclick by himself to refresh it. - int oldWindowCenter = ourCanvas.getCurrentWindow().getWindowXPositionCenter(); - int newWindowCenter = (int)Math.ceil((double)newSize * ((double)oldWindowCenter / (double)oldSize)); - ourCanvas.setWindowCenterPosition(newWindowCenter); - } - } -} diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/ParentHistogramCanvasPaintListener.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/ParentHistogramCanvasPaintListener.java deleted file mode 100644 index 63ca7e392b..0000000000 --- a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/ParentHistogramCanvasPaintListener.java +++ /dev/null @@ -1,289 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009 Ericsson - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v1.0 which - * accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * William Bourque - Initial API and implementation - * - * Modifications: - * 2010-07-16 Yuriy Vashchuk - Base class simplification. Redraw bug correction. - * Double Buffering implementation. - *******************************************************************************/ - -package org.eclipse.linuxtools.lttng.ui.views.histogram; - -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.PaintEvent; - -import org.eclipse.swt.graphics.Color; -import org.eclipse.swt.graphics.GC; -import org.eclipse.swt.graphics.Image; - -/** - * HistogramCanvasPaintListener - *

- * Implementation of a PaintListener for the specific need of the ParentHistogramCanvas. - *

- * The difference with the default one is that this one take a content that is the power of 2 higher - * than the display size.

- * - * When it is time to draw, it takes the closest power of 2 smaller than the canvas size; it is then easy to - * concatenate the interval as they are both power of 2.

- * The difference between the power of 2 and the not-power-of-2 canvas size is then filled by drawing bar that are - * slightly larger every (power/canvasSize) interval.

- */ -public class ParentHistogramCanvasPaintListener extends HistogramCanvasPaintListener -{ - private static ParentHistogramCanvas parentCanvas = null; - - /** - * ParentHistogramCanvasPaintListener constructor - * - * @param newCanvas Related canvas - */ - public ParentHistogramCanvasPaintListener(ParentHistogramCanvas newCanvas) { - parentCanvas = newCanvas; - } - - // *** VERIFY *** - // Is it good to put this synchronized? - // - /** - * Draw the histogram bars in the canvas.

- * This drawing function expect the content to be the power of 2 higher than the canvas size. - * The bars size will be slightly dynamic to fill the gap between the power and the canvas size.

- * - * Note : This draw function is somewhat heavier than the default one. - * - * @param event The generated paint event when redraw is called. - */ - @Override - public synchronized void drawHistogram(GC imageGC, Image image) { - final HistogramContent tmpContent = parentCanvas.getHistogramContent(); - final int tmpBarWidth = tmpContent.getBarsWidth(); - - // Calculate the closest power of 2 just smaller than the canvas size - final int closestPowerToCanvas = (int)Math.pow(2, Math.floor( Math.log( image.getBounds().width ) / Math.log(2.0) )); - - // First clear the whole canvas to have a clean section where to draw - clearDrawingSection(imageGC, image, parentCanvas); - - // Make sure the canvas didn't change size, it which case we need to recalculate our heights - recalculateHeightIfCanvasSizeChanged(); - - // Calculate the factor of difference between canvas and the power - final double factor = (double)image.getBounds().width / (double)closestPowerToCanvas; - // Calculate how many interval will need to be concatenated into one pixel - final int intervalDifference = (tmpContent.getNbElement() / closestPowerToCanvas)*tmpBarWidth; - - // This keep a link between the position in "power" and the pixel we draw - // I.e. correlation between position in the power ("fake" pixels) and the position in the canvas ("real" pixels) - // So if pos == 30 and factor == 1.5, we know that the pixel that draw this pos is (30 * 1.5) == 45 - int posInPower = 0; - int widthFilled = 0; - - // This will be the color for all the bars that wil be draw below. - imageGC.setBackground( new Color( imageGC.getDevice(), 74, 112, 139) ); - - // Read from 0 up to the currently ready position - // We advance by "intervalDifference" as the bars migth not represent 1 interval only - int itemWidth = 0; - int thisElementHeight = 0; - for( int contentPos=0; contentPos < tmpContent.getReadyUpToPosition(); contentPos += intervalDifference ) { - // Width of the current item. - // Vary because of the difference between the power of 2 and the canvas size - // Ex: if power == 1024 and canvas == 1500, a bars every (1024/1500) will have a size of 2 instead of 1. - itemWidth = (int)( Math.ceil((double)(posInPower+1)*factor) - Math.ceil((double)posInPower*factor) ); - itemWidth = itemWidth * tmpBarWidth; - - // Concatenate all the element in the interval - // Ex : if power == 1024 and content == 2048, every (2048/1024)*bars_width will be concatenated - thisElementHeight = 0; - for ( int concatPos=0; concatPos image.getBounds().height ? 0 : image.getBounds().height - thisElementHeight), - itemWidth, - thisElementHeight - ); - - // Keep in a variable how much width we filld so far - widthFilled += itemWidth; - // Keep a correlation between fake_pixel -> real_pixel, - // this is used to calculate the width of each element - posInPower++; - } - } - - /* - * The function will make sure that the "max difference average" factor is still the same as before; - * if not, the heigth of the events will be recalculated.

- * - * The factor might change if the canvas is resized by a big factor.

- */ - protected void recalculateHeightIfCanvasSizeChanged() { - final HistogramContent tmpContent = parentCanvas.getHistogramContent(); - // We need to ajust the "maxDifferenceToAverageFactor" as the bars we draw might be slitghly larger than the value asked - // Each "interval" are concatenated when draw so the worst case should be : - // contentSize / (closest power of 2 to canvasMaxSize) - // Ex : if canvasSize is 1500 -> (2048 / 1024) == 2 so maxDiff should be twice larger - // - // His is set in the create content of the canvas, but we need to recalculate it - // here because the window might have been resized! - final int exp = (int)Math.floor( Math.log( (double)tmpContent.getCanvasWindowSize() ) / Math.log(2.0) ); - final int contentSize = (int)Math.pow(2, exp); - final double maxBarsDiffFactor = ((double)tmpContent.getNbElement() / (double)contentSize ); - - // Floating point comparaison : - // We consider it is different if the difference is greater than 10^-3 - if ( Math.abs(maxBarsDiffFactor - tmpContent.getMaxDifferenceToAverageFactor()) > 0.001 ) { - // The factor changed! That's unfortunate because it will take a while to recalculate. - tmpContent.setMaxDifferenceToAverageFactor(maxBarsDiffFactor); - tmpContent.recalculateHeightFactor(); - tmpContent.recalculateEventHeight(); - } - } - - /** - * Function called when the canvas need to redraw.

- * - * @param event The generated paint event when redraw is called. - */ - private final String DATA_KEY = "double-buffer-image"; //$NON-NLS-1$ - @Override - public void paintControl(PaintEvent event) { - - if (parentCanvas.getSize().x > 0 && parentCanvas.getSize().y > 0) { - Image image = (Image) parentCanvas.getData(DATA_KEY); - - // Creates new image only absolutely necessary. - if (image == null - || image.getBounds().width != parentCanvas.getClientArea().width - || image.getBounds().height != parentCanvas.getClientArea().height) { - - image = new Image( - event.display, - parentCanvas.getClientArea().width, - parentCanvas.getClientArea().height - ); - - parentCanvas.setData(DATA_KEY, image); -// isFinished = false; - } - - // Initializes the graphics context of the image. - GC imageGC = new GC(image); - - // If the content is null or has rady to draw we quit the function here - if ( (parentCanvas.getHistogramContent() != null) - && (parentCanvas.getHistogramContent().getReadyUpToPosition() != 0) ) { - - // Call the function that draw the bars -// if (!isFinished) { - drawHistogram(imageGC, image); -// isFinished = HistogramCanvas.getHistogramView().getDataBackgroundFullRequest().isCompleted(); -// } - - Image img = new Image (image.getDevice(), image, SWT.IMAGE_COPY); - GC imgGC = new GC(img); - - // If we have a selected window set to visible, call the function to draw it - if ( (parentCanvas.getCurrentWindow() != null) && (parentCanvas.getCurrentWindow().getSelectedWindowVisible()) ) { - drawSelectedWindow( - imgGC, - img - ); - } - - // Draws the buffer image onto the canvas. - event.gc.drawImage(img, 0, 0); - - imgGC.dispose(); - img.dispose(); - } - - imageGC.dispose(); - } - - } - - /** - * Draw the selection window in the canvas.

- * This draw a square around the selected section with a crosshair in the middle. - * The square cannot be smaller than "MINIMUM_WINDOW_WIDTH" - * - * @param imageGC GC content. - * @param image Image content. - */ - public void drawSelectedWindow(GC imageGC, Image image) { - // Get the window position... this would fail if the window is not initialized yet - final int positionCenter = parentCanvas.getCurrentWindow().getWindowXPositionCenter(); - final int positionLeft = parentCanvas.getCurrentWindow().getWindowXPositionLeft(); - final int positionRight = parentCanvas.getCurrentWindow().getWindowXPositionRight(); - - final int imageHeight = image.getBounds().height; - final int imageHalfHeight = image.getBounds().height / 2; - final int crosshairHalfWidth = HistogramConstant.SELECTION_CROSSHAIR_WIDTH / 2; - final int lineHalfWidth = HistogramConstant.SELECTION_LINE_WIDTH / 2; - - // Draw the crosshair - imageGC.setForeground( new Color (imageGC.getDevice(), 255, 128, 0) ); - imageGC.setLineWidth(HistogramConstant.SELECTION_CROSSHAIR_WIDTH); - imageGC.setLineStyle(SWT.LINE_SOLID); - if(imageHeight > 40) { - imageGC.drawLine( - positionCenter - crosshairHalfWidth, - imageHalfHeight - 20, - positionCenter - crosshairHalfWidth, - imageHalfHeight + 20 - ); - } - if(positionRight - positionLeft > 40) { - imageGC.drawLine( - positionCenter - 20, - imageHalfHeight - crosshairHalfWidth, - positionCenter + 20, - imageHalfHeight - crosshairHalfWidth - ); - } - - // Draw the selection window square - imageGC.setLineWidth(HistogramConstant.SELECTION_LINE_WIDTH); - imageGC.setLineStyle(SWT.LINE_SOLID); - imageGC.drawRoundRectangle( - positionLeft + lineHalfWidth, - lineHalfWidth, - (positionRight - positionLeft) - lineHalfWidth, - imageHeight - HistogramConstant.SELECTION_LINE_WIDTH, - 15, - 15 - ); - - // Show the selection - imageGC.setBackground( new Color (imageGC.getDevice(), 255, 128, 0) ); - imageGC.setAlpha(25); - imageGC.fillRoundRectangle( - positionLeft + 1, - lineHalfWidth + 1, - (positionRight - positionLeft) - lineHalfWidth - 1, - imageHeight - lineHalfWidth - 1, - 15, - 15 - ); - } - -} diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/TimeRangeHistogram.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/TimeRangeHistogram.java new file mode 100644 index 0000000000..265e269bed --- /dev/null +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/TimeRangeHistogram.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2011 Ericsson + * + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Francois Chouinard - Initial API and implementation + *******************************************************************************/ + +package org.eclipse.linuxtools.lttng.ui.views.histogram; + +import org.eclipse.swt.widgets.Composite; + +/** + * TimeRangeHistogram + *

+ * A basic histogram with the following additional features: + *

+ */ +public class TimeRangeHistogram extends Histogram { + + // ------------------------------------------------------------------------ + // Attributes + // ------------------------------------------------------------------------ + + HistogramZoom fZoom; + + // ------------------------------------------------------------------------ + // Constructor + // ------------------------------------------------------------------------ + + public TimeRangeHistogram(HistogramView view, Composite parent) { + super(view, parent); + fZoom = new HistogramZoom(this, fCanvas, getStartTime(), getTimeLimit()); + } + + // ------------------------------------------------------------------------ + // Operations + // ------------------------------------------------------------------------ + + @Override + public void updateTimeRange(long startTime, long endTime) { + ((HistogramView) fParentView).updateTimeRange(startTime, endTime); + } + + @Override + public synchronized void clear() { + if (fZoom != null) + fZoom.stop(); + super.clear(); + } + + public synchronized void setTimeRange(long startTime, long duration) { + fZoom.setNewRange(startTime, duration); + } + + public void setFullRange(long startTime, long endTime) { + fZoom.setFullRange(startTime, endTime); + } + +} diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/TimeTextGroup.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/TimeTextGroup.java deleted file mode 100644 index 3d760d0b54..0000000000 --- a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/TimeTextGroup.java +++ /dev/null @@ -1,506 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2009 Ericsson - * - * All rights reserved. This program and the accompanying materials are - * made available under the terms of the Eclipse Public License v1.0 which - * accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * Francois Chouinard - Initial API and implementation - *******************************************************************************/ - -package org.eclipse.linuxtools.lttng.ui.views.histogram; - -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.FocusEvent; -import org.eclipse.swt.events.FocusListener; -import org.eclipse.swt.events.KeyEvent; -import org.eclipse.swt.events.KeyListener; -import org.eclipse.swt.graphics.Font; -import org.eclipse.swt.graphics.FontData; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Display; -import org.eclipse.swt.widgets.Group; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Text; - -/** - * TimeTextGroup - *

- * Special control for HistogramView - *

- * This control will give you a group, a text box and a label at once. - */ -public class TimeTextGroup implements FocusListener, KeyListener { - -/* - // 2010-06-10 Yuriy: Has been moved to header into HistogramView.java - protected static final String NANOSEC_LABEL = "sec"; -*/ - private static final String LONGEST_STRING_VALUE = "." + Long.MAX_VALUE; //$NON-NLS-1$ - private static final int MAX_CHAR_IN_TEXTBOX = LONGEST_STRING_VALUE.length(); - - // The "small font" height used to display time will be "default font" minus this constant - private static final int VERY_SMALL_FONT_MODIFIER = 2; - private static final int SMALL_FONT_MODIFIER = 1; - - // Indentation size -// private static final int DEFAULT_INDENT_SIZE = 10; - - private HistogramView parentView = null; - private AsyncTimeTextGroupRedrawer asyncRedrawer = null; - - private Group grpName = null; - private Text txtNanosec = null; - private Label lblNanosec = null; - - private long timeValue = 0L; - - /** - * Default Constructor.

- * - * @param newParentView Parent HistogramView - * @param parent Parent Composite, used to position the inner controls. - * @param textStyle Style of the textbox. Usually SWT.BORDER or SWT.NONE (or anything that suit a Text) - * @param groupStyle Style of the group. Anything that suite a Text - */ - public TimeTextGroup(HistogramView newParentView, Composite parent, int textStyle, int groupStyle) { - this(newParentView, parent, textStyle, groupStyle, "", HistogramConstant.formatNanoSecondsTime(0L), false); //$NON-NLS-1$ - } - - /** - * Default Constructor with adjustement for small screen.

- * - * @param newParentView Parent HistogramView - * @param parent Parent Composite, used to position the inner controls. - * @param textStyle Style of the textbox. Usually SWT.BORDER or SWT.NONE (or anything that suit a Text) - * @param groupStyle Style of the group. Anything that suite a Text - * @param isSpaceSaverNeeded Value that tell if we try to save some space in the control. - */ - public TimeTextGroup(HistogramView newParentView, Composite parent, int textStyle, int groupStyle, boolean isSpaceSaverNeeded) { - this(newParentView, parent, textStyle, groupStyle, "", HistogramConstant.formatNanoSecondsTime(0L), isSpaceSaverNeeded); //$NON-NLS-1$ - } - - /** - * Default Constructor, allow you to give the groupname and the textbox value.

- * - * @param newParentView Parent HistogramView - * @param parent Parent Composite, used to position the inner controls. - * @param textStyle Style of the textbox. Usually SWT.BORDER or SWT.NONE (or anything that suit a Text) - * @param groupStyle Style of the group. Anything that suite a Text - * @param groupValue Value (label) of the group. - * @param textValue Value of the textbox. - */ - public TimeTextGroup(HistogramView newParentView, Composite parent, int textStyle, int groupStyle, String groupValue, String textValue) { - this(newParentView, parent, textStyle, groupStyle, groupValue, textValue, false); - } - - /** - * Default Constructor with adjustment for small screen, allow you to give the group name and the text box value.

- * - * @param newParentView Parent HistogramView - * @param parent Parent Composite, used to position the inner controls. - * @param textStyle Style of the text box. Usually SWT.BORDER or SWT.NONE (or anything that suit a Text) - * @param groupStyle Style of the group. Anything that suite a Text - * @param groupValue Value (label) of the group. - * @param textValue Value of the text box. - * @param isSpaceSaverNeeded Value that tell if we try to save some space in the control. - */ - public TimeTextGroup(HistogramView newParentView, Composite parent, int textStyle, int groupStyle, String groupValue, String textValue, boolean isSpaceSaverNeeded) { - Font font = parent.getFont(); - FontData tmpFontData = font.getFontData()[0]; - - Font smallFont = null; - int textBoxSize = -1; -// int indentSize = -1; - - // If we were asked to save size, calculate the correct value here - if ( isSpaceSaverNeeded == true ) { - smallFont = new Font(font.getDevice(), tmpFontData.getName(), tmpFontData.getHeight()-VERY_SMALL_FONT_MODIFIER, tmpFontData.getStyle()); - - // No minimum textBoxSize and no indent size - textBoxSize = 0; -// indentSize = 0; - } - else { - // We use only a slightly smaller font - smallFont = new Font(font.getDevice(), tmpFontData.getName(), tmpFontData.getHeight()-SMALL_FONT_MODIFIER, tmpFontData.getStyle()); - - // ** Creation of the textbox - // Calculate the optimal size of the textbox already - // This will avoid the control to move around and resize when bigger value are given - textBoxSize = HistogramConstant.getTextSizeInControl(parent, LONGEST_STRING_VALUE); - - // Default indent -// indentSize = DEFAULT_INDENT_SIZE; - } - - parentView = newParentView; - - // ** Creation of the group -// GridLayout gridLayoutgroup = new GridLayout(2, false); - GridLayout gridLayoutgroup = new GridLayout(1, false); - gridLayoutgroup.horizontalSpacing = 0; - gridLayoutgroup.verticalSpacing = 0; - grpName = new Group(parent, groupStyle); - grpName.setText(groupValue); - grpName.setFont(smallFont); - grpName.setLayout(gridLayoutgroup); - - txtNanosec = new Text(grpName, textStyle); - txtNanosec.setTextLimit( MAX_CHAR_IN_TEXTBOX ); - txtNanosec.setText(textValue); - txtNanosec.setFont(smallFont); - GridData gridDataTextBox = new GridData(SWT.LEFT, SWT.CENTER, true, false); - gridDataTextBox.horizontalIndent = 0; // indentSize; - gridDataTextBox.verticalIndent = 0; - gridDataTextBox.minimumWidth = textBoxSize; - txtNanosec.setLayoutData(gridDataTextBox); - - // ** Creation of the label -/* - lblNanosec = new Label(grpName, SWT.LEFT); - lblNanosec.setText(NANOSEC_LABEL); - lblNanosec.setFont(smallFont); - GridData gridDataLabel = new GridData(SWT.LEFT, SWT.CENTER, false, false); - gridDataLabel.horizontalIndent = indentSize; - gridDataLabel.verticalIndent = 0; - lblNanosec.setLayoutData(gridDataLabel); -*/ - - // Add all listener - addNeededListeners(); - } - - /* - * Create and add all listeners needed by our control.

- */ - protected void addNeededListeners() { - - // AsyncCanvasRedrawer is an internal class - // This is used to redraw the canvas without danger from a different thread - asyncRedrawer = new AsyncTimeTextGroupRedrawer(this); - - txtNanosec.addFocusListener(this); - txtNanosec.addKeyListener(this); - } - - /** - * Getter for the layout data currently in use.

- * - * @return the layout - */ - public Object getLayoutData() { - return grpName.getLayoutData(); - } - - /** - * Set a new layoutData for our control.

- * - * @param layoutData the new layout data - */ - public void setLayoutData(Object layoutData) { - grpName.setLayoutData(layoutData); - } - - /** - * Get the control's parent.

- * - * @return Currently used parent - */ - public Composite getParent() { - return grpName.getParent(); - } - - /** - * Set a new parent for the control.

- * - * @return Currently used parent - */ - public void setParent(Composite newParent) { - grpName.setParent(newParent); - txtNanosec.setParent(newParent); - lblNanosec.setParent(newParent); - } - - - public boolean isDisposed() { - return grpName.isDisposed(); - } - - /** - * Getter for the time value of the control.

- * - * @return The nanoseconds time value - */ - public long getValue() { - return timeValue; - } - - /** - * Set a new String value to the control.

- * Note : The String value will be converted in long before being applied; - * if any conversion error occur, 0 will be used.

- * - * @param newTimeAsString The value to convert and set. - */ - public void setValue(String newTimeAsString) { - long timeAsLong = HistogramConstant.convertStringToNanoseconds(newTimeAsString); - setValue( timeAsLong ); - } - - /** - * Set a new value to the control.

- * Note : The value will be formatted as nanosecond value, - * missing zero will be added if needed.

- * - * @param newTime The value to set. - */ - public void setValue(long newTime) { - timeValue = newTime; - txtNanosec.setText( HistogramConstant.formatNanoSecondsTime(newTime) ); - } - - /** - * Set a new String value, asynchronously.

- * This will call setValue(String) in async.Exec to avoid Thread Access problem to UI.

- * - * @param newTimeAsString The value to convert and set. - */ - public void setValueAsynchronously(String newTimeAsString) { - long timeAsLong = HistogramConstant.convertStringToNanoseconds(newTimeAsString); - setValueAsynchronously( timeAsLong ); - } - - /** - * Set a new String value, asynchronously.

- * This will call setValue(long) in async.Exec to avoid Thread Access problem to UI.

- * - * @param newTimeAsString The value to set. - */ - public void setValueAsynchronously(long newTime) { - // Set the correct value ASAP - timeValue = newTime; - - // Create a new redrawer in case it doesn't exist yet (we never know with thread!) - if ( asyncRedrawer == null ) { - asyncRedrawer = new AsyncTimeTextGroupRedrawer(this); - } - - asyncRedrawer.asynchronousSetValue(newTime); - } - - /** - * Set a new group name (label) for this control.

- * - * @param newName The new name to set. - */ - public void setGroupName(String newName) { - grpName.setText(newName); - } - - /** - * Set a new group name (label) for this control, asynchronously.

- * This will call setValue(long) in async.Exec to avoid Thread Access problem to UI.

- * - * @param newName The new name to set. - */ - public void setGroupNameAsynchronously(String newGroupName) { - // Create a new redrawer in case it doesn't exist yet (we never know with thread!) - if ( asyncRedrawer == null ) { - asyncRedrawer = new AsyncTimeTextGroupRedrawer(this); - } - - asyncRedrawer.asynchronousSetGroupName(newGroupName); - } - - - /** - * Method to call the "Asynchronous redrawer" for this time text group

- * This allow safe redraw from different threads. - */ - public void redrawAsynchronously() { - // Create a new redrawer in case it doesn't exist yet (we never know with thread!) - if ( asyncRedrawer == null ) { - asyncRedrawer = new AsyncTimeTextGroupRedrawer(this); - } - - asyncRedrawer.asynchronousRedraw(); - } - - /** - * Redraw the control - */ - public void redraw () { - grpName.redraw(); - txtNanosec.redraw(); - lblNanosec.redraw(); - } - - /* - * This function is called when an user enter a new string in the control by hand.

- * It will ensure the format of the String is valid. - */ - protected void handleNewStringValue() { - String valueInText = txtNanosec.getText(); - long valueAsLong = HistogramConstant.convertStringToNanoseconds(valueInText); - - if ( getValue() != valueAsLong ) { - setValue(valueAsLong); - // Notify our parent that the control was updated - notifyParentUpdatedTextGroupValue(); - } - } - - /** - * This function notify our parent HistogramView that our value changed. - */ - public void notifyParentUpdatedTextGroupValue() { - parentView.timeTextGroupChangeNotification(); - } - - /** - * Function that is called when the canvas get focus.

- * - * Doesn't do anything yet... - * - * @param event The focus event generated. - */ - @Override - public void focusGained(FocusEvent event) { - // Nothing to do yet - } - - /** - * Function that is called when the canvas loose focus.

- * It will validate that the String entered by the user (if any) is valid.

- * - * @param event The focus event generated. - */ - @Override - public void focusLost(FocusEvent event) { - handleNewStringValue(); - } - - /** - * Function that is called when a key is pressed.

- * Possible actions : - * - Enter (CR) : Validate the entered String.

- * - * @param event The KeyEvent generated when the key was pressed. - */ - @Override - public void keyPressed(KeyEvent event) { - switch (event.keyCode) { - // SWT.CR is "ENTER" Key - case SWT.CR: - handleNewStringValue(); - break; - default: - break; - } - } - - /** - * Function that is called when a key is released.

- * Possible actions : - * Nothing yet - * - * @param event The KeyEvent generated when the key was pressed. - */ - @Override - public void keyReleased(KeyEvent e) { - - } -} - -/** - * AsyncTimeTextGroupRedrawer Inner Class - *

- * Asynchronous redrawer for the TimeTextGroup - *

- * This class role is to call method that update the UI on asynchronously. - * This should prevent any "invalid thread access" exception when trying to update UI from a different thread. - */ -class AsyncTimeTextGroupRedrawer { - - private TimeTextGroup parentTimeTextGroup = null; - - /** - * AsyncTimeTextGroupRedrawer constructor. - * - * @param newParent Related time text group. - */ - public AsyncTimeTextGroupRedrawer(TimeTextGroup newParent) { - parentTimeTextGroup = newParent; - } - - /** - * Asynchronous SetValue for time text group. - * - * Basically, it just run "getParent().setValue(time)" in asyncExec. - * - * @param newTime The new time to set - */ - public void asynchronousSetValue(final long newTime) { - // Ignore setting of value if widget is disposed - if (parentTimeTextGroup.isDisposed()) return; - - Display display = parentTimeTextGroup.getParent().getDisplay(); - display.asyncExec(new Runnable() { - @Override - public void run() { - if (!parentTimeTextGroup.isDisposed()) { - parentTimeTextGroup.setValue(newTime); - } - } - }); - } - - /** - * Asynchronous SetGroupName for time text group. - * - * Basically, it just run "getParent().setGroupName(name)" in asyncExec. - * - * @param newGroupName The new group name to set - */ - public void asynchronousSetGroupName(String newGroupName) { - // Ignore setting of name if widget is disposed - if (parentTimeTextGroup.isDisposed()) return; - - final String tmpName = newGroupName; - Display display = parentTimeTextGroup.getParent().getDisplay(); - display.asyncExec(new Runnable() { - @Override - public void run() { - if (!parentTimeTextGroup.isDisposed()) { - parentTimeTextGroup.setGroupName(tmpName); - } - } - }); - } - - /** - * Function to redraw the related time text group asynchonously.

- * - * Basically, it just run "getParent().redraw()" in asyncExec. - * - */ - public void asynchronousRedraw() { - // Ignore redraw if widget is disposed - if (parentTimeTextGroup.isDisposed()) return; - - Display display = parentTimeTextGroup.getParent().getDisplay(); - display.asyncExec(new Runnable() { - @Override - public void run() { - if (!parentTimeTextGroup.isDisposed()) { - parentTimeTextGroup.getParent().redraw(); - } - } - }); - } -} \ No newline at end of file diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/messages.properties b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/messages.properties index f6d232292b..2078673bfe 100644 --- a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/messages.properties +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/messages.properties @@ -1,3 +1,2 @@ HistogramView_currentEventLabel=Current Event (sec) -HistogramView_windowCenterLabel=Window Center (sec) HistogramView_windowSpanLabel=Window Span (sec) diff --git a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/project/dialogs/ImportTraceWizardPage.java b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/project/dialogs/ImportTraceWizardPage.java index 36670ef2c7..ba8e2999c9 100644 --- a/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/project/dialogs/ImportTraceWizardPage.java +++ b/org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/project/dialogs/ImportTraceWizardPage.java @@ -13,7 +13,7 @@ package org.eclipse.linuxtools.lttng.ui.views.project.dialogs; import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.linuxtools.lttng.LttngException; +import org.eclipse.linuxtools.lttng.exceptions.LttngException; import org.eclipse.linuxtools.lttng.trace.LTTngTraceVersion; import org.eclipse.linuxtools.lttng.ui.views.project.handlers.TraceErrorHandler; import org.eclipse.linuxtools.lttng.ui.views.project.model.LTTngProjectNode; diff --git a/org.eclipse.linuxtools.lttng/META-INF/MANIFEST.MF b/org.eclipse.linuxtools.lttng/META-INF/MANIFEST.MF index c836b188bc..73ee3033eb 100644 --- a/org.eclipse.linuxtools.lttng/META-INF/MANIFEST.MF +++ b/org.eclipse.linuxtools.lttng/META-INF/MANIFEST.MF @@ -15,6 +15,7 @@ Bundle-ActivationPolicy: lazy Export-Package: org.eclipse.linuxtools.lttng, org.eclipse.linuxtools.lttng.control, org.eclipse.linuxtools.lttng.event, + org.eclipse.linuxtools.lttng.exceptions, org.eclipse.linuxtools.lttng.model, org.eclipse.linuxtools.lttng.request, org.eclipse.linuxtools.lttng.signal, diff --git a/org.eclipse.linuxtools.lttng/src/org/eclipse/linuxtools/lttng/LttngException.java b/org.eclipse.linuxtools.lttng/src/org/eclipse/linuxtools/lttng/LttngException.java deleted file mode 100644 index 36de9fae25..0000000000 --- a/org.eclipse.linuxtools.lttng/src/org/eclipse/linuxtools/lttng/LttngException.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.eclipse.linuxtools.lttng; - -/** - * LttngException - *

- * Super exception class for Lttng - */ -public class LttngException extends Exception { - static final long serialVersionUID = 4016530589556719360L; - - public LttngException(String errMsg) { - super(errMsg); - } -} diff --git a/org.eclipse.linuxtools.lttng/src/org/eclipse/linuxtools/lttng/exceptions/EventOutOfSequenceException.java b/org.eclipse.linuxtools.lttng/src/org/eclipse/linuxtools/lttng/exceptions/EventOutOfSequenceException.java new file mode 100644 index 0000000000..5e002803f5 --- /dev/null +++ b/org.eclipse.linuxtools.lttng/src/org/eclipse/linuxtools/lttng/exceptions/EventOutOfSequenceException.java @@ -0,0 +1,17 @@ +/** + * + */ +package org.eclipse.linuxtools.lttng.exceptions; + +/** + * @author francois + * + */ +public class EventOutOfSequenceException extends Exception { + + private static final long serialVersionUID = -3537822357348706661L; + + public EventOutOfSequenceException(String errMsg) { + super(errMsg); + } +} diff --git a/org.eclipse.linuxtools.lttng/src/org/eclipse/linuxtools/lttng/exceptions/LttngException.java b/org.eclipse.linuxtools.lttng/src/org/eclipse/linuxtools/lttng/exceptions/LttngException.java new file mode 100644 index 0000000000..00226c85fe --- /dev/null +++ b/org.eclipse.linuxtools.lttng/src/org/eclipse/linuxtools/lttng/exceptions/LttngException.java @@ -0,0 +1,14 @@ +package org.eclipse.linuxtools.lttng.exceptions; + +/** + * LttngException + *

+ * Super exception class for Lttng + */ +public class LttngException extends Exception { + static final long serialVersionUID = 4016530589556719360L; + + public LttngException(String errMsg) { + super(errMsg); + } +} diff --git a/org.eclipse.linuxtools.lttng/src/org/eclipse/linuxtools/lttng/trace/LTTngTrace.java b/org.eclipse.linuxtools.lttng/src/org/eclipse/linuxtools/lttng/trace/LTTngTrace.java index 060cad3a0e..ae5b10d658 100644 --- a/org.eclipse.linuxtools.lttng/src/org/eclipse/linuxtools/lttng/trace/LTTngTrace.java +++ b/org.eclipse.linuxtools.lttng/src/org/eclipse/linuxtools/lttng/trace/LTTngTrace.java @@ -16,7 +16,6 @@ import java.util.HashMap; import java.util.Iterator; import java.util.Vector; -import org.eclipse.linuxtools.lttng.LttngException; import org.eclipse.linuxtools.lttng.event.LttngEvent; import org.eclipse.linuxtools.lttng.event.LttngEventContent; import org.eclipse.linuxtools.lttng.event.LttngEventReference; @@ -24,6 +23,7 @@ import org.eclipse.linuxtools.lttng.event.LttngEventSource; import org.eclipse.linuxtools.lttng.event.LttngEventType; import org.eclipse.linuxtools.lttng.event.LttngLocation; import org.eclipse.linuxtools.lttng.event.LttngTimestamp; +import org.eclipse.linuxtools.lttng.exceptions.LttngException; import org.eclipse.linuxtools.lttng.jni.JniEvent; import org.eclipse.linuxtools.lttng.jni.JniMarker; import org.eclipse.linuxtools.lttng.jni.JniTrace; diff --git a/org.eclipse.linuxtools.lttng/src/org/eclipse/linuxtools/lttng/trace/LTTngTraceVersion.java b/org.eclipse.linuxtools.lttng/src/org/eclipse/linuxtools/lttng/trace/LTTngTraceVersion.java index 884af99e34..6532aed227 100644 --- a/org.eclipse.linuxtools.lttng/src/org/eclipse/linuxtools/lttng/trace/LTTngTraceVersion.java +++ b/org.eclipse.linuxtools.lttng/src/org/eclipse/linuxtools/lttng/trace/LTTngTraceVersion.java @@ -11,7 +11,7 @@ package org.eclipse.linuxtools.lttng.trace; * William Bourque (wbourque@gmail.com) - Initial API and implementation *******************************************************************************/ -import org.eclipse.linuxtools.lttng.LttngException; +import org.eclipse.linuxtools.lttng.exceptions.LttngException; import org.eclipse.linuxtools.lttng.jni.exception.JniTraceVersionException; import org.eclipse.linuxtools.lttng.jni.factory.JniTraceVersion; diff --git a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/events/TmfEventsTable.java b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/events/TmfEventsTable.java index 9e9f1bd159..2989b8d29a 100644 --- a/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/events/TmfEventsTable.java +++ b/org.eclipse.linuxtools.tmf.ui/src/org/eclipse/linuxtools/tmf/ui/viewers/events/TmfEventsTable.java @@ -1555,6 +1555,8 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS // the method fTrace.getRank() from interfering and delaying ongoing requests. final TmfDataRequest subRequest = new TmfDataRequest(TmfEvent.class, 0, 1, ExecutionType.FOREGROUND) { + TmfTimestamp ts = new TmfTimestamp(signal.getCurrentTime()); + @Override public void handleData(TmfEvent event) { super.handleData(event); @@ -1565,7 +1567,7 @@ public class TmfEventsTable extends TmfComponent implements IGotoMarker, IColorS // Verify if event is within the trace range final TmfTimestamp timestamp[] = new TmfTimestamp[1]; - timestamp[0] = signal.getCurrentTime(); + timestamp[0] = ts; // signal.getCurrentTime(); if (timestamp[0].compareTo(fTrace.getStartTime(), true) == -1) { timestamp[0] = fTrace.getStartTime(); } diff --git a/org.eclipse.linuxtools.tmf/src/org/eclipse/linuxtools/tmf/signal/TmfRangeSynchSignal.java b/org.eclipse.linuxtools.tmf/src/org/eclipse/linuxtools/tmf/signal/TmfRangeSynchSignal.java index 61f90eddad..b73b0d7fce 100644 --- a/org.eclipse.linuxtools.tmf/src/org/eclipse/linuxtools/tmf/signal/TmfRangeSynchSignal.java +++ b/org.eclipse.linuxtools.tmf/src/org/eclipse/linuxtools/tmf/signal/TmfRangeSynchSignal.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2009 Ericsson + * Copyright (c) 2009, 2011 Ericsson * * All rights reserved. This program and the accompanying materials are * made available under the terms of the Eclipse Public License v1.0 which @@ -18,25 +18,24 @@ import org.eclipse.linuxtools.tmf.event.TmfTimestamp; /** * TmfRangeSynchSignal *

- * TODO: Implement me. Please. */ public class TmfRangeSynchSignal extends TmfSignal { - private final TmfTimeRange fCurrentRange; - private final TmfTimestamp fCurrentTime; + private final TmfTimeRange fCurrentRange; + private final TmfTimestamp fCurrentTime; - public TmfRangeSynchSignal(Object source, TmfTimeRange range, TmfTimestamp ts) { - super(source); - fCurrentRange = range; - fCurrentTime = ts; - } + public TmfRangeSynchSignal(Object source, TmfTimeRange range, TmfTimestamp ts) { + super(source); + fCurrentRange = range; + fCurrentTime = ts; + } - public TmfTimeRange getCurrentRange() { - return fCurrentRange; - } + public TmfTimeRange getCurrentRange() { + return fCurrentRange; + } - public TmfTimestamp getCurrentTime() { - return fCurrentTime; - } + public TmfTimestamp getCurrentTime() { + return fCurrentTime; + } }