ae9f844d33f1224135b20681e83b3b8b80105674
[WebKit-https.git] / Source / WebInspectorUI / UserInterface / Views / TreeOutlineDataGridSynchronizer.js
1 /*
2  * Copyright (C) 2013 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 WebInspector.TreeOutlineDataGridSynchronizer = function(treeOutline, dataGrid, delegate)
27 {
28     // FIXME: Convert this to a WebInspector.Object subclass, and call super().
29     // WebInspector.Object.call(this);
30
31     this._treeOutline = treeOutline;
32     this._dataGrid = dataGrid;
33     this._delegate = delegate || null;
34     this._enabled = true;
35
36     this._treeOutline.element.parentNode.addEventListener("scroll", this._treeOutlineScrolled.bind(this));
37     this._dataGrid.scrollContainer.addEventListener("scroll", this._dataGridScrolled.bind(this));
38
39     this._treeOutline.__dataGridNode = this._dataGrid;
40
41     this._dataGrid.addEventListener(WebInspector.DataGrid.Event.ExpandedNode, this._dataGridNodeExpanded, this);
42     this._dataGrid.addEventListener(WebInspector.DataGrid.Event.CollapsedNode, this._dataGridNodeCollapsed, this);
43     this._dataGrid.addEventListener(WebInspector.DataGrid.Event.SelectedNodeChanged, this._dataGridNodeSelected, this);
44
45     // FIXME: This is a hack. TreeOutline should just dispatch events via WebInspector.Object.
46     var existingOnAdd = treeOutline.onadd;
47     var existingOnRemove = treeOutline.onremove;
48     var existingOnExpand = treeOutline.onexpand;
49     var existingOnCollapse = treeOutline.oncollapse;
50     var existingOnHidden = treeOutline.onhidden;
51     var existingOnSelect = treeOutline.onselect;
52
53     treeOutline.onadd = function(element) {
54         this._treeElementAdded(element);
55         if (existingOnAdd)
56             existingOnAdd.call(treeOutline, element);
57     }.bind(this);
58
59     treeOutline.onremove = function(element) {
60         this._treeElementRemoved(element);
61         if (existingOnRemove)
62             existingOnRemove.call(treeOutline, element);
63     }.bind(this);
64
65     treeOutline.onexpand = function(element) {
66         this._treeElementExpanded(element);
67         if (existingOnExpand)
68             existingOnExpand.call(treeOutline, element);
69     }.bind(this);
70
71     treeOutline.oncollapse = function(element) {
72         this._treeElementCollapsed(element);
73         if (existingOnCollapse)
74             existingOnCollapse.call(treeOutline, element);
75     }.bind(this);
76
77     treeOutline.onhidden = function(element, hidden) {
78         this._treeElementHiddenChanged(element, hidden);
79         if (existingOnHidden)
80             existingOnHidden.call(treeOutline, element, hidden);
81     }.bind(this);
82
83     treeOutline.onselect = function(element, selectedByUser) {
84         this._treeElementSelected(element, selectedByUser);
85         if (existingOnSelect)
86             existingOnSelect.call(treeOutline, element, selectedByUser);
87     }.bind(this);
88 };
89
90 WebInspector.TreeOutlineDataGridSynchronizer.prototype = {
91     constructor: WebInspector.TreeOutlineDataGridSynchronizer,
92     __proto__: WebInspector.Object.prototype,
93
94     // Public
95
96     get treeOutline()
97     {
98         return this._treeOutline;
99     },
100
101     get dataGrid()
102     {
103         return this._dataGrid;
104     },
105
106     get delegate()
107     {
108         return this._delegate;
109     },
110
111     get enabled()
112     {
113         return this._enabled;
114     },
115
116     set enabled(x)
117     {
118         this._enabled = x || false;
119     },
120
121     associate: function(treeElement, dataGridNode)
122     {
123         console.assert(treeElement);
124         console.assert(dataGridNode);
125
126         treeElement.__dataGridNode = dataGridNode;
127         dataGridNode.__treeElement = treeElement;
128     },
129
130     synchronize: function()
131     {
132         this._dataGrid.scrollContainer.scrollTop = this._treeOutline.element.parentNode.scrollTop;
133         if (this._treeOutline.selectedTreeElement)
134             this._treeOutline.selectedTreeElement.__dataGridNode.select(true);
135         else if (this._dataGrid.selectedNode)
136             this._dataGrid.selectedNode.deselect(true);
137     },
138
139     treeElementForDataGridNode: function(dataGridNode)
140     {
141         return dataGridNode.__treeElement || null;
142     },
143
144     dataGridNodeForTreeElement: function(treeElement)
145     {
146         if (treeElement.__dataGridNode)
147             return treeElement.__dataGridNode;
148
149         if (typeof this._delegate.dataGridNodeForTreeElement === "function") {
150             var dataGridNode = this._delegate.dataGridNodeForTreeElement(treeElement);
151             if (dataGridNode)
152                 this.associate(treeElement, dataGridNode);
153             return dataGridNode;
154         }
155
156         return null;
157     },
158
159     // Private
160
161     _treeOutlineScrolled: function(event)
162     {
163         if (!this._enabled)
164             return;
165
166         if (this._ignoreNextTreeOutlineScrollEvent) {
167             delete this._ignoreNextTreeOutlineScrollEvent;
168             return;
169         }
170
171         this._ignoreNextDataGridScrollEvent = true;
172         this._dataGrid.scrollContainer.scrollTop = this._treeOutline.element.parentNode.scrollTop;
173     },
174
175     _dataGridScrolled: function(event)
176     {
177         if (!this._enabled)
178             return;
179
180         if (this._ignoreNextDataGridScrollEvent) {
181             delete this._ignoreNextDataGridScrollEvent;
182             return;
183         }
184
185         this._ignoreNextTreeOutlineScrollEvent = true;
186         this._treeOutline.element.parentNode.scrollTop = this._dataGrid.scrollContainer.scrollTop;
187     },
188
189     _dataGridNodeSelected: function(event)
190     {
191         if (!this._enabled)
192             return;
193
194         var dataGridNode = this._dataGrid.selectedNode;
195         if (dataGridNode)
196             dataGridNode.__treeElement.select(true, true, true, true);
197     },
198
199     _dataGridNodeExpanded: function(event)
200     {
201         if (!this._enabled)
202             return;
203
204         var dataGridNode = event.data.dataGridNode;
205         console.assert(dataGridNode);
206
207         if (!dataGridNode.__treeElement.expanded)
208             dataGridNode.__treeElement.expand();
209     },
210
211     _dataGridNodeCollapsed: function(event)
212     {
213         if (!this._enabled)
214             return;
215
216         var dataGridNode = event.data.dataGridNode;
217         console.assert(dataGridNode);
218
219         if (dataGridNode.__treeElement.expanded)
220             dataGridNode.__treeElement.collapse();
221     },
222
223     _treeElementSelected: function(treeElement, selectedByUser)
224     {
225         if (!this._enabled)
226             return;
227
228         var dataGridNode = treeElement.__dataGridNode;
229         console.assert(dataGridNode);
230
231         dataGridNode.select(true);
232     },
233
234     _treeElementAdded: function(treeElement)
235     {
236         if (!this._enabled)
237             return;
238
239         var dataGridNode = this.dataGridNodeForTreeElement(treeElement);
240         console.assert(dataGridNode);
241
242         var parentDataGridNode = treeElement.parent.__dataGridNode;
243         console.assert(dataGridNode);
244
245         var childIndex = treeElement.parent.children.indexOf(treeElement);
246         console.assert(childIndex !== -1);
247
248         parentDataGridNode.insertChild(dataGridNode, childIndex);
249     },
250
251     _treeElementRemoved: function(treeElement)
252     {
253         if (!this._enabled)
254             return;
255
256         var dataGridNode = treeElement.__dataGridNode;
257         console.assert(dataGridNode);
258
259         if (dataGridNode.parent)
260             dataGridNode.parent.removeChild(dataGridNode);
261     },
262
263     _treeElementExpanded: function(treeElement)
264     {
265         if (!this._enabled)
266             return;
267
268         var dataGridNode = treeElement.__dataGridNode;
269         console.assert(dataGridNode);
270
271         if (!dataGridNode.expanded)
272             dataGridNode.expand();
273     },
274
275     _treeElementCollapsed: function(treeElement)
276     {
277         if (!this._enabled)
278             return;
279
280         var dataGridNode = treeElement.__dataGridNode;
281         console.assert(dataGridNode);
282
283         if (dataGridNode.expanded)
284             dataGridNode.collapse();
285     },
286
287     _treeElementHiddenChanged: function(treeElement, hidden)
288     {
289         if (!this._enabled)
290             return;
291
292         var dataGridNode = treeElement.__dataGridNode;
293         console.assert(dataGridNode);
294
295         dataGridNode.element.classList.toggle("hidden", hidden);
296     }
297 };
298
299 WebInspector.TreeOutlineDataGridSynchronizer.prototype.__proto__ = WebInspector.Object.prototype;