• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) 2007, 2008 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 *
8 * 1.  Redistributions of source code must retain the above copyright
9 *     notice, this list of conditions and the following disclaimer.
10 * 2.  Redistributions in binary form must reproduce the above copyright
11 *     notice, this list of conditions and the following disclaimer in the
12 *     documentation and/or other materials provided with the distribution.
13 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 *     its contributors may be used to endorse or promote products derived
15 *     from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29WebInspector.DatabasesPanel = function(database)
30{
31    WebInspector.Panel.call(this);
32
33    this.sidebarElement = document.createElement("div");
34    this.sidebarElement.id = "databases-sidebar";
35    this.sidebarElement.className = "sidebar";
36    this.element.appendChild(this.sidebarElement);
37
38    this.sidebarResizeElement = document.createElement("div");
39    this.sidebarResizeElement.className = "sidebar-resizer-vertical";
40    this.sidebarResizeElement.addEventListener("mousedown", this._startSidebarDragging.bind(this), false);
41    this.element.appendChild(this.sidebarResizeElement);
42
43    this.sidebarTreeElement = document.createElement("ol");
44    this.sidebarTreeElement.className = "sidebar-tree";
45    this.sidebarElement.appendChild(this.sidebarTreeElement);
46
47    this.sidebarTree = new TreeOutline(this.sidebarTreeElement);
48
49    this.databaseViews = document.createElement("div");
50    this.databaseViews.id = "database-views";
51    this.element.appendChild(this.databaseViews);
52
53    this.reset();
54}
55
56WebInspector.DatabasesPanel.prototype = {
57    toolbarItemClass: "databases",
58
59    get toolbarItemLabel()
60    {
61        return WebInspector.UIString("Databases");
62    },
63
64    show: function()
65    {
66        WebInspector.Panel.prototype.show.call(this);
67        this._updateSidebarWidth();
68    },
69
70    reset: function()
71    {
72        if (this._databases) {
73            var databasesLength = this._databases.length;
74            for (var i = 0; i < databasesLength; ++i) {
75                var database = this._databases[i];
76
77                delete database._tableViews;
78                delete database._queryView;
79            }
80        }
81
82        this._databases = [];
83
84        this.sidebarTree.removeChildren();
85        this.databaseViews.removeChildren();
86    },
87
88    handleKeyEvent: function(event)
89    {
90        this.sidebarTree.handleKeyEvent(event);
91    },
92
93    addDatabase: function(database)
94    {
95        this._databases.push(database);
96
97        var databaseTreeElement = new WebInspector.DatabaseSidebarTreeElement(database);
98        database._databasesTreeElement = databaseTreeElement;
99
100        this.sidebarTree.appendChild(databaseTreeElement);
101    },
102
103    showDatabase: function(database, tableName)
104    {
105        if (!database)
106            return;
107
108        if (this.visibleDatabaseView)
109            this.visibleDatabaseView.hide();
110
111        var view;
112        if (tableName) {
113            if (!("_tableViews" in database))
114                database._tableViews = {};
115            view = database._tableViews[tableName];
116            if (!view) {
117                view = new WebInspector.DatabaseTableView(database, tableName);
118                database._tableViews[tableName] = view;
119            }
120        } else {
121            view = database._queryView;
122            if (!view) {
123                view = new WebInspector.DatabaseQueryView(database);
124                database._queryView = view;
125            }
126        }
127
128        view.show(this.databaseViews);
129
130        this.visibleDatabaseView = view;
131    },
132
133    closeVisibleView: function()
134    {
135        if (this.visibleDatabaseView)
136            this.visibleDatabaseView.hide();
137        delete this.visibleDatabaseView;
138    },
139
140    updateDatabaseTables: function(database)
141    {
142        if (!database || !database._databasesTreeElement)
143            return;
144
145        database._databasesTreeElement.shouldRefreshChildren = true;
146
147        if (!("_tableViews" in database))
148            return;
149
150        var tableNamesHash = {};
151        var tableNames = database.tableNames;
152        var tableNamesLength = tableNames.length;
153        for (var i = 0; i < tableNamesLength; ++i)
154            tableNamesHash[tableNames[i]] = true;
155
156        for (var tableName in database._tableViews) {
157            if (!(tableName in tableNamesHash)) {
158                if (this.visibleDatabaseView === database._tableViews[tableName])
159                    this.closeVisibleView();
160                delete database._tableViews[tableName];
161            }
162        }
163    },
164
165    dataGridForResult: function(result)
166    {
167        if (!result.rows.length)
168            return null;
169
170        var columns = {};
171
172        var rows = result.rows;
173        for (var columnIdentifier in rows.item(0)) {
174            var column = {};
175            column.width = columnIdentifier.length;
176            column.title = columnIdentifier;
177
178            columns[columnIdentifier] = column;
179        }
180
181        var nodes = [];
182        var length = rows.length;
183        for (var i = 0; i < length; ++i) {
184            var data = {};
185
186            var row = rows.item(i);
187            for (var columnIdentifier in row) {
188                // FIXME: (Bug 19439) We should specially format SQL NULL here
189                // (which is represented by JavaScript null here, and turned
190                // into the string "null" by the String() function).
191                var text = String(row[columnIdentifier]);
192                data[columnIdentifier] = text;
193                if (text.length > columns[columnIdentifier].width)
194                    columns[columnIdentifier].width = text.length;
195            }
196
197            var node = new WebInspector.DataGridNode(data, false);
198            node.selectable = false;
199            nodes.push(node);
200        }
201
202        var totalColumnWidths = 0;
203        for (var columnIdentifier in columns)
204            totalColumnWidths += columns[columnIdentifier].width;
205
206        // Calculate the percentage width for the columns.
207        const minimumPrecent = 5;
208        var recoupPercent = 0;
209        for (var columnIdentifier in columns) {
210            var width = columns[columnIdentifier].width;
211            width = Math.round((width / totalColumnWidths) * 100);
212            if (width < minimumPrecent) {
213                recoupPercent += (minimumPrecent - width);
214                width = minimumPrecent;
215            }
216
217            columns[columnIdentifier].width = width;
218        }
219
220        // Enforce the minimum percentage width.
221        while (recoupPercent > 0) {
222            for (var columnIdentifier in columns) {
223                if (columns[columnIdentifier].width > minimumPrecent) {
224                    --columns[columnIdentifier].width;
225                    --recoupPercent;
226                    if (!recoupPercent)
227                        break;
228                }
229            }
230        }
231
232        // Change the width property to a string suitable for a style width.
233        for (var columnIdentifier in columns)
234            columns[columnIdentifier].width += "%";
235
236        var dataGrid = new WebInspector.DataGrid(columns);
237        var length = nodes.length;
238        for (var i = 0; i < length; ++i)
239            dataGrid.appendChild(nodes[i]);
240
241        return dataGrid;
242    },
243
244    _startSidebarDragging: function(event)
245    {
246        WebInspector.elementDragStart(this.sidebarResizeElement, this._sidebarDragging.bind(this), this._endSidebarDragging.bind(this), event, "col-resize");
247    },
248
249    _sidebarDragging: function(event)
250    {
251        this._updateSidebarWidth(event.pageX);
252
253        event.preventDefault();
254    },
255
256    _endSidebarDragging: function(event)
257    {
258        WebInspector.elementDragEnd(event);
259    },
260
261    _updateSidebarWidth: function(width)
262    {
263        if (this.sidebarElement.offsetWidth <= 0) {
264            // The stylesheet hasn't loaded yet or the window is closed,
265            // so we can't calculate what is need. Return early.
266            return;
267        }
268
269        if (!("_currentSidebarWidth" in this))
270            this._currentSidebarWidth = this.sidebarElement.offsetWidth;
271
272        if (typeof width === "undefined")
273            width = this._currentSidebarWidth;
274
275        width = Number.constrain(width, Preferences.minSidebarWidth, window.innerWidth / 2);
276
277        this._currentSidebarWidth = width;
278
279        this.sidebarElement.style.width = width + "px";
280        this.databaseViews.style.left = width + "px";
281        this.sidebarResizeElement.style.left = (width - 3) + "px";
282    }
283}
284
285WebInspector.DatabasesPanel.prototype.__proto__ = WebInspector.Panel.prototype;
286
287WebInspector.DatabaseSidebarTreeElement = function(database)
288{
289    this.database = database;
290
291    WebInspector.SidebarTreeElement.call(this, "database-sidebar-tree-item", "", "", database, true);
292
293    this.refreshTitles();
294}
295
296WebInspector.DatabaseSidebarTreeElement.prototype = {
297    onselect: function()
298    {
299        WebInspector.panels.databases.showDatabase(this.database);
300    },
301
302    oncollapse: function()
303    {
304        // Request a refresh after every collapse so the next
305        // expand will have an updated table list.
306        this.shouldRefreshChildren = true;
307    },
308
309    onpopulate: function()
310    {
311        this.removeChildren();
312
313        var tableNames = this.database.tableNames;
314        var tableNamesLength = tableNames.length;
315        for (var i = 0; i < tableNamesLength; ++i)
316            this.appendChild(new WebInspector.SidebarDatabaseTableTreeElement(this.database, tableNames[i]));
317    },
318
319    get mainTitle()
320    {
321        return this.database.name;
322    },
323
324    set mainTitle(x)
325    {
326        // Do nothing.
327    },
328
329    get subtitle()
330    {
331        return this.database.displayDomain;
332    },
333
334    set subtitle(x)
335    {
336        // Do nothing.
337    }
338}
339
340WebInspector.DatabaseSidebarTreeElement.prototype.__proto__ = WebInspector.SidebarTreeElement.prototype;
341
342WebInspector.SidebarDatabaseTableTreeElement = function(database, tableName)
343{
344    this.database = database;
345    this.tableName = tableName;
346
347    WebInspector.SidebarTreeElement.call(this, "database-table-sidebar-tree-item small", tableName, "", null, false);
348}
349
350WebInspector.SidebarDatabaseTableTreeElement.prototype = {
351    onselect: function()
352    {
353        WebInspector.panels.databases.showDatabase(this.database, this.tableName);
354    }
355}
356
357WebInspector.SidebarDatabaseTableTreeElement.prototype.__proto__ = WebInspector.SidebarTreeElement.prototype;
358