tracebook: first commit

Signed-off-by: Fabrizio Iannetti <fabrizio.iannetti@protonmail.com>
This commit is contained in:
Fabrizio Iannetti 2023-02-17 17:37:46 +01:00
commit 5ed58483cd
17 changed files with 644 additions and 0 deletions

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View File

@ -0,0 +1 @@
/bin/

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>org.eclipse.tracecompass.incubator.tracebook.ui</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.ManifestBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.SchemaBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,2 @@
eclipse.preferences.version=1
encoding/<project>=UTF-8

View File

@ -0,0 +1,9 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=17
org.eclipse.jdt.core.compiler.compliance=17
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
org.eclipse.jdt.core.compiler.release=enabled
org.eclipse.jdt.core.compiler.source=17

View File

@ -0,0 +1,20 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Tracebook
Bundle-SymbolicName: org.eclipse.tracecompass.incubator.tracebook.ui;singleton:=true
Bundle-Version: 1.0.0.qualifier
Require-Bundle: org.eclipse.core.runtime;bundle-version="3.26.100",
org.eclipse.tracecompass.common.core;bundle-version="5.1.1",
org.eclipse.tracecompass.tmf.core;bundle-version="8.3.0",
org.eclipse.tracecompass.tmf.ui;bundle-version="8.1.0",
org.eclipse.tracecompass.incubator.tmf.ui.multiview.ui;bundle-version="0.1.1",
org.eclipse.nebula.widgets.opal.commons,
org.eclipse.tracecompass.analysis.os.linux.core;bundle-version="7.0.0",
org.eclipse.tracecompass.analysis.graph.core;bundle-version="4.0.0",
org.eclipse.jdt.annotation;bundle-version="2.2.700",
org.eclipse.ui;bundle-version="3.201.200",
org.eclipse.swtchart
Automatic-Module-Name: org.eclipse.tracecompass.incubator.tmf.ui.tracebook
Bundle-ActivationPolicy: lazy
Bundle-Activator: org.eclipse.tracecompass.incubator.tracebook.ui.Activator
Bundle-RequiredExecutionEnvironment: JavaSE-17

View File

@ -0,0 +1,5 @@
source.. = src/
output.. = bin/
bin.includes = META-INF/,\
.,\
plugin.xml

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 B

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin>
<extension
point="org.eclipse.ui.views">
<view
class="org.eclipse.tracecompass.incubator.tracebook.ui.view.TraceBookView"
id="org.eclipse.tracecompass.incubator.tmf.ui.tracebook.TreaceBookView"
name="Tracebook"
restorable="true">
</view>
</extension>
</plugin>

View File

@ -0,0 +1,86 @@
package org.eclipse.tracecompass.incubator.tracebook.ui;
import java.io.IOException;
import java.net.URL;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.jface.resource.ImageRegistry;
import org.eclipse.swt.graphics.Image;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;
public class Activator extends AbstractUIPlugin {
public static final String PLUGIN_ID = "org.eclipse.tracecompass.incubator.tracebook.ui";
public static final String IMAGE_CPU_USAGE = "icons/cpuusage.png";
private static @Nullable Activator fPlugin;
public Activator() {
}
// ------------------------------------------------------------------------
// Accessors
// ------------------------------------------------------------------------
/**
* Returns the shared instance
*
* @return the shared instance
*/
public static Activator getDefault() {
Activator plugin = fPlugin;
if (plugin == null) {
throw new IllegalStateException();
}
return plugin;
}
/**
* Gets the absolute path from a path relative to this plugin's root
*
* @param relativePath
* The path relative to this plugin
* @return The absolute path corresponding to this relative path
*/
public @Nullable IPath getAbsolutePath(Path relativePath) {
URL location = FileLocator.find(getBundle(), relativePath, null);
try {
IPath path = new Path(FileLocator.toFileURL(location).getPath());
return path;
} catch (IOException e) {
return null;
}
}
// ------------------------------------------------------------------------
// Operators
// ------------------------------------------------------------------------
@Override
public void start(@Nullable BundleContext context) throws Exception {
super.start(context);
fPlugin = this;
}
@Override
public void stop(@Nullable BundleContext context) throws Exception {
fPlugin = null;
super.stop(context);
}
public static Image getImage(String imageId) {
ImageRegistry imageRegistry = getDefault().getImageRegistry();
Image image = imageRegistry.get(imageId);
if (image == null) {
image = imageDescriptorFromPlugin(PLUGIN_ID, imageId).createImage();
imageRegistry.put(imageId, image);
}
return image;
}
}

View File

@ -0,0 +1,177 @@
package org.eclipse.tracecompass.incubator.tracebook.ui.controls;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Sash;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import org.eclipse.tracecompass.incubator.tracebook.ui.providers.ProviderPresenter.ProviderPresentationInfo;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.PlatformUI;
public class Section extends Composite {
// private static final String MOVE_DOWN_IMAGE = "arrow_down.png"; //$NON-NLS-1$
// private static final String MOVE_UP_IMAGE = "arrow_up.png"; //$NON-NLS-1$
public static class ToolAction implements SelectionListener {
@Override
public void widgetSelected(SelectionEvent e) {
}
@Override
public void widgetDefaultSelected(SelectionEvent e) {
widgetSelected(e);
}
}
SelectionListener moveUp = new ToolAction() {
@Override
public void widgetSelected(SelectionEvent e) {
SashForm sashForm = (SashForm) getParent();
Control[] children = sashForm.getChildren();
Control previous = null;
for (Control control : children) {
if (control instanceof Sash) {
continue;
}
if (control.equals(Section.this)) {
control.moveAbove(previous);
sashForm.layout(true);
break;
}
previous = control;
}
}
};
SelectionListener moveDown = new ToolAction() {
@Override
public void widgetSelected(SelectionEvent e) {
SashForm sashForm = (SashForm) getParent();
Control[] children = sashForm.getChildren();
Control previous = null;
for (Control control : children) {
if (control instanceof Sash) {
continue;
}
if (control.equals(Section.this)) {
previous = control;
} else if (previous != null) {
control.moveAbove(previous);
sashForm.layout(true);
break;
}
}
}
};
SelectionListener remove = new ToolAction() {
@Override
public void widgetSelected(SelectionEvent e) {
// Composite parent = getParent();
// dispose();
// parent.layout(true);
if (onCloseListener != null) {
onCloseListener.widgetDisposed(null);
}
}
};
static class ConfigureDialog extends Dialog {
private DisposeListener onClose;
protected ConfigureDialog(Shell parentShell, DisposeListener onClose) {
super(parentShell);
this.onClose = onClose;
setShellStyle(SWT.RESIZE | SWT.MODELESS | SWT.CLOSE);
}
@Override
protected Control createDialogArea(Composite parent) {
Composite composite = (Composite) super.createDialogArea(parent);
parent.getShell().setText("Configure Section");
parent.getShell().addDisposeListener(onClose);
return composite;
}
public void onTop() {
try {
getContents().getShell().forceActive();
} catch (Exception e) {
// ignore exceptions, like disposed widgets
}
}
}
private ConfigureDialog configureDialog = null;
private DisposeListener onCloseListener;
private Runnable onPaintListener;
SelectionListener configure = new ToolAction() {
@Override
public void widgetSelected(SelectionEvent e) {
if (configureDialog != null) {
configureDialog.onTop();
} else {
configureDialog = new ConfigureDialog(getShell(),e1 -> configureDialog = null);
configureDialog.open();
}
}
};
public Section(Composite parent, Color bgColor, ProviderPresentationInfo info) {
super(parent, SWT.NONE);
// parent has 3 columns: toolbar, table/tree/text, graph (xy or timechart)
setLayout(new GridLayout(3, false));
setBackground(bgColor);
Composite laneBar = new Composite(this, SWT.NONE);
laneBar.setBackground(bgColor);
laneBar.setLayoutData(GridDataFactory.fillDefaults().grab(false, true).create());
GridLayoutFactory.fillDefaults().applyTo(laneBar);
ToolBar toolBar = new ToolBar(laneBar, SWT.VERTICAL);
GridDataFactory.fillDefaults().grab(true, false).applyTo(toolBar);
if (info.image != null) {
createToolItem(toolBar, info.image).addSelectionListener(configure);
}
// createToolItem(toolBar, MOVE_UP_IMAGE).addSelectionListener(moveUp);
// createToolItem(toolBar, MOVE_DOWN_IMAGE).addSelectionListener(moveDown);
createToolItem(toolBar, PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_ELCL_REMOVE)).addSelectionListener(remove);
VerticalLabel label = new VerticalLabel(laneBar);
label.setText(info.name);
label.setBackground(new Color(240, 240, 240));
GridDataFactory.fillDefaults().hint(1, 1).grab(true, true).applyTo(label);
}
private static ToolItem createToolItem(ToolBar toolBar, Image image) {
ToolItem toolItem = new ToolItem(toolBar, SWT.PUSH);
toolItem.setImage(image);
return toolItem;
}
public void onClose(DisposeListener listener) {
this.onCloseListener = listener;
}
public void onPaint(Runnable listener) {
this.onPaintListener = listener;
}
// private static ToolItem createToolItem(ToolBar toolBar, final String imageFileName) {
// final Image image = SWTGraphicUtil.createImageFromFile("images/" + imageFileName); //$NON-NLS-1$
// ToolItem toolItem = createToolItem(toolBar, image);
// toolItem.setImage(image);
// SWTGraphicUtil.addDisposer(toolItem, image);
// return toolItem;
// }
}

View File

@ -0,0 +1,32 @@
package org.eclipse.tracecompass.incubator.tracebook.ui.controls;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Transform;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
public class VerticalLabel extends Canvas {
private String text = "";
public VerticalLabel(Composite parent) {
super(parent, SWT.NONE);
addPaintListener(e -> paintLabel(e));
}
public void setText(String text) {
this.text = text;
}
private void paintLabel(PaintEvent e) {
Point textExtent = e.gc.textExtent(text);
Transform t = new Transform(getDisplay());
t.translate((e.width - textExtent.y) / 2, (e.height + textExtent.x) / 2);
t.rotate(-90);
float[] p = new float[] {0, 0};
t.transform(p);
e.gc.setAdvanced(true);
e.gc.setTransform(t);
e.gc.drawText(text, e.x, e.y);
}
}

View File

@ -0,0 +1,54 @@
package org.eclipse.tracecompass.incubator.tracebook.ui.providers;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.swt.graphics.Image;
import org.eclipse.tracecompass.incubator.tracebook.ui.Activator;
import org.eclipse.tracecompass.internal.analysis.os.linux.core.cpuusage.CpuUsageDataProvider;
import org.eclipse.tracecompass.tmf.core.dataprovider.IDataProviderDescriptor;
/**
* This class returns presentation information (name, icon) for known data providers.
*
* @author fab
*
*/
@SuppressWarnings("restriction")
public class ProviderPresenter {
private static ProviderPresenter fInstance = new ProviderPresenter();
// map providerId -> presentation info
private Map<String, ProviderPresentationInfo> fInfo = new HashMap<>();
private ProviderPresenter() {
// cpu provider
fInfo.put(CpuUsageDataProvider.ID, ProviderPresentationInfo.create("CPU", "", Activator.getImage(Activator.IMAGE_CPU_USAGE)));
}
public static class ProviderPresentationInfo {
public String name;
public String description;
public Image image;
public static ProviderPresentationInfo create(IDataProviderDescriptor descriptor) {
return create(descriptor.getName(), descriptor.getDescription(), null);
}
public static ProviderPresentationInfo create(String name, String description, Image image) {
ProviderPresentationInfo info = new ProviderPresentationInfo();
info.name = name;
info.description = description;
info.image = image;
return info;
}
}
public static ProviderPresenter getInstance() {
return fInstance;
}
public ProviderPresentationInfo presentationFor(IDataProviderDescriptor descriptor) {
return fInfo.computeIfAbsent(descriptor.getId(), id -> ProviderPresentationInfo.create(descriptor));
}
}

View File

@ -0,0 +1,107 @@
package org.eclipse.tracecompass.incubator.tracebook.ui.view;
import java.util.Objects;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.tracecompass.incubator.internal.tmf.ui.multiview.ui.view.IMultiViewer;
import org.eclipse.tracecompass.incubator.internal.tmf.ui.multiview.ui.view.xychart.ChartMultiViewer;
import org.eclipse.tracecompass.incubator.tracebook.ui.controls.Section;
import org.eclipse.tracecompass.incubator.tracebook.ui.providers.ProviderPresenter;
import org.eclipse.tracecompass.internal.tmf.ui.viewers.xychart.TmfXYChartTimeAdapter;
import org.eclipse.tracecompass.tmf.core.dataprovider.IDataProviderDescriptor;
import org.eclipse.tracecompass.tmf.core.dataprovider.IDataProviderDescriptor.ProviderType;
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
import org.eclipse.tracecompass.tmf.ui.signal.TmfTimeViewAlignmentInfo;
import org.eclipse.tracecompass.tmf.ui.viewers.TmfViewer;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.ITimeDataProvider;
@SuppressWarnings("restriction")
final class SectionForMultiViewer extends Section implements IMultiViewer{
private IDataProviderDescriptor fProvider;
private TmfViewer fViewer;
public SectionForMultiViewer(Composite parent, IDataProviderDescriptor provider, ITmfTrace trace) {
super(parent, parent.getBackground(), ProviderPresenter.getInstance().presentationFor(provider));
this.fProvider = provider;
if (provider.getType() == ProviderType.TREE_TIME_XY) {
createXYGraph(trace);
} else if(provider.getType() == ProviderType.TIME_GRAPH) {
createTimeGraph(trace);
} else {
Label label = new Label(this, SWT.NONE);
label.setText("Not supported");
GridDataFactory.fillDefaults().grab(true, true).applyTo(label);
}
}
@Override
public void performAlign(int offset, int width) {
// TODO Auto-generated method stub
}
@Override
public TmfTimeViewAlignmentInfo getTimeViewAlignmentInfo() {
// TODO Auto-generated method stub
return new TmfTimeViewAlignmentInfo(getShell(), toDisplay(0, 0), 0);
}
@Override
public int getAvailableWidth(int requestedOffset) {
// TODO Auto-generated method stub
return 0;
}
@Override
public String getName() {
return fProvider.getName();
}
@Override
public void dispose() {
if (isDisposed()) return;
Composite parent = getParent();
super.dispose();
if (parent != null && !parent.isDisposed()) {
parent.layout(true);
}
}
private void createTimeGraph(ITmfTrace trace) {
// TODO Auto-generated method stub
Label label = new Label(this, SWT.CENTER);
label.setText("Timegraph");
GridDataFactory.fillDefaults().grab(true, true).applyTo(label);
}
private void createXYGraph(ITmfTrace trace) {
Composite composite = new Composite(this, SWT.NONE);
GridDataFactory.fillDefaults().grab(true, true).applyTo(composite);
composite.setLayout(new FillLayout());
composite.setBackground(getBackground());
ChartMultiViewer viewer = new ChartMultiViewer(composite, fProvider.getId());
//viewer.setStatusLineManager(getViewSite().getActionBars().getStatusLineManager());
if (trace != null) {
viewer.loadTrace(trace);
}
// A workaround for XYCharts to realign after a selection
// changes leading to possible changing of Y axis labels' width.
// if (viewer.getLeftChildViewer() instanceof AbstractSelectTreeViewer2) {
// AbstractSelectTreeViewer2 tree = (AbstractSelectTreeViewer2) viewer.getLeftChildViewer();
// tree.addSelectionChangeListener(e -> alignViewers(false));
// }
fViewer = viewer;
}
public ITimeDataProvider getTimeDataProvider() {
if (fViewer instanceof ChartMultiViewer) {
ChartMultiViewer viewer = (ChartMultiViewer) fViewer;
TmfXYChartTimeAdapter timeProvider = new TmfXYChartTimeAdapter(Objects.requireNonNull(viewer.getChartViewer()));
return timeProvider;
}
return null;
}
}

View File

@ -0,0 +1,102 @@
package org.eclipse.tracecompass.incubator.tracebook.ui.view;
import java.util.List;
import java.util.Objects;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.tracecompass.incubator.internal.tmf.ui.multiview.ui.view.AbstractMultiView;
import org.eclipse.tracecompass.incubator.internal.tmf.ui.multiview.ui.view.IMultiViewer;
import org.eclipse.tracecompass.internal.tmf.ui.viewers.xychart.TmfXYChartTimeAdapter;
import org.eclipse.tracecompass.tmf.core.dataprovider.DataProviderManager;
import org.eclipse.tracecompass.tmf.core.dataprovider.IDataProviderDescriptor;
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.widgets.Utils.TimeFormat;
import org.eclipse.ui.dialogs.ListSelectionDialog;
/**
* A View that can display a Tracebook, i.e. a collection of charts from different providers.
*
* @author Fabrizio Iannetti
*
*/
@SuppressWarnings("restriction") // TODO: move/modify MultiView logic here or extend MultiView and make API
public class TraceBookView extends AbstractMultiView {
public static final String ID = "org.eclipse.tracecompass.incubator.tmf.ui.tracebook.TreaceBookView";
public TraceBookView() {
super(ID);
}
@Override
protected void partControlCreated(Composite mainComposite, SashForm sashForm) {
hideTimeScales();
}
@Override
protected void createMenuItems() {
IMenuManager menuManager = getViewSite().getActionBars().getMenuManager();
menuManager.add(createAddSectionAction());
}
private IAction createAddSectionAction() {
return new Action("Add Section", IAction.AS_PUSH_BUTTON) {
@Override
public void run() {
openDataProviderDialog(getTrace());
}
};
}
private void openDataProviderDialog(ITmfTrace trace) {
Shell shell = getViewSite().getWorkbenchWindow().getShell();
List<IDataProviderDescriptor> providers = getProvidersList(trace);
ListSelectionDialog dialog = ListSelectionDialog.of(providers)
.labelProvider(new LabelProvider() {
@Override
public String getText(Object element) {
IDataProviderDescriptor provider = (IDataProviderDescriptor) element;
return provider.getName();
}
})
.title("Add Section")
.message("Select the data provider for the new section")
.create(shell);
if (dialog.open() == Window.OK) {
Object[] selected = dialog.getResult();
for (Object object : selected) {
IDataProviderDescriptor provider = (IDataProviderDescriptor) object;
SectionForMultiViewer lane = new SectionForMultiViewer(getLanesParent(), provider, getTrace());
addSection(lane);
lane.onClose(e -> removeLane(lane));
}
}
}
private void addSection(SectionForMultiViewer section) {
if (!hasLanes()) {
setTimeProvider(section.getTimeDataProvider());
section.onPaint(() -> redrawTimeScales());
}
addLane(section);
// if (!hasLanes()) {
// viewer.getChartViewer().getSwtChart().addPaintListener(e -> redrawTimeScales());
// TmfXYChartTimeAdapter timeProvider = new TmfXYChartTimeAdapter(Objects.requireNonNull(viewer.getChartViewer()));
// timeProvider.setTimeFormat(TimeFormat.CALENDAR.convert());
// setTimeProvider(timeProvider);
// }
}
private List<IDataProviderDescriptor> getProvidersList(ITmfTrace trace) {
List<IDataProviderDescriptor> descriptors =
DataProviderManager.getInstance().getAvailableProviders(trace);
return descriptors;
}
}