SpaceTimeDetailCanvas.java

Go to the documentation of this file.
00001 package edu.rice.cs.hpc.traceviewer.main;
00002 
00003 import java.util.concurrent.ExecutorService;
00004 import java.util.concurrent.Executors;
00005 
00006 import org.eclipse.core.commands.ExecutionException;
00007 import org.eclipse.core.commands.operations.IOperationHistoryListener;
00008 import org.eclipse.core.commands.operations.IUndoableOperation;
00009 import org.eclipse.core.commands.operations.OperationHistoryEvent;
00010 import org.eclipse.core.commands.operations.OperationHistoryFactory;
00011 import org.eclipse.core.runtime.Status;
00012 import org.eclipse.core.runtime.jobs.IJobChangeEvent;
00013 import org.eclipse.core.runtime.jobs.IJobChangeListener;
00014 import org.eclipse.jface.action.Action;
00015 import org.eclipse.swt.SWT;
00016 import org.eclipse.swt.events.DisposeEvent;
00017 import org.eclipse.swt.events.DisposeListener;
00018 import org.eclipse.swt.events.KeyEvent;
00019 import org.eclipse.swt.events.KeyListener;
00020 import org.eclipse.swt.events.PaintEvent;
00021 import org.eclipse.swt.graphics.GC;
00022 import org.eclipse.swt.graphics.Image;
00023 import org.eclipse.swt.graphics.ImageData;
00024 import org.eclipse.swt.graphics.Point;
00025 import org.eclipse.swt.graphics.Rectangle;
00026 import org.eclipse.swt.widgets.Composite;
00027 import org.eclipse.swt.widgets.Label;
00028 import org.eclipse.ui.IWorkbenchWindow;
00029 import org.eclipse.ui.services.ISourceProviderService;
00030 
00031 import edu.rice.cs.hpc.data.experiment.extdata.IBaseData;
00032 import edu.rice.cs.hpc.traceviewer.operation.BufferRefreshOperation;
00033 import edu.rice.cs.hpc.traceviewer.operation.DepthOperation;
00034 import edu.rice.cs.hpc.traceviewer.operation.PositionOperation;
00035 import edu.rice.cs.hpc.traceviewer.operation.TraceOperation;
00036 import edu.rice.cs.hpc.traceviewer.operation.ZoomOperation;
00037 import edu.rice.cs.hpc.traceviewer.painter.AbstractTimeCanvas;
00038 import edu.rice.cs.hpc.traceviewer.painter.BufferPaint;
00039 import edu.rice.cs.hpc.traceviewer.painter.ISpaceTimeCanvas;
00040 import edu.rice.cs.hpc.traceviewer.painter.ImageTraceAttributes;
00041 import edu.rice.cs.hpc.traceviewer.painter.ResizeListener;
00042 import edu.rice.cs.hpc.traceviewer.services.ProcessTimelineService;
00043 import edu.rice.cs.hpc.traceviewer.spaceTimeData.Frame;
00044 import edu.rice.cs.hpc.traceviewer.spaceTimeData.Position;
00045 import edu.rice.cs.hpc.traceviewer.spaceTimeData.SpaceTimeDataController;
00046 import edu.rice.cs.hpc.traceviewer.data.timeline.ProcessTimeline;
00047 import edu.rice.cs.hpc.traceviewer.util.Utility;
00048 import edu.rice.cs.hpc.traceviewer.data.util.Constants;
00049 import edu.rice.cs.hpc.traceviewer.data.util.Debugger;
00050 
00051 
00052 /*************************************************************************
00053  * 
00054  *  Canvas onto which the detail view is painted. Also takes care of
00055  *  zooming responsibilities of the detail view.
00056  *
00057  ************************************************************************/
00058 public class SpaceTimeDetailCanvas extends AbstractTimeCanvas 
00059     implements IOperationHistoryListener, ISpaceTimeCanvas
00060 {   
00062     protected SpaceTimeDataController stData;
00063 
00065     private Action homeButton;
00066     
00068     private Action openButton;
00069     
00071     private Action saveButton;
00072     
00074     private Action tZoomInButton;
00075     
00077     private Action tZoomOutButton;
00078     
00080     private Action pZoomInButton;
00081     
00083     private Action pZoomOutButton;
00084 
00085     private Action goEastButton, goNorthButton, goWestButton, goSouthButton;
00086         
00088     final private Point selectionTopLeft, selectionBottomRight;
00089         
00091     private Composite labelGroup;
00092    
00094     private Label timeLabel;
00095    
00097     private Label processLabel;
00098     
00100     private Label crossHairLabel;
00101         
00103     private final static int MIN_PROC_DISP = 1;
00104     
00105     final private ImageTraceAttributes oldAttributes;
00106     
00107     final private ProcessTimelineService ptlService;
00108     
00109     final IWorkbenchWindow window;
00110 
00111     final private ExecutorService threadExecutor;
00112     
00114     public SpaceTimeDetailCanvas(IWorkbenchWindow window, Composite _composite)
00115     {
00116         super(_composite, SWT.NO_BACKGROUND, RegionType.Rectangle );
00117         oldAttributes = new ImageTraceAttributes();
00118 
00119         selectionTopLeft = new Point(0,0);
00120         selectionBottomRight = new Point(0,0);
00121         stData = null;
00122         
00123         initMouseSelection();
00124         
00125         ISourceProviderService service = (ISourceProviderService)window.
00126                 getService(ISourceProviderService.class);
00127         ptlService = (ProcessTimelineService) service.
00128                 getSourceProvider(ProcessTimelineService.PROCESS_TIMELINE_PROVIDER);
00129         
00130         this.window = window;
00131         
00132         // set the number of maximum threads in the pool to the number of hardware threads
00133         threadExecutor = Executors.newFixedThreadPool( Utility.getNumThreads(0) ); 
00134         
00135         addDisposeListener( new DisposeListener() {
00136             
00137             @Override
00138             public void widgetDisposed(DisposeEvent e) {
00139                 // TODO Auto-generated method stub
00140                 dispose();
00141             }
00142         });
00143     }
00144 
00145 
00146     private void initMouseSelection()
00147     {
00148         initSelectionRectangle();
00149     }
00150     
00151     /*****
00152      * set new database and refresh the screen
00153      * @param dataTraces
00154      *****/
00155     public void updateView(SpaceTimeDataController _stData) {
00156 
00157         super.init();
00158 
00159         if (this.stData == null) 
00160         {
00161             addCanvasListener();
00162             OperationHistoryFactory.getOperationHistory().addOperationHistoryListener(this);
00163         }
00164 
00165         // reinitialize the selection rectangle
00166         initSelectionRectangle();
00167 
00168         this.stData = _stData;
00169 
00170         // init configuration
00171         Position p = new Position(-1, -1);
00172         stData.getAttributes().setPosition(p);
00173         stData.getAttributes().setDepth(0);
00174         
00175         this.home();
00176 
00177         this.saveButton.setEnabled(true);
00178         this.openButton.setEnabled(true);
00179     }
00180     
00181     /***
00182      * add listeners to the canvas 
00183      * caution: this method can only be called at most once ! 
00184      */
00185     private void addCanvasListener() {
00186 
00187         addPaintListener(this);
00188         
00189         addKeyListener( new KeyListener(){
00190             public void keyPressed(KeyEvent e) {}
00191 
00192             public void keyReleased(KeyEvent e) {
00193                 switch (e.keyCode) {
00194                 
00195                 case SWT.ARROW_DOWN:
00196                     goSouth();
00197                     break;
00198                 case SWT.ARROW_UP:
00199                     goNorth();
00200                     break;
00201                 case SWT.ARROW_LEFT:
00202                     goEast();
00203                     break;
00204                 case SWT.ARROW_RIGHT:
00205                     goWest();
00206                     break;              
00207                 }
00208             }           
00209         });
00210                 
00211         // ------------------------------------------------------------------------------------
00212         // A listener for resizing the the window.
00213         // In order to get the last resize position, we will use timer to check if the current
00214         //  resize event is invoked "long" enough to the first resize event.
00215         // If this is the case, then run rebuffering, otherwise just no-op.
00216         // ------------------------------------------------------------------------------------
00217         final ResizeListener listener = new ResizeListener( new DetailBufferPaint() ); 
00218         addControlListener(listener);
00219         getDisplay().addFilter(SWT.MouseDown, listener);
00220         getDisplay().addFilter(SWT.MouseUp, listener);
00221     }
00222     
00223     
00224     /*************************************************************************
00225      * Sets the bounds of the data displayed on the detail canvas to be those 
00226      * specified by the zoom operation and adjusts everything accordingly.
00227      *************************************************************************/
00228     public void zoom(long _topLeftTime, int _topLeftProcess, long _bottomRightTime, int _bottomRightProcess)
00229     {
00230         final ImageTraceAttributes attributes = stData.getAttributes();
00231         attributes.setTime(_topLeftTime, _bottomRightTime);
00232         attributes.assertTimeBounds(stData.getTimeWidth());
00233         
00234         attributes.setProcess(_topLeftProcess, _bottomRightProcess);
00235         attributes.assertProcessBounds(stData.getTotalTraceCount());
00236         
00237         final long numTimeDisplayed = this.getNumTimeUnitDisplayed();
00238         if (numTimeDisplayed < Constants.MIN_TIME_UNITS_DISP)
00239         {
00240             long begTime = _topLeftTime + (numTimeDisplayed - Constants.MIN_TIME_UNITS_DISP) / 2;
00241             long endTime = _topLeftTime + Constants.MIN_TIME_UNITS_DISP;
00242             attributes.setTime(begTime, endTime);
00243         }
00244         
00245         final double numProcessDisp = this.getNumProcessesDisplayed();
00246         if (numProcessDisp < MIN_PROC_DISP)
00247         {
00248             int endProcess = _topLeftProcess + MIN_PROC_DISP;
00249             attributes.setProcess(_topLeftProcess, endProcess );
00250         }
00251 
00252         updateButtonStates();
00253         
00254         // ----------------------------------------------------------------------------
00255         // hack solution: we need to gather the data first, then we ask other views 
00256         //  to update their contents
00257         // ----------------------------------------------------------------------------
00258         refresh(true);
00259     }
00260     
00261     /*******************************************************************************
00262      * Initialize attributes of selection rectangle
00263      *******************************************************************************/
00264     private void initSelectionRectangle() 
00265     {
00266         selectionTopLeft.x = 0;
00267         selectionTopLeft.y = 0;
00268         selectionBottomRight.x = 0;
00269         selectionBottomRight.y = 0;
00270     }
00271     
00272     /*******************************************************************************
00273      * Actually does the repainting of the canvas when a PaintEvent is sent to it
00274      * (basically when anything at all is changed anywhere on the application 
00275      * OR when redraw() is called).
00276      ******************************************************************************/
00277     public void paintControl(PaintEvent event)
00278     {       
00279         if (this.stData == null)
00280             return;
00281 
00282         super.paintControl(event);
00283 
00284         final ImageTraceAttributes attributes = stData.getAttributes();
00285         
00286         //draws cross hairs
00287         long selectedTime = attributes.getPosition().time - attributes.getTimeBegin();
00288         int selectedProcess = attributes.getPosition().process - attributes.getProcessBegin();
00289         
00290         int topPixelCrossHairX = (int)(Math.round(selectedTime*getScalePixelsPerTime())-10);
00291         int topPixelCrossHairY = (int)(Math.round((selectedProcess+.5)*getScalePixelsPerRank())-10);
00292         
00293         event.gc.setForeground(getDisplay().getSystemColor(SWT.COLOR_WHITE));
00294         event.gc.fillRectangle(topPixelCrossHairX,topPixelCrossHairY+8,20,4);
00295         event.gc.fillRectangle(topPixelCrossHairX+8,topPixelCrossHairY,4,20);
00296     }
00297 
00298     /**************************************************************************
00299      * Initializes the buttons above the detail canvas.
00300      **************************************************************************/
00301     public void setButtons(Action[] toolItems)
00302     {
00303         homeButton = toolItems[0];
00304         openButton = toolItems[1];
00305         saveButton = toolItems[2];
00306         tZoomInButton = toolItems[5];
00307         tZoomOutButton = toolItems[6];
00308         pZoomInButton = toolItems[7];
00309         pZoomOutButton = toolItems[8];
00310         
00311         goEastButton = toolItems[9];
00312         goNorthButton = toolItems[10];
00313         goSouthButton = toolItems[11];
00314         goWestButton = toolItems[12];
00315     }
00316     
00317     /**************************************************************************
00318      * The action that gets performed when the 'home' button is pressed - 
00319      * the bounds are reset so that the viewer is zoomed all the way out on the
00320      * image.
00321      **************************************************************************/
00322     public void home()
00323     {
00324         //if this is the first time painting,
00325         //some stuff needs to get initialized
00326         Frame frame = new Frame(stData.getAttributes().getFrame());
00327         frame.begProcess = 0;
00328         frame.endProcess = stData.getTotalTraceCount();
00329         frame.begTime = 0;
00330         frame.endTime = stData.getTimeWidth();
00331         
00332         notifyChanges(ZoomOperation.ActionHome, frame);
00333     }
00334     
00335     /**************************************************************************
00336      * The action that gets performed when the 'open' button is pressed - 
00337      * sets everything to the data stored in the Frame toBeOpened.
00338      **************************************************************************/
00339     public void open(Frame toBeOpened)
00340     {
00341         notifyChanges("Frame", toBeOpened); 
00342     }
00343     
00344     /**************************************************************************
00345      * The action that gets performed when the 'save' button is pressed - 
00346      * it stores all the relevant data to this current configuration to a new 
00347      * Frame.
00348      **************************************************************************/
00349     public Frame save()
00350     {
00351         return stData.getAttributes().getFrame();
00352     }
00353     
00354     
00355     
00356     /**************************************************************************
00357      * The action that gets performed when the 'process zoom in' button is pressed - 
00358      * zooms in processwise with a scale of .4.
00359      **************************************************************************/
00360     public void processZoomIn()
00361     {
00362         final double SCALE = .4;
00363         final ImageTraceAttributes attributes = stData.getAttributes();
00364         
00365         double yMid = (attributes.getProcessEnd()+attributes.getProcessBegin())/2.0;
00366         
00367         final double numProcessDisp = attributes.getProcessInterval();
00368         
00369         int p2 = (int) Math.ceil( yMid+numProcessDisp*SCALE );
00370         int p1 = (int) Math.floor( yMid-numProcessDisp*SCALE );
00371         
00372         attributes.assertProcessBounds(stData.getTotalTraceCount());
00373         
00374         if(p2 == attributes.getProcessEnd() && p1 == attributes.getProcessBegin())
00375         {
00376             if(numProcessDisp == 2)
00377                 p2--;
00378             else if(numProcessDisp > 2)
00379             {
00380                 p2--;
00381                 p1++;
00382             }
00383         }
00384         final Frame frame = new Frame(stData.getAttributes().getFrame());
00385         frame.begProcess = p1;
00386         frame.endProcess = p2;
00387 
00388         notifyChanges("Zoom-in ranks", frame);
00389     }
00390 
00391     /**************************************************************************
00392      * The action that gets performed when the 'process zoom out' button is pressed - 
00393      * zooms out processwise with a scale of .625.
00394      **************************************************************************/
00395     public void processZoomOut()
00396     {
00397         final double SCALE = .625;
00398         final ImageTraceAttributes attributes = stData.getAttributes();
00399         
00400         //zoom out works as follows: find mid point of times (yMid).
00401         //Add/Subtract 1/2 of the scaled numProcessDisp to yMid to get new endProcess and begProcess
00402         double yMid = ((double)attributes.getProcessEnd() + (double)attributes.getProcessBegin())/2.0;
00403         
00404         final double numProcessDisp = attributes.getProcessInterval();
00405         
00406 
00407         int p2 = (int) Math.min( stData.getTotalTraceCount(), Math.ceil( yMid+numProcessDisp*SCALE ) );
00408         int p1 = (int) Math.max( 0, Math.floor( yMid-numProcessDisp*SCALE ) );
00409         
00410         if(p2 == attributes.getProcessEnd() && p1 == attributes.getProcessBegin())
00411         {
00412             if(numProcessDisp == 2)
00413                 p2++;
00414             else if(numProcessDisp > 2)
00415             {
00416                 p2++;
00417                 p1--;
00418             }
00419         }
00420         final Frame frame = new Frame(stData.getAttributes().getFrame());
00421         frame.begProcess = p1;
00422         frame.endProcess = p2;
00423 
00424         notifyChanges("Zoom-out ranks", frame);
00425     }
00426 
00427     
00428     /**************************************************************************
00429      * The action that gets performed when the 'time zoom in' button is pressed - 
00430      * zooms in timewise with a scale of .4.
00431      **************************************************************************/
00432     public void timeZoomIn()
00433     {
00434         final double SCALE = .4;
00435         final ImageTraceAttributes attributes = stData.getAttributes();
00436         
00437         long xMid = (attributes.getTimeEnd() + attributes.getTimeBegin()) / 2;
00438         
00439         final long numTimeUnitsDisp = attributes.getTimeInterval();
00440         
00441         long t2 = xMid + (long)(numTimeUnitsDisp * SCALE);
00442         long t1 = xMid - (long)(numTimeUnitsDisp * SCALE);
00443 
00444         final Frame frame = new Frame(stData.getAttributes().getFrame());
00445         frame.begTime = t1;
00446         frame.endTime = t2;
00447         
00448         notifyChanges("Zoom-in time", frame);
00449     }
00450 
00451     /**************************************************************************
00452      * The action that gets performed when the 'time zoom out' button is pressed - 
00453      * zooms out timewise with a scale of .625.
00454      **************************************************************************/
00455     public void timeZoomOut()
00456     {
00457         final double SCALE = 0.625;
00458         final ImageTraceAttributes attributes = stData.getAttributes();
00459         
00460         //zoom out works as follows: find mid point of times (xMid).
00461         //Add/Subtract 1/2 of the scaled numTimeUnitsDisp to xMid to get new endTime and begTime
00462         long xMid = (attributes.getTimeEnd() + attributes.getTimeBegin()) / 2;
00463         
00464         final long td2 = (long)(this.getNumTimeUnitDisplayed() * SCALE); 
00465         long t2 = Math.min( stData.getTimeWidth(), xMid + td2);
00466         final long td1 = (long)(this.getNumTimeUnitDisplayed() * SCALE);
00467         long t1 = Math.max(0, xMid - td1);
00468 
00469         final Frame frame = new Frame(stData.getAttributes().getFrame());
00470         frame.begTime = t1;
00471         frame.endTime = t2;
00472         
00473         notifyChanges("Zoom-out time", frame);
00474     }
00475     
00476     /**************************************************************************
00477      * Gets the scale along the x-axis (pixels per time unit).
00478      **************************************************************************/
00479     @Override
00480     public double getScalePixelsPerTime()
00481     {
00482         return (double)stData.getAttributes().numPixelsH / (double)this.getNumTimeUnitDisplayed();
00483     }
00484     
00485     /**************************************************************************
00486      * Gets the scale along the y-axis (pixels per process).
00487      **************************************************************************/
00488     @Override
00489     public double getScalePixelsPerRank()
00490     {
00491         return (double)stData.getAttributes().numPixelsV / this.getNumProcessesDisplayed();
00492     }
00493     
00494     /**************************************************************************
00495      * Sets the depth to newDepth.
00496      **************************************************************************/
00497     public void setDepth(int newDepth)
00498     {
00499         stData.getAttributes().setDepth(newDepth);
00500         refresh(false);
00501     }
00502     
00503     
00504     /**************************************************************************
00505      * Sets up the labels (the ones below the detail canvas).
00506      **************************************************************************/
00507     public void setLabels(Composite _labelGroup)
00508     {
00509         labelGroup = _labelGroup;
00510         
00511         timeLabel = new Label(labelGroup, SWT.LEFT);
00512         processLabel = new Label(labelGroup, SWT.CENTER);
00513         crossHairLabel = new Label(labelGroup, SWT.RIGHT);
00514     }
00515    
00516     /**************************************************************************
00517      * Updates what the labels display to the viewer's current state.
00518      **************************************************************************/
00519     private void adjustLabels()
00520     {
00521         final ImageTraceAttributes attributes = stData.getAttributes();
00522         
00523         timeLabel.setText("Time Range: [" + (attributes.getTimeBegin()/1000)/1000.0 + "s, "
00524                             + (attributes.getTimeEnd()/1000)/1000.0 +  "s]");
00525         timeLabel.setSize(timeLabel.computeSize(SWT.DEFAULT, SWT.DEFAULT));
00526         
00527 
00528         final IBaseData traceData = stData.getBaseData();
00529         if (traceData == null) {
00530             // we don't want to throw an exception here, so just do nothing
00531             System.out.println("Data null, skipping the rest.");
00532             return;
00533         }
00534         stData.getAttributes().assertProcessBounds(traceData.getNumberOfRanks());
00535 
00536         final String processes[] = traceData.getListOfRanks();
00537 
00538         int proc_start = attributes.getProcessBegin();
00539         if (proc_start < 0 || proc_start >= processes.length)
00540             proc_start = 0;
00541         
00542         // -------------------------------------------------------------------------------------------------
00543         // bug fix: since the end of the process is the ceiling of the selected region,
00544         //          and the range of process rendering is based on inclusive min and exclusive max, then
00545         //          we need to decrement the value of max process (in the range).
00546         // WARN: the display of process range should be then between inclusive min and inclusive max
00547         //
00548         // TODO: we should fix the rendering to inclusive min and inclusive max, otherwise it is too much
00549         //       headache to maintain
00550         // -------------------------------------------------------------------------------------------------
00551         int proc_end   = attributes.getProcessEnd() - 1;
00552         if (proc_end>=processes.length)
00553             proc_end = processes.length-1;
00554         
00555         processLabel.setText("Rank Range: [" + processes[proc_start] + "," + processes[proc_end]+"]");
00556         processLabel.setSize(processLabel.computeSize(SWT.DEFAULT, SWT.DEFAULT));
00557         
00558         if(stData == null)
00559             crossHairLabel.setText("Select Sample For Cross Hair");
00560         else
00561         {
00562             final Position position = stData.getAttributes().getPosition();
00563             final long selectedTime = position.time;
00564             final int rank = position.process;
00565             
00566             if ( rank >= 0 && rank < processes.length ) {               
00567                 crossHairLabel.setText("Cross Hair: (" + (selectedTime/1000)/1000.0 + "s, " + processes[rank] + ")");
00568             } else {
00569                 // in case of incorrect filtering where user may have empty ranks or incorrect filters, we don't display the rank
00570                 crossHairLabel.setText("Cross Hair: (" + (selectedTime/1000)/1000.0 + "s, ?)");
00571             }
00572         }
00573         
00574         labelGroup.setSize(labelGroup.computeSize(SWT.DEFAULT, SWT.DEFAULT));
00575     }
00576     
00577     /**************************************************************************
00578      * Updates what the position of the selected box is.
00579      **************************************************************************/
00580     private void adjustSelection(Rectangle selection)
00581     {
00582         selectionTopLeft.x = Math.max(selection.x, 0);
00583         selectionTopLeft.y = Math.max(selection.y, 0);
00584         
00585         final Rectangle view = getClientArea();
00586         
00587         selectionBottomRight.x = Math.min(selection.width+selection.x, view.width-1);
00588         selectionBottomRight.y = Math.min(selection.height+selection.y, view.height-1);
00589         
00590         if (selectionTopLeft.x < 0 || selectionBottomRight.x < 0 || view.x < 0) {
00591             Debugger.printDebug(1, "STDC Error: negative time " + view + 
00592                     " [" + selectionTopLeft.x + ", " + selectionBottomRight.x + "]");
00593         }
00594     }
00595     
00596     /**************************************************************************
00597      * create a new region of trace view, and check if the cross hair is inside
00598      *  the new region or not. If this is not the case, we force the position
00599      *  of crosshair to be inside the region 
00600      **************************************************************************/
00601     private void setDetail()
00602     {
00603         ImageTraceAttributes attributes = stData.getAttributes();
00604         int topLeftProcess = attributes.getProcessBegin() + (int) (selectionTopLeft.y / getScalePixelsPerRank());
00605         long topLeftTime   = attributes.getTimeBegin() + (long)(selectionTopLeft.x / getScalePixelsPerTime());
00606         
00607         // ---------------------------------------------------------------------------------------
00608         // we should include the partial selection of a time or a process
00609         // for instance if the user selects processes where the max process is between
00610         //  10 and 11, we should include process 11 (just like keynote selection)
00611         // ---------------------------------------------------------------------------------------
00612         int bottomRightProcess = attributes.getProcessBegin() + (int) Math.ceil( (selectionBottomRight.y / getScalePixelsPerRank()) );
00613         long bottomRightTime   = attributes.getTimeBegin() + (long)Math.ceil( (selectionBottomRight.x / getScalePixelsPerTime()) );
00614 
00615 
00616         final Frame frame = new Frame(stData.getAttributes().getFrame());
00617         frame.begTime = topLeftTime;
00618         frame.endTime = bottomRightTime;
00619         frame.begProcess = topLeftProcess;
00620         frame.endProcess = bottomRightProcess;
00621         
00622         notifyChanges("Zoom", frame);
00623     }
00624     
00625   
00626     private boolean canGoEast() {
00627         return (stData.getAttributes().getTimeBegin() > 0);
00628     }
00629     
00630     private boolean canGoWest() {
00631         return (stData.getAttributes().getTimeEnd()< this.stData.getTimeWidth());
00632     }
00633     
00634     private boolean canGoNorth() {
00635         return (stData.getAttributes().getProcessBegin()>0);
00636     }
00637     
00638     private boolean canGoSouth() {
00639         return (stData.getAttributes().getProcessEnd()<this.stData.getTotalTraceCount());
00640     }
00641     /**********
00642      * check the status of all buttons
00643      */
00644     private void updateButtonStates() 
00645     {
00646         final ImageTraceAttributes attributes = stData.getAttributes();
00647         
00648         this.tZoomInButton.setEnabled( this.getNumTimeUnitDisplayed() > Constants.MIN_TIME_UNITS_DISP );
00649         this.tZoomOutButton.setEnabled(attributes.getTimeBegin()>0 || attributes.getTimeEnd()<stData.getTimeWidth() );
00650         
00651         this.pZoomInButton.setEnabled( getNumProcessesDisplayed() > MIN_PROC_DISP );
00652         this.pZoomOutButton.setEnabled( attributes.getProcessBegin()>0 || attributes.getProcessEnd()<stData.getTotalTraceCount());
00653         
00654         this.goEastButton.setEnabled( canGoEast() );
00655         this.goWestButton.setEnabled( canGoWest() );
00656         this.goNorthButton.setEnabled( canGoNorth() );
00657         this.goSouthButton.setEnabled( canGoSouth() );
00658         
00659         homeButton.setEnabled( attributes.getTimeBegin()>0 || attributes.getTimeEnd()<stData.getTimeWidth()
00660                 || attributes.getProcessBegin()>0 || attributes.getProcessEnd()<stData.getTotalTraceCount() );
00661     }
00662     
00663     final static private double SCALE_MOVE = 0.20;
00664     
00665     /***
00666      * go to the left one step
00667      */
00668     public void goEast()
00669     {
00670         if (!canGoEast())
00671             return;
00672         
00673         final ImageTraceAttributes attributes = stData.getAttributes();
00674         
00675         long topLeftTime = attributes.getTimeBegin();
00676         long bottomRightTime = attributes.getTimeEnd();
00677         
00678         long deltaTime = bottomRightTime - topLeftTime;
00679         final long moveTime = (long)java.lang.Math.ceil(deltaTime * SCALE_MOVE);
00680         topLeftTime = topLeftTime - moveTime;
00681         
00682         if (topLeftTime < 0) {
00683             topLeftTime = 0;
00684         }
00685         bottomRightTime = topLeftTime + deltaTime;
00686         
00687         setTimeRange(topLeftTime, bottomRightTime);
00688         
00689         updateButtonStates();
00690     }
00691     
00692     /***
00693      * go to the right one step
00694      */
00695     public void goWest()
00696     {
00697         if (!canGoWest())
00698             return;
00699         
00700         final ImageTraceAttributes attributes = stData.getAttributes();
00701         
00702         long topLeftTime = attributes.getTimeBegin();
00703         long bottomRightTime = attributes.getTimeEnd();
00704         
00705         long deltaTime = bottomRightTime - topLeftTime;
00706         final long moveTime = (long)java.lang.Math.ceil(deltaTime * SCALE_MOVE);
00707         bottomRightTime = bottomRightTime + moveTime;
00708         
00709         if (bottomRightTime > stData.getTimeWidth()) {
00710             bottomRightTime = stData.getTimeWidth();
00711         }
00712         topLeftTime = bottomRightTime - deltaTime;
00713         
00714         setTimeRange(topLeftTime, bottomRightTime);
00715         
00716         this.updateButtonStates();
00717     }
00718     
00719     /***
00720      * set a new range of X-axis
00721      * @param topLeftTime
00722      * @param bottomRightTime
00723      */
00724     public void setTimeRange(long topLeftTime, long bottomRightTime)
00725     {
00726         final Frame frame = new Frame(stData.getAttributes().getFrame());
00727         frame.begTime = topLeftTime;
00728         frame.endTime = bottomRightTime;
00729         
00730         notifyChanges("Zoom H", frame);
00731     }
00732 
00733     /*******
00734      * go north one step
00735      */
00736     public void goNorth() {
00737         if (!canGoNorth())
00738             return;
00739         
00740         final ImageTraceAttributes attributes = stData.getAttributes();
00741         
00742         int proc_begin = attributes.getProcessBegin();
00743         int proc_end = attributes.getProcessEnd();
00744         final int delta = proc_end - proc_begin;
00745         final int move = (int) java.lang.Math.ceil(delta * SCALE_MOVE);
00746 
00747         proc_begin = proc_begin - move;
00748         
00749         if (proc_begin < 0) {
00750             proc_begin = 0;
00751         }
00752         proc_end = proc_begin + delta;
00753         this.setProcessRange(proc_begin, proc_end);
00754         this.updateButtonStates();
00755     }
00756 
00757     /*******
00758      * go south one step
00759      */
00760     public void goSouth() {
00761         if (!canGoSouth())
00762             return;
00763         
00764         final ImageTraceAttributes attributes = stData.getAttributes();
00765         
00766         int proc_begin = attributes.getProcessBegin();
00767         int proc_end = attributes.getProcessEnd();
00768         final int delta = proc_end - proc_begin;
00769         final int move = (int) java.lang.Math.ceil(delta * SCALE_MOVE);
00770 
00771         proc_end = proc_end + move;
00772         
00773         if (proc_end > stData.getTotalTraceCount()) {
00774             proc_end = stData.getTotalTraceCount();
00775         }
00776         proc_begin = proc_end - delta;
00777         this.setProcessRange(proc_begin, proc_end);
00778         this.updateButtonStates();
00779     }
00780     
00781     /***
00782      * set a new range for Y-axis
00783      * @param pBegin: the top position
00784      * @param pEnd: the bottom position
00785      */
00786     private void setProcessRange(int pBegin, int pEnd) 
00787     {
00788         final ImageTraceAttributes attributes = stData.getAttributes();
00789         final Frame frame = new Frame(attributes.getFrame());
00790         frame.begProcess = pBegin;
00791         frame.endProcess = pEnd;
00792         
00793         notifyChanges("Zoom V", frame);
00794     }
00795 
00796     private Position updatePosition(Point mouseDown)
00797     {
00798         final ImageTraceAttributes attributes = stData.getAttributes();
00799         final Rectangle view = getClientArea();
00800         int selectedProcess;
00801 
00802         //need to do different things if there are more traces to paint than pixels
00803         if(view.height > getNumProcessesDisplayed())
00804         {
00805             selectedProcess = (int)(attributes.getProcessBegin()+mouseDown.y/getScalePixelsPerRank());
00806         }
00807         else
00808         {
00809             selectedProcess = (int)(attributes.getProcessBegin()+(mouseDown.y*(getNumProcessesDisplayed()))/view.height);
00810         }
00811         long closeTime = attributes.getTimeBegin() + (long)(mouseDown.x / getScalePixelsPerTime());
00812         
00813         if (closeTime > attributes.getTimeEnd()) {
00814             System.err.println("ERR STDC SCSSample time: " + closeTime +" max time: " + 
00815                     attributes.getTimeEnd() + "\t new: " + ((attributes.getTimeBegin() + attributes.getTimeEnd()) >> 1));
00816             closeTime = (attributes.getTimeBegin() + attributes.getTimeEnd()) >> 1;
00817         }
00818         
00819         return new Position(closeTime, selectedProcess);
00820     }
00821     
00822     
00823     private long getNumTimeUnitDisplayed()
00824     {
00825         return (stData.getAttributes().getTimeInterval());
00826     }
00827     
00828     private double getNumProcessesDisplayed()
00829     {
00830         return (stData.getAttributes().getProcessInterval());
00831     }
00832     
00833 
00834     
00835     /*********************************************************************************
00836      * Refresh the content of the canvas with new input data or boundary or parameters
00837      *  
00838      *  @param refreshData boolean whether we need to refresh and read again the data or not
00839      *********************************************************************************/
00840     public void refresh(boolean refreshData) {
00841         //Debugger.printTrace("STDC rebuffer");
00842         //Okay, so here's how this works. In order to draw to an Image (the Eclipse kind)
00843         //you need to draw to its GC. So, we have this bufferImage that we draw to, so
00844         //we get its GC (bufferGC), and then pass that GC to paintViewport, which draws
00845         //everything to it. Then the image is copied to the canvas on the screen with that
00846         //event.gc.drawImage call down there below the 'if' block - this is called "double buffering," 
00847         //and it's useful because it prevent the screen from flickering (if you draw directly then
00848         //you would see each sample as it was getting drawn very quickly, which you would
00849         //interpret as flickering. This way, you finish the puzzle before you put it on the
00850         //table).
00851 
00852         // -----------------------------------------------------------------------
00853         // imageFinal is the final image with info of the depth and number of samples
00854         // the size of the final image is the same of the size of the canvas
00855         // -----------------------------------------------------------------------
00856 
00857         final Rectangle view = getClientArea();
00858                 
00859         final Image imageFinal = new Image(getDisplay(), view.width, view.height);
00860         final GC bufferGC = new GC(imageFinal);
00861         bufferGC.setBackground(Constants.COLOR_WHITE);
00862         bufferGC.fillRectangle(0,0,view.width,view.height);
00863         
00864         // -----------------------------------------------------------------------
00865         // imageOrig is the original image without "attributes" such as depth
00866         // this imageOrig will be used by SummaryView to count the number of colors
00867         // the size of the "original" image should be equivalent to the minimum of 
00868         //  the number of ranks or the number of pixels
00869         // -----------------------------------------------------------------------
00870         
00871         int numLines = Math.min(view.height, stData.getAttributes().getProcessInterval() );
00872         final Image imageOrig = new Image(getDisplay(), view.width, numLines);
00873         
00874         final GC origGC = new GC(imageOrig);
00875         origGC.setBackground(Constants.COLOR_WHITE);
00876         origGC.fillRectangle(0,0,view.width, numLines);
00877 
00878         // -----------------------------------------------------------------------
00879         // main method to paint to the canvas
00880         // if there's no exception or interruption, we redraw the canvas
00881         // -----------------------------------------------------------------------
00882 
00883         ImageTraceAttributes attributes = stData.getAttributes();
00884         final boolean changedBounds = (refreshData? refreshData : !attributes.sameTrace(oldAttributes) );
00885         
00886         attributes.numPixelsH = view.width;
00887         attributes.numPixelsV = view.height;
00888         
00889         oldAttributes.copy(attributes);
00890         if (changedBounds) {
00891             final int num_traces = Math.min(attributes.numPixelsV, attributes.getProcessInterval());
00892             ProcessTimeline []traces = new ProcessTimeline[ num_traces ];
00893             ptlService.setProcessTimeline(traces);
00894         }
00895 
00896         /*************************************************************************
00897          *  Paints the specified time units and processes at the specified depth
00898          *  on the SpaceTimeCanvas using the SpaceTimeSamplePainter given. Also paints
00899          *  the sample's max depth before becoming overDepth on samples that have gone over depth.
00900          *************************************************************************/
00901         DetailViewPaint detailPaint = new DetailViewPaint(bufferGC, origGC, stData, 
00902                     attributes, changedBounds, window, this, threadExecutor); 
00903 
00904         detailPaint.setUser(true);
00905         detailPaint.addJobChangeListener(new IJobChangeListener() {
00906             
00907             @Override
00908             public void sleeping(IJobChangeEvent event) {}
00909             
00910             @Override
00911             public void scheduled(IJobChangeEvent event) {}
00912             
00913             @Override
00914             public void running(IJobChangeEvent event) {}
00915             
00916             @Override
00917             public void done(IJobChangeEvent event) {
00918                 if (event.getResult() == Status.OK_STATUS)
00919                 {
00920                     donePainting(imageOrig, imageFinal, changedBounds);
00921                 } else
00922                 {
00923                     // we don't need this "new image" since the paint fails
00924                     imageFinal.dispose();   
00925                 }
00926                 // free resources 
00927                 bufferGC.dispose();
00928                 origGC.dispose();
00929                 imageOrig.dispose();
00930             }
00931             
00932             @Override
00933             public void awake(IJobChangeEvent event) {}
00934             
00935             @Override
00936             public void aboutToRun(IJobChangeEvent event) {}
00937         });
00938         detailPaint.schedule();
00939     }
00940     
00941 
00942     private void donePainting(Image imageOrig, Image imageFinal, boolean refreshData)
00943     {       
00944         if (imageBuffer != null) {
00945             imageBuffer.dispose();
00946         }
00947         imageBuffer = imageFinal;
00948         
00949         // in case of filter, we may need to change the cursor position
00950         if (refreshData) {
00951             final String []ranks = stData.getBaseData().getListOfRanks();
00952             final Position p = stData.getAttributes().getPosition();
00953             
00954             if (p.process > ranks.length-1) {
00955                 // out of range: need to change the cursor position
00956                 Position new_p = new Position( p.time, ranks.length >> 1 );
00957                 notifyChangePosition(new_p);
00958             }
00959         }
00960         super.redraw();
00961 
00962         // -----------------------------------------------------------------------
00963         // notify to all other views that a new image has been created,
00964         //  and it needs to refresh the view
00965         // -----------------------------------------------------------------------
00966         notifyChangeBuffer(imageOrig.getImageData());
00967         
00968         updateButtonStates();
00969     }
00970     
00971     
00972     /*
00973      * (non-Javadoc)
00974      * @see org.eclipse.swt.widgets.Widget#dispose()
00975      */
00976     public void dispose () { 
00977         threadExecutor.shutdown();
00978         super.dispose();
00979     }
00980 
00981     //-----------------------------------------------------------------------------------------
00982     // Part for notifying changes to other views
00983     //-----------------------------------------------------------------------------------------
00984     
00985     
00986     /***********************************************************************************
00987      * notify changes to other views
00988      * 
00989      * @param _topLeftTime
00990      * @param _topLeftProcess
00991      * @param _bottomRightTime
00992      * @param _bottomRightProcess
00993      ***********************************************************************************/
00994     private void notifyChanges(String label, Frame frame) 
00995     {
00996         String sLabel = (label == null ? "Set region" : label);
00997         Debugger.printDebug(1, "STDC " + sLabel + " : " + frame);
00998         // forces all other views to refresh with the new region
00999         try {
01000             // notify change of ROI
01001             TraceOperation.getOperationHistory().execute(
01002                     new ZoomOperation(sLabel, frame), 
01003                     null, null);
01004             
01005         } catch (ExecutionException e) {
01006             // TODO Auto-generated catch block
01007             e.printStackTrace();
01008         }
01009     }
01010     
01011     /***********************************************************************************
01012      * notify cursor position change to other views
01013      * 
01014      * @param position
01015      ***********************************************************************************/
01016     private void notifyChangePosition(Position position) 
01017     {
01018         try {
01019             TraceOperation.getOperationHistory().execute(
01020                     new PositionOperation(position), 
01021                     null, null);
01022         } catch (ExecutionException e) {
01023             e.printStackTrace();
01024         }
01025     }
01026     
01027     /***********************************************************************************
01028      * Notify other views (especially summary view) that we have changed the buffer.
01029      * The other views need to refresh the display if needed.
01030      * 
01031      * @param imageData
01032      ***********************************************************************************/
01033     private void notifyChangeBuffer(ImageData imageData)
01034     {
01035         // -----------------------------------------------------------------------
01036         // notify to SummaryView that a new image has been created,
01037         //  and it needs to refresh the view
01038         // -----------------------------------------------------------------------
01039 
01040         BufferRefreshOperation brOp = new BufferRefreshOperation("refresh", imageData);
01041         try {
01042             TraceOperation.getOperationHistory().execute(brOp, null, null);
01043         } catch (ExecutionException e) {
01044             e.printStackTrace();
01045         }
01046     }
01047 
01048     //-----------------------------------------------------------------------------------------
01049     // Part for handling operation triggered from other views
01050     //-----------------------------------------------------------------------------------------
01051     private HistoryOperation historyOperation = new HistoryOperation();
01052     
01053     @Override
01054     public void historyNotification(final OperationHistoryEvent event) {
01055         final IUndoableOperation operation = event.getOperation();
01056 
01057         // handling the operations
01058         if (operation.hasContext(TraceOperation.traceContext) ||
01059                 operation.hasContext(PositionOperation.context)) 
01060         {
01061             int type = event.getEventType();
01062             // warning: hack solution
01063             // this space time detail canvas has priority to execute first before the others
01064             // the reason is most objects requires a new value of process time lines
01065             //  however this objects are set by this class
01066             switch (type)
01067             {
01068             case OperationHistoryEvent.ABOUT_TO_EXECUTE:
01069             case OperationHistoryEvent.ABOUT_TO_REDO:
01070             case OperationHistoryEvent.ABOUT_TO_UNDO:
01071                 historyOperation.setOperation(operation);
01072                 
01073                 // we don't want to run the operation in a separate thread or in the UI thread
01074                 // since this operation can incur an exception such as time out or connection error.
01075                 // instead, we should run within the current process (it isn't ideal, but it works
01076                 //  just fine at the moment)
01077                 
01078                 historyOperation.run();
01079                 break;
01080             }
01081         }
01082     }
01083     
01084     
01085     //-----------------------------------------------------------------------------------------
01086     // PRIVATE CLASSES
01087     //-----------------------------------------------------------------------------------------
01088     
01089 
01090     /*************************************************************************
01091      * 
01092      * Resizing thread by listening to the event if a user has finished
01093      *  the resizing or not
01094      *
01095      *************************************************************************/
01096     private class DetailBufferPaint implements BufferPaint
01097     {
01098 
01099         @Override
01100         public void rebuffering() {
01101             // force the paint to refresh the data          
01102             final ImageTraceAttributes attr = stData.getAttributes();
01103             notifyChanges("Resize", attr.getFrame() );
01104         }
01105     }
01106 
01107     /*****
01108      * 
01109      * Thread-centric operation to perform undoable operations asynchronously
01110      *
01111      *****/
01112     private class HistoryOperation implements Runnable
01113     {
01114         private IUndoableOperation operation;
01115         
01116         public void setOperation(IUndoableOperation operation) {
01117             this.operation = operation;
01118         }
01119         
01120         @Override
01121         public void run() {
01122             // zoom in/out or change of ROI ?
01123             if (operation instanceof ZoomOperation) {
01124                 Frame frame = ((ZoomOperation)operation).getFrame();
01125                 final ImageTraceAttributes attributes = stData.getAttributes();
01126                 
01127                 Debugger.printDebug(1, "STDC: " + attributes + "\t New: " + frame);
01128                 //stData.getAttributes().setPosition(frame.position);
01129                 stData.getAttributes().setFrame(frame);
01130                 zoom(frame.begTime, frame.begProcess, frame.endTime, frame.endProcess);
01131             }
01132             // change of cursor position ?
01133             else if (operation instanceof PositionOperation) {
01134                 Position p = ((PositionOperation)operation).getPosition();
01135                 stData.getAttributes().setPosition(p);
01136 
01137                 // just change the position, doesn't need to fully refresh
01138                 redraw();
01139             } 
01140             else if (operation instanceof DepthOperation) {
01141                 int depth = ((DepthOperation)operation).getDepth();
01142                 setDepth(depth);
01143             }
01144             adjustLabels();
01145         }
01146     }
01147 
01148     @Override
01149     protected void changePosition(Point point) 
01150     {
01151         Position position = updatePosition(point);
01152         notifyChangePosition(position);
01153     }
01154 
01155 
01156     @Override
01157     protected void changeRegion(Rectangle region) 
01158     {
01159         //If we're zoomed in all the way don't do anything
01160         if(getNumTimeUnitDisplayed() == Constants.MIN_TIME_UNITS_DISP)
01161         {
01162             if(getNumTimeUnitDisplayed() > MIN_PROC_DISP)
01163             {
01164                 adjustSelection(region);
01165                 setDetail();
01166             }
01167         }
01168         else
01169         {
01170             adjustSelection(region);
01171             setDetail();
01172         }
01173     }
01174 }

Generated on 5 May 2015 for HPCVIEWER by  doxygen 1.6.1