Home | History | Annotate | Download | only in ui
      1 <!DOCTYPE html>
      2 <!--
      3 Copyright (c) 2012 The Chromium Authors. All rights reserved.
      4 Use of this source code is governed by a BSD-style license that can be
      5 found in the LICENSE file.
      6 -->
      7 
      8 <link rel="import" href="/tracing/base/task.html">
      9 <link rel="import" href="/tracing/core/filter.html">
     10 <link rel="import" href="/tracing/model/event_set.html">
     11 
     12 <script>
     13 'use strict';
     14 
     15 /**
     16  * @fileoverview FindController.
     17  */
     18 tr.exportTo('tr.ui', function() {
     19   var Task = tr.b.Task;
     20 
     21   function FindController(brushingStateController) {
     22     this.brushingStateController_ = brushingStateController;
     23     this.filterHits_ = new tr.model.EventSet();
     24     this.currentHitIndex_ = -1;
     25     this.activePromise_ = Promise.resolve();
     26     this.activeTask_ = undefined;
     27   };
     28 
     29   FindController.prototype = {
     30     __proto__: Object.prototype,
     31 
     32     get model() {
     33       return this.brushingStateController_.model;
     34     },
     35 
     36     get brushingStateController() {
     37       return this.brushingStateController_;
     38     },
     39 
     40     enqueueOperation_: function(operation) {
     41       var task;
     42       if (operation instanceof tr.b.Task)
     43         task = operation;
     44       else
     45         task = new tr.b.Task(operation, this);
     46       if (this.activeTask_) {
     47         this.activeTask_ = this.activeTask_.enqueue(task);
     48       } else {
     49         // We're enqueuing the first task, schedule it.
     50         this.activeTask_ = task;
     51         this.activePromise_ = Task.RunWhenIdle(this.activeTask_);
     52         this.activePromise_.then(function() {
     53           this.activePromise_ = undefined;
     54           this.activeTask_ = undefined;
     55         }.bind(this));
     56       }
     57     },
     58 
     59     /**
     60      * Updates the filter hits based on the provided |filterText|. Returns a
     61      * promise which resolves when |filterHits| has been refreshed.
     62      */
     63     startFiltering: function(filterText) {
     64       var sc = this.brushingStateController_;
     65       if (!sc)
     66         return;
     67 
     68       // TODO(beaudoin): Cancel anything left in the task queue, without
     69       // invalidating the promise.
     70       this.enqueueOperation_(function() {
     71         this.filterHits_ = new tr.model.EventSet();
     72         this.currentHitIndex_ = -1;
     73       }.bind(this));
     74 
     75       // Try constructing a UIState from the filterText.
     76       // UIState.fromUserFriendlyString will throw an error only if the string
     77       // is syntactically correct to a UI state string but with invalid values.
     78       // It will return undefined if there is no syntactic match.
     79       var stateFromString;
     80       try {
     81         stateFromString = sc.uiStateFromString(filterText);
     82       } catch (e) {
     83         this.enqueueOperation_(function() {
     84           var overlay = new tr.ui.b.Overlay();
     85           overlay.textContent = e.message;
     86           overlay.title = 'UI State Navigation Error';
     87           overlay.visible = true;
     88         });
     89         return this.activePromise_;
     90       }
     91 
     92       if (stateFromString !== undefined) {
     93         this.enqueueOperation_(
     94             sc.navToPosition.bind(this, stateFromString, true));
     95       } else {
     96         // filterText is not a navString here -- proceed with find and filter.
     97         if (filterText.length === 0) {
     98           this.enqueueOperation_(sc.findTextCleared.bind(sc));
     99         } else {
    100           var filter = new tr.c.FullTextFilter(filterText);
    101           var filterHits = new tr.model.EventSet();
    102           this.enqueueOperation_(sc.addAllEventsMatchingFilterToSelectionAsTask(
    103               filter, filterHits));
    104           this.enqueueOperation_(function() {
    105             this.filterHits_ = filterHits;
    106             sc.findTextChangedTo(filterHits);
    107           }.bind(this));
    108         }
    109       }
    110       return this.activePromise_;
    111     },
    112 
    113     /**
    114      * Returns the most recent filter hits as a tr.model.EventSet. Call
    115      * |startFiltering| to ensure this is up to date after the filter settings
    116      * have been changed.
    117      */
    118     get filterHits() {
    119       return this.filterHits_;
    120     },
    121 
    122     get currentHitIndex() {
    123       return this.currentHitIndex_;
    124     },
    125 
    126     find_: function(dir) {
    127       var firstHit = this.currentHitIndex_ === -1;
    128       if (firstHit && dir < 0)
    129         this.currentHitIndex_ = 0;
    130 
    131       var N = this.filterHits.length;
    132       this.currentHitIndex_ = (this.currentHitIndex_ + dir + N) % N;
    133 
    134       if (!this.brushingStateController_)
    135         return;
    136 
    137       this.brushingStateController_.findFocusChangedTo(
    138           this.filterHits.subEventSet(this.currentHitIndex_, 1));
    139     },
    140 
    141     findNext: function() {
    142       this.find_(1);
    143     },
    144 
    145     findPrevious: function() {
    146       this.find_(-1);
    147     }
    148   };
    149 
    150   return {
    151     FindController: FindController
    152   };
    153 });
    154 </script>
    155