Web Inspector: Create Separate Model and View Objects for RemoteObjects / ObjectPrevi...
[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     WebInspector.Object.call(this);
29
30     this._treeOutline = treeOutline;
31     this._dataGrid = dataGrid;
32     this._delegate = delegate || null;
33     this._enabled = true;
34
35     this._treeOutline.element.parentNode.addEventListener("scroll", this._treeOutlineScrolled.bind(this));
36     this._dataGrid.scrollContainer.addEventListener("scroll", this._dataGridScrolled.bind(this));
37
38     this._treeOutline.__dataGridNode = this._dataGrid;
39
40     this._dataGrid.addEventListener(WebInspector.DataGrid.Event.ExpandedNode, this._dataGridNodeExpanded, this);
41     this._dataGrid.addEventListener(WebInspector.DataGrid.Event.CollapsedNode, this._dataGridNodeCollapsed, this);
42     this._dataGrid.addEventListener(WebInspector.DataGrid.Event.SelectedNodeChanged, this._dataGridNodeSelected, this);
43
44     // FIXME: This is a hack. TreeOutline should just dispatch events via WebInspector.Object.
45     var existingOnAdd = treeOutline.onadd;
46     var existingOnRemove = treeOutline.onremove;
47     var existingOnExpand = treeOutline.onexpand;
48     var existingOnCollapse = treeOutline.oncollapse;
49     var existingOnHidden = treeOutline.onhidden;
50     var existingOnSelect = treeOutline.onselect;
51
52     treeOutline.onadd = function(element) {
53         this._treeElementAdded(element);
54         if (existingOnAdd)
55             existingOnAdd.call(treeOutline, element);
56     }.bind(this);
57
58     treeOutline.onremove = function(element) {
59         this._treeElementRemoved(element);
60         if (existingOnRemove)
61             existingOnRemove.call(treeOutline, element);
62     }.bind(this);
63
64     treeOutline.onexpand = function(element) {
65         this._treeElementExpanded(element);
66         if (existingOnExpand)
67             existingOnExpand.call(treeOutline, element);
68     }.bind(this);
69
70     treeOutline.oncollapse = function(element) {
71         this._treeElementCollapsed(element);
72         if (existingOnCollapse)
73             existingOnCollapse.call(treeOutline, element);
74     }.bind(this);
75
76     treeOutline.onhidden = function(element, hidden) {
77         this._treeElementHiddenChanged(element, hidden);
78         if (existingOnHidden)
79             existingOnHidden.call(treeOutline, element, hidden);
80     }.bind(this);
81
82     treeOutline.onselect = function(element, selectedByUser) {
83         this._treeElementSelected(element, selectedByUser);
84         if (existingOnSelect)
85             existingOnSelect.call(treeOutline, element, selectedByUser);
86     }.bind(this);
87 };
88
89 WebInspector.TreeOutlineDataGridSynchronizer.prototype = {
90     constructor: WebInspector.TreeOutlineDataGridSynchronizer,
91     __proto__: WebInspector.Object.prototype,
92
93     // Public
94
95     get treeOutline()
96     {
97         return this._treeOutline;
98     },
99
100     get dataGrid()
101     {
102         return this._dataGrid;
103     },
104
105     get delegate()
106     {
107         return this._delegate;
108     },
109
110     get enabled()
111     {
112         return this._enabled;
113     },
114
115     set enabled(x)
116     {
117         this._enabled = x || false;
118     },
119
120     associate: function(treeElement, dataGridNode)
121     {
122         console.assert(treeElement);
123         console.assert(dataGridNode);
124
125         treeElement.__dataGridNode = dataGridNode;
126         dataGridNode.__treeElement = treeElement;
127     },
128
129     synchronize: function()
130     {
131         this._dataGrid.scrollContainer.scrollTop = this._treeOutline.element.parentNode.scrollTop;
132         if (this._treeOutline.selectedTreeElement)
133             this._treeOutline.selectedTreeElement.__dataGridNode.select(true);
134         else if (this._dataGrid.selectedNode)
135             this._dataGrid.selectedNode.deselect(true);
136     },
137
138     treeElementForDataGridNode: function(dataGridNode)
139     {
140         return dataGridNode.__treeElement || null;
141     },
142
143     dataGridNodeForTreeElement: function(treeElement)
144     {
145         if (treeElement.__dataGridNode)
146             return treeElement.__dataGridNode;
147
148         if (typeof this._delegate.dataGridNodeForTreeElement === "function") {
149             var dataGridNode = this._delegate.dataGridNodeForTreeElement(treeElement);
150             if (dataGridNode)
151                 this.associate(treeElement, dataGridNode);
152             return dataGridNode;
153         }
154
155         return null;
156     },
157
158     // Private
159
160     _treeOutlineScrolled: function(event)
161     {
162         if (!this._enabled)
163             return;
164
165         if (this._ignoreNextTreeOutlineScrollEvent) {
166             delete this._ignoreNextTreeOutlineScrollEvent;
167             return;
168         }
169
170         this._ignoreNextDataGridScrollEvent = true;
171         this._dataGrid.scrollContainer.scrollTop = this._treeOutline.element.parentNode.scrollTop;
172     },
173
174     _dataGridScrolled: function(event)
175     {
176         if (!this._enabled)
177             return;
178
179         if (this._ignoreNextDataGridScrollEvent) {
180             delete this._ignoreNextDataGridScrollEvent;
181             return;
182         }
183
184         this._ignoreNextTreeOutlineScrollEvent = true;
185         this._treeOutline.element.parentNode.scrollTop = this._dataGrid.scrollContainer.scrollTop;
186     },
187
188     _dataGridNodeSelected: function(event)
189     {
190         if (!this._enabled)
191             return;
192
193         var dataGridNode = this._dataGrid.selectedNode;
194         if (dataGridNode)
195             dataGridNode.__treeElement.select(true, true, true, true);
196     },
197
198     _dataGridNodeExpanded: function(event)
199     {
200         if (!this._enabled)
201             return;
202
203         var dataGridNode = event.data.dataGridNode;
204         console.assert(dataGridNode);
205
206         if (!dataGridNode.__treeElement.expanded)
207             dataGridNode.__treeElement.expand();
208     },
209
210     _dataGridNodeCollapsed: function(event)
211     {
212         if (!this._enabled)
213             return;
214
215         var dataGridNode = event.data.dataGridNode;
216         console.assert(dataGridNode);
217
218         if (dataGridNode.__treeElement.expanded)
219             dataGridNode.__treeElement.collapse();
220     },
221
222     _treeElementSelected: function(treeElement, selectedByUser)
223     {
224         if (!this._enabled)
225             return;
226
227         var dataGridNode = treeElement.__dataGridNode;
228         console.assert(dataGridNode);
229
230         dataGridNode.select(true);
231     },
232
233     _treeElementAdded: function(treeElement)
234     {
235         if (!this._enabled)
236             return;
237
238         var dataGridNode = this.dataGridNodeForTreeElement(treeElement);
239         console.assert(dataGridNode);
240
241         var parentDataGridNode = treeElement.parent.__dataGridNode;
242         console.assert(dataGridNode);
243
244         var childIndex = treeElement.parent.children.indexOf(treeElement);
245         console.assert(childIndex !== -1);
246
247         parentDataGridNode.insertChild(dataGridNode, childIndex);
248     },
249
250     _treeElementRemoved: function(treeElement)
251     {
252         if (!this._enabled)
253             return;
254
255         var dataGridNode = treeElement.__dataGridNode;
256         console.assert(dataGridNode);
257
258         if (dataGridNode.parent)
259             dataGridNode.parent.removeChild(dataGridNode);
260     },
261
262     _treeElementExpanded: function(treeElement)
263     {
264         if (!this._enabled)
265             return;
266
267         var dataGridNode = treeElement.__dataGridNode;
268         console.assert(dataGridNode);
269
270         if (!dataGridNode.expanded)
271             dataGridNode.expand();
272     },
273
274     _treeElementCollapsed: function(treeElement)
275     {
276         if (!this._enabled)
277             return;
278
279         var dataGridNode = treeElement.__dataGridNode;
280         console.assert(dataGridNode);
281
282         if (dataGridNode.expanded)
283             dataGridNode.collapse();
284     },
285
286     _treeElementHiddenChanged: function(treeElement, hidden)
287     {
288         if (!this._enabled)
289             return;
290
291         var dataGridNode = treeElement.__dataGridNode;
292         console.assert(dataGridNode);
293
294         dataGridNode.element.classList.toggle("hidden", hidden);
295     }
296 };
297
298 WebInspector.TreeOutlineDataGridSynchronizer.prototype.__proto__ = WebInspector.Object.prototype;