/**********************************************************************
* Copyright (c) 2013, 2015 Ericsson
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License v1.0 which
* accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Bernd Hufmann - Initial API and implementation
**********************************************************************/
package org.eclipse.tracecompass.tmf.ui.views;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Sash;
import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager;
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
import org.eclipse.tracecompass.tmf.ui.signal.TmfTimeViewAlignmentInfo;
import org.eclipse.tracecompass.tmf.ui.signal.TmfTimeViewAlignmentSignal;
import org.eclipse.tracecompass.tmf.ui.viewers.TmfViewer;
import org.eclipse.tracecompass.tmf.ui.viewers.xycharts.TmfXYChartViewer;
/**
* Base class to be used with a chart viewer {@link TmfXYChartViewer}.
* It is responsible to instantiate the viewer class and load the trace
* into the viewer when the view is created.
*
* @author Bernd Hufmann
*/
public abstract class TmfChartView extends TmfView implements ITmfTimeAligned {
private static final int[] DEFAULT_WEIGHTS = {1, 3};
// ------------------------------------------------------------------------
// Attributes
// ------------------------------------------------------------------------
/** The TMF XY Chart reference */
private TmfXYChartViewer fChartViewer;
/** The Trace reference */
private ITmfTrace fTrace;
/** A composite that allows us to add margins */
private Composite fXYViewerContainer;
private TmfViewer fTmfViewer;
private SashForm fSashForm;
private Listener fSashDragListener;
// ------------------------------------------------------------------------
// Constructors
// ------------------------------------------------------------------------
/**
* Standard Constructor
*
* @param viewName
* The view name
*/
public TmfChartView(String viewName) {
super(viewName);
}
// ------------------------------------------------------------------------
// Accessors
// ------------------------------------------------------------------------
/**
* Returns the TMF XY chart viewer implementation.
*
* @return the TMF XY chart viewer {@link TmfXYChartViewer}
*/
protected TmfXYChartViewer getChartViewer() {
return fChartViewer;
}
/**
* Create a {@link TmfViewer} instance to be added to the left composite
* of the sash. Default implementation provides an empty composite and
* don't overwrite this method if not needed.
*
* @param parent
* the parent control
* @return a {@link TmfViewer} instance
* @since 2.0
*/
protected @NonNull TmfViewer createLeftChildViewer(Composite parent) {
return new EmptyViewer(parent);
}
/**
* Create the TMF XY chart viewer implementation
*
* @param parent
* the parent control
*
* @return The TMF XY chart viewer {@link TmfXYChartViewer}
* @since 1.0
*/
abstract protected TmfXYChartViewer createChartViewer(Composite parent);
/**
* Returns the ITmfTrace implementation
*
* @return the ITmfTrace implementation {@link ITmfTrace}
*/
protected ITmfTrace getTrace() {
return fTrace;
}
/**
* Sets the ITmfTrace implementation
*
* @param trace
* The ITmfTrace implementation {@link ITmfTrace}
*/
protected void setTrace(ITmfTrace trace) {
fTrace = trace;
}
// ------------------------------------------------------------------------
// Operations
// ------------------------------------------------------------------------
@Override
public void createPartControl(Composite parent) {
super.createPartControl(parent);
fSashForm = new SashForm(parent, SWT.NONE);
fTmfViewer = createLeftChildViewer(fSashForm);
fXYViewerContainer = new Composite(fSashForm, SWT.NONE);
GridLayout layout = new GridLayout();
layout.marginHeight = 0;
layout.marginWidth = 0;
fXYViewerContainer.setLayout(layout);
fChartViewer = createChartViewer(fXYViewerContainer);
fChartViewer.setSendTimeAlignSignals(true);
fChartViewer.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
fChartViewer.getControl().addPaintListener(new PaintListener() {
@Override
public void paintControl(PaintEvent e) {
// Sashes in a SashForm are being created on layout so add the
// drag listener here
if (fSashDragListener == null) {
for (Control control : fSashForm.getChildren()) {
if (control instanceof Sash) {
fSashDragListener = new Listener() {
@Override
public void handleEvent(Event event) {
TmfSignalManager.dispatchSignal(new TmfTimeViewAlignmentSignal(fSashForm, getTimeViewAlignmentInfo()));
}
};
control.removePaintListener(this);
control.addListener(SWT.Selection, fSashDragListener);
// There should be only one sash
break;
}
}
}
}
});
fSashForm.setWeights(DEFAULT_WEIGHTS);
ITmfTrace trace = TmfTraceManager.getInstance().getActiveTrace();
if (trace != null) {
setTrace(trace);
loadTrace();
}
}
@Override
public void dispose() {
super.dispose();
if (fChartViewer != null) {
fChartViewer.dispose();
}
if (fTmfViewer != null) {
fTmfViewer.dispose();
}
}
@Override
public void setFocus() {
fChartViewer.getControl().setFocus();
}
/**
* Load the trace into view.
*/
protected void loadTrace() {
if (fChartViewer != null) {
fChartViewer.loadTrace(fTrace);
}
}
/**
* @since 1.0
*/
@Override
public TmfTimeViewAlignmentInfo getTimeViewAlignmentInfo() {
if (fChartViewer == null) {
return null;
}
return new TmfTimeViewAlignmentInfo(fChartViewer.getControl().getShell(), fSashForm.toDisplay(0, 0), getTimeAxisOffset());
}
private int getTimeAxisOffset() {
return fSashForm.getChildren()[0].getSize().x + fSashForm.getSashWidth() + fChartViewer.getPointAreaOffset();
}
/**
* @since 1.0
*/
@Override
public int getAvailableWidth(int requestedOffset) {
if (fChartViewer == null) {
return 0;
}
int pointAreaWidth = fChartViewer.getPointAreaWidth();
int curTimeAxisOffset = getTimeAxisOffset();
if (pointAreaWidth <= 0) {
pointAreaWidth = fSashForm.getBounds().width - curTimeAxisOffset;
}
int endOffset = curTimeAxisOffset + pointAreaWidth;
GridLayout layout = (GridLayout) fXYViewerContainer.getLayout();
int endOffsetWithoutMargin = endOffset + layout.marginRight;
int availableWidth = endOffsetWithoutMargin - requestedOffset;
availableWidth = Math.min(fSashForm.getBounds().width, Math.max(0, availableWidth));
return availableWidth;
}
/**
* @since 1.0
*/
@Override
public void performAlign(int offset, int width) {
int total = fSashForm.getBounds().width;
int plotAreaOffset = fChartViewer.getPointAreaOffset();
int width1 = Math.max(0, offset - plotAreaOffset - fSashForm.getSashWidth());
int width2 = Math.max(0, total - width1 - fSashForm.getSashWidth());
if (width1 >= 0 && width2 > 0 || width1 > 0 && width2 >= 0) {
fSashForm.setWeights(new int[] { width1, width2 });
fSashForm.layout();
}
Composite composite = fXYViewerContainer;
GridLayout layout = (GridLayout) composite.getLayout();
int timeAxisWidth = getAvailableWidth(offset);
int marginSize = timeAxisWidth - width;
layout.marginRight = Math.max(0, marginSize);
composite.layout();
}
// ------------------------------------------------------------------------
// Helpers
// ------------------------------------------------------------------------
/**
* Empty @{link TmfViewer} class.
*/
private class EmptyViewer extends TmfViewer {
private Composite fComposite;
public EmptyViewer(Composite parent) {
super(parent);
fComposite = new Composite(parent, SWT.NONE);
}
@Override
public void refresh() {
}
@Override
public Control getControl() {
return fComposite;
}
}
}