blob: 4122f96f3ece073d4fdb0025a30a8c77bc3ddeec [file] [log] [blame]
Chris Craik44c28202015-05-12 17:25:16 -07001<!DOCTYPE html>
2<!--
3Copyright (c) 2015 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="/base/event_target.html">
9<link rel="import" href="/base/task.html">
10<link rel="import" href="/core/selection.html">
11<link rel="import" href="/core/brushing_state.html">
12<link rel="import" href="/core/trace_model/selection_state.html">
13<link rel="import" href="/core/timeline_viewport.html">
14<link rel="import" href="/core/ui_state.html">
15
16<script>
17'use strict';
18
19tv.exportTo('tv.c', function() {
20 var BrushingState = tv.c.BrushingState;
21 var Selection = tv.c.Selection;
22 var SelectionState = tv.c.trace_model.SelectionState;
23 var Viewport = tv.c.TimelineViewport;
24
25 function SelectionController(timelineView) {
26 tv.b.EventTarget.call(this);
27
28 this.timelineView_ = timelineView;
29 this.currentBrushingState_ = new BrushingState();
30
31 this.onPopState_ = this.onPopState_.bind(this);
32 this.historyEnabled_ = false;
33 this.selections_ = {};
34 }
35
36 SelectionController.prototype = {
37 __proto__: tv.b.EventTarget.prototype,
38
39 dispatchChangeEvent_: function() {
40 var e = new tv.b.Event('change', false, false);
41 this.dispatchEvent(e);
42 },
43
44 get model() {
45 if (!this.timelineView_)
46 return undefined;
47 return this.timelineView_.model;
48 },
49
50 get trackView() {
51 if (!this.timelineView_)
52 return undefined;
53 return this.timelineView_.trackView;
54 },
55
56 get viewport() {
57 if (!this.timelineView_)
58 return undefined;
59 if (!this.timelineView_.trackView)
60 return undefined;
61 return this.timelineView_.trackView.viewport;
62 },
63
64 /* History system */
65 get historyEnabled() {
66 return this.historyEnabled_;
67 },
68
69 set historyEnabled(historyEnabled) {
70 this.historyEnabled_ = !!historyEnabled;
71 if (historyEnabled)
72 window.addEventListener('popstate', this.onPopState_);
73 else
74 window.removeEventListener('popstate', this.onPopState_);
75 },
76
77 modelWillChange: function() {
78 if (this.currentBrushingState_.isAppliedToModel)
79 this.currentBrushingState_.unapplyFromModelSelectionState();
80 },
81
82 modelDidChange: function() {
83 this.selections_ = {};
84 this.currentBrushingState_.applyToModelSelectionState(this.model);
85
86 var e = new tv.b.Event('model-changed', false, false);
87 this.dispatchEvent(e);
88 },
89
90 onUserInitiatedSelectionChange_: function() {
91 var selection = this.selection;
92 if (this.historyEnabled) {
93 // Save the selection so that when back button is pressed,
94 // it could be retrieved.
95 this.selections_[selection.guid] = selection;
96 var state = {
97 selection_guid: selection.guid
98 };
99
100 window.history.pushState(state, document.title);
101 }
102 },
103
104 onPopState_: function(e) {
105 if (e.state === null)
106 return;
107
108 var selection = this.selections_[e.state.selection_guid];
109 if (selection) {
110 var newState = this.currentBrushingState_.clone();
111 newState.selection = selection;
112 this.currentBrushingState = newState;
113 }
114 e.stopPropagation();
115 },
116
117 get selection() {
118 return this.currentBrushingState_.selection;
119 },
120 get findMatches() {
121 return this.currentBrushingState_.findMatches;
122 },
123
124 get selectionOfInterest() {
125 return this.currentBrushingState_.selectionOfInterest;
126 },
127
128 get currentBrushingState() {
129 return this.currentBrushingState_;
130 },
131
132 set currentBrushingState(newBrushingState) {
133 if (newBrushingState.isAppliedToModel)
134 throw new Error('Cannot apply this state, it is applied');
135
136 // This function uses value-equality on the states so that state can
137 // changed to a clone of itself without causing a change event, while
138 // still having the actual state object change to the new clone.
139 var hasValueChanged = !this.currentBrushingState_.equals(
140 newBrushingState);
141
142 if (newBrushingState !== this.currentBrushingState_ &&
143 hasValueChanged == false) {
144 this.currentBrushingState_.transferModelOwnershipToClone(
145 newBrushingState);
146 this.currentBrushingState_ = newBrushingState;
147 return;
148 }
149
150 if (this.currentBrushingState_.isAppliedToModel)
151 this.currentBrushingState_.unapplyFromModelSelectionState();
152
153 this.currentBrushingState_ = newBrushingState;
154
155 if (this.model)
156 this.currentBrushingState_.applyToModelSelectionState(this.model);
157
158 this.dispatchChangeEvent_();
159 },
160
161 /**
162 * @param {Filter} filter The filter to use for finding matches.
163 * @param {Selection} selection The selection to add matches to.
164 * @return {Task} which performs the filtering.
165 */
166 addAllEventsMatchingFilterToSelectionAsTask: function(filter, selection) {
167 var timelineView = this.timelineView_.trackView;
168 if (!timelineView)
169 return new tv.b.Task();
170 return timelineView.addAllEventsMatchingFilterToSelectionAsTask(
171 filter, selection);
172 },
173
174 findTextChangedTo: function(allPossibleMatches) {
175 var newBrushingState = this.currentBrushingState_.clone();
176 newBrushingState.findMatches = allPossibleMatches;
177 this.currentBrushingState = newBrushingState;
178 },
179
180 findFocusChangedTo: function(currentFocus) {
181 var newBrushingState = this.currentBrushingState_.clone();
182 newBrushingState.selection = currentFocus;
183 this.currentBrushingState = newBrushingState;
184
185 this.onUserInitiatedSelectionChange_();
186 },
187
188 findTextCleared: function() {
189 if (this.xNavStringMarker_ !== undefined) {
190 this.model.removeAnnotation(this.xNavStringMarker_);
191 this.xNavStringMarker_ = undefined;
192 }
193
194 if (this.guideLineAnnotation_ !== undefined) {
195 this.model.removeAnnotation(this.guideLineAnnotation_);
196 this.guideLineAnnotation_ = undefined;
197 }
198
199 var newBrushingState = this.currentBrushingState_.clone();
200 newBrushingState.selection = new Selection();
201 newBrushingState.findMatches = new Selection();
202 this.currentBrushingState = newBrushingState;
203
204 this.onUserInitiatedSelectionChange_();
205 },
206
207 uiStateFromString: function(string) {
208 return tv.c.UIState.fromUserFriendlyString(
209 this.model, this.viewport, string);
210 },
211
212 navToPosition: function(uiState, showNavLine) {
213 this.trackView.navToPosition(uiState, showNavLine);
214 },
215
216 changeSelectionFromTimeline: function(selection) {
217 var newBrushingState = this.currentBrushingState_.clone();
218 newBrushingState.selection = selection;
219 newBrushingState.findMatches = new Selection();
220 this.currentBrushingState = newBrushingState;
221
222 this.onUserInitiatedSelectionChange_();
223 },
224
225 showScriptControlSelection: function(selection) {
226 var newBrushingState = this.currentBrushingState_.clone();
227 newBrushingState.selection = selection;
228 newBrushingState.findMatches = new Selection();
229 this.currentBrushingState = newBrushingState;
230 },
231
232 changeSelectionFromRequestSelectionChangeEvent: function(selection) {
233 var newBrushingState = this.currentBrushingState_.clone();
234 newBrushingState.selection = selection;
235 newBrushingState.findMatches = new Selection();
236 this.currentBrushingState = newBrushingState;
237
238 this.onUserInitiatedSelectionChange_();
239 },
240
241 changeAnalysisViewRelatedEvents: function(selection) {
242 var newBrushingState = this.currentBrushingState_.clone();
243 newBrushingState.analysisViewRelatedEvents = selection;
244 this.currentBrushingState = newBrushingState;
245 }
246 };
247
248 return {
249 SelectionController: SelectionController
250 };
251});
252</script>