Upstream version 7.35.144.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / devtools / front_end / SourcesSearchScope.js
1 /*
2  * Copyright (C) 2011 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  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. AND ITS CONTRIBUTORS
17  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC.
20  * OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 /**
30  * @constructor
31  * @implements {WebInspector.SearchScope}
32  */
33 WebInspector.SourcesSearchScope = function()
34 {
35     // FIXME: Add title once it is used by search controller.
36     this._searchId = 0;
37     this._workspace = WebInspector.workspace;
38 }
39
40 WebInspector.SourcesSearchScope.prototype = {
41     /**
42      * @param {!WebInspector.Progress} progress
43      * @param {function(boolean)} indexingFinishedCallback
44      */
45     performIndexing: function(progress, indexingFinishedCallback)
46     {
47         this.stopSearch();
48
49         var projects = this._workspace.projects().filter(this._filterOutServiceProjects);
50         var barrier = new CallbackBarrier();
51         var compositeProgress = new WebInspector.CompositeProgress(progress);
52         progress.addEventListener(WebInspector.Progress.Events.Canceled, indexingCanceled);
53         for (var i = 0; i < projects.length; ++i) {
54             var project = projects[i];
55             var projectProgress = compositeProgress.createSubProgress(project.uiSourceCodes().length);
56             project.indexContent(projectProgress, barrier.createCallback());
57         }
58         barrier.callWhenDone(indexingFinishedCallback.bind(this, true));
59
60         function indexingCanceled()
61         {
62             indexingFinishedCallback(false);
63             progress.done();
64         }
65     },
66
67     /**
68      * @param {!WebInspector.Project} project
69      */
70     _filterOutServiceProjects: function(project)
71     {
72         return !project.isServiceProject() || project.type() === WebInspector.projectTypes.Formatter;
73     },
74
75     /**
76      * @param {!WebInspector.SearchConfig} searchConfig
77      * @param {!WebInspector.Progress} progress
78      * @param {function(!WebInspector.FileBasedSearchResultsPane.SearchResult)} searchResultCallback
79      * @param {function(boolean)} searchFinishedCallback
80      */
81     performSearch: function(searchConfig, progress, searchResultCallback, searchFinishedCallback)
82     {
83         this.stopSearch();
84         this._searchResultCallback = searchResultCallback;
85         this._searchFinishedCallback = searchFinishedCallback;
86         this._searchConfig = searchConfig;
87
88         var projects = this._workspace.projects().filter(this._filterOutServiceProjects);
89         var barrier = new CallbackBarrier();
90         var compositeProgress = new WebInspector.CompositeProgress(progress);
91         for (var i = 0; i < projects.length; ++i) {
92             var project = projects[i];
93             var weight = project.uiSourceCodes().length;
94             var projectProgress = new WebInspector.CompositeProgress(compositeProgress.createSubProgress(weight));
95             var findMatchingFilesProgress = projectProgress.createSubProgress();
96             var searchContentProgress = projectProgress.createSubProgress();
97             var barrierCallback = barrier.createCallback();
98             var callback = this._processMatchingFilesForProject.bind(this, this._searchId, project, searchContentProgress, barrierCallback);
99             project.findFilesMatchingSearchRequest(searchConfig.queries(), searchConfig.fileQueries(), !searchConfig.ignoreCase, searchConfig.isRegex, findMatchingFilesProgress, callback);
100         }
101         barrier.callWhenDone(this._searchFinishedCallback.bind(this, true));
102     },
103
104     /**
105      * @param {number} searchId
106      * @param {!WebInspector.Project} project
107      * @param {!WebInspector.Progress} progress
108      * @param {function()} callback
109      * @param {!Array.<string>} files
110      */
111     _processMatchingFilesForProject: function(searchId, project, progress, callback, files)
112     {
113         if (searchId !== this._searchId) {
114             this._searchFinishedCallback(false);
115             return;
116         }
117
118         if (!files.length) {
119             progress.done();
120             callback();
121             return;
122         }
123
124         progress.setTotalWork(files.length);
125
126         var fileIndex = 0;
127         var maxFileContentRequests = 20;
128         var callbacksLeft = 0;
129
130         for (var i = 0; i < maxFileContentRequests && i < files.length; ++i)
131             scheduleSearchInNextFileOrFinish.call(this);
132
133         /**
134          * @param {!string} path
135          * @this {WebInspector.SourcesSearchScope}
136          */
137         function searchInNextFile(path)
138         {
139             var uiSourceCode = project.uiSourceCode(path);
140             if (!uiSourceCode) {
141                 --callbacksLeft;
142                 progress.worked(1);
143                 scheduleSearchInNextFileOrFinish.call(this);
144                 return;
145             }
146             uiSourceCode.requestContent(contentLoaded.bind(this, path));
147         }
148
149         /**
150          * @this {WebInspector.SourcesSearchScope}
151          */
152         function scheduleSearchInNextFileOrFinish()
153         {
154             if (fileIndex >= files.length) {
155                 if (!callbacksLeft) {
156                     progress.done();
157                     callback();
158                     return;
159                 }
160                 return;
161             }
162
163             ++callbacksLeft;
164             var path = files[fileIndex++];
165             setTimeout(searchInNextFile.bind(this, path), 0);
166         }
167
168         /**
169          * @param {!string} path
170          * @param {?string} content
171          * @this {WebInspector.SourcesSearchScope}
172          */
173         function contentLoaded(path, content)
174         {
175             /**
176              * @param {!WebInspector.ContentProvider.SearchMatch} a
177              * @param {!WebInspector.ContentProvider.SearchMatch} b
178              */
179             function matchesComparator(a, b)
180             {
181                 return a.lineNumber - b.lineNumber;
182             }
183
184             progress.worked(1);
185             var matches = [];
186             var queries = this._searchConfig.queries();
187             if (content !== null) {
188                 for (var i = 0; i < queries.length; ++i) {
189                     var nextMatches = WebInspector.ContentProvider.performSearchInContent(content, queries[i], !this._searchConfig.ignoreCase, this._searchConfig.isRegex)
190                     matches = matches.mergeOrdered(nextMatches, matchesComparator);
191                 }
192             }
193             var uiSourceCode = project.uiSourceCode(path);
194             if (matches && uiSourceCode) {
195                 var searchResult = new WebInspector.FileBasedSearchResultsPane.SearchResult(uiSourceCode, matches);
196                 this._searchResultCallback(searchResult);
197             }
198
199             --callbacksLeft;
200             scheduleSearchInNextFileOrFinish.call(this);
201         }
202     },
203
204     stopSearch: function()
205     {
206         ++this._searchId;
207     },
208
209     /**
210      * @param {!WebInspector.SearchConfig} searchConfig
211      * @return {!WebInspector.FileBasedSearchResultsPane}
212      */
213     createSearchResultsPane: function(searchConfig)
214     {
215         return new WebInspector.FileBasedSearchResultsPane(searchConfig);
216     }
217 }