1 /* 2 * Copyright (C) 2013 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 * @implements {WebInspector.ProjectDelegate} 34 * @param {!WebInspector.Workspace} workspace 35 * @param {string} id 36 * @param {!WebInspector.projectTypes} type 37 */ 38 WebInspector.ContentProviderBasedProjectDelegate = function(workspace, id, type) 39 { 40 this._type = type; 41 /** @type {!Object.<string, !WebInspector.ContentProvider>} */ 42 this._contentProviders = {}; 43 this._workspace = workspace; 44 this._id = id; 45 this._projectStore = workspace.addProject(id, this); 46 } 47 48 WebInspector.ContentProviderBasedProjectDelegate.prototype = { 49 /** 50 * @return {string} 51 */ 52 type: function() 53 { 54 return this._type; 55 }, 56 57 /** 58 * @return {string} 59 */ 60 displayName: function() 61 { 62 // Overriddden by subclasses 63 return ""; 64 }, 65 66 /** 67 * @return {string} 68 */ 69 url: function() 70 { 71 // Overriddden by subclasses 72 return ""; 73 }, 74 75 /** 76 * @param {string} path 77 * @param {function(?Date, ?number)} callback 78 */ 79 requestMetadata: function(path, callback) 80 { 81 callback(null, null); 82 }, 83 84 /** 85 * @param {string} path 86 * @param {function(?string)} callback 87 */ 88 requestFileContent: function(path, callback) 89 { 90 var contentProvider = this._contentProviders[path]; 91 contentProvider.requestContent(callback); 92 93 /** 94 * @param {?string} content 95 * @param {boolean} encoded 96 * @param {string} mimeType 97 */ 98 function innerCallback(content, encoded, mimeType) 99 { 100 callback(content); 101 } 102 }, 103 104 /** 105 * @return {boolean} 106 */ 107 canSetFileContent: function() 108 { 109 return false; 110 }, 111 112 /** 113 * @param {string} path 114 * @param {string} newContent 115 * @param {function(?string)} callback 116 */ 117 setFileContent: function(path, newContent, callback) 118 { 119 callback(null); 120 }, 121 122 /** 123 * @return {boolean} 124 */ 125 canRename: function() 126 { 127 return false; 128 }, 129 130 /** 131 * @param {string} path 132 * @param {string} newName 133 * @param {function(boolean, string=, string=, string=, !WebInspector.ResourceType=)} callback 134 */ 135 rename: function(path, newName, callback) 136 { 137 this.performRename(path, newName, innerCallback.bind(this)); 138 139 /** 140 * @param {boolean} success 141 * @param {string=} newName 142 * @this {WebInspector.ContentProviderBasedProjectDelegate} 143 */ 144 function innerCallback(success, newName) 145 { 146 if (success) 147 this._updateName(path, /** @type {string} */ (newName)); 148 callback(success, newName); 149 } 150 }, 151 152 /** 153 * @param {string} path 154 * @param {function()=} callback 155 */ 156 refresh: function(path, callback) 157 { 158 if (callback) 159 callback(); 160 }, 161 162 /** 163 * @param {string} path 164 */ 165 excludeFolder: function(path) 166 { 167 }, 168 169 /** 170 * @param {string} path 171 * @param {?string} name 172 * @param {string} content 173 * @param {function(?string)} callback 174 */ 175 createFile: function(path, name, content, callback) 176 { 177 }, 178 179 /** 180 * @param {string} path 181 */ 182 deleteFile: function(path) 183 { 184 }, 185 186 remove: function() 187 { 188 }, 189 190 /** 191 * @param {string} path 192 * @param {string} newName 193 * @param {function(boolean, string=)} callback 194 */ 195 performRename: function(path, newName, callback) 196 { 197 callback(false); 198 }, 199 200 /** 201 * @param {string} path 202 * @param {string} newName 203 */ 204 _updateName: function(path, newName) 205 { 206 var oldPath = path; 207 var copyOfPath = path.split("/"); 208 copyOfPath[copyOfPath.length - 1] = newName; 209 var newPath = copyOfPath.join("/"); 210 this._contentProviders[newPath] = this._contentProviders[oldPath]; 211 delete this._contentProviders[oldPath]; 212 }, 213 214 /** 215 * @param {string} path 216 * @param {string} query 217 * @param {boolean} caseSensitive 218 * @param {boolean} isRegex 219 * @param {function(!Array.<!WebInspector.ContentProvider.SearchMatch>)} callback 220 */ 221 searchInFileContent: function(path, query, caseSensitive, isRegex, callback) 222 { 223 var contentProvider = this._contentProviders[path]; 224 contentProvider.searchInContent(query, caseSensitive, isRegex, callback); 225 }, 226 227 /** 228 * @param {!WebInspector.ProjectSearchConfig} searchConfig 229 * @param {!Array.<string>} filesMathingFileQuery 230 * @param {!WebInspector.Progress} progress 231 * @param {function(!Array.<string>)} callback 232 */ 233 findFilesMatchingSearchRequest: function(searchConfig, filesMathingFileQuery, progress, callback) 234 { 235 var result = []; 236 var paths = filesMathingFileQuery; 237 var totalCount = paths.length; 238 if (totalCount === 0) { 239 // searchInContent should call back later. 240 setTimeout(doneCallback, 0); 241 return; 242 } 243 244 var barrier = new CallbackBarrier(); 245 progress.setTotalWork(paths.length); 246 for (var i = 0; i < paths.length; ++i) 247 searchInContent.call(this, paths[i], barrier.createCallback(searchInContentCallback.bind(null, paths[i]))); 248 barrier.callWhenDone(doneCallback); 249 250 /** 251 * @param {string} path 252 * @param {function(boolean)} callback 253 * @this {WebInspector.ContentProviderBasedProjectDelegate} 254 */ 255 function searchInContent(path, callback) 256 { 257 var queriesToRun = searchConfig.queries().slice(); 258 searchNextQuery.call(this); 259 260 /** 261 * @this {WebInspector.ContentProviderBasedProjectDelegate} 262 */ 263 function searchNextQuery() 264 { 265 if (!queriesToRun.length) { 266 callback(true); 267 return; 268 } 269 var query = queriesToRun.shift(); 270 this._contentProviders[path].searchInContent(query, !searchConfig.ignoreCase(), searchConfig.isRegex(), contentCallback.bind(this)); 271 } 272 273 /** 274 * @param {!Array.<!WebInspector.ContentProvider.SearchMatch>} searchMatches 275 * @this {WebInspector.ContentProviderBasedProjectDelegate} 276 */ 277 function contentCallback(searchMatches) 278 { 279 if (!searchMatches.length) { 280 callback(false); 281 return; 282 } 283 searchNextQuery.call(this); 284 } 285 } 286 287 /** 288 * @param {string} path 289 * @param {boolean} matches 290 */ 291 function searchInContentCallback(path, matches) 292 { 293 if (matches) 294 result.push(path); 295 progress.worked(1); 296 } 297 298 function doneCallback() 299 { 300 callback(result); 301 progress.done(); 302 } 303 }, 304 305 /** 306 * @param {!WebInspector.Progress} progress 307 */ 308 indexContent: function(progress) 309 { 310 setTimeout(progress.done.bind(progress), 0); 311 }, 312 313 /** 314 * @param {string} parentPath 315 * @param {string} name 316 * @param {string} url 317 * @param {!WebInspector.ContentProvider} contentProvider 318 * @return {string} 319 */ 320 addContentProvider: function(parentPath, name, url, contentProvider) 321 { 322 var path = parentPath ? parentPath + "/" + name : name; 323 if (this._contentProviders[path]) 324 return path; 325 var fileDescriptor = new WebInspector.FileDescriptor(parentPath, name, url, url, contentProvider.contentType()); 326 this._contentProviders[path] = contentProvider; 327 this._projectStore.addFile(fileDescriptor); 328 return path; 329 }, 330 331 /** 332 * @param {string} path 333 */ 334 removeFile: function(path) 335 { 336 delete this._contentProviders[path]; 337 this._projectStore.removeFile(path); 338 }, 339 340 /** 341 * @return {!Object.<string, !WebInspector.ContentProvider>} 342 */ 343 contentProviders: function() 344 { 345 return this._contentProviders; 346 }, 347 348 reset: function() 349 { 350 this._contentProviders = {}; 351 this._workspace.removeProject(this._id); 352 this._projectStore = this._workspace.addProject(this._id, this); 353 } 354 } 355