/*****************************************************************************
* 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.SortedSet;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.PreferenceConverter;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.ScrollBar;
import eu.geclipse.traceview.ITrace;
import eu.geclipse.traceview.preferences.PreferenceConstants;
public abstract class AbstractGraphPaintListener implements PaintListener {
// constants
protected final static int leftRulerWidth = 25;
protected final static int bottomRulerWidth = 25;
protected final static int leftMargin = leftRulerWidth + 5;
protected final static int bottomMargin = bottomRulerWidth + 5;
protected final static int arc = 6;
public IPropertyChangeListener listener;
// scrollbar
protected ScrollBar horizontalScrollBar;
protected ScrollBar verticalScrollBar;
// visible
protected int fromProcessLine = 0;
protected int toProcessLine = 0;
// size
protected int hSpace = 6;
protected int vSpace = 6;
protected int yOffset;
protected int eventSize = 2;
protected int fontsize = 8;
protected int width;
protected int height;
// presentation
protected Color selectionColor;
// black
protected Color black;
// lines
protected Color line1;
protected Color line5;
protected Color line10;
protected boolean antialiasing;
protected GC gc;
protected AbstractGraphVisualization eventGraph;
protected Font smallFont;
protected int numProc;
protected boolean fastRedraw;
protected long fullRedrawDuration;
protected AbstractGraphPaintListener( final AbstractGraphVisualization eventGraph ) {
this.listener = new IPropertyChangeListener() {
public void propertyChange( final PropertyChangeEvent event ) {
handleProperyChanged( event );
}
};
IPreferenceStore store = Activator.getDefault().getPreferenceStore();
store.addPropertyChangeListener( this.listener );
this.eventGraph = eventGraph;
updatePropertiesFromPreferences();
setHorizontal( 0 );
setVertical( 0 );
this.black = Display.getDefault().getSystemColor( SWT.COLOR_BLACK);
this.line1 = new Color( Display.getDefault(), new RGB( 196, 196, 196 ) );
this.line5 = new Color( Display.getDefault(), new RGB( 128, 128, 128 ) );
this.line10 = new Color( Display.getDefault(), new RGB( 64, 64, 64 ) );
}
/**
* @param selection
*/
public void setVertical( final int selection ) {
this.fromProcessLine = selection / this.vSpace;
this.yOffset = selection % this.vSpace - this.vSpace / 2;
}
public abstract void setHorizontal( int i );
void updatePropertiesFromPreferences() {
IPreferenceStore store = Activator.getDefault().getPreferenceStore();
// settings
this.antialiasing = store.getBoolean( PreferenceConstants.P_ANTI_ALIASING );
// selection color
this.selectionColor = new Color( this.eventGraph.getDisplay(),
PreferenceConverter.getColor( store,
PreferenceConstants.P_SELECTION_COLOR ) );
}
protected void handleProperyChanged( final PropertyChangeEvent event ) {
IPreferenceStore store = Activator.getDefault().getPreferenceStore();
// settings
if( event.getProperty().equals( PreferenceConstants.P_ANTI_ALIASING ) ) {
if( event.getNewValue() instanceof String ) {
this.antialiasing = Boolean.getBoolean( ( String )event.getNewValue() );
} else {
this.antialiasing = ( ( Boolean )event.getNewValue() ).booleanValue();
}
this.eventGraph.redraw();
}
// Selection Color
else if( event.getProperty().equals( PreferenceConstants.P_SELECTION_COLOR ) ) {
this.selectionColor.dispose();
this.selectionColor = new Color( Display.getDefault(),
PreferenceConverter.getColor( store,
event.getProperty() ) );
this.eventGraph.redraw();
}
}
public void setFont( final Font font ) {
FontData fontData = font.getFontData()[ 0 ];
fontData.setHeight( this.fontsize );
fontData.setStyle( SWT.NORMAL );
this.smallFont = new Font( font.getDevice(), fontData );
}
protected void drawVRulerWithMovingLine( final GC rulerGC, final int line, final int y ) {
rulerGC.setForeground( rulerGC.getDevice().getSystemColor( SWT.COLOR_BLACK ) );
rulerGC.setBackground( rulerGC.getDevice().getSystemColor( SWT.COLOR_WHITE ) );
rulerGC.fillRoundRectangle( 0, 0, leftRulerWidth, this.height
- bottomMargin, arc, arc );
rulerGC.drawRoundRectangle( 0, 0, leftRulerWidth, this.height
- bottomMargin, arc, arc );
drawVRuler( rulerGC, line );
rulerGC.drawLine( 20, y , 22, y );
String text = getLabelForLine( line );
rulerGC.drawText( text, 3, y - 7 );
}
protected void drawVRuler( final GC rulerGC, final int lineToSkip ) {
rulerGC.setForeground( rulerGC.getDevice().getSystemColor( SWT.COLOR_BLACK ) );
rulerGC.setFont( this.smallFont );
rulerGC.setClipping( 1, 1, 24, this.height - 31 );
for( int i = this.fromProcessLine, y = 0 - this.yOffset; i < this.toProcessLine; i++, y += this.vSpace ) {
if (i == lineToSkip) continue;
if (this.vSpace > 8 || i % 2 == 0) {
String text = getLabelForLine( i );
rulerGC.drawText( text, 3, y - 7 + this.eventSize / 2 );
}
rulerGC.drawLine( 20, y + this.eventSize / 2, 22, y + this.eventSize / 2 );
}
}
protected String getLabelForLine( final int procLine ) {
SortedSet<Integer> procSet = this.eventGraph.getLineToProcessMapping().get( procLine );
StringBuilder sb = new StringBuilder();
Iterator<Integer> it = procSet.iterator();
if (it.hasNext()) {
int procNr = it.next().intValue();
boolean hidden = this.eventGraph.hideProcess[procNr];
if (hidden) sb.append( '(' );
sb.append( procNr );
if (hidden) sb.append( ')' );
while (it.hasNext()) {
procNr = it.next().intValue();
hidden = this.eventGraph.hideProcess[procNr];
sb.append( ',' );
if (hidden) sb.append( '(' );
sb.append( procNr );
if (hidden) sb.append( ')' );
}
} else {
sb.append( 'X' );
}
return sb.toString();
}
protected void drawGridHLines() {
this.gc.setForeground( this.line1 );
LineType hLines = this.eventGraph.getHLines();
if( hLines != LineType.Lines_None ) {
if (this.fastRedraw) hLines = LineType.Lines_10;
for( int i = this.fromProcessLine, y = 0 - this.yOffset + this.eventSize / 2; i < this.toProcessLine; i++, y += this.vSpace )
{
if( i % 10 == 0 ) {
this.gc.setForeground( this.line10 );
this.gc.drawLine( 31, y, this.width - 1, y );
this.gc.setForeground( this.line1 );
} else if( ( hLines == LineType.Lines_5 || hLines == LineType.Lines_1 )
&& i % 5 == 0 )
{
this.gc.setForeground( this.line5 );
this.gc.drawLine( 31, y, this.width - 1, y );
this.gc.setForeground( this.line5 );
} else if( hLines == LineType.Lines_1 ) {
this.gc.drawLine( 31, y, this.width - 1, y );
}
}
}
}
/**
* Draw the controls.
*/
protected void drawBackground() {
// color
this.gc.setForeground( this.gc.getDevice()
.getSystemColor( SWT.COLOR_WIDGET_NORMAL_SHADOW ) );
this.gc.setBackground( this.gc.getDevice().getSystemColor( SWT.COLOR_WHITE ) );
// main
this.gc.fillRectangle( leftMargin,
0,
this.width - leftMargin,
this.height - bottomMargin );
this.gc.drawRectangle( leftMargin,
0,
this.width - leftMargin,
this.height - bottomMargin );
// bottom
this.gc.fillRoundRectangle( leftMargin,
this.height - bottomRulerWidth,
this.width - leftMargin,
bottomRulerWidth,
arc,
arc );
this.gc.drawRoundRectangle( leftMargin,
this.height - bottomRulerWidth,
this.width - leftMargin,
bottomRulerWidth,
arc,
arc );
// left
this.gc.fillRoundRectangle( 0, 0, leftRulerWidth, this.height
- bottomMargin, arc, arc );
this.gc.drawRoundRectangle( 0, 0, leftRulerWidth, this.height
- bottomMargin, arc, arc );
}
/**
* Draw a connection with an arrowhead from (x1,y1) to (x2,y2).
*
* @param x1
* @param y1
* @param x2
* @param y2
*/
protected void connection( final int x1,
final int y1,
final int x2,
final int y2,
final boolean spacing)
{
if( this.fastRedraw ) {
this.gc.drawLine( x2, y2, x1, y1 );
} else {
long xv = x2 - x1;
long yv = y2 - y1;
float c = ( float )Math.sqrt( xv * xv + yv * yv );
int ex = (int)( ( xv / c * getArrowSize() ) + 0.5);
int ey = (int)( ( yv / c * getArrowSize() ) + 0.5);
int ox = spacing ? ex : 0;
int oy = spacing ? ey : 0;
this.gc.drawLine( x2 - ox, y2 - oy, x1 + ox, y1 + oy );
int[] arrowhead = {
x2 - ox,
y2 - oy,
x2 - ox - ex - ey,
y2 - oy - ey + ex,
x2 - ox - ex + ey,
y2 - oy - ey - ex
};
this.gc.fillPolygon( arrowhead );
}
}
public abstract int getArrowSize();
public void setHorizontalScrollBar( final ScrollBar bar ) {
this.horizontalScrollBar = bar;
this.horizontalScrollBar.setPageIncrement( this.hSpace );
this.horizontalScrollBar.addListener( SWT.Selection, new Listener() {
public void handleEvent( final Event e ) {
// might need fixed bug 323092 to work reliable
AbstractGraphPaintListener.this.fastRedraw = e.detail == SWT.DRAG;
handleHorizontalScrollBar();
}
} );
}
public void setVerticalScrollBar( final ScrollBar bar ) {
this.verticalScrollBar = bar;
this.verticalScrollBar.setPageIncrement( this.vSpace );
this.verticalScrollBar.addListener( SWT.Selection, new Listener() {
public void handleEvent( final Event e ) {
// might need fixed bug 323092 to work reliable
AbstractGraphPaintListener.this.fastRedraw = e.detail == SWT.DRAG;
handleVerticalScrollBar();
}
} );
}
protected void handleHorizontalScrollBar() {
int selection = this.horizontalScrollBar.getSelection();
setHorizontal( selection );
this.eventGraph.redraw();
}
protected void handleVerticalScrollBar() {
int selection = this.verticalScrollBar.getSelection();
setVertical( selection );
this.eventGraph.redraw();
}
public int getEventSize() {
return this.eventSize;
}
public int getHSpace() {
return this.hSpace;
}
public int getVSpace() {
return this.vSpace;
}
public int getYOffset() {
return this.yOffset;
}
public int getFromProcessLine() {
return this.fromProcessLine;
}
protected boolean procDrawingEnabled( final int procId, final boolean ignoreHide ) {
return (!this.eventGraph.hideProcess[procId] || ignoreHide) &&
this.eventGraph.getProcessToLineMapping()[procId] != -1;
}
protected boolean procDrawingEnabled( final int procId ) {
return procDrawingEnabled( procId, false );
}
protected int getYPosForProcId( final int procId ) {
int line = this.eventGraph.getProcessToLineMapping()[procId];
return ( line - this.fromProcessLine ) * this.vSpace
- this.yOffset + this.eventSize / 2;
}
public boolean isInGraphArea(int x, int y) {
return x >= 31 && y >= 1 && x <= this.width - 31 && y <= this.height - 31;
}
public void updateSelectionRectangle(Rectangle selectionRect, MouseEvent e) {
GC selectionGC = new GC(this.eventGraph);
selectionGC.setClipping( 31, 1, this.width - 31, this.height - 31 );
selectionGC.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_WHITE));
selectionGC.setXORMode(true);
if (selectionRect.width != 0 || selectionRect.height != 0) {
selectionGC.drawRectangle(selectionRect);
}
if (e != null) {
selectionRect.width = e.x - selectionRect.x;
selectionRect.height = e.y - selectionRect.y;
if (selectionRect.width != 0 || selectionRect.height != 0) {
selectionGC.drawRectangle(selectionRect);
}
}
selectionGC.dispose();
}
public abstract void handleResize();
public abstract void print( final GC gc2 );
public abstract void setTrace( final ITrace trace );
}