KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > search > internal > core > text > TextSearchVisitor


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.search.internal.core.text;
12
13 import java.io.IOException JavaDoc;
14 import java.nio.charset.IllegalCharsetNameException JavaDoc;
15 import java.nio.charset.UnsupportedCharsetException JavaDoc;
16 import java.util.HashMap JavaDoc;
17 import java.util.Map JavaDoc;
18 import java.util.regex.Matcher JavaDoc;
19 import java.util.regex.Pattern JavaDoc;
20
21 import org.eclipse.core.filebuffers.FileBuffers;
22 import org.eclipse.core.filebuffers.ITextFileBuffer;
23 import org.eclipse.core.filebuffers.ITextFileBufferManager;
24 import org.eclipse.core.filebuffers.LocationKind;
25
26 import org.eclipse.core.runtime.CoreException;
27 import org.eclipse.core.runtime.IProgressMonitor;
28 import org.eclipse.core.runtime.IStatus;
29 import org.eclipse.core.runtime.MultiStatus;
30 import org.eclipse.core.runtime.NullProgressMonitor;
31 import org.eclipse.core.runtime.OperationCanceledException;
32 import org.eclipse.core.runtime.Platform;
33 import org.eclipse.core.runtime.Status;
34 import org.eclipse.core.runtime.content.IContentDescription;
35 import org.eclipse.core.runtime.content.IContentType;
36 import org.eclipse.core.runtime.content.IContentTypeManager;
37 import org.eclipse.core.runtime.jobs.Job;
38
39 import org.eclipse.core.resources.IFile;
40
41 import org.eclipse.jface.text.IDocument;
42
43 import org.eclipse.ui.IEditorInput;
44 import org.eclipse.ui.IEditorPart;
45 import org.eclipse.ui.IEditorReference;
46 import org.eclipse.ui.IFileEditorInput;
47 import org.eclipse.ui.IWorkbench;
48 import org.eclipse.ui.IWorkbenchPage;
49 import org.eclipse.ui.IWorkbenchWindow;
50 import org.eclipse.ui.texteditor.ITextEditor;
51
52 import org.eclipse.search.ui.NewSearchUI;
53
54 import org.eclipse.search.core.text.TextSearchMatchAccess;
55 import org.eclipse.search.core.text.TextSearchRequestor;
56 import org.eclipse.search.core.text.TextSearchScope;
57
58 import org.eclipse.search.internal.ui.Messages;
59 import org.eclipse.search.internal.ui.SearchMessages;
60 import org.eclipse.search.internal.ui.SearchPlugin;
61
62 /**
63  * The visitor that does the actual work.
64  */

65 public class TextSearchVisitor {
66     
67     public static class ReusableMatchAccess extends TextSearchMatchAccess {
68         
69         private int fOffset;
70         private int fLength;
71         private IFile fFile;
72         private CharSequence JavaDoc fContent;
73         
74         public void initialize(IFile file, int offset, int length, CharSequence JavaDoc content) {
75             fFile= file;
76             fOffset= offset;
77             fLength= length;
78             fContent= content;
79         }
80                 
81         public IFile getFile() {
82             return fFile;
83         }
84         
85         public int getMatchOffset() {
86             return fOffset;
87         }
88         
89         public int getMatchLength() {
90             return fLength;
91         }
92
93         public int getFileContentLength() {
94             return fContent.length();
95         }
96
97         public char getFileContentChar(int offset) {
98             return fContent.charAt(offset);
99         }
100
101         public String JavaDoc getFileContent(int offset, int length) {
102             return fContent.subSequence(offset, offset + length).toString(); // must pass a copy!
103
}
104     }
105     
106
107     private final TextSearchRequestor fCollector;
108     private final Matcher JavaDoc fMatcher;
109     
110     private Map JavaDoc fDocumentsInEditors;
111         
112     private IProgressMonitor fProgressMonitor;
113
114     private int fNumberOfScannedFiles;
115     private int fNumberOfFilesToScan;
116     private IFile fCurrentFile;
117
118     private final MultiStatus fStatus;
119     
120     private final FileCharSequenceProvider fFileCharSequenceProvider;
121     
122     private final ReusableMatchAccess fMatchAccess;
123     
124     public TextSearchVisitor(TextSearchRequestor collector, Pattern JavaDoc searchPattern) {
125         fCollector= collector;
126         fStatus= new MultiStatus(NewSearchUI.PLUGIN_ID, IStatus.OK, SearchMessages.TextSearchEngine_statusMessage, null);
127         
128         fMatcher= searchPattern.pattern().length() == 0 ? null : searchPattern.matcher(new String JavaDoc());
129         
130         fFileCharSequenceProvider= new FileCharSequenceProvider();
131         fMatchAccess= new ReusableMatchAccess();
132     }
133     
134     public IStatus search(IFile[] files, IProgressMonitor monitor) {
135         fProgressMonitor= monitor == null ? new NullProgressMonitor() : monitor;
136         fNumberOfScannedFiles= 0;
137         fNumberOfFilesToScan= files.length;
138         fCurrentFile= null;
139         
140         Job monitorUpdateJob= new Job(SearchMessages.TextSearchVisitor_progress_updating_job) {
141             private int fLastNumberOfScannedFiles= 0;
142             
143             public IStatus run(IProgressMonitor inner) {
144                 while (!inner.isCanceled()) {
145                     IFile file= fCurrentFile;
146                     if (file != null) {
147                         String JavaDoc fileName= file.getName();
148                         Object JavaDoc[] args= { fileName, new Integer JavaDoc(fNumberOfScannedFiles), new Integer JavaDoc(fNumberOfFilesToScan)};
149                         fProgressMonitor.subTask(Messages.format(SearchMessages.TextSearchVisitor_scanning, args));
150                         int steps= fNumberOfScannedFiles - fLastNumberOfScannedFiles;
151                         fProgressMonitor.worked(steps);
152                         fLastNumberOfScannedFiles += steps;
153                     }
154                     try {
155                         Thread.sleep(100);
156                     } catch (InterruptedException JavaDoc e) {
157                         return Status.OK_STATUS;
158                     }
159                 }
160                 return Status.OK_STATUS;
161             }
162         };
163
164         try {
165             String JavaDoc taskName= fMatcher == null ? SearchMessages.TextSearchVisitor_filesearch_task_label : Messages.format(SearchMessages.TextSearchVisitor_textsearch_task_label, fMatcher.pattern().pattern());
166             fProgressMonitor.beginTask(taskName, fNumberOfFilesToScan);
167             monitorUpdateJob.setSystem(true);
168             monitorUpdateJob.schedule();
169             try {
170                 fCollector.beginReporting();
171                 processFiles(files);
172                 return fStatus;
173             } finally {
174                 monitorUpdateJob.cancel();
175             }
176         } finally {
177             fProgressMonitor.done();
178             fCollector.endReporting();
179         }
180     }
181         
182     public IStatus search(TextSearchScope scope, IProgressMonitor monitor) {
183         return search(scope.evaluateFilesInScope(fStatus), monitor);
184     }
185     
186     private void processFiles(IFile[] files) {
187         fDocumentsInEditors= evalNonFileBufferDocuments();
188         for (int i= 0; i < files.length; i++) {
189             fCurrentFile= files[i];
190             boolean res= processFile(fCurrentFile);
191             if (!res)
192                 break;
193         }
194         fDocumentsInEditors= null;
195     }
196     
197     /**
198      * @return returns a map from IFile to IDocument for all open, dirty editors
199      */

200     private Map JavaDoc evalNonFileBufferDocuments() {
201         Map JavaDoc result= new HashMap JavaDoc();
202         IWorkbench workbench= SearchPlugin.getDefault().getWorkbench();
203         IWorkbenchWindow[] windows= workbench.getWorkbenchWindows();
204         for (int i= 0; i < windows.length; i++) {
205             IWorkbenchPage[] pages= windows[i].getPages();
206             for (int x= 0; x < pages.length; x++) {
207                 IEditorReference[] editorRefs= pages[x].getEditorReferences();
208                 for (int z= 0; z < editorRefs.length; z++) {
209                     IEditorPart ep= editorRefs[z].getEditor(false);
210                     if (ep instanceof ITextEditor && ep.isDirty()) { // only dirty editors
211
evaluateTextEditor(result, ep);
212                     }
213                 }
214             }
215         }
216         return result;
217     }
218
219     private void evaluateTextEditor(Map JavaDoc result, IEditorPart ep) {
220         IEditorInput input= ep.getEditorInput();
221         if (input instanceof IFileEditorInput) {
222             IFile file= ((IFileEditorInput) input).getFile();
223             if (!result.containsKey(file)) { // take the first editor found
224
ITextFileBufferManager bufferManager= FileBuffers.getTextFileBufferManager();
225                 ITextFileBuffer textFileBuffer= bufferManager.getTextFileBuffer(file.getFullPath(), LocationKind.IFILE);
226                 if (textFileBuffer != null) {
227                     // file buffer has precedence
228
result.put(file, textFileBuffer.getDocument());
229                 } else {
230                     // use document provider
231
IDocument document= ((ITextEditor) ep).getDocumentProvider().getDocument(input);
232                     if (document != null) {
233                         result.put(file, document);
234                     }
235                 }
236             }
237         }
238     }
239
240     public boolean processFile(IFile file) {
241         try {
242             if (!fCollector.acceptFile(file) || fMatcher == null) {
243                return true;
244             }
245                 
246             IDocument document= getOpenDocument(file);
247             
248             if (document != null) {
249                 DocumentCharSequence documentCharSequence= new DocumentCharSequence(document);
250                 // assume all documents are non-binary
251
locateMatches(file, documentCharSequence);
252             } else {
253                 CharSequence JavaDoc seq= null;
254                 try {
255                     seq= fFileCharSequenceProvider.newCharSequence(file);
256                     if (hasBinaryContent(seq, file) && !fCollector.reportBinaryFile(file)) {
257                         return true;
258                     }
259                     locateMatches(file, seq);
260                 } catch (FileCharSequenceProvider.FileCharSequenceException e) {
261                     e.throwWrappedException();
262                 } finally {
263                     if (seq != null) {
264                         try {
265                             fFileCharSequenceProvider.releaseCharSequence(seq);
266                         } catch (IOException JavaDoc e) {
267                             SearchPlugin.log(e);
268                         }
269                     }
270                 }
271             }
272         } catch (UnsupportedCharsetException JavaDoc e) {
273             String JavaDoc[] args= { getCharSetName(file), file.getFullPath().makeRelative().toString()};
274             String JavaDoc message= Messages.format(SearchMessages.TextSearchVisitor_unsupportedcharset, args);
275             fStatus.add(new Status(IStatus.WARNING, NewSearchUI.PLUGIN_ID, IStatus.WARNING, message, e));
276         } catch (IllegalCharsetNameException JavaDoc e) {
277             String JavaDoc[] args= { getCharSetName(file), file.getFullPath().makeRelative().toString()};
278             String JavaDoc message= Messages.format(SearchMessages.TextSearchVisitor_illegalcharset, args);
279             fStatus.add(new Status(IStatus.WARNING, NewSearchUI.PLUGIN_ID, IStatus.WARNING, message, e));
280         } catch (IOException JavaDoc e) {
281             String JavaDoc[] args= { getExceptionMessage(e), file.getFullPath().makeRelative().toString()};
282             String JavaDoc message= Messages.format(SearchMessages.TextSearchVisitor_error, args);
283             fStatus.add(new Status(IStatus.WARNING, NewSearchUI.PLUGIN_ID, IStatus.WARNING, message, e));
284         } catch (CoreException e) {
285             String JavaDoc[] args= { getExceptionMessage(e), file.getFullPath().makeRelative().toString()};
286             String JavaDoc message= Messages.format(SearchMessages.TextSearchVisitor_error, args);
287             fStatus.add(new Status(IStatus.WARNING, NewSearchUI.PLUGIN_ID, IStatus.WARNING, message, e));
288         } catch (StackOverflowError JavaDoc e) {
289             String JavaDoc message= SearchMessages.TextSearchVisitor_patterntoocomplex0;
290             fStatus.add(new Status(IStatus.ERROR, NewSearchUI.PLUGIN_ID, IStatus.ERROR, message, e));
291             return false;
292         } finally {
293             fNumberOfScannedFiles++;
294         }
295         if (fProgressMonitor.isCanceled())
296             throw new OperationCanceledException(SearchMessages.TextSearchVisitor_canceled);
297         
298         return true;
299     }
300     
301     private boolean hasBinaryContent(CharSequence JavaDoc seq, IFile file) throws CoreException {
302         IContentDescription desc= file.getContentDescription();
303         if (desc != null) {
304             IContentType contentType= desc.getContentType();
305             if (contentType != null && contentType.isKindOf(Platform.getContentTypeManager().getContentType(IContentTypeManager.CT_TEXT))) {
306                 return false;
307             }
308         }
309         
310         // avoid calling seq.length() at it runs through the complete file,
311
// thus it would do so for all binary files.
312
try {
313             int limit= FileCharSequenceProvider.BUFFER_SIZE;
314             for (int i= 0; i < limit; i++) {
315                 if (seq.charAt(i) == '\0') {
316                     return true;
317                 }
318             }
319         } catch (IndexOutOfBoundsException JavaDoc e) {
320         }
321         return false;
322     }
323
324     private void locateMatches(IFile file, CharSequence JavaDoc searchInput) throws CoreException {
325         try {
326             fMatcher.reset(searchInput);
327             int k= 0;
328             while (fMatcher.find()) {
329                 int start= fMatcher.start();
330                 int end= fMatcher.end();
331                 if (end != start) { // don't report 0-length matches
332
fMatchAccess.initialize(file, start, end - start, searchInput);
333                     boolean res= fCollector.acceptPatternMatch(fMatchAccess);
334                     if (!res) {
335                         return; // no further reporting requested
336
}
337                 }
338                 if (k++ == 20) {
339                     if (fProgressMonitor.isCanceled()) {
340                         throw new OperationCanceledException(SearchMessages.TextSearchVisitor_canceled);
341                     }
342                     k= 0;
343                 }
344             }
345         } finally {
346             fMatchAccess.initialize(null, 0, 0, new String JavaDoc()); // clear references
347
}
348     }
349     
350     
351     private String JavaDoc getExceptionMessage(Exception JavaDoc e) {
352         String JavaDoc message= e.getLocalizedMessage();
353         if (message == null) {
354             return e.getClass().getName();
355         }
356         return message;
357     }
358
359     private IDocument getOpenDocument(IFile file) {
360         IDocument document= (IDocument) fDocumentsInEditors.get(file);
361         if (document == null) {
362             ITextFileBufferManager bufferManager= FileBuffers.getTextFileBufferManager();
363             ITextFileBuffer textFileBuffer= bufferManager.getTextFileBuffer(file.getFullPath(), LocationKind.IFILE);
364             if (textFileBuffer != null) {
365                 document= textFileBuffer.getDocument();
366             }
367         }
368         return document;
369     }
370     
371     private String JavaDoc getCharSetName(IFile file) {
372         try {
373             return file.getCharset();
374         } catch (CoreException e) {
375             return "unknown"; //$NON-NLS-1$
376
}
377     }
378
379 }
380
381
Popular Tags