--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sysperfana/perfinvestigator/com.nokia.carbide.cpp.pi/src/com/nokia/carbide/cpp/internal/pi/visual/PICompositePanel.java Thu Feb 11 15:32:31 2010 +0200
@@ -0,0 +1,1381 @@
+/*
+ * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * This component and the accompanying materials are made available
+ * under the terms of the License "Eclipse Public License v1.0"
+ * which accompanies this distribution, and is available
+ * at the URL "http://www.eclipse.org/legal/epl-v10.html".
+ *
+ * Initial Contributors:
+ * Nokia Corporation - initial contribution.
+ *
+ * Contributors:
+ *
+ * Description:
+ *
+ */
+
+package com.nokia.carbide.cpp.internal.pi.visual;
+
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.util.ArrayList;
+import java.util.Enumeration;
+
+import javax.swing.JDialog;
+
+import org.eclipse.draw2d.FigureCanvas;
+import org.eclipse.draw2d.FlowLayout;
+import org.eclipse.draw2d.Graphics;
+import org.eclipse.draw2d.MouseMotionListener;
+import org.eclipse.draw2d.Panel;
+import org.eclipse.draw2d.geometry.Point;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.events.ControlAdapter;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.MouseMoveListener;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Menu;
+import org.eclipse.swt.widgets.ScrollBar;
+import org.eclipse.swt.widgets.Slider;
+
+import com.nokia.carbide.cpp.internal.pi.analyser.NpiInstanceRepository;
+import com.nokia.carbide.cpp.internal.pi.analyser.ProfileVisualiser;
+import com.nokia.carbide.cpp.internal.pi.analyser.TestGUI;
+import com.nokia.carbide.cpp.internal.pi.manager.PluginInitialiser;
+import com.nokia.carbide.cpp.internal.pi.plugin.model.IContextMenu;
+import com.nokia.carbide.cpp.internal.pi.plugin.model.IEventListener;
+import com.nokia.carbide.cpp.pi.editors.PIPageEditor;
+import com.nokia.carbide.cpp.pi.util.ColorPalette;
+import com.nokia.carbide.cpp.pi.util.GeneralMessages;
+
+public class PICompositePanel implements ActionListener, PIEventListener {
+ private SashForm sashForm;
+ private Slider slider = null;
+
+ private static final long serialVersionUID = -6350043592270317606L;
+
+ private static final int MOUSE_DOWN = 0;
+ private static final int MOUSE_MOVE = 1;
+ private static final int MOUSE_DOUBLECLICK = 2;
+
+ private ArrayList<GraphComponentWrapper> graphComponents;
+ private ProfileVisualiser profVisu;
+
+ public int lastSampleX = 0;
+ private int sizeX = 0;
+ private int sizeY = 450;
+ private int preferredSizeX = 100000;
+ private int preferredSizeY = 0; // this is constant!
+
+ private double selectionStart = -1;
+ private double selectionEnd = -1;
+
+ private boolean buttonDown = false;
+ private boolean dragOn = false;
+ private double origStart = 0;
+ private double scale = 10;
+ private double previousScale = 10;
+
+ private PIVisualSharedData sharedData;
+
+ JDialog dialog = null;
+
+ SynchroniseDialog dialogPanel = null;
+ private GenericTraceGraph activeGraph = null;
+
+ // create a ScrollComposite, with a horizontal scrollbar, containing a
+ // sashForm without a scrollbar
+ public PICompositePanel(Composite parent,
+ ProfileVisualiser profileVisualiser) {
+ // all graphs will go into a vertical SashForm
+ this.sashForm = new SashForm(parent, SWT.VERTICAL);
+ this.sashForm.SASH_WIDTH = 5; // 5 pixel wide sash
+ this.sashForm.setLayout(new FillLayout());
+
+ // this.scrolled.setContent(this.sashForm);
+ //
+ // // listen for when the horizontal scroll bar is selected
+ // final ScrollBar horizontalBar = this.scrolled.getHorizontalBar();
+ //
+ // horizontalBar.addSelectionListener(new SelectionListener() {
+ // public void widgetSelected(SelectionEvent e) {
+ // // since other pages associated with the GppTraceGraph scroll when
+ // this page scrolls,
+ // // also let listening plugins know
+ // int ai = AnalysisIdentifier.getIdentifier();
+ // Enumeration enu = PluginInitialiser.getPluginInstances(ai, "com.nokia.carbide.cpp.internal.pi.plugin.model.IEventListener"); //$NON-NLS-1$
+ // if (enu != null) {
+ // Event event = new Event();
+ // event.x = scrolled.getOrigin().x;
+ // event.y = scrolled.getOrigin().y;
+ // event.data = "FigureCanvas"; //$NON-NLS-1$
+ //
+ // while (enu.hasMoreElements())
+ // {
+ // IEventListener plugin = (IEventListener)enu.nextElement();
+ // plugin.receiveEvent("scroll", event); //$NON-NLS-1$
+ // }
+ // }
+ // }
+ //
+ // public void widgetDefaultSelected(SelectionEvent e) {
+ // widgetSelected(e);
+ // }
+ // });
+ //
+ // // minor scroll is 10 pixels
+ // horizontalBar.setIncrement(10);
+ //
+ // // major scroll is the width of the window
+ // horizontalBar.setPageIncrement(this.scrolled.getBounds().width);
+ // this.scrolled.addControlListener(new ControlAdapter()
+ // {
+ // public void controlResized(ControlEvent e) {
+ // horizontalBar.setPageIncrement(scrolled.getBounds().width);
+ // }
+ // });
+
+ this.graphComponents = new ArrayList<GraphComponentWrapper>();
+ this.profVisu = profileVisualiser;
+ this.sharedData = new PIVisualSharedData();
+ }
+
+ public SashForm getSashForm() {
+ return this.sashForm;
+ }
+
+ // returns true if the graph needs to be updated (it is either
+ // active or visible)
+ public boolean hasToBeUpdated(GenericTraceGraph graph) {
+ if (graph.getVisualSize().height > 0)
+ return true;
+ else if (graph.equals(this.getActiveGraph()))
+ return true;
+ else
+ return false;
+ }
+
+ // this method adds listeners to graph selections
+ private void addMouseListeners(final GraphComponentWrapper wrap,
+ FigureCanvas graphCanvas) {
+ if (wrap.panel == null)
+ return;
+
+ if (wrap.graphComponent instanceof MouseMotionListener) {
+ wrap.panel
+ .addMouseMotionListener((MouseMotionListener) wrap.graphComponent);
+ }
+
+ if (wrap.graphComponent instanceof MouseMoveListener) {
+ if (graphCanvas != null)
+ graphCanvas
+ .addMouseMoveListener((MouseMoveListener) wrap.graphComponent);
+ }
+
+ if (wrap.graphComponent instanceof MouseListener) {
+ if (graphCanvas != null)
+ graphCanvas
+ .addMouseListener((MouseListener) wrap.graphComponent);
+ }
+
+ if (graphCanvas == null)
+ return;
+
+ final FigureCanvas graphCanvasFinal = graphCanvas;
+ graphCanvas.addMouseListener(new MouseListener() {
+ public void mouseDown(MouseEvent me) {
+ // for button 3, show the popup context menu
+ if (me.button == 3) // button 3
+ {
+ final int x = me.x; // don't worry about me.x, this is
+ // always a valid coordinate within the
+ // panel
+ final int y = me.y;
+ final MouseEvent meFinal = me;
+ Display.getDefault().syncExec(new Runnable() {
+ public void run() {
+ Menu menu = TestGUI.getInstance()
+ .getGraphPopupMenu(
+ profVisu.getContentPane()
+ .getShell(), true);
+
+ // add submenu items
+ addSubGraphMenuItems(menu, meFinal);
+ menu.setLocation(graphCanvasFinal.toDisplay(x, y));
+ }
+ });
+ return;
+ }
+
+ /*
+ * for other buttons, we may be deleting the current graph
+ * selection or, by dragging, creating a new selection
+ */
+ buttonDown = true;
+ dragOn = false;
+
+ // me.x will always be a valid coordinate within the Widget,
+ // rounded to the nearest millisecond
+ // since this is the FigureCanvas, not the Panel, adjust x
+ selectionStart = (int) ((me.x + getScrolledOrigin().x) * scale + .0005);
+
+ origStart = selectionStart;
+
+ // send the message to the component under the mouse
+ if (me.getSource() instanceof GraphComponentWrapper) {
+ GenericTraceGraph source = ((GraphComponentWrapper) me
+ .getSource()).getGraphComponent();
+ if (source instanceof PIEventListener
+ && hasToBeUpdated(source)) {
+ PIEventListener lis = (PIEventListener) source;
+
+ for (int i = 0; i < graphComponents.size(); i++) {
+ GenericTraceGraph possible = (GenericTraceGraph) graphComponents
+ .get(i).graphComponent;
+ if (possible.equals(source)) {
+ PIEvent be = new PIEvent(source,
+ PIEvent.MOUSE_PRESSED);
+ lis.piEventReceived(be);
+ }
+ }
+ }
+ }
+ }
+
+ public void mouseUp(MouseEvent me) {
+ // ignore releases of button 3 (context menu button)
+ if (me.button == 3) // button 3
+ return;
+
+ // otherwise, either remove the current selection or replace it
+ // with a new one
+ buttonDown = false;
+
+ if (dragOn) // if dragging was done
+ {
+ if (selectionStart == selectionEnd) {
+ // no range is selected
+ selectionStart = -1;
+ selectionEnd = -1;
+ }
+ if (selectionStart < 0 && selectionStart != -1) {
+ selectionStart = 0;
+ }
+
+ double maxEndTime = PIPageEditor.currentPageEditor()
+ .getMaxEndTime() * 1000;
+ if (selectionStart > maxEndTime) {
+ // no range is selected
+ selectionStart = 0;
+ selectionEnd = 0;
+ profVisu.getTimeString().setText(
+ ProfileVisualiser.getTimeInterval(
+ selectionStart / 1000,
+ selectionEnd / 1000));
+ } else if (selectionEnd > maxEndTime) {
+ selectionEnd = maxEndTime + .0005;
+ profVisu.getTimeString().setText(
+ ProfileVisualiser.getTimeInterval(
+ selectionStart / 1000,
+ selectionEnd / 1000));
+ }
+
+ setSelectionFields();
+
+ // inform all subcomponents that the selection area has
+ // changed
+ PIEvent be = new PIEvent(new double[] { selectionStart,
+ selectionEnd }, PIEvent.SELECTION_AREA_CHANGED);
+ sendEventToSubComponents(be);
+ repaintComponent();
+
+ // since some pages that depend on the selection start and
+ // end times may not have
+ // graph components (e.g., the function call plugin page),
+ // also let listening plugins know
+ Enumeration e = PluginInitialiser
+ .getPluginInstances(NpiInstanceRepository
+ .getInstance().activeUid(),
+ "com.nokia.carbide.cpp.internal.pi.plugin.model.IEventListener"); //$NON-NLS-1$
+ if (e != null) {
+ Event event = new Event();
+ event.start = (int) selectionStart;
+ event.end = (int) selectionEnd;
+
+ while (e.hasMoreElements()) {
+ IEventListener plugin = (IEventListener) e
+ .nextElement();
+ plugin.receiveEvent("changeSelection", event); //$NON-NLS-1$
+ }
+ }
+
+ dragOn = false;
+ }
+ }
+
+ public void mouseDoubleClick(MouseEvent me) {
+ sendEventToSubGraphs(PICompositePanel.MOUSE_DOUBLECLICK, me);
+ buttonDown = false;
+ }
+ });
+
+ graphCanvas.addMouseMoveListener(new MouseMoveListener() {
+ public void mouseMove(MouseEvent me) {
+
+ int xOrigin = getScrolledOrigin().x;
+
+ me.x += xOrigin;
+
+ if (!buttonDown) {
+ sendEventToSubGraphs(PICompositePanel.MOUSE_MOVE, me);
+ return;
+ }
+
+ // dragging is moving the mouse while a button (other than
+ // button 3) is down
+ dragOn = true;
+
+ // round to the nearest millisecond
+ selectionEnd = (int) (me.x * scale + .0005);
+
+ // mouse event may return out of range X, that may
+ // crash when we use it to index data array
+ selectionEnd = selectionEnd >= 0 ? selectionEnd : 0;
+
+ if (me.x >= xOrigin + sashForm.getBounds().width) {
+ selectionEnd = ((int) ((xOrigin
+ + sashForm.getBounds().width - 1)
+ * scale + .0005));
+ }
+
+ if (selectionEnd < origStart) // if selection is drawn from
+ // right to left
+ {
+ selectionStart = selectionEnd;
+ selectionEnd = origStart;
+ } else if (selectionEnd > origStart) {
+ selectionStart = origStart;
+ }
+
+ setSelectionFields();
+
+ PIPageEditor.currentPageEditor().setLocalTime(
+ selectionStart / 1000, selectionEnd / 1000);
+
+ // until mouse button is released, change the time interval
+ // display only on this page
+ profVisu.getTimeString().setText(
+ ProfileVisualiser.getTimeInterval(
+ selectionStart / 1000, selectionEnd / 1000));
+
+ drawSelectionRect(me);
+ repaintComponent();
+
+ // why is this not in repaintComponent?
+ wrap.panel.repaint();
+ }
+ });
+ }
+
+ private void drawSelectionRect(MouseEvent me) {
+ if ((me.getSource() == null)
+ || !(me.getSource() instanceof Control/* Panel */))
+ return;
+
+ // do not use scrolled.getContent().getBounds() because that is the
+ // whole
+ // length, not the visable one
+ Rectangle rect = this.sashForm.getBounds();
+ Point origin = getScrolledOrigin();
+
+ int newX;
+ int tmpMeX = me.x;
+
+ // mouse event may return out of range X, that may
+ // crash when we use it to index data array
+ tmpMeX = tmpMeX >= 0 ? tmpMeX : 0;
+ if (tmpMeX >= origin.x + sashForm.getBounds().width) {
+ tmpMeX = origin.x + sashForm.getBounds().width - 1;
+ }
+
+ if (tmpMeX - origin.x < 20) {
+ newX = tmpMeX - 20;
+ if (newX < 0)
+ newX = 0;
+ } else {
+ newX = tmpMeX + 20;
+ }
+
+ boolean changeOrigin = false;
+
+ // Scroll each of the windows in the ScrolledComposite so that the
+ // rectangle is visible
+ if (newX < origin.x) {
+ // scroll to the left
+ this.setScrolledOrigin(newX, origin.y);
+ changeOrigin = true;
+ } else if (newX > origin.x + rect.width) {
+ // scroll to the right
+ this.setScrolledOrigin(newX - rect.width, origin.y);
+ changeOrigin = true;
+ }
+
+ if (changeOrigin) {
+ // since other pages associated with the GppTraceGraph scroll when
+ // this page scrolls,
+ // also let listening plugins know
+ Enumeration enu = PluginInitialiser
+ .getPluginInstances(NpiInstanceRepository.getInstance()
+ .activeUid(),
+ "com.nokia.carbide.cpp.internal.pi.plugin.model.IEventListener"); //$NON-NLS-1$
+ if (enu != null) {
+ origin = getScrolledOrigin();
+ Event event = new Event();
+ event.x = origin.x;
+ event.y = origin.y;
+ event.data = "FigureCanvas"; //$NON-NLS-1$
+
+ while (enu.hasMoreElements()) {
+ IEventListener plugin = (IEventListener) enu.nextElement();
+ plugin.receiveEvent("scroll", event); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+
+ public PIVisualSharedData getSharedData() {
+ return this.sharedData;
+ }
+
+ public void setToolTipTextForGraphComponent(GenericTraceGraph graph,
+ String text) {
+ if (this.graphComponents != null) {
+ for (int i = 0; i < graphComponents.size(); i++) {
+ GraphComponentWrapper wrap = graphComponents.get(i);
+ if (wrap.graphComponent.equals(graph)) {
+ wrap.figureCanvas.setToolTipText(text);
+ }
+ }
+ }
+ }
+
+ public void setScrolledOrigin(int x, int y) {
+ if (this.graphComponents != null) {
+ for (int i = 0; i < graphComponents.size(); i++) {
+ FigureCanvas figureCanvas = graphComponents.get(i).figureCanvas;
+
+ if (figureCanvas == null)
+ continue;
+
+ figureCanvas.getViewport().setViewLocation(x, y);
+ if (figureCanvas.getViewport().getViewLocation().x != x) {
+ // force the viewport to accept the new value
+ figureCanvas.getViewport().getHorizontalRangeModel()
+ .setMaximum(this.sizeX);
+ figureCanvas.getViewport().setViewLocation(x, y);
+ }
+ }
+ }
+ }
+
+ public Point getScrolledOrigin() {
+ // this assumes that setScrolledOrigin() is keeping all graphs scrolled
+ // the same amount
+ if (this.graphComponents == null)
+ return null;
+ else
+ return graphComponents.get(0).figureCanvas.getViewport()
+ .getViewLocation();
+ }
+
+ public void setCurrentInfoComponent(Component currentComponent) {
+ this.profVisu.vPanelRepaint(currentComponent);
+ }
+
+ private void sendEventToSubGraphs(int type, MouseEvent me) {
+ FigureCanvas figureCanvas;
+ GraphComponentWrapper component = null;
+
+ if (!(me.getSource() instanceof FigureCanvas))
+ return;
+
+ figureCanvas = (FigureCanvas) me.getSource();
+
+ // find the component whose FigureCanvas this is
+ for (int i = 0; i < this.graphComponents.size(); i++)
+ if (this.graphComponents.get(i).figureCanvas == figureCanvas) {
+ component = this.graphComponents.get(i);
+ break;
+ }
+
+ if (component == null)
+ return;
+
+ // loop through the subcomponents, finding listeners
+ for (int i = 0; i < component.subGraphs.size(); i++) {
+ GraphComponentWrapper subComponents = component.subGraphs.get(i);
+ Object subgraphComponent = subComponents.getGraphComponent();
+ if (subgraphComponent instanceof MouseListener) {
+ MouseListener listener = (MouseListener) subgraphComponent;
+ if (type == PICompositePanel.MOUSE_DOUBLECLICK)
+ listener.mouseDoubleClick(me);
+ else if (type == PICompositePanel.MOUSE_DOWN)
+ listener.mouseDown(me);
+ }
+ if (subgraphComponent instanceof MouseMoveListener) {
+ MouseMoveListener listener = (MouseMoveListener) subgraphComponent;
+ if (type == PICompositePanel.MOUSE_MOVE)
+ listener.mouseMove(me);
+ }
+ }
+ }
+
+ private void addSubGraphMenuItems(Menu menu, MouseEvent me) {
+ FigureCanvas figureCanvas;
+ GraphComponentWrapper component = null;
+
+ if (!(me.getSource() instanceof FigureCanvas))
+ return;
+
+ figureCanvas = (FigureCanvas) me.getSource();
+
+ // find the component whose FigureCanvas this is
+ for (int i = 0; i < this.graphComponents.size(); i++)
+ if (this.graphComponents.get(i).figureCanvas == figureCanvas) {
+ component = this.graphComponents.get(i);
+ break;
+ }
+
+ if (component == null)
+ return;
+
+ // find this component's context menu items
+ if (component.graphComponent instanceof IContextMenu) {
+ ((IContextMenu) component.graphComponent).addContextMenuItems(menu,
+ me);
+ }
+
+ // loop through the subcomponents, finding context menu items
+ for (int i = 0; i < component.subGraphs.size(); i++) {
+ GraphComponentWrapper subComponents = component.subGraphs.get(i);
+ Object subgraphComponent = subComponents.getGraphComponent();
+ if (subgraphComponent instanceof IContextMenu) {
+ ((IContextMenu) subgraphComponent)
+ .addContextMenuItems(menu, me);
+ }
+ }
+ }
+
+ private void sendEventToSubComponents(Object event) {
+ for (int i = 0; i < graphComponents.size(); i++) {
+ GenericTraceGraph component = graphComponents.get(i)
+ .getGraphComponent();
+
+ // forward the events only if the component has height
+ // which means that it is not hidden, or if the component is
+ // the currently active component
+ if (hasToBeUpdated(component)) {
+ if (event instanceof ActionEvent
+ && component instanceof ActionListener) {
+ ((ActionListener) component)
+ .actionPerformed((ActionEvent) event);
+ }
+ if (event instanceof PIEvent
+ && component instanceof PIEventListener) {
+ ((PIEventListener) component)
+ .piEventReceived((PIEvent) event);
+ }
+ if (event instanceof FocusEvent
+ && component instanceof FocusListener) {
+ FocusEvent fe = (FocusEvent) event;
+ if (fe.getID() == FocusEvent.FOCUS_GAINED) {
+ ((FocusListener) component).focusGained(fe);
+ } else if (fe.getID() == FocusEvent.FOCUS_LOST) {
+ ((FocusListener) component).focusLost(fe);
+ }
+ }
+ }
+ }
+ }
+
+ private void sendEventToActiveSubComponent(Object event) {
+ Object component = this.getActiveGraph();
+
+ if (event instanceof ActionEvent && component instanceof ActionListener) {
+ ((ActionListener) component).actionPerformed((ActionEvent) event);
+ }
+ if (event instanceof PIEvent && component instanceof PIEventListener) {
+ ((PIEventListener) component).piEventReceived((PIEvent) event);
+ }
+ if (event instanceof FocusEvent && component instanceof FocusListener) {
+ FocusEvent fe = (FocusEvent) event;
+ if (fe.getID() == FocusEvent.FOCUS_GAINED) {
+ ((FocusListener) component).focusGained(fe);
+ } else if (fe.getID() == FocusEvent.FOCUS_LOST) {
+ ((FocusListener) component).focusLost(fe);
+ }
+ }
+ }
+
+ public void piEventReceived(PIEvent be) {
+ this.sendEventToSubComponents(be);
+ }
+
+ public void selectionChanged() {
+ this.selectFrame();
+ PIEvent be = new PIEvent(new double[] { selectionStart, selectionEnd },
+ PIEvent.SELECTION_AREA_CHANGED);
+ this.sendEventToSubComponents(be);
+ }
+
+ public void actionPerformed(ActionEvent ae) {
+ this.sendEventToSubComponents(ae);
+ if ((ae.getActionCommand() == "start") //$NON-NLS-1$
+ || (ae.getActionCommand() == "end")) //$NON-NLS-1$
+ {
+ this.selectFrame();
+ PIEvent be = new PIEvent(new double[] { selectionStart,
+ selectionEnd }, PIEvent.SELECTION_AREA_CHANGED);
+ this.sendEventToSubComponents(be);
+ }
+ }
+
+ public void focusGained(FocusEvent fe) {
+ }
+
+ public void paintComponent(PaintEvent paintEvent) {
+ this.refreshSubcomponentValues();
+ }
+
+ public void repaintComponent() {
+ this.refreshSubcomponentValues();
+ }
+
+ public void paintLeftLegend() {
+ if (this.graphComponents != null) {
+ // for each graph component set updated values
+ for (int i = 0; i < graphComponents.size(); i++) {
+ GraphComponentWrapper wrap = graphComponents.get(i);
+ if (wrap.leftLegend != null) {
+ wrap.leftLegend.redraw();
+ }
+ }
+ }
+ }
+
+ private void refreshSubcomponentValues() {
+ if (this.graphComponents != null) {
+ // for each graph component set updated values
+ for (int i = 0; i < graphComponents.size(); i++) {
+ GraphComponentWrapper wrap = graphComponents.get(i);
+ GenericTraceGraph component = wrap.getGraphComponent();
+ component.setSize(this.sizeX, this.sizeY);
+ component.setScale(this.scale);
+ component.setSelectionEnd(this.selectionEnd);
+ component.setSelectionStart(this.selectionStart);
+ if (wrap.figureCanvas != null) {
+ component.setVisualSize(
+ wrap.figureCanvas.getClientArea().width,
+ wrap.figureCanvas.getClientArea().height);
+ wrap.figureCanvas.redraw();
+ wrap.leftLegend.redraw();
+ }
+ }
+ }
+ }
+
+ public void addGraphComponent(GenericTraceGraph component, String title,
+ Class pluginClass, GraphDrawRequest request) {
+ // insert CompositePanel into wrapper and put it into top part of the
+ // splitpane
+ component.importParentComponent(this);
+
+ GraphComponentWrapper wrap;
+
+ // add the wrapper to the SashForm
+ wrap = new GraphComponentWrapper(this, component, request, pluginClass
+ .getName());
+ this.graphComponents.add(wrap);
+
+ FigureCanvas graphCanvas = null;
+
+ // This treats all getGraphClassToDraw editor pages the same
+ if (request == null
+ || request.getGraphClassToDraw(component.graphIndex).size() == 0) {
+ graphCanvas = wrap.setCanvas(component, title, this.sashForm,
+ SWT.NONE);
+ }
+
+ // add any mouse listeners from the base class
+ this.addMouseListeners(wrap, graphCanvas);
+ repaintComponent();
+
+ for (int i = 0; i < graphComponents.size(); i++) {
+ wrap = graphComponents.get(i);
+ wrap.newPluginAdded();
+ }
+ }
+
+ public void setSelectionFields(int selectionStart, int selectionEnd) {
+ this.selectionStart = selectionStart;
+ this.selectionEnd = selectionEnd;
+ setSelectionFields();
+ }
+
+ private void setSelectionFields() {
+ if (selectionStart == -1 || selectionEnd == -1) {
+ this.profVisu.setTimeInterval(0, 0);
+ this.selectionStart = -1;
+ this.selectionEnd = -1;
+ } else {
+ double start = selectionStart / 1000;
+ double end = selectionEnd / 1000;
+
+ if ((PIPageEditor.currentPageEditor().getStartTime() != start)
+ || (PIPageEditor.currentPageEditor().getEndTime() != end)) {
+ this.profVisu.setTimeInterval(start, end);
+ this.profVisu.action("changeInterval"); //$NON-NLS-1$
+ }
+ }
+ }
+
+ public double getSelectionStart() {
+ return this.selectionStart;
+ }
+
+ public double getSelectionEnd() {
+ return this.selectionEnd;
+ }
+
+ /*
+ * Check the current page editor's start and end times
+ */
+ public boolean validInterval() {
+ if ((PIPageEditor.currentPageEditor().getStartTime() < 0.0f)
+ || (PIPageEditor.currentPageEditor().getEndTime() < 0.0f))
+ return false;
+
+ int start = (int) (PIPageEditor.currentPageEditor().getStartTime() * 1000);
+ int end = (int) (PIPageEditor.currentPageEditor().getEndTime() * 1000);
+
+ if (start > this.lastSampleX)
+ start = this.lastSampleX;
+
+ if (end > this.lastSampleX)
+ end = this.lastSampleX;
+
+ if ((start >= end) || (start < 0))
+ return false;
+
+ return true;
+ }
+
+ /*
+ * Based on the current page editor's start and end times, set this
+ * PICompositePanel's start and end times.
+ */
+ private void selectFrame() {
+ if ((PIPageEditor.currentPageEditor().getStartTime() < 0.0f)
+ || (PIPageEditor.currentPageEditor().getEndTime() < 0.0f))
+ return;
+
+ double start = PIPageEditor.currentPageEditor().getStartTime();
+ double end = PIPageEditor.currentPageEditor().getEndTime();
+
+ selectionStart = start * 1000;
+ selectionEnd = end * 1000;
+
+ if (selectionStart > (double) this.lastSampleX)
+ selectionStart = (double) this.lastSampleX;
+
+ if (selectionEnd > (double) this.lastSampleX)
+ selectionEnd = (double) this.lastSampleX;
+
+ if ((selectionEnd - selectionStart) <= 0.5) {
+ selectionStart = -1;
+ selectionEnd = -1;
+ }
+
+ if (selectionStart < 0 && selectionStart != -1) {
+ selectionStart = 0;
+ }
+
+ setSelectionFields();
+ repaintComponent();
+
+ for (int i = 0; i < graphComponents.size(); i++) {
+ FigureCanvas figureCanvas = graphComponents.get(i).figureCanvas;
+ if (figureCanvas != null)
+ figureCanvas.update();
+ }
+ }
+
+ public void zoomTo(double start, double end) {
+ this.scale = 10;
+ this.setSizeX(false);
+
+ // Window size
+ Composite parent = NpiInstanceRepository.getInstance()
+ .activeUidGetParentComposite();
+ if (parent == null) {
+ // no parent composite is only for temp instance used by non-GUI
+ // importer
+ GeneralMessages.showErrorMessage(Messages
+ .getString("PICompositePanel.0")); //$NON-NLS-1$
+ return;
+ }
+
+ Rectangle window = parent.getBounds();
+
+ // it shouldn't be, but it happened
+ if (window.width <= 0)
+ return;
+
+ // Set new scale
+ int windowLength = window.width;
+ double traceLength = end - start;
+ double dFactor = ((double) traceLength / (double) windowLength) * 10;
+
+ this.scale = dFactor;
+
+ // Snap to next Zoom out factor unless it fits exactly
+ if (this.scale != nextScale(nextScale(this.scale, true), false))
+ this.scale = nextScale(this.scale, true);
+
+ // inform all subcomponents
+ PIEvent be = new PIEvent(new Double(scale), PIEvent.SCALE_CHANGED);
+ this.sendEventToSubComponents(be);
+
+ this.setSizeX(false);
+ repaintComponent();
+ }
+
+ public void forceSizeX() {
+
+ }
+
+ public void setSizeX(boolean forceUpdate) {
+ double sample = this.lastSampleX;
+ int prefSize = (int) (sample / scale);
+
+ if ((this.preferredSizeX == prefSize)
+ && (this.sizeX == this.preferredSizeX) && !forceUpdate)
+ return;
+
+ this.preferredSizeX = prefSize;
+ this.sizeX = this.preferredSizeX;
+
+ // make sure all graphs of this sashForm get the new width
+ Control[] controls = this.sashForm.getChildren();
+
+ for (int i = 0; i < controls.length; i++) {
+ if (!(controls[i] instanceof GraphComposite))
+ continue;
+
+ GraphComposite composite = (GraphComposite) controls[i];
+ FigureCanvas figureCanvas = composite.figureCanvas;
+ Panel panel = (Panel) figureCanvas.getContents();
+
+ panel.setPreferredSize(prefSize, this.preferredSizeY);
+ if (prefSize >= figureCanvas.getClientArea().width) {
+ panel.setSize(prefSize, this.preferredSizeY);
+ }
+
+ }
+
+ this.sashForm.layout();
+ this.sashForm.redraw();
+ }
+
+ public void setActive(GenericTraceGraph graph) {
+ activeGraph = graph;
+ }
+
+ public GenericTraceGraph getActiveGraph() {
+ return activeGraph;
+ }
+
+ public void setSelectionCenter() {
+ if (selectionStart == -1 && selectionEnd == -1) {
+ this.updateVisibleCenter();
+ return;
+ }
+ previousScale = scale;
+
+ Rectangle window = this.sashForm.getBounds();
+
+ int uid = NpiInstanceRepository.getInstance().activeUid();
+ if (window.width == 0) {
+ // use the width from the active page
+ int currentPage = PIPageEditor.currentPageEditor().getCurrentPage();
+ window = NpiInstanceRepository.getInstance().getProfilePage(uid,
+ currentPage).getTopComposite().getSashForm().getBounds();
+ }
+
+ // Whole trace
+ double selectionLength = selectionEnd - selectionStart;
+ double selectionMiddle = selectionStart + (selectionLength / 2);
+ int windowLength = (int) (window.width * (this.scale / 10));
+ int newPositionX = (int) ((selectionMiddle / 10) - ((double) windowLength / 2));
+
+ newPositionX = (int) ((double) newPositionX / (this.scale / 10));
+
+ if (newPositionX < 0) {
+ newPositionX = 0;
+ }
+
+ this.setScrolledOrigin(newPositionX, 0);
+ repaintComponent();
+ }
+
+ private void updateVisibleCenter() {
+ double centerPosition = getSelection()
+ + (this.sashForm.getBounds().width / 2);
+
+ if (scale < previousScale)
+ centerPosition = centerPosition * previousScale / scale;
+ else if (scale > previousScale)
+ centerPosition = centerPosition * scale / previousScale;
+
+ previousScale = scale;
+
+ centerPosition = centerPosition - this.sashForm.getBounds().width / 2;
+
+ setOrigin((int) centerPosition, 0);
+ repaintComponent();
+ }
+
+ private int getSelection() {
+ if (this.slider == null)
+ return 0;
+ else
+ return this.slider.getSelection();
+ }
+
+ private void setOrigin(int originX, int originY) {
+ // for all components in the sashForm, except the one with the slider,
+ // adjust the graphs
+ }
+
+ public void performSynchronise() {
+ if (dialog == null) {
+ // dialog = new JFrame();
+ dialog = new JDialog();
+ dialog.setTitle("Syncronise"); //$NON-NLS-1$
+ dialogPanel = new SynchroniseDialog(this);
+ dialog.setContentPane(dialogPanel);
+ dialog.setSize(200, 100);
+ dialog.setLocation(50, 50);
+ dialog.setResizable(false);
+ dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
+ }
+ dialog.setVisible(true);
+ }
+
+ public void synchroniseOk() {
+ dialog.dispose();
+ String synchString = dialogPanel.getGppFileName();
+ Double synchValue = new Double(synchString);
+ PIEvent be = new PIEvent(synchValue, PIEvent.SYNCHRONISE);
+ this.sendEventToActiveSubComponent(be);
+ repaintComponent();
+ }
+
+ public void synchroniseCancel() {
+ dialog.dispose();
+ }
+
+ /**
+ * using log10 to extract the first digit in decimal and make any number
+ * fall into buckets to promote/demote to scale of ..., 0.1, 0.2, 0.5, 1, 2,
+ * 5 ...
+ */
+ private double nextScale(double scale, boolean bigger) {
+ double logScale = Math.log10(scale);
+ double floorLogScale = Math.floor(Math.log10(scale));
+ double mostSignificantDigit = Math.rint(Math.pow(10,
+ (logScale - floorLogScale)));
+ double powerOfTen = Math.pow(10, floorLogScale);
+
+ if (bigger) {
+ if (mostSignificantDigit < 2) {
+ mostSignificantDigit = 2;
+ } else if (mostSignificantDigit < 5) {
+ mostSignificantDigit = 5;
+ } else {
+ mostSignificantDigit = 10;
+ }
+ } else {
+ if (mostSignificantDigit > 5) {
+ mostSignificantDigit = 5;
+ } else if (mostSignificantDigit > 2) {
+ mostSignificantDigit = 2;
+ } else if (mostSignificantDigit > 1) {
+ mostSignificantDigit = 1;
+ } else {
+ mostSignificantDigit = 0.5;
+ }
+ }
+
+ double result = mostSignificantDigit * powerOfTen;
+
+ if (result < 0.1)
+ result = 0.1;
+
+ return result;
+ }
+
+ public void performZoomCommand(String zoomCommand) {
+ // only apply when the currently visible page has a graph
+ if (getActiveGraph() == null)
+ return;
+
+ int uid = NpiInstanceRepository.getInstance().activeUid();
+
+ if (zoomCommand.equals("changeInterval")) { //$NON-NLS-1$
+ // just use a refresh because drag select uses this too
+ // we keep this update here instead of in ProfileVisualiser
+ // to consolidate all screen related calls to be in this file
+ getSashForm().update();
+ return;
+ }
+
+ // the rest are all real zoom command that need repaint on of the image
+ for (int i = 0; i < graphComponents.size(); i++) {
+ GraphComponentWrapper wrap = graphComponents.get(i);
+ GenericTraceGraph component = wrap.getGraphComponent();
+ component.setGraphImageChanged(true);
+ }
+
+ // zoom out
+ if (zoomCommand.equals("+")) //$NON-NLS-1$
+ {
+ PICompositePanel visibleComposite = NpiInstanceRepository
+ .getInstance().getProfilePage(uid,
+ PIPageEditor.currentPageIndex()).getTopComposite();
+ Composite parent = NpiInstanceRepository.getInstance()
+ .activeUidGetParentComposite();
+ if (parent == null) {
+ // no parent composite is only for temp instance used by non-GUI
+ // importer
+ GeneralMessages.showErrorMessage(Messages
+ .getString("PICompositePanel.1")); //$NON-NLS-1$
+ return;
+ }
+
+ // bail out if we already made the whole graph visible
+ if (visibleComposite.lastSampleX / scale <= parent.getBounds().width) // TODO
+ // visibleComposite
+ return;
+
+ // if the scale will not change, do not redraw
+ if (scale == nextScale(scale, true))
+ return;
+
+ scale = nextScale(scale, true);
+
+ PIEvent be = new PIEvent(new Double(scale), PIEvent.SCALE_CHANGED);
+ this.sendEventToSubComponents(be);
+
+ this.setSizeX(false);
+ this.setSelectionCenter();
+ }
+ // zoom in
+ else if (zoomCommand.equals("-")) //$NON-NLS-1$
+ {
+ // if the scale will not change, do not redraw
+ if (scale <= 0)
+ return;
+
+ if (scale == nextScale(scale, false))
+ return;
+
+ scale = nextScale(scale, false);
+
+ PIEvent be = new PIEvent(new Double(scale), PIEvent.SCALE_CHANGED);
+ this.sendEventToSubComponents(be);
+
+ this.setSizeX(false);
+ this.setSelectionCenter();
+ }
+ // show whole graph
+ else if (zoomCommand.equals("++")) //$NON-NLS-1$
+ {
+ PICompositePanel visibleComposite = NpiInstanceRepository
+ .getInstance().getProfilePage(uid,
+ PIPageEditor.currentPageIndex()).getTopComposite();
+
+ performZoomToGraph(visibleComposite,
+ NpiInstanceRepository.getInstance()
+ .activeUidGetParentComposite().getBounds().width);
+ }
+ // zoom to selected time interval
+ else if (zoomCommand.equals("--")) //$NON-NLS-1$
+ {
+ selectFrame();
+ if (selectionStart != -1 && selectionEnd != -1) {
+ zoomTo(selectionStart / 10, selectionEnd / 10);
+ setSelectionCenter();
+ } else {
+ GeneralMessages
+ .showErrorMessage(Messages
+ .getString("PICompositePanel.selectNonEmptyTimeInterval")); //$NON-NLS-1$
+ }
+ }
+ }
+
+ public void performZoomToGraph(PICompositePanel visibleComposite, int width) {
+ // left margin is not available for painting
+ int availableWidth = width - GenericTraceGraph.yLegendWidth;
+ // NOTE: assumes tabs without graphs have sample == 0
+ if (visibleComposite.lastSampleX <= 0)
+ return;
+
+ double new_scale = scale;
+
+ // first zoom in until it is too big to fit
+ while (visibleComposite.lastSampleX / new_scale <= availableWidth)
+ new_scale = nextScale(new_scale, false);
+
+ // now zoom out until it just fits
+ while (visibleComposite.lastSampleX / new_scale > availableWidth)
+ new_scale = nextScale(new_scale, true);
+
+ if (new_scale == scale)
+ return;
+
+ scale = new_scale;
+
+ PIEvent be = new PIEvent(new Double(scale), PIEvent.SCALE_CHANGED);
+ this.sendEventToSubComponents(be);
+
+ this.setSizeX(false);
+ this.setSelectionCenter();
+ }
+
+ public class GraphComponentWrapper {
+ public GenericTraceGraph graphComponent;
+ public FigureCanvas leftLegend;
+ public FigureCanvas figureCanvas;
+ public Panel panel = null;
+ public ArrayList<GraphComponentWrapper> subGraphs;
+ private GraphDrawRequest howToDraw;
+ private String myPluginName;
+ private PICompositePanel compositePanel;
+
+ public GraphComponentWrapper(PICompositePanel compositePanel,
+ GenericTraceGraph graph, GraphDrawRequest howToDraw,
+ String myPluginName) {
+ this.compositePanel = compositePanel;
+ this.graphComponent = graph;
+ this.howToDraw = howToDraw;
+ this.myPluginName = myPluginName;
+
+ this.subGraphs = new ArrayList<GraphComponentWrapper>();
+ }
+
+ public FigureCanvas setCanvas(GenericTraceGraph component,
+ String title, Composite parent, int style) {
+ final GenericTraceGraph componentFinal = component;
+ final ArrayList<GraphComponentWrapper> subGraphsFinal = this.subGraphs;
+ final GraphComponentWrapper wrapFinal = this;
+ final PICompositePanel compositePanelFinal = this.compositePanel;
+
+ GraphComposite composite = new GraphComposite(parent, style, title);
+ this.leftLegend = composite.leftLegend;
+ this.figureCanvas = composite.figureCanvas;
+
+ this.leftLegend.setBackground(ColorPalette.getColor(new RGB(255,
+ 255, 255)));
+ final FigureCanvas leftLegendFinal = leftLegend;
+ leftLegend.addControlListener(new ControlAdapter() {
+ public void controlResized(ControlEvent e) {
+ leftLegendFinal.setSize(GenericTraceGraph.yLegendWidth,
+ leftLegendFinal.getSize().y);
+ componentFinal.paintLeftLegend(leftLegendFinal, null);
+ }
+ });
+
+ leftLegend.addPaintListener(new PaintListener() {
+ public void paintControl(PaintEvent e) {
+ // draw only if the graph is visible
+ if (compositePanelFinal.hasToBeUpdated(componentFinal))
+ componentFinal.paintLeftLegend(leftLegendFinal, e.gc);
+ }
+ });
+
+ this.figureCanvas.setBackground(ColorPalette.getColor(new RGB(255,
+ 255, 255)));
+
+ if (this.panel == null) {
+ this.panel = new Panel() {
+ public void paint(Graphics graphics) {
+ // draw only if the graph is visible
+ if (compositePanelFinal.hasToBeUpdated(componentFinal)) {
+ componentFinal.paint(this, graphics);
+
+ for (int i = 0; i < subGraphsFinal.size(); i++) {
+ GraphComponentWrapper wrap = subGraphsFinal
+ .get(i);
+ wrap.setVisualParametersFrom(wrapFinal);
+ wrap.graphComponent.paint(panel, graphics);
+ }
+ }
+ }
+ };
+ }
+ panel.setLayoutManager(new FlowLayout());
+ figureCanvas.setContents(panel);
+
+ // listen for when the horizontal scroll bar is selected
+ final ScrollBar horizontalBar = figureCanvas.getHorizontalBar();
+
+ horizontalBar.addSelectionListener(new SelectionListener() {
+ public void widgetSelected(SelectionEvent e) {
+ // since other pages associated with the GppTraceGraph
+ // scroll when this page scrolls,
+ // also let listening plugins know
+ Enumeration enu = PluginInitialiser
+ .getPluginInstances(NpiInstanceRepository
+ .getInstance().activeUid(),
+ "com.nokia.carbide.cpp.internal.pi.plugin.model.IEventListener"); //$NON-NLS-1$
+ if (enu != null) {
+ Event event = new Event();
+ event.x = figureCanvas.getViewport().getViewLocation().x;
+ event.y = figureCanvas.getViewport().getViewLocation().y;
+ event.data = "FigureCanvas"; //$NON-NLS-1$
+
+ while (enu.hasMoreElements()) {
+ IEventListener plugin = (IEventListener) enu
+ .nextElement();
+ plugin.receiveEvent("scroll", event); //$NON-NLS-1$
+ }
+ }
+ }
+
+ public void widgetDefaultSelected(SelectionEvent e) {
+ widgetSelected(e);
+ }
+ });
+
+ // minor scroll is 10 pixels
+ horizontalBar.setIncrement(10);
+
+ // major scroll is the width of the window
+ horizontalBar.setPageIncrement(figureCanvas.getBounds().width);
+ figureCanvas.addControlListener(new ControlAdapter() {
+ public void controlResized(ControlEvent e) {
+ horizontalBar
+ .setPageIncrement(figureCanvas.getBounds().width);
+ graphComponent.setGraphImageChanged(true);
+ graphComponent.repaint();
+ }
+ });
+
+ return this.figureCanvas;
+ }
+
+ public void setVisualParametersFrom(GraphComponentWrapper parent) {
+ if (graphComponent == null)
+ return;
+
+ GenericTraceGraph gtg = parent.getGraphComponent();
+ this.graphComponent.setScale(gtg.getScale());
+ this.graphComponent.setVisualSize(gtg.getVisualSizeX(), gtg
+ .getVisualSizeY());
+ }
+
+ public void newPluginAdded()// ArrayList<GraphComponentWrapper>
+ // graphComponents)
+ {
+ if (this.myPluginName == null)
+ return;
+
+ this.subGraphs.clear();
+
+ for (int i = 0; i < graphComponents.size(); i++) {
+ GraphComponentWrapper wrap = graphComponents.get(i);
+ if (wrap.howToDraw != null) {
+ // This treats all getGraphClassToDraw editor pages the same
+ ArrayList e2 = wrap.howToDraw
+ .getGraphClassToDraw(wrap.graphComponent.graphIndex);
+ for (int j = 0; j < e2.size(); j++) {
+ String s = (String) e2.get(j);
+ if (this.myPluginName.equals(s)) {
+ this.subGraphs.add(wrap);
+ }
+ }
+ }
+ }
+ }
+
+ public GenericTraceGraph getGraphComponent() {
+ return this.graphComponent;
+ }
+ }
+
+ public double getScale() {
+ return scale;
+ }
+
+ public ProfileVisualiser getVisualiser() {
+ return this.profVisu;
+ }
+
+ public void selectWholeGraph() {
+
+ // Get visible composite
+ int uid = NpiInstanceRepository.getInstance().activeUid();
+ PICompositePanel visibleComposite = NpiInstanceRepository.getInstance()
+ .getProfilePage(uid, PIPageEditor.currentPageIndex())
+ .getTopComposite();
+
+ // Set selectionStart and selectionEnd
+ selectionStart = 0;
+ selectionEnd = visibleComposite.lastSampleX;
+ setSelectionFields();
+
+ // inform all subcomponents that the selection area has changed
+ PIEvent be = new PIEvent(new double[] { selectionStart, selectionEnd },
+ PIEvent.SELECTION_AREA_CHANGED);
+ sendEventToSubComponents(be);
+ repaintComponent();
+
+ // since some pages that depend on the selection start and end times may
+ // not have
+ // graph components (e.g., the function call plugin page), also let
+ // listening plugins know
+ Enumeration e = PluginInitialiser
+ .getPluginInstances(NpiInstanceRepository.getInstance()
+ .activeUid(),
+ "com.nokia.carbide.cpp.internal.pi.plugin.model.IEventListener"); //$NON-NLS-1$
+ if (e != null) {
+ Event event = new Event();
+ event.start = (int) selectionStart;
+ event.end = (int) selectionEnd;
+
+ while (e.hasMoreElements()) {
+ IEventListener plugin = (IEventListener) e.nextElement();
+ plugin.receiveEvent("changeSelection", event); //$NON-NLS-1$
+ }
+ }
+ //
+ }
+}
\ No newline at end of file