/*****************************************************************************
* 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.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.LinkedList;
import java.util.Set;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.MouseMoveListener;
import org.eclipse.swt.graphics.Cursor;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.ui.PartInitException;
import eu.geclipse.traceview.IProcess;
public abstract class AbstractGraphMouseAdapter implements MouseListener, MouseMoveListener {
protected AbstractGraphVisualization graph;
private int vRulerSelection;
private Cursor moveProcCursor;
private Rectangle selectionRect;
protected AbstractGraphMouseAdapter( final AbstractGraphVisualization graph ) {
this.graph = graph;
this.moveProcCursor= new Cursor(this.graph.getDisplay(), SWT.CURSOR_SIZENS);
}
public void mouseDoubleClick( MouseEvent e ) {
int graphHeight = this.graph.getClientArea().height - 30;
if( e.x > 0 && e.y > 0 && e.x < 30 && e.y < graphHeight ) {
int y = getLineNumber( e.y );
if (y != -1) {
boolean[] hideProcs = this.graph.getHideProcess();
Set<Integer> procs = this.graph.getLineToProcessMapping().get( y );
for (Integer proc : procs) {
hideProcs[proc.intValue()] ^= true;
}
this.graph.setHideProcess( hideProcs );
}
}
}
public void mouseMove( final MouseEvent e ) {
if ((e.stateMask & SWT.BUTTON1) != 0) {
if (this.vRulerSelection != -1) {
GC rulerGC = new GC(this.graph);
this.graph.getEventGraphPaintListener().drawVRulerWithMovingLine( rulerGC, this.vRulerSelection, e.y );
rulerGC.dispose();
}
if ( selectionRect != null ) {
this.graph.getEventGraphPaintListener().updateSelectionRectangle(selectionRect, e);
}
} else if ((e.stateMask & SWT.BUTTON1) == 0) {
updateMouseCursor( e );
}
}
protected void updateMouseCursor( final MouseEvent e ) {
int graphHeight = this.graph.getClientArea().height - 30;
if( e.x > 0 && e.y > 0 && e.x < 30 && e.y < graphHeight &&
getLineNumber( e.y ) != -1 ) {
this.graph.setCursor( this.moveProcCursor );
} else {
this.graph.setCursor( null );
}
}
public void mouseUp( MouseEvent e ) {
checkVRuler( e.x, e.y, false );
updateMouseCursor( e );
if ( selectionRect != null ) {
this.graph.getEventGraphPaintListener().updateSelectionRectangle(selectionRect, null);
Object[] objs = getObjectsForArea(selectionRect);
List<Object> objList = Arrays.asList( objs );
if (!objList.isEmpty()) {
updateSelection(e, objList);
this.graph.redraw();
}
selectionRect = null;
}
}
private void updateSelection(final MouseEvent e, final List<Object> newSelection) {
try {
ISelection selection = null;
ISelectionProvider selectionProvider =
Activator.getDefault()
.getWorkbench()
.getActiveWorkbenchWindow()
.getActivePage()
.showView( "eu.geclipse.traceview.views.TraceView" )
.getSite()
.getSelectionProvider();
StructuredSelection oldSelection = ( StructuredSelection )selectionProvider.getSelection();
if ((e.stateMask & SWT.CTRL) != 0 && oldSelection != null) {
List oldSelectionList = new ArrayList( oldSelection.toList() );
if (!oldSelectionList.containsAll( newSelection )) {
if (e.button == 1) {
for (Object obj : newSelection){
if (!oldSelectionList.contains( obj )) oldSelectionList.add( obj );
}
selection = new StructuredSelection( oldSelectionList );
}
} else {
selection = new StructuredSelection( oldSelectionList );
}
}
if (selection == null) {
selection = new StructuredSelection( newSelection );
}
selectionProvider.setSelection( selection );
} catch( PartInitException exception ) {
Activator.logException( exception );
}
}
public void mouseDown( final MouseEvent e ) {
checkVRuler( e.x, e.y, true );
Object[] objs = getObjectsForPosition( e.x, e.y, (e.stateMask & SWT.CTRL) == 0 );
if( objs.length != 0 && (e.button == 1 || e.button == 3) ) {
List<Object> objList = Arrays.asList( objs );
updateSelection(e, objList);
this.graph.redraw();
}
if (e.button == 1 && this.graph.getEventGraphPaintListener().isInGraphArea(e.x, e.y)) {
selectionRect = new Rectangle(e.x, e.y, 0, 0);
}
}
protected int getLineNumber( final int yPos ) {
return getLineNumber( yPos, false, false );
}
protected int getLineNumber( final int yPos, boolean areaBelowProcess, boolean mapAreaBelowLastLineToLastLine ) {
int yOffset = this.graph.getEventGraphPaintListener().getYOffset();
int eventSize = this.graph.getEventGraphPaintListener().getEventSize();
int vSpace = this.graph.getEventGraphPaintListener().getVSpace();
int numProcLines = this.graph.getLineToProcessMapping().size();
int processLine = -1;
int tmp = yPos + yOffset - eventSize / 2;
if (areaBelowProcess) {
if (tmp < 0) processLine = -1;
else processLine = tmp / vSpace;
} else {
if( tmp % vSpace <= eventSize / 2 ) {
processLine = tmp / vSpace;
}
if( vSpace - ( tmp % vSpace ) <= eventSize / 2 ) {
processLine = tmp / vSpace + 1;
}
}
if ( processLine != -1 ) {
processLine += this.graph.getEventGraphPaintListener().getFromProcessLine();
if( processLine >= numProcLines ) {
if (mapAreaBelowLastLineToLastLine) {
processLine = numProcLines - 1;
} else {
processLine = -1;
}
}
}
return processLine;
}
public void checkVRuler( int xPos, int yPos, boolean clicked ) {
int graphHeight = this.graph.getClientArea().height - 30;
int y = getLineNumber( yPos );
if (clicked) this.vRulerSelection = -1;
if( xPos > 0 && yPos > 0 && xPos < 30 && yPos < graphHeight &&
(clicked || this.vRulerSelection != -1)) {
if (y != -1) {
if (clicked) this.vRulerSelection = y;
else {
this.graph.mergeProcessLines( this.vRulerSelection, y );
}
} else {
if (!clicked) {
y = getLineNumber( yPos, true, true );
if ( y < this.vRulerSelection ) {
if (y + 1 < this.graph.getLineToProcessMapping().size()) {
this.graph.moveProcessLine( this.vRulerSelection, y + 1 );
}
} else {
this.graph.moveProcessLine( this.vRulerSelection, y );
}
}
}
} else if ( !clicked && this.vRulerSelection != -1) {
this.vRulerSelection = -1;
this.graph.redraw();
}
}
public Object[] getObjectsForPosition( int xPos, int yPos, boolean allowTraceObj ) {
List<Object> objList = new LinkedList<Object>();
int y = getLineNumber( yPos );
if( this.graph.getEventGraphPaintListener().isInGraphArea(xPos, yPos) ) {
if( y != -1 ) {
for (Integer proc : this.graph.getLineToProcessMapping().get( y ) ) {
Object obj = getObjectOnProcess( xPos, proc.intValue() );
if ( obj != null ) {
objList.add( obj );
}
}
if ( objList.size() == 0 ) {
objList.addAll( getProcessesOnLine( y ) );
}
} else {
if (allowTraceObj) objList.add( this.graph.getTrace() );
}
}
return objList.toArray();
}
public Object[] getObjectsForArea( final Rectangle rect ) {
Rectangle rect2 = new Rectangle( rect.x, rect.y, rect.width, rect.height );
if( rect2.width < 0 ) {
rect2.x += rect2.width;
rect2.width *= -1;
}
if( rect2.height < 0 ) {
rect2.y += rect2.height;
rect2.height *= -1;
}
List<Object> objList = new LinkedList<Object>();
int yStart = getLineNumber( rect2.y, true, true ) + 1;
int yEnd = getLineNumber( rect2.y + rect2.height, true, true );
for( int y = yStart; y <= yEnd; y++ ) {
if( y != -1 ) {
for (Integer proc : this.graph.getLineToProcessMapping().get( y ) ) {
List<Object> objs = getObjectsOnProcess( rect2.x, rect2.x + rect2.width, proc.intValue() );
objList.addAll( objs );
}
}
}
return objList.toArray();
}
public List<IProcess> getProcessesOnLine( int line ) {
List<IProcess> procList = new LinkedList<IProcess>();
for (Integer proc : this.graph.getLineToProcessMapping().get( line ) ) {
procList.add( this.graph.getTrace().getProcess( proc.intValue() ) );
}
return procList;
}
public abstract Object getObjectOnProcess( final int xPos, final int procNr );
public abstract List<Object> getObjectsOnProcess( final int xStart, final int xEnd, final int procNr );
}