1<!DOCTYPE html> 2<!-- 3Copyright (c) 2012 The Chromium Authors. All rights reserved. 4Use of this source code is governed by a BSD-style license that can be 5found 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 */ 18tr.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