Bug 1169120 - Waterfall should preserve the currently selected marker after resizing, r=jsantell
authorVictor Porof <vporof@mozilla.com>
Thu, 28 May 2015 00:30:21 -0400
changeset 245868 103c08c8fc61a82801bf5db85155dd08e55d5839
parent 245867 299a93ea3f842aadefb98a87b6e9c4996e7163d8
child 245869 b524aa2ea971d1d89faf9a3bfe17486773d2b6bf
push id13206
push uservporof@mozilla.com
push dateThu, 28 May 2015 04:30:36 +0000
treeherderfx-team@103c08c8fc61 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjsantell
bugs1169120
milestone41.0a1
Bug 1169120 - Waterfall should preserve the currently selected marker after resizing, r=jsantell
browser/devtools/performance/test/browser_timeline-waterfall-rerender.js
browser/devtools/performance/views/details-waterfall.js
browser/devtools/shared/widgets/AbstractTreeItem.jsm
--- a/browser/devtools/performance/test/browser_timeline-waterfall-rerender.js
+++ b/browser/devtools/performance/test/browser_timeline-waterfall-rerender.js
@@ -26,23 +26,32 @@ function* spawnTest() {
   let initialBarsCount = $$(".waterfall-marker-bar").length;
 
   // Select a portion of the overview.
   let timeline = OverviewView.graphs.get("timeline");
   let rerendered = WaterfallView.once(EVENTS.WATERFALL_RENDERED);
   timeline.setSelection({ start: 0, end: timeline.width / 2 })
   yield rerendered;
 
+  // Focus the second item in the tree.
+  WaterfallView._markersRoot.getChild(1).focus();
+
   let beforeResizeBarsCount = $$(".waterfall-marker-bar").length;
   ok(beforeResizeBarsCount < initialBarsCount,
     "A subset of the total markers was selected.");
 
+  is(Array.indexOf($$(".waterfall-tree-item"), $(".waterfall-tree-item:focus")), 2,
+    "The correct item was focused in the tree.");
+
   rerendered = WaterfallView.once(EVENTS.WATERFALL_RENDERED);
   EventUtils.sendMouseEvent({ type: "mouseup" }, WaterfallView.detailsSplitter);
   yield rerendered;
 
   let afterResizeBarsCount = $$(".waterfall-marker-bar").length;
   is(afterResizeBarsCount, beforeResizeBarsCount,
     "The same subset of the total markers remained visible.");
 
+  is(Array.indexOf($$(".waterfall-tree-item"), $(".waterfall-tree-item:focus")), 2,
+    "The correct item is still focused in the tree.");
+
   yield teardown(panel);
   finish();
 }
--- a/browser/devtools/performance/views/details-waterfall.js
+++ b/browser/devtools/performance/views/details-waterfall.js
@@ -78,19 +78,21 @@ let WaterfallView = Heritage.extend(Deta
    * updating the markers detail view.
    */
   _onMarkerSelected: function (event, marker) {
     let recording = PerformanceController.getCurrentRecording();
     let frames = recording.getFrames();
 
     if (event === "selected") {
       this.details.render({ toolbox: gToolbox, marker, frames });
+      this._selected = marker;
     }
     if (event === "unselected") {
       this.details.empty();
+      this._selected = null;
     }
   },
 
   /**
    * Called when the marker details view is resized.
    */
   _onResize: function () {
     setNamedTimeout("waterfall-resize", WATERFALL_RESIZE_EVENTS_DRAIN, () => {
@@ -152,12 +154,21 @@ let WaterfallView = Heritage.extend(Deta
     root.on("selected", this._onMarkerSelected);
     root.on("unselected", this._onMarkerSelected);
 
     this.breakdownContainer.innerHTML = "";
     root.attachTo(this.breakdownContainer);
 
     this.headerContainer.innerHTML = "";
     header.attachTo(this.headerContainer);
+
+    // If an item was previously selected in this view, attempt to
+    // re-select it by traversing the newly created tree.
+    if (this._selected) {
+      let item = root.find(i => i.marker == this._selected);
+      if (item) {
+        item.focus();
+      }
+    }
   },
 
   toString: () => "[object WaterfallView]"
 });
--- a/browser/devtools/shared/widgets/AbstractTreeItem.jsm
+++ b/browser/devtools/shared/widgets/AbstractTreeItem.jsm
@@ -321,16 +321,43 @@ AbstractTreeItem.prototype = {
    * @param number index
    * @return AbstractTreeItem
    */
   getChild: function(index = 0) {
     return this._childTreeItems[index];
   },
 
   /**
+   * Calls the provided function on all the descendants of this item.
+   * If this item was never expanded, then no descendents exist yet.
+   * @param function cb
+   */
+  traverse: function(cb) {
+    for (let child of this._childTreeItems) {
+      cb(child);
+      child.bfs();
+    }
+  },
+
+  /**
+   * Calls the provided function on all descendants of this item until
+   * a truthy value is returned by the predicate.
+   * @param function predicate
+   * @return AbstractTreeItem
+   */
+  find: function(predicate) {
+    for (let child of this._childTreeItems) {
+      if (predicate(child) || child.find(predicate)) {
+        return child;
+      }
+    }
+    return null;
+  },
+
+  /**
    * Shows or hides all the children of this item in the tree. If neessary,
    * populates this item with children.
    *
    * @param boolean visible
    *        True if the children should be visible, false otherwise.
    */
   _toggleChildren: function(visible) {
     if (visible) {