/*****************************************************************************
* Copyright (c) 2009 g-Eclipse Consortium
* 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
*
* Initial development of the original code was made for the
* g-Eclipse project founded by European Union
* project number: FP6-IST-034327 http://www.geclipse.eu/
*
* Contributors:
* Thomas Koeckerbauer - MNM-Team, LMU Munich, code cleanup of logical and physical trace viewers
*****************************************************************************/
package eu.geclipse.traceview.internal;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.Vector;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.ActionContributionItem;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jface.action.IMenuCreator;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.window.DefaultToolTip;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.ui.IViewSite;
import eu.geclipse.traceview.IEvent;
import eu.geclipse.traceview.IEventMarker;
import eu.geclipse.traceview.ITrace;
import eu.geclipse.traceview.TraceVisualization;
import eu.geclipse.traceview.views.TraceView;
public abstract class AbstractGraphVisualization extends TraceVisualization {
protected EventMarkers eventMarkers;
protected LineType hLines;
protected LineType vLines;
protected ITrace trace;
protected List<SortedSet<Integer>> lineToProcMapping;
protected int[] procToLineMapping;
protected boolean[] hideProcess;
public AbstractGraphVisualization( final Composite parent,
final int style,
final IViewSite viewSite,
final ITrace trace )
{
super( parent, style | SWT.V_SCROLL | SWT.H_SCROLL );
this.trace = trace;
// layout
GridData layoutData = new GridData();
layoutData.horizontalAlignment = SWT.FILL;
layoutData.grabExcessHorizontalSpace = true;
layoutData.verticalAlignment = SWT.FILL;
layoutData.grabExcessVerticalSpace = true;
this.setLayoutData( layoutData );
// set defaults
this.hLines = LineType.Lines_1;
this.vLines = LineType.Lines_1;
// create process mapping
resetOrdering();
// get the Event Markers
this.eventMarkers = new EventMarkers( trace );
TraceView view = ( TraceView )Activator.getDefault()
.getWorkbench()
.getActiveWorkbenchWindow()
.getActivePage()
.getActivePart();
Menu menu = view.getContextMenuManager().createContextMenu( this );
setMenu( menu );
addListener( SWT.Resize, new Listener() {
public void handleEvent( final Event e ) {
handleResize();
}
} );
addDisposeListener( new DisposeListener() {
public void widgetDisposed( final DisposeEvent e ) {
IPreferenceStore store = Activator.getDefault().getPreferenceStore();
store.removePropertyChangeListener( getEventGraphPaintListener().listener );
}
} );
}
public void registerPaintListener( final AbstractGraphPaintListener eventGraphPaintListener ) {
eventGraphPaintListener.setHorizontalScrollBar( getHorizontalBar() );
eventGraphPaintListener.setVerticalScrollBar( getVerticalBar() );
eventGraphPaintListener.setFont( getFont() );
eventGraphPaintListener.setTrace( this.trace );
addPaintListener( eventGraphPaintListener );
}
public void registerMouseListener( final AbstractGraphMouseAdapter mouseAdapter ) {
addMouseListener( mouseAdapter );
addMouseMoveListener( mouseAdapter );
@SuppressWarnings("unused")
DefaultToolTip toolTip = new DefaultToolTip( this ) {
@Override
protected boolean shouldCreateToolTip( final Event event ) {
Object[] objs = mouseAdapter.getObjectsForPosition( event.x, event.y, true );
return objs.length != 0 && getText( objs ) != null;
}
@Override
protected String getText( final Event event ) {
Object[] objs = mouseAdapter.getObjectsForPosition( event.x, event.y, true );
return getText( objs );
}
protected String getText( Object[] objs ) {
String result = null;
if( objs.length != 0 ) {
result = ""; //$NON-NLS-1$
for (Object obj : objs) {
if (result.length() != 0) result += '\n';
if (obj.toString() != null) result += obj.toString();
if (obj instanceof IEvent) {
for( IEventMarker eventmarker : getEventMarkers() ) {
eventmarker.mark( (IEvent)obj );
String markerString = eventmarker.getToolTip();
if (markerString != null) {
result += '\n' + markerString;
}
}
}
}
if (result.length() == 0) result = null;
}
return result;
}
};
}
private void setHLines( final LineType lines ) {
this.hLines = lines;
redraw();
}
private void setVLines( final LineType lines ) {
this.vLines = lines;
redraw();
}
protected void changeLineStyle( final int direction ) {
LineType style = null;
if( direction < 0 ) {
style = getVLines();
} else {
style = getHLines();
}
if( style == LineType.Lines_None ) {
style = LineType.Lines_1;
} else if( style == LineType.Lines_1 ) {
style = LineType.Lines_5;
} else if( style == LineType.Lines_5 ) {
style = LineType.Lines_10;
} else if( style == LineType.Lines_10 ) {
style = LineType.Lines_None;
}
if( direction < 0 ) {
setVLines( style );
} else {
setHLines( style );
}
}
public List<IEventMarker> getEventMarkers() {
return this.eventMarkers.getEventMarkers();
}
protected void handleResize() {
getEventGraphPaintListener().handleResize();
}
public LineType getHLines() {
return this.hLines;
}
public LineType getVLines() {
return this.vLines;
}
@Override
public ITrace getTrace() {
return this.trace;
}
@Override
public void printTrace( final GC gc ) {
getEventGraphPaintListener().print( gc );
}
void setLineToProcessMapping(List<SortedSet<Integer>> mapping) {
this.lineToProcMapping = mapping;
updateProcessToLineMapping();
redraw();
}
void updateProcessToLineMapping() {
for(int i = 0; i < this.trace.getNumberOfProcesses(); i++) {
this.procToLineMapping[i] = -1;
}
for(int line = 0; line < this.lineToProcMapping.size(); line++) {
for(Integer proc : this.lineToProcMapping.get( line )) {
this.procToLineMapping[proc.intValue()] = line;
}
}
}
public List<SortedSet<Integer>> getLineToProcessMapping() {
return this.lineToProcMapping;
}
public void setProcessToLineMapping( int[] procToLineMapping ) {
this.procToLineMapping = procToLineMapping;
updateLineToProcessMapping();
redraw();
}
void removeEmptyLines() {
Iterator<SortedSet<Integer>> it = this.lineToProcMapping.iterator();
while (it.hasNext()) {
SortedSet<Integer> set = it.next();
if (set.isEmpty()) {
it.remove();
}
}
updateProcessToLineMapping();
redraw();
}
void updateLineToProcessMapping() {
this.lineToProcMapping = new LinkedList<SortedSet<Integer>>();
for (int proc = 0; proc < this.procToLineMapping.length; proc++) {
int line = this.procToLineMapping[proc];
if (line != -1) {
while(this.lineToProcMapping.size() <= line ) {
this.lineToProcMapping.add( new TreeSet<Integer>() );
}
this.lineToProcMapping.get( line ).add( Integer.valueOf( proc ) );
}
}
}
public int[] getProcessToLineMapping() {
return this.procToLineMapping;
}
public boolean[] getHideProcess() {
return this.hideProcess;
}
public void setHideProcess( boolean[] hideProcess ) {
this.hideProcess = hideProcess;
redraw();
}
void resetOrdering() {
this.procToLineMapping = new int[this.trace.getNumberOfProcesses()];
this.hideProcess = new boolean[this.trace.getNumberOfProcesses()];
for (int i = 0; i < this.trace.getNumberOfProcesses(); i++) {
this.procToLineMapping[i] = i;
}
updateLineToProcessMapping();
}
@Override
public IContributionItem[] getToolBarItems() {
Vector<IContributionItem> items = new Vector<IContributionItem>();
Action reset = new Action( Messages.getString( "AbstractGraphVisualization.Reset" ), //$NON-NLS-1$
Activator.getImageDescriptor( "icons/reset.gif" ) ) { //$NON-NLS-1$
@Override
public void run() {
resetOrdering();
redraw();
}
};
items.add( new ActionContributionItem( reset ) );
Action markerSelectionAction = new Action( Messages.getString("AbstractGraphVisualization.toggleMarkers"), //$NON-NLS-1$
Activator.getImageDescriptor( "icons/marker.gif" ) ) { //$NON-NLS-1$
@Override
public void run() {
MarkerOrderDialog dialog = new MarkerOrderDialog( getShell() );
dialog.setEventMarkerEntries( eventMarkers.getEventMarkerEntries() );
if (dialog.open() == Window.OK) {
eventMarkers.eventMarkerEntries = dialog.getEventMarkerEntries();
eventMarkers.buildEventMarkersList();
redraw();
}
}
};
IMenuCreator menuCreator = new MarkerSelectionMenuCreator( this );
markerSelectionAction.setMenuCreator( menuCreator );
items.add( new ActionContributionItem( markerSelectionAction ) );
return items.toArray( new IContributionItem[ items.size() ] );
}
public abstract AbstractGraphPaintListener getEventGraphPaintListener();
public void mergeProcessLines( int fromLine, int toLine ) {
int[] mapping = getProcessToLineMapping();
for ( Integer proc : getLineToProcessMapping().get( fromLine ) ) {
mapping[proc.intValue()] = toLine;
}
setProcessToLineMapping( mapping );
removeEmptyLines();
}
public void swapProcessLines( int lineA, int lineB ) {
int[] mapping = getProcessToLineMapping();
for (int i = 0; i < mapping.length; i++) {
if (mapping[i] == lineA ) mapping[i] = lineB;
else if (mapping[i] == lineB ) mapping[i] = lineA;
}
setProcessToLineMapping( mapping );
}
public void moveProcessLine( int oldLine, int newLine ) {
int[] mapping = getProcessToLineMapping();
for (int i = 0; i < mapping.length; i++) {
if (oldLine > newLine) {
if (mapping[i] >= newLine && mapping[i] < oldLine) mapping[i]++;
else if (mapping[i] == oldLine) mapping[i] = newLine;
} else {
if (mapping[i] <= newLine && mapping[i] > oldLine) mapping[i]--;
else if (mapping[i] == oldLine) mapping[i] = newLine;
}
}
setProcessToLineMapping( mapping );
}
}