sysperfana/perfinvestigator/com.nokia.carbide.cpp.pi/src/com/nokia/carbide/cpp/internal/pi/visual/PICompositePanel.java
/*
* 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$
}
}
//
}
}