Very stable and almost final version ofthe histogram view. Fix resize, silly SWT...
authorWilliam Bourque <william.bourque@polymtl.ca>
Fri, 23 Apr 2010 19:05:36 +0000 (19:05 +0000)
committerWilliam Bourque <william.bourque@polymtl.ca>
Fri, 23 Apr 2010 19:05:36 +0000 (19:05 +0000)
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramCanvasControlListener.java
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramContent.java
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramRequest.java
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/HistogramView.java
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/ParentHistogramCanvas.java
org.eclipse.linuxtools.lttng.ui/src/org/eclipse/linuxtools/lttng/ui/views/histogram/ParentHistogramCanvasPaintListener.java

index cda50f53e1d696e2a18a24130b693c6b6326f277..6df72388cb35fbe58c6bdd74e1a93c8657f9992a 100644 (file)
@@ -39,7 +39,7 @@ public class HistogramCanvasControlListener implements ControlListener {
         * 
         * We need to tell the content that the canvas size changed and to recenter the windows
         * 
-        * @param event         The controle event generated by the resize.
+        * @param event         The control event generated by the resize.
         */
        public void controlResized(ControlEvent event) {
                
index 281406ddc49480df4c320de0e60a40cc8db8d757..6ddad8303f98837554f2ceb38afd02d8e13423cf 100644 (file)
@@ -36,6 +36,8 @@ public class HistogramContent {
        // This value is used to calculate at which point we should "cut" bar that are too tall.
        // Default value is large enought so that no bar should be cut
        protected Double  maxDifferenceToAverage = HistogramConstant.DEFAULT_DIFFERENCE_TO_AVERAGE;
+       // This is a factor we might apply on the max difference to average, as example if we concatenate interval together
+       protected Double  maxDifferenceFactor = 1.0;
        
        // By default we will only consider element up to this position 
        protected Integer       readyUpToPosition = 0;
@@ -75,9 +77,7 @@ public class HistogramContent {
                canvasWindowSize = newCanvasSize;
                barsWidth = newBarWidth;
                maxHeight = newMaxHeight;
-               
-               // Max difference is a bit special, we need to call set
-               setMaxDifferenceToAverage(newDiffToAverage);
+               maxDifferenceToAverage = newDiffToAverage;
                
                // Create a new element table from the above value
                // The table will not get initialized until resetTable() is called. 
@@ -480,9 +480,6 @@ public class HistogramContent {
                return endTime;
        }
        
-       // *** TODO ***
-       // Implement a way to "compress" a table if the endtime change.
-       // That way, the end time could change without having to reset the table data.
        /**
         * Setter for the end time of the content.<p>
         * Note : You probably want to call "resetTable()" if you change this, otherwise data might be inconsistent.
@@ -530,9 +527,9 @@ public class HistogramContent {
        public void recalculateHeightFactor() {
                // Recalculate the new HeightFactor for the element; 
                //              the highest bar will get "maxHeight" and other bar a fraction of it.
-               // If a maxDifferenceToAverage exist, this is considered here 
-               if ( heighestEventCount > (maxDifferenceToAverage * averageNumberOfEvents) ) {
-                       heightFactor = (double)maxHeight/( maxDifferenceToAverage * (double)averageNumberOfEvents);
+               double diffToConsider = (maxDifferenceToAverage * maxDifferenceFactor * (double)barsWidth);
+               if ( heighestEventCount > (int)(diffToConsider * (double)averageNumberOfEvents) ) {
+                       heightFactor = (double)maxHeight/( diffToConsider * (double)averageNumberOfEvents);
                }
                else {
                        heightFactor = (double)maxHeight/(double)heighestEventCount;
@@ -668,13 +665,38 @@ public class HistogramContent {
         * This determine at which point a bar too tall is "cut". Set a very large value (like 1000.0) to ignore.
         * 
         * Note : this is used in some drawing calculation so make sure this number make sense.
-        * Note : the given number is multiplied by the bar width, as we have bigger bar (so more events as average to consider)
         * Note : you might want to call recalculateEventHeight() if you change this.
         * 
         * @param newDiffToAverage      The new maximum difference to the average to use.
         */
        public void setMaxDifferenceToAverage(Double newDiffToAverage) {
-               maxDifferenceToAverage = (newDiffToAverage*barsWidth);
+               maxDifferenceToAverage = newDiffToAverage;
+       }
+       
+       
+       /**
+        * Getter for a factor applied to the max difference to the average height a bar can have.<p>
+        * This is muliplied to maxDifferenceToAverage. Set to value 1.0 to ignore.
+        * 
+        * Note : this is useful if you concatenate some intervals to gether but want the average to be consistent
+        * 
+        * @return      maximum difference to the average we currently use.
+        */
+       public Double getMaxDifferenceToAverageFactor() {
+               return maxDifferenceFactor;
+       }
+       
+       /**
+        * Setter for a factor applied to the max difference to the average height a bar can have.<p>
+        * 
+        * Note : this is used in some drawing calculation so make sure this number make sense.
+        * Note : you might want to call recalculateEventHeight() if you change this.
+        * Note : setting to 0 will cause bar to have a zero size... use 1.0 to desactivate
+        * 
+        * @param newFactor             The new factor to use.
+        */
+       public void setMaxDifferenceToAverageFactor(Double newFactor) {
+               maxDifferenceFactor = newFactor;
        }
        
        
index 1e959d5925a1bd0ed2e0a6e709a68c0810c452d7..db8db7cc797d95d3f2de23f6a7326bf7bd6f602c 100644 (file)
@@ -34,8 +34,6 @@ public class HistogramRequest extends TmfEventRequest<LttngEvent> {
        
        protected Integer       lastDrawPosition = 0;
        
-       protected Boolean       requestCompleted = false;
-       
        protected HistogramCanvas parentCanvas = null;
        
        /**
@@ -87,7 +85,8 @@ public class HistogramRequest extends TmfEventRequest<LttngEvent> {
        //      However, the request with number of events will loop until it reach its number or EOF
        //  We have to filter out ourself the extra useless events!
        //
-        if ( (evt[0] != null) && (requestCompleted == false) ) {
+        if (evt[0] != null) {
+        
                LttngEvent tmpEvent = (LttngEvent)evt[0];
                
                // This check is linked to the evil fix mentionned above
@@ -143,19 +142,20 @@ public class HistogramRequest extends TmfEventRequest<LttngEvent> {
                                        redrawAsyncronously();
                                }
                }
-               else {
-                       //System.out.println("Requested Timerange is : " + histogramContent.getStartTime() + " / " + histogramContent.getEndTime());
-                       //System.out.println("Time is : " + tmpEvent.getTimestamp().getValue());
-                       // *** FIXME ***
-               // *** EVIL FIX ***
-                // Because of the other evil bug (see above), we have to ignore extra useless events we will get
-                       // However, we might be far away from the end so we better start a redraw now
-                       if (tmpEvent.getTimestamp().getValue() >= histogramContent.getEndTime()) {
-                               redrawAsyncronously();
-                               requestCompleted = true;
-                       }
-               }
                }
+        // We got a null event! This mean we reach the end of the request. 
+        // Save the last interval we had, so we won't miss the very last events at the end. 
+        else {
+               // Save the last events
+               histogramContent.getElementByIndex(lastInterval).intervalNbEvents = nbEventsInInterval;
+               // We reached the end of the request, so assume we fill up the content as well
+                       histogramContent.setReadyUpToPosition(histogramContent.getNbElement());
+                       
+                       // If the interval wasn't null, count this as a "non empty" interval
+                       if (nbEventsInInterval > 0) {
+                               nbIntervalNotEmpty++;
+                       }
+        }
     }
        
        /**
@@ -191,7 +191,6 @@ public class HistogramRequest extends TmfEventRequest<LttngEvent> {
     @Override
     public void handleCancel() {
        redrawAsyncronously();
-               requestCompleted = true;
     }
        
     /**
index 5c27943421895630738644efbe4c5bab45954134..afb414a05d435419caf24f5b854b0632b45fe5b0 100644 (file)
@@ -11,7 +11,6 @@
  *******************************************************************************/
 package org.eclipse.linuxtools.lttng.ui.views.histogram;
 
-
 import org.eclipse.linuxtools.lttng.event.LttngEvent;
 import org.eclipse.linuxtools.lttng.event.LttngTimestamp;
 import org.eclipse.linuxtools.tmf.event.TmfTimeRange;
@@ -23,6 +22,8 @@ import org.eclipse.linuxtools.tmf.signal.TmfSignalHandler;
 import org.eclipse.linuxtools.tmf.signal.TmfTimeSynchSignal;
 import org.eclipse.linuxtools.tmf.ui.views.TmfView;
 import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ControlEvent;
+import org.eclipse.swt.events.ControlListener;
 import org.eclipse.swt.graphics.Font;
 import org.eclipse.swt.graphics.FontData;
 import org.eclipse.swt.layout.GridData;
@@ -39,7 +40,7 @@ import org.eclipse.swt.widgets.Text;
  * This view is composed of 2 canvas, one for the whole experiment and one for the selectionned window in the experiment.
  * It also contain a certain number of controls to print or change informations about the experiment.
  */
-public class HistogramView extends TmfView {
+public class HistogramView extends TmfView implements ControlListener {
        
        // *** TODO ***
        // Here is what's left to do in this view
@@ -49,7 +50,6 @@ public class HistogramView extends TmfView {
        //                      updated from different threads; we need to carefully decide when/where to redraw them.
        //              This is a real problem since there is a lot of thread going on in this view.
        //              All basic control should be subclassed to offer "Asynchronous" functions.
-       // 2- Find a way to totally fix the SWT bug in createPartControl()
        
     public static final String ID = "org.eclipse.linuxtools.lttng.ui.views.histogram";
     
@@ -59,10 +59,11 @@ public class HistogramView extends TmfView {
     // Size of the "fulll trace" canvas
     private static final int FULL_TRACE_CANVAS_HEIGHT = 25;
     private static final int FULL_TRACE_BAR_WIDTH = 1;
-    private static final double FULL_TRACE_DIFFERENCE_TO_AVERAGE = 2.0;
+    private static final double FULL_TRACE_DIFFERENCE_TO_AVERAGE = 1.5;
     
     // Size of the "Selected Window" canvas
     private static final int SELECTED_WINDOW_CANVAS_WIDTH = 300;
+    private static final int SMALL_SELECTED_WINDOW_CANVAS_WIDTH = 200;
     private static final int SELECTED_WINDOW_CANVAS_HEIGHT = 60;
     private static final int SELECTED_WINDOW_BAR_WIDTH = 1;
     private static final double SELECTED_WINDOW_DIFFERENCE_TO_AVERAGE = 10.0;
@@ -101,9 +102,6 @@ public class HistogramView extends TmfView {
        private Long selectedWindowTimerange = 0L;
        private Long currentEventTime = 0L;
        
-       // This need to be a class variable to enable "small screen" ajustement
-    private Integer selectedCanvasWidth = 0;
-       
     // *** All the UI control below
        //
        // NOTE : All textboxes will be READ_ONLY.
@@ -147,6 +145,7 @@ public class HistogramView extends TmfView {
                
                Font smallFont = null;
                int  nbEventWidth = -1; 
+               int selectedCanvasWidth = -1;
                boolean doesTimeTextGroupNeedAdjustment = false;
                
                // Calculate if we need "small screen" fixes
@@ -154,22 +153,13 @@ public class HistogramView extends TmfView {
                        // A lot smaller font for timstampe
                        smallFont = new Font(font.getDevice(), tmpFontData.getName(), tmpFontData.getHeight() - VERY_SMALL_FONT_MODIFIER, tmpFontData.getStyle());
                        
+                       // Smaller selection window canvas
+                       selectedCanvasWidth = SMALL_SELECTED_WINDOW_CANVAS_WIDTH;
                        // Smaller event number text field
                        nbEventWidth = NB_EVENTS_FIXED_WIDTH/2;
                        
                        // Tell the text group to ajust
                        doesTimeTextGroupNeedAdjustment = true;
-                       
-                       // *** BUG ***
-                       // This might NOT be respected because of the way SWT draw its control, as startTime and endTime 
-                       //              might take more space than the control. 
-                       // However, SWT is too DUMB to have a way to fix a Text size so there is no way I can know the size 
-                       //      it will take. The only ways to avoid this bug is to :
-                       // 1- Put a size to the canvas that we know to be bigger than the Texts. This is dumb as we try to SAVE space
-                       // 2- Avoid to use "SWT.FILL" on the Canvas. On that case, we WILL have a gap between the canvas and the next text field.
-                       //
-                       // Neither solution is good but 2 is slightly better. Way to go SWT!
-                       selectedCanvasWidth = SELECTED_WINDOW_CANVAS_WIDTH - (SELECTED_WINDOW_CANVAS_WIDTH/3);
                }
                else {
                        // Slightly smaller font for timestamp
@@ -295,9 +285,49 @@ public class HistogramView extends TmfView {
                txtWindowStopTime.setText("");
                txtWindowStopTime.setLayoutData(gridDataWindowStop);
                
-               
-               
-               // *** Everything related to the spinner is below
+               GridData gridDataSpacer = new GridData(SWT.FILL, SWT.TOP, true, true, 1, 1);
+               gridDataSpacer.minimumWidth = nbEventWidth;
+               // *** HACK ***
+               // To align properly AND to make sure the canvas size is fixed, we NEED to make sure all "section" of the 
+               //              gridlayout are taken (and if possible of a fixed size).
+               // However, SWT is VERY VERY DUMB and won't consider griddata that contain no control. 
+               // Since there will be missing a section, the SelectedWindowCanvas + NbEventsText will take 3 spaces, but
+               //              startTimeText + stopTimeText will take only 2 (as if empty the other griddata of 1 will get ignored).
+               // StopTime will then take over the missing space; I want to align "stopTime" right on the end of canvas, so 
+               //              the added space to stop time would make it being aligned improperly
+               // So I NEED the empty griddata to be considered! 
+               // Visually : 
+               // |---------------|---------------|-----------|
+               // |SelectionCanvas SelectionCanvas|NbEventText|
+               // |SelectionCanvas SelectionCanvas|NbEventText|
+               // |---------------|---------------|-----------|
+               // |StartTime      |       StopTime|    ???    |
+               // |---------------|---------------|-----------|
+               //
+               // So since SWT will only consider griddata with control, 
+               //              I need to create a totally useless control in the ??? section.
+               // That's ugly, useless and it generally a bad practice.
+               //
+               // *** SUB-HACK ***
+               // Other interesting fact about SWT : the way it draws (Fill/Expand control in grid) will change if 
+               //              the control is a Text of a Label. 
+               // A Label here will be "pushed" by startTime/stopTime Text and won't fill the full space as NbEventText.
+               // A Text  here will NOT be "pushed" and would give a nice visual output.
+               //              (NB : No, I am NOT kidding, try it for yourself!)
+               //
+               // Soooooo I guess I will use a Text here. Way to go SWT!
+               // Downside is that disabled textbox has a slightly different color (even if you change it) so if I want
+               //              to make the text "invisible", I have to keep it editable, so it can be selected.
+               //
+               // Label uselessControlToByPassSWTStupidBug = new Label(layoutSelectionWindow, SWT.BORDER); // WON'T align correctly!!!
+               Text uselessControlToByPassSWTStupidBug = new Text(layoutSelectionWindow, SWT.READ_ONLY); // WILL align correctly!!!
+               uselessControlToByPassSWTStupidBug.setEditable(false);
+               uselessControlToByPassSWTStupidBug.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_TITLE_INACTIVE_BACKGROUND));
+               uselessControlToByPassSWTStupidBug.setLayoutData(gridDataSpacer);
+               
+               
+               
+               // *** Everything related to the time text group is below
                GridData gridDataCurrentEvent = new GridData(SWT.CENTER, SWT.CENTER, true, true, 1, 2);
                ntgCurrentEventTime = new TimeTextGroup(this, layoutTimesSpinner, SWT.BORDER, SWT.BORDER, EVENT_CURRENT_TIME_LABEL_TEXT, HistogramConstant.formatNanoSecondsTime( 0L ), doesTimeTextGroupNeedAdjustment);
                ntgCurrentEventTime.setLayoutData(gridDataCurrentEvent);
@@ -351,6 +381,9 @@ public class HistogramView extends TmfView {
                if ( (dataBackgroundFullRequest == null) && (tmpExperiment != null) ) {
                        createCanvasAndRequests(tmpExperiment);
                }
+               
+               // Call a redraw for everything
+               parent.redraw();
        }
        
        /**
@@ -437,8 +470,7 @@ public class HistogramView extends TmfView {
                fullExperimentCanvas.getHistogramContent().resetTable(newExperiment.getStartTime().getValue(), newExperiment.getEndTime().getValue());
                
                // Create the content for the selected window. 
-               selectedCanvasWidth = selectedWindowCanvas.getSize().x;
-               selectedWindowCanvas.createNewHistogramContent(selectedCanvasWidth ,SELECTED_WINDOW_BAR_WIDTH, SELECTED_WINDOW_CANVAS_HEIGHT, SELECTED_WINDOW_DIFFERENCE_TO_AVERAGE);
+               selectedWindowCanvas.createNewHistogramContent(selectedWindowCanvas.getSize().x ,SELECTED_WINDOW_BAR_WIDTH, SELECTED_WINDOW_CANVAS_HEIGHT, SELECTED_WINDOW_DIFFERENCE_TO_AVERAGE);
                selectedWindowCanvas.getHistogramContent().resetTable(fullExperimentCanvas.getCurrentWindow().getTimestampLeft(), fullExperimentCanvas.getCurrentWindow().getTimestampRight());
                
                // Make sure the UI object are sane
@@ -773,4 +805,34 @@ public class HistogramView extends TmfView {
        selectedWindowCanvas.redrawAsynchronously();
        }
        
+       /**
+        * Method called when the view is moved.<p>
+        * 
+        * Just redraw everything...
+        * 
+        * @param event         The controle event generated by the move.
+        */
+       public void controlMoved(ControlEvent event) {
+               parent.redraw();
+       }
+       
+       /**
+        * Method called when the view is resized.<p>
+        * 
+        * We will make sure that the size didn't change more than the content size.<p>
+        * Otherwise we need to perform a new request for the full experiment because we are missing data).
+        * 
+        * @param event         The control event generated by the resize.
+        */
+       public void controlResized(ControlEvent event) {
+               
+               // Ouch! The screen enlarged (screen resolution changed?) so far that we miss content to fill the space.
+               // Perform a new full request... this is quite heavy.
+               if ( parent.getDisplay().getBounds().width > fullExperimentCanvas.getHistogramContent().getNbElement() ) {
+                       if ( lastUsedExperiment != null ) {
+                               performAllTraceEventsRequest(lastUsedExperiment);
+                       }
+               }
+               
+       }
 }
index ef287e73a185f2cf6861cd104b5ac451dddd2db9..4344c1c7f05e250b8fc8115f1482ef4230b22616 100644 (file)
@@ -67,6 +67,16 @@ public class ParentHistogramCanvas extends HistogramCanvas {
                
                // Create the content
                histogramContent = new HistogramContent( contentSize, canvasSize, widthPerBar, barsHeight, maxBarsDifferenceToAverage);
+               
+               // We need to ajust the "maxDifferenceToAverageFactor" as the bars we draw might be slitghly larger than the value asked
+               // Each "interval" are concatenated when draw so the worst case should be : 
+               // contentSize / (closest power of 2 to canvasMaxSize)
+               // Ex : if canvasSize is 1500 -> (2048 / 1024) == 2  so maxDiff should be twice larger
+               //
+               // Note : this is not perfect, if the screen is resized after we calculate this, the resulting output can be quite ugly
+               // For this reason, this will be recalculated in the paintListener as well. 
+               double maxBarsDiffFactor = ((double)contentSize / Math.pow(2, exp-1));
+               histogramContent.setMaxDifferenceToAverageFactor(maxBarsDiffFactor);
        }
        
        /*
index e63eac45bfab04318b5acdd3ebd480f760d81e50..1ea696401d462df71a612f6597af3cd2b4214ea5 100644 (file)
@@ -57,6 +57,9 @@ public class ParentHistogramCanvasPaintListener extends HistogramCanvasPaintList
                // Calculate the closest power of 2 just smaller than the canvas size
                int closestPowerToCanvas = (int)Math.pow(2, Math.floor( Math.log( canvasSize ) / Math.log(2.0) ));
                
+               // Make sure the canvas didn't change size, it which case we need to recalculate our heights
+               recalculateHeightIfCanvasSizeChanged();
+               
                // Calculate the factor of difference between canvas and the power
                double factor = (double)canvasSize / (double)closestPowerToCanvas;
                // Calculate how many interval will need to be concatenated into one pixel
@@ -108,4 +111,32 @@ public class ParentHistogramCanvasPaintListener extends HistogramCanvasPaintList
            Rectangle rect = new Rectangle(widthFilled, 0, event.width, event.height);
            event.gc.fillRectangle(rect);
        }
+       
+       /*
+        * The function will make sure that the "max difference average" factor is still the same as before;
+        *              if not, the heigth of the events will be recalculated.<p>
+        * 
+        * The factor might change if the canvas is resized by a big factor.<p>
+        */
+       protected void recalculateHeightIfCanvasSizeChanged() {
+               HistogramContent tmpContent = parentCanvas.getHistogramContent();
+               // We need to ajust the "maxDifferenceToAverageFactor" as the bars we draw might be slitghly larger than the value asked
+               // Each "interval" are concatenated when draw so the worst case should be : 
+               // contentSize / (closest power of 2 to canvasMaxSize)
+               // Ex : if canvasSize is 1500 -> (2048 / 1024) == 2  so maxDiff should be twice larger
+               //
+               // His is set in the create content of the canvas, but we need to recalculate it 
+               //      here because the window might have been resized!
+               int exp = (int)Math.floor( Math.log( (double)tmpContent.getCanvasWindowSize() ) / Math.log(2.0) );
+               int contentSize = (int)Math.pow(2, exp);
+               Double maxBarsDiffFactor = ((double)tmpContent.getNbElement() / (double)contentSize );
+               
+               if ( maxBarsDiffFactor != tmpContent.getMaxDifferenceToAverageFactor() ) {
+                       // The factor changed! That's unfortunate because it will take a while to recalculate.
+                       tmpContent.setMaxDifferenceToAverageFactor(maxBarsDiffFactor);
+                       tmpContent.recalculateHeightFactor();
+                       tmpContent.recalculateEventHeight();
+               }
+       }
+       
 }
This page took 0.033598 seconds and 5 git commands to generate.