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.SplitView} 34 * @param {!WebInspector.FileSystemModel.FileSystem} fileSystem 35 */ 36WebInspector.FileSystemView = function(fileSystem) 37{ 38 WebInspector.SplitView.call(this, true, false, "fileSystemViewSplitViewState"); 39 this.element.classList.add("file-system-view"); 40 this.element.classList.add("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().classList.add("outline-disclosure", "sidebar"); 46 47 var rootItem = new WebInspector.FileSystemView.EntryTreeElement(this, fileSystem.root); 48 rootItem.expanded = true; 49 this._directoryTree.appendChild(rootItem); 50 this._visibleView = null; 51 52 this._refreshButton = new WebInspector.StatusBarButton(WebInspector.UIString("Refresh"), "refresh-storage-status-bar-item"); 53 this._refreshButton.visible = true; 54 this._refreshButton.addEventListener("click", this._refresh, this); 55 56 this._deleteButton = new WebInspector.StatusBarButton(WebInspector.UIString("Delete"), "delete-storage-status-bar-item"); 57 this._deleteButton.visible = true; 58 this._deleteButton.addEventListener("click", this._confirmDelete, this); 59} 60 61WebInspector.FileSystemView.prototype = { 62 /** 63 * @type {!Array.<!Element>} 64 */ 65 get statusBarItems() 66 { 67 return [this._refreshButton.element, this._deleteButton.element]; 68 }, 69 70 /** 71 * @type {!WebInspector.View} 72 */ 73 get visibleView() 74 { 75 return this._visibleView; 76 }, 77 78 /** 79 * @param {!WebInspector.View} view 80 */ 81 showView: function(view) 82 { 83 if (this._visibleView === view) 84 return; 85 if (this._visibleView) 86 this._visibleView.detach(); 87 this._visibleView = view; 88 view.show(this.mainElement()); 89 }, 90 91 _refresh: function() 92 { 93 this._directoryTree.children[0].refresh(); 94 }, 95 96 _confirmDelete: function() 97 { 98 if (confirm(WebInspector.UIString("Are you sure you want to delete the selected entry?"))) 99 this._delete(); 100 }, 101 102 _delete: function() 103 { 104 this._directoryTree.selectedTreeElement.deleteEntry(); 105 }, 106 107 __proto__: WebInspector.SplitView.prototype 108} 109 110/** 111 * @constructor 112 * @extends {TreeElement} 113 * @param {!WebInspector.FileSystemView} fileSystemView 114 * @param {!WebInspector.FileSystemModel.Entry} entry 115 */ 116WebInspector.FileSystemView.EntryTreeElement = function(fileSystemView, entry) 117{ 118 TreeElement.call(this, entry.name, null, entry.isDirectory); 119 120 this._entry = entry; 121 this._fileSystemView = fileSystemView; 122} 123 124WebInspector.FileSystemView.EntryTreeElement.prototype = { 125 /** 126 * @override 127 */ 128 onattach: function() 129 { 130 var selection = this.listItemElement.createChild("div", "selection"); 131 this.listItemElement.insertBefore(selection, this.listItemElement.firstChild); 132 }, 133 134 /** 135 * @override 136 * @return {boolean} 137 */ 138 onselect: function() 139 { 140 if (!this._view) { 141 if (this._entry.isDirectory) 142 this._view = new WebInspector.DirectoryContentView(); 143 else { 144 var file = /** @type {!WebInspector.FileSystemModel.File} */ (this._entry); 145 this._view = new WebInspector.FileContentView(file); 146 } 147 } 148 this._fileSystemView.showView(this._view); 149 this.refresh(); 150 return false; 151 }, 152 153 /** 154 * @override 155 */ 156 onpopulate: function() 157 { 158 this.refresh(); 159 }, 160 161 /** 162 * @param {number} errorCode 163 * @param {!Array.<!WebInspector.FileSystemModel.Entry>=} entries 164 */ 165 _directoryContentReceived: function(errorCode, entries) 166 { 167 if (errorCode === FileError.NOT_FOUND_ERR) { 168 if (this.parent !== this.treeOutline) 169 this.parent.refresh(); 170 return; 171 } 172 173 if (errorCode !== 0 || !entries) { 174 console.error("Failed to read directory: " + errorCode); 175 return; 176 } 177 178 entries.sort(WebInspector.FileSystemModel.Entry.compare); 179 if (this._view) 180 this._view.showEntries(entries); 181 182 var oldChildren = this.children.slice(0); 183 184 var newEntryIndex = 0; 185 var oldChildIndex = 0; 186 var currentTreeItem = 0; 187 while (newEntryIndex < entries.length && oldChildIndex < oldChildren.length) { 188 var newEntry = entries[newEntryIndex]; 189 var oldChild = oldChildren[oldChildIndex]; 190 var order = newEntry.name.compareTo(oldChild._entry.name); 191 192 if (order === 0) { 193 if (oldChild._entry.isDirectory) 194 oldChild.shouldRefreshChildren = true; 195 else 196 oldChild.refresh(); 197 198 ++newEntryIndex; 199 ++oldChildIndex; 200 ++currentTreeItem; 201 continue; 202 } 203 if (order < 0) { 204 this.insertChild(new WebInspector.FileSystemView.EntryTreeElement(this._fileSystemView, newEntry), currentTreeItem); 205 ++newEntryIndex; 206 ++currentTreeItem; 207 continue; 208 } 209 210 this.removeChildAtIndex(currentTreeItem); 211 ++oldChildIndex; 212 } 213 for (; newEntryIndex < entries.length; ++newEntryIndex) 214 this.appendChild(new WebInspector.FileSystemView.EntryTreeElement(this._fileSystemView, entries[newEntryIndex])); 215 216 for (; oldChildIndex < oldChildren.length; ++oldChildIndex) 217 this.removeChild(oldChildren[oldChildIndex]); 218 }, 219 220 refresh: function() 221 { 222 if (!this._entry.isDirectory) { 223 if (this._view && this._view === this._fileSystemView.visibleView) { 224 var fileContentView = /** @type {!WebInspector.FileContentView} */ (this._view); 225 fileContentView.refresh(); 226 } 227 } else 228 this._entry.requestDirectoryContent(this._directoryContentReceived.bind(this)); 229 }, 230 231 deleteEntry: function() 232 { 233 this._entry.deleteEntry(this._deletionCompleted.bind(this)); 234 }, 235 236 _deletionCompleted: function() 237 { 238 if (this._entry != this._entry.fileSystem.root) 239 this.parent.refresh(); 240 }, 241 242 __proto__: TreeElement.prototype 243} 244