1 /* 2 * Copyright (C) 2012 Google 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 are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 /** 32 * @constructor 33 * @extends {WebInspector.SidebarView} 34 * @param {WebInspector.FileSystemModel.FileSystem} fileSystem 35 */ 36 WebInspector.FileSystemView = function(fileSystem) 37 { 38 WebInspector.SidebarView.call(this, WebInspector.SidebarView.SidebarPosition.Start, "FileSystemViewSidebarWidth"); 39 this.element.addStyleClass("file-system-view"); 40 this.element.addStyleClass("storage-view"); 41 42 var directoryTreeElement = this.element.createChild("ol", "filesystem-directory-tree"); 43 this._directoryTree = new TreeOutline(directoryTreeElement); 44 this.sidebarElement.appendChild(directoryTreeElement); 45 this.sidebarElement.addStyleClass("outline-disclosure"); 46 this.sidebarElement.addStyleClass("sidebar"); 47 48 var rootItem = new WebInspector.FileSystemView.EntryTreeElement(this, fileSystem.root); 49 rootItem.expanded = true; 50 this._directoryTree.appendChild(rootItem); 51 this._visibleView = null; 52 53 this._refreshButton = new WebInspector.StatusBarButton(WebInspector.UIString("Refresh"), "refresh-storage-status-bar-item"); 54 this._refreshButton.visible = true; 55 this._refreshButton.addEventListener("click", this._refresh, this); 56 57 this._deleteButton = new WebInspector.StatusBarButton(WebInspector.UIString("Delete"), "delete-storage-status-bar-item"); 58 this._deleteButton.visible = true; 59 this._deleteButton.addEventListener("click", this._confirmDelete, this); 60 } 61 62 WebInspector.FileSystemView.prototype = { 63 /** 64 * @type {Array.<Element>} 65 */ 66 get statusBarItems() 67 { 68 return [this._refreshButton.element, this._deleteButton.element]; 69 }, 70 71 /** 72 * @type {WebInspector.View} 73 */ 74 get visibleView() 75 { 76 return this._visibleView; 77 }, 78 79 /** 80 * @param {WebInspector.View} view 81 */ 82 showView: function(view) 83 { 84 if (this._visibleView === view) 85 return; 86 if (this._visibleView) 87 this._visibleView.detach(); 88 this._visibleView = view; 89 view.show(this.mainElement); 90 }, 91 92 _refresh: function() 93 { 94 this._directoryTree.children[0].refresh(); 95 }, 96 97 _confirmDelete: function() 98 { 99 if (confirm(WebInspector.UIString("Are you sure you want to delete the selected entry?"))) 100 this._delete(); 101 }, 102 103 _delete: function() 104 { 105 this._directoryTree.selectedTreeElement.deleteEntry(); 106 }, 107 108 __proto__: WebInspector.SidebarView.prototype 109 } 110 111 /** 112 * @constructor 113 * @extends {TreeElement} 114 * @param {WebInspector.FileSystemView} fileSystemView 115 * @param {WebInspector.FileSystemModel.Entry} entry 116 */ 117 WebInspector.FileSystemView.EntryTreeElement = function(fileSystemView, entry) 118 { 119 TreeElement.call(this, entry.name, null, entry.isDirectory); 120 121 this._entry = entry; 122 this._fileSystemView = fileSystemView; 123 } 124 125 WebInspector.FileSystemView.EntryTreeElement.prototype = { 126 onattach: function() 127 { 128 var selection = this.listItemElement.createChild("div", "selection"); 129 this.listItemElement.insertBefore(selection, this.listItemElement.firstChild); 130 }, 131 132 onselect: function() 133 { 134 if (!this._view) { 135 if (this._entry.isDirectory) 136 this._view = new WebInspector.DirectoryContentView(); 137 else { 138 var file = /** @type {WebInspector.FileSystemModel.File} */ (this._entry); 139 this._view = new WebInspector.FileContentView(file); 140 } 141 } 142 this._fileSystemView.showView(this._view); 143 this.refresh(); 144 }, 145 146 onpopulate: function() 147 { 148 this.refresh(); 149 }, 150 151 /** 152 * @param {number} errorCode 153 * @param {Array.<WebInspector.FileSystemModel.Entry>=} entries 154 */ 155 _directoryContentReceived: function(errorCode, entries) 156 { 157 if (errorCode === FileError.NOT_FOUND_ERR) { 158 if (this.parent !== this.treeOutline) 159 this.parent.refresh(); 160 return; 161 } 162 163 if (errorCode !== 0 || !entries) { 164 console.error("Failed to read directory: " + errorCode); 165 return; 166 } 167 168 entries.sort(WebInspector.FileSystemModel.Entry.compare); 169 if (this._view) 170 this._view.showEntries(entries); 171 172 var oldChildren = this.children.slice(0); 173 174 var newEntryIndex = 0; 175 var oldChildIndex = 0; 176 var currentTreeItem = 0; 177 while (newEntryIndex < entries.length && oldChildIndex < oldChildren.length) { 178 var newEntry = entries[newEntryIndex]; 179 var oldChild = oldChildren[oldChildIndex]; 180 var order = newEntry.name.compareTo(oldChild._entry.name); 181 182 if (order === 0) { 183 if (oldChild._entry.isDirectory) 184 oldChild.shouldRefreshChildren = true; 185 else 186 oldChild.refresh(); 187 188 ++newEntryIndex; 189 ++oldChildIndex; 190 ++currentTreeItem; 191 continue; 192 } 193 if (order < 0) { 194 this.insertChild(new WebInspector.FileSystemView.EntryTreeElement(this._fileSystemView, newEntry), currentTreeItem); 195 ++newEntryIndex; 196 ++currentTreeItem; 197 continue; 198 } 199 200 this.removeChildAtIndex(currentTreeItem); 201 ++oldChildIndex; 202 } 203 for (; newEntryIndex < entries.length; ++newEntryIndex) 204 this.appendChild(new WebInspector.FileSystemView.EntryTreeElement(this._fileSystemView, entries[newEntryIndex])); 205 206 for (; oldChildIndex < oldChildren.length; ++oldChildIndex) 207 this.removeChild(oldChildren[oldChildIndex]); 208 }, 209 210 refresh: function() 211 { 212 if (!this._entry.isDirectory) { 213 if (this._view && this._view === this._fileSystemView.visibleView) { 214 var fileContentView = /** @type {WebInspector.FileContentView} */ (this._view); 215 fileContentView.refresh(); 216 } 217 } else 218 this._entry.requestDirectoryContent(this._directoryContentReceived.bind(this)); 219 }, 220 221 deleteEntry: function() 222 { 223 this._entry.deleteEntry(this._deletionCompleted.bind(this)); 224 }, 225 226 _deletionCompleted: function() 227 { 228 if (this._entry != this._entry.fileSystem.root) 229 this.parent.refresh(); 230 }, 231 232 __proto__: TreeElement.prototype 233 } 234