KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > ui > propertiesfileeditor > PropertyKeyHyperlink


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.jdt.internal.ui.propertiesfileeditor;
12
13 import java.lang.reflect.InvocationTargetException JavaDoc;
14 import com.ibm.icu.text.Collator;
15 import java.util.ArrayList JavaDoc;
16 import java.util.Arrays JavaDoc;
17 import java.util.List JavaDoc;
18 import java.util.regex.Pattern JavaDoc;
19
20 import org.eclipse.core.runtime.Assert;
21 import org.eclipse.core.runtime.CoreException;
22 import org.eclipse.core.runtime.IAdaptable;
23 import org.eclipse.core.runtime.IProgressMonitor;
24 import org.eclipse.core.runtime.IStatus;
25 import org.eclipse.core.runtime.NullProgressMonitor;
26 import org.eclipse.core.runtime.PlatformObject;
27 import org.eclipse.core.runtime.Status;
28 import org.eclipse.core.runtime.SubProgressMonitor;
29
30 import org.eclipse.core.filebuffers.FileBuffers;
31 import org.eclipse.core.filebuffers.ITextFileBuffer;
32 import org.eclipse.core.filebuffers.ITextFileBufferManager;
33 import org.eclipse.core.filebuffers.LocationKind;
34
35 import org.eclipse.core.resources.IResource;
36 import org.eclipse.core.resources.IStorage;
37
38 import org.eclipse.swt.widgets.Shell;
39
40 import org.eclipse.jface.dialogs.ErrorDialog;
41 import org.eclipse.jface.dialogs.MessageDialog;
42 import org.eclipse.jface.operation.IRunnableWithProgress;
43 import org.eclipse.jface.resource.ImageDescriptor;
44 import org.eclipse.jface.viewers.ILabelProvider;
45 import org.eclipse.jface.window.Window;
46
47 import org.eclipse.jface.text.BadLocationException;
48 import org.eclipse.jface.text.IDocument;
49 import org.eclipse.jface.text.IRegion;
50 import org.eclipse.jface.text.hyperlink.IHyperlink;
51
52 import org.eclipse.ui.IEditorPart;
53 import org.eclipse.ui.IStorageEditorInput;
54 import org.eclipse.ui.PartInitException;
55 import org.eclipse.ui.dialogs.TwoPaneElementSelector;
56 import org.eclipse.ui.model.IWorkbenchAdapter;
57 import org.eclipse.ui.model.WorkbenchLabelProvider;
58 import org.eclipse.ui.texteditor.IEditorStatusLine;
59 import org.eclipse.ui.texteditor.ITextEditor;
60
61 import org.eclipse.search.core.text.TextSearchEngine;
62 import org.eclipse.search.core.text.TextSearchMatchAccess;
63 import org.eclipse.search.core.text.TextSearchRequestor;
64 import org.eclipse.search.core.text.TextSearchScope;
65
66 import org.eclipse.jdt.core.IJavaElement;
67 import org.eclipse.jdt.core.JavaCore;
68 import org.eclipse.jdt.core.JavaModelException;
69 import org.eclipse.jdt.core.search.IJavaSearchConstants;
70 import org.eclipse.jdt.core.search.IJavaSearchScope;
71 import org.eclipse.jdt.core.search.SearchEngine;
72 import org.eclipse.jdt.core.search.SearchMatch;
73 import org.eclipse.jdt.core.search.SearchPattern;
74 import org.eclipse.jdt.core.search.SearchRequestor;
75
76 import org.eclipse.jdt.internal.corext.util.Messages;
77 import org.eclipse.jdt.internal.corext.util.SearchUtils;
78
79 import org.eclipse.jdt.ui.JavaUI;
80
81 import org.eclipse.jdt.internal.ui.IJavaStatusConstants;
82 import org.eclipse.jdt.internal.ui.JavaPlugin;
83 import org.eclipse.jdt.internal.ui.javaeditor.EditorUtility;
84 import org.eclipse.jdt.internal.ui.util.ExceptionHandler;
85 import org.eclipse.jdt.internal.ui.util.PatternConstructor;
86
87
88 /**
89  * Properties key hyperlink.
90  * <p>
91  * XXX: This does not work for properties files coming from a JAR due to
92  * missing J Core functionality. For details see:
93  * https://bugs.eclipse.org/bugs/show_bug.cgi?id=22376
94  * </p>
95  *
96  * @since 3.1
97  */

98 public class PropertyKeyHyperlink implements IHyperlink {
99
100
101     private static class KeyReference extends PlatformObject implements IWorkbenchAdapter, Comparable JavaDoc {
102
103         private static final Collator fgCollator= Collator.getInstance();
104
105         private IStorage storage;
106         private int offset;
107         private int length;
108
109
110         private KeyReference(IStorage storage, int offset, int length) {
111             Assert.isNotNull(storage);
112             this.storage= storage;
113             this.offset= offset;
114             this.length= length;
115         }
116
117         /*
118          * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
119          */

120         public Object JavaDoc getAdapter(Class JavaDoc adapter) {
121             if (adapter == IWorkbenchAdapter.class)
122                 return this;
123             else
124                 return super.getAdapter(adapter);
125         }
126         /*
127          * @see org.eclipse.ui.model.IWorkbenchAdapter#getChildren(java.lang.Object)
128          */

129         public Object JavaDoc[] getChildren(Object JavaDoc o) {
130             return null;
131         }
132         /*
133          * @see org.eclipse.ui.model.IWorkbenchAdapter#getImageDescriptor(java.lang.Object)
134          */

135         public ImageDescriptor getImageDescriptor(Object JavaDoc object) {
136             IWorkbenchAdapter wbAdapter= (IWorkbenchAdapter)storage.getAdapter(IWorkbenchAdapter.class);
137             if (wbAdapter != null)
138                 return wbAdapter.getImageDescriptor(storage);
139             return null;
140         }
141         /*
142          * @see org.eclipse.ui.model.IWorkbenchAdapter#getLabel(java.lang.Object)
143          */

144         public String JavaDoc getLabel(Object JavaDoc o) {
145
146             ITextFileBufferManager manager= FileBuffers.getTextFileBufferManager();
147             try {
148                 manager.connect(storage.getFullPath(), LocationKind.NORMALIZE, null);
149                 try {
150                     ITextFileBuffer buffer= manager.getTextFileBuffer(storage.getFullPath(), LocationKind.NORMALIZE);
151                     IDocument document= buffer.getDocument();
152                     if (document != null) {
153                         int line= document.getLineOfOffset(offset) + 1;
154                         Object JavaDoc[] args= new Object JavaDoc[] { new Integer JavaDoc(line), storage.getFullPath() };
155                         return Messages.format(PropertiesFileEditorMessages.OpenAction_SelectionDialog_elementLabel, args);
156                     }
157                 } finally {
158                     manager.disconnect(storage.getFullPath(), LocationKind.NORMALIZE, null);
159                 }
160             } catch (CoreException e) {
161                 JavaPlugin.log(e.getStatus());
162             } catch (BadLocationException e) {
163                 JavaPlugin.log(e);
164             }
165
166             return storage.getFullPath().toString();
167         }
168         /*
169          * @see org.eclipse.ui.model.IWorkbenchAdapter#getParent(java.lang.Object)
170          */

171         public Object JavaDoc getParent(Object JavaDoc o) {
172             return null;
173         }
174
175         public int compareTo(Object JavaDoc o) {
176             KeyReference otherRef= (KeyReference)o;
177             String JavaDoc thisPath= storage.getFullPath().toString();
178             String JavaDoc otherPath= otherRef.storage.getFullPath().toString();
179             int result= fgCollator.compare(thisPath, otherPath);
180             if (result != 0)
181                 return result;
182             else
183                 return offset - otherRef.offset;
184         }
185     }
186
187
188     private static class ResultCollector extends TextSearchRequestor {
189
190         private List JavaDoc fResult;
191         private boolean fIsKeyDoubleQuoted;
192
193         public ResultCollector(List JavaDoc result, boolean isKeyDoubleQuoted) {
194             fResult= result;
195             fIsKeyDoubleQuoted= isKeyDoubleQuoted;
196         }
197
198         public boolean acceptPatternMatch(TextSearchMatchAccess matchAccess) throws CoreException {
199             int start= matchAccess.getMatchOffset();
200             int length= matchAccess.getMatchLength();
201             
202             if (fIsKeyDoubleQuoted) {
203                 start= start + 1;
204                 length= length - 2;
205             }
206             fResult.add(new KeyReference(matchAccess.getFile(), start, length));
207             return true;
208         }
209     }
210
211
212     private IRegion fRegion;
213     private String JavaDoc fPropertiesKey;
214     private Shell fShell;
215     private IStorage fStorage;
216     private ITextEditor fEditor;
217
218
219     /**
220      * Creates a new properties key hyperlink.
221      *
222      * @param region the region
223      * @param key the properties key
224      * @param editor the text editor
225      */

226     public PropertyKeyHyperlink(IRegion region, String JavaDoc key, ITextEditor editor) {
227         Assert.isNotNull(region);
228         Assert.isNotNull(key);
229         Assert.isNotNull(editor);
230
231         fRegion= region;
232         fPropertiesKey= key;
233         fEditor= editor;
234         IStorageEditorInput storageEditorInput= (IStorageEditorInput)fEditor.getEditorInput();
235         fShell= fEditor.getEditorSite().getShell();
236         try {
237             fStorage= storageEditorInput.getStorage();
238         } catch (CoreException e) {
239             fStorage= null;
240         }
241     }
242
243     /*
244      * @see org.eclipse.jdt.internal.ui.javaeditor.IHyperlink#getHyperlinkRegion()
245      */

246     public IRegion getHyperlinkRegion() {
247         return fRegion;
248     }
249
250     /*
251      * @see org.eclipse.jdt.internal.ui.javaeditor.IHyperlink#open()
252      */

253     public void open() {
254         if (!checkEnabled())
255             return;
256
257         // Search the key
258
IResource resource= (IResource)fStorage;
259         KeyReference[] references= null;
260         if (resource != null)
261             references= search(resource.getProject(), fPropertiesKey);
262
263         if (references == null)
264             return; // canceled by the user
265

266         if (references.length == 0) {
267             String JavaDoc message= PropertiesFileEditorMessages.OpenAction_error_messageNoResult;
268             showErrorInStatusLine(message);
269             return;
270         }
271
272         open(references);
273
274     }
275
276     private boolean checkEnabled() {
277          // XXX: Can be removed once support for JARs is available (see class Javadoc for details)
278
return fStorage instanceof IResource;
279     }
280
281     private void open(KeyReference[] keyReferences) {
282         Assert.isLegal(keyReferences != null && keyReferences.length > 0);
283
284         if (keyReferences.length == 1)
285             open(keyReferences[0]);
286         else
287             open(select(keyReferences));
288     }
289
290     /**
291      * Opens a dialog which allows to select a key reference.
292      * <p>
293      * FIXME: The lower pane is currently not sorted due to https://bugs.eclipse.org/bugs/show_bug.cgi?id=84220
294      * </p>
295      *
296      * @param keyReferences the array of key references
297      * @return the selected key reference or <code>null</code> if canceled by the user
298      */

299     private KeyReference select(final KeyReference[] keyReferences) {
300         Arrays.sort(keyReferences);
301         final int length= keyReferences.length;
302         ILabelProvider labelProvider= new WorkbenchLabelProvider() {
303             public String JavaDoc decorateText(String JavaDoc input, Object JavaDoc element) {
304                 KeyReference keyRef= (KeyReference)element;
305                 IStorage storage= keyRef.storage;
306                 String JavaDoc name= storage.getName();
307                 if (name == null)
308                     return input;
309
310                 int count= 0;
311                 for (int i= 0; i < length; i++) {
312                     if (keyReferences[i].storage.equals(storage))
313                         count++;
314                 }
315                 if (count > 1) {
316                     Object JavaDoc[] args= new Object JavaDoc[] { name, new Integer JavaDoc(count) };
317                     name= Messages.format(PropertiesFileEditorMessages.OpenAction_SelectionDialog_elementLabelWithMatchCount, args);
318                 }
319
320                 return name;
321             }
322         };
323
324         TwoPaneElementSelector dialog= new TwoPaneElementSelector(fShell, labelProvider, new WorkbenchLabelProvider());
325         dialog.setLowerListLabel(PropertiesFileEditorMessages.OpenAction_SelectionDialog_details);
326         dialog.setMultipleSelection(false);
327         dialog.setTitle(PropertiesFileEditorMessages.OpenAction_SelectionDialog_title);
328         dialog.setMessage(PropertiesFileEditorMessages.OpenAction_SelectionDialog_message);
329         dialog.setElements(keyReferences);
330
331         if (dialog.open() == Window.OK) {
332             Object JavaDoc[] result= dialog.getResult();
333             if (result != null && result.length == 1)
334              return (KeyReference)result[0];
335         }
336
337         return null;
338     }
339
340     private void open(KeyReference keyReference) {
341         if (keyReference == null)
342             return;
343
344         try {
345             IEditorPart part= EditorUtility.openInEditor(keyReference.storage, true);
346             EditorUtility.revealInEditor(part, keyReference.offset, keyReference.length);
347         } catch (JavaModelException e) {
348             JavaPlugin.log(new Status(IStatus.ERROR, JavaPlugin.getPluginId(),
349                 IJavaStatusConstants.INTERNAL_ERROR, PropertiesFileEditorMessages.OpenAction_error_message, e));
350
351             ErrorDialog.openError(fShell,
352                 getErrorDialogTitle(),
353                 PropertiesFileEditorMessages.OpenAction_error_messageProblems,
354                 e.getStatus());
355
356         } catch (PartInitException x) {
357
358             String JavaDoc message= null;
359
360             IWorkbenchAdapter wbAdapter= (IWorkbenchAdapter)((IAdaptable)keyReference).getAdapter(IWorkbenchAdapter.class);
361             if (wbAdapter != null)
362                 message= Messages.format(PropertiesFileEditorMessages.OpenAction_error_messageArgs,
363                         new String JavaDoc[] { wbAdapter.getLabel(keyReference), x.getLocalizedMessage() } );
364
365             if (message == null)
366                 message= Messages.format(PropertiesFileEditorMessages.OpenAction_error_message, x.getLocalizedMessage());
367
368             MessageDialog.openError(fShell,
369                 PropertiesFileEditorMessages.OpenAction_error_messageProblems,
370                 message);
371         }
372     }
373
374     private String JavaDoc getErrorDialogTitle() {
375         return PropertiesFileEditorMessages.OpenAction_error_title;
376     }
377
378     private void showError(CoreException e) {
379         ExceptionHandler.handle(e, fShell, getErrorDialogTitle(), PropertiesFileEditorMessages.OpenAction_error_message);
380     }
381
382     private void showErrorInStatusLine(final String JavaDoc message) {
383         fShell.getDisplay().beep();
384         final IEditorStatusLine statusLine= (IEditorStatusLine)fEditor.getAdapter(IEditorStatusLine.class);
385         if (statusLine != null) {
386             fShell.getDisplay().asyncExec(new Runnable JavaDoc() {
387                 /*
388                  * @see java.lang.Runnable#run()
389                  */

390                 public void run() {
391                     statusLine.setMessage(true, message, null);
392                 }
393             });
394         }
395     }
396
397     /**
398      * Returns whether we search the key in double-quotes or not.
399      * <p>
400      * XXX: This is a hack to improve the accuracy of matches, see https://bugs.eclipse.org/bugs/show_bug.cgi?id=81140
401      * </p>
402      *
403      * @return <code>true</code> if we search for double-quoted key
404      */

405     private boolean useDoubleQuotedKey() {
406         if (fStorage == null)
407             return false;
408
409         String JavaDoc name= fStorage.getName();
410
411         return name != null && !"about.properties".equals(name) && !"feature.properties".equals(name) && !"plugin.properties".equals(name); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
412
}
413
414     /**
415      * Searches references to the given key in the given scope.
416      *
417      * @param scope the scope
418      * @param key the properties key
419      * @return the references or <code>null</code> if the search has been canceled by the user
420      */

421     private KeyReference[] search(final IResource scope, String JavaDoc key) {
422         if (key == null)
423             return new KeyReference[0];
424
425         final List JavaDoc result= new ArrayList JavaDoc(5);
426         final String JavaDoc searchString;
427
428         // XXX: This is a hack to improve the accuracy of matches, see https://bugs.eclipse.org/bugs/show_bug.cgi?id=81140
429
final boolean useDoubleQuotedKey= useDoubleQuotedKey();
430         if (useDoubleQuotedKey) {
431             StringBuffer JavaDoc buf= new StringBuffer JavaDoc("\""); //$NON-NLS-1$
432
buf.append(fPropertiesKey);
433             buf.append('"');
434             searchString= buf.toString();
435         } else
436             searchString= fPropertiesKey;
437
438         try {
439             fEditor.getEditorSite().getWorkbenchWindow().getWorkbench().getProgressService().busyCursorWhile(
440                 new IRunnableWithProgress() {
441                     public void run(IProgressMonitor monitor) throws InvocationTargetException JavaDoc, InterruptedException JavaDoc {
442                         if (monitor == null)
443                             monitor= new NullProgressMonitor();
444                         
445                         monitor.beginTask("", 5); //$NON-NLS-1$
446
try {
447                             ResultCollector collector= new ResultCollector(result, useDoubleQuotedKey);
448                             TextSearchEngine engine= TextSearchEngine.create();
449                             Pattern JavaDoc searchPattern= PatternConstructor.createPattern(searchString, true, false);
450                             engine.search(createScope(scope), collector, searchPattern, new SubProgressMonitor(monitor, 4));
451                             
452                             if (result.size() == 0 && useDoubleQuotedKey) {
453                                 //Try without, maybe an eclipse style NLS string
454
IJavaElement element= JavaCore.create(scope);
455                                 if (element == null)
456                                     return;
457                                 
458                                 int includeMask = IJavaSearchScope.SOURCES | IJavaSearchScope.APPLICATION_LIBRARIES | IJavaSearchScope.REFERENCED_PROJECTS;
459                                 IJavaSearchScope javaSearchScope= SearchEngine.createJavaSearchScope(new IJavaElement[] { element }, includeMask);
460     
461                                 SearchPattern pattern= SearchPattern.createPattern(fPropertiesKey, IJavaSearchConstants.FIELD, IJavaSearchConstants.REFERENCES, SearchPattern.R_PATTERN_MATCH | SearchPattern.R_CASE_SENSITIVE);
462                                 try {
463                                     new SearchEngine().search(pattern, SearchUtils.getDefaultSearchParticipants(), javaSearchScope, new SearchRequestor() {
464                                         public void acceptSearchMatch(SearchMatch match) throws CoreException {
465                                             result.add(new KeyReference((IStorage)match.getResource(), match.getOffset(), match.getLength()));
466                                         }
467                                     }, new SubProgressMonitor(monitor, 1));
468                                 } catch (CoreException e) {
469                                     throw new InvocationTargetException JavaDoc(e);
470                                 }
471                             } else {
472                                 monitor.worked(1);
473                             }
474                         } finally {
475                             monitor.done();
476                         }
477                     }
478                 }
479             );
480         } catch (InvocationTargetException JavaDoc ex) {
481             String JavaDoc message= PropertiesFileEditorMessages.OpenAction_error_messageErrorSearchingKey;
482             showError(new CoreException(new Status(IStatus.ERROR, JavaUI.ID_PLUGIN, IStatus.OK, message, ex.getTargetException())));
483         } catch (InterruptedException JavaDoc ex) {
484             return null; // canceled
485
}
486
487         return (KeyReference[])result.toArray(new KeyReference[result.size()]);
488     }
489
490     private static TextSearchScope createScope(IResource scope) {
491         ArrayList JavaDoc fileNamePatternStrings= new ArrayList JavaDoc();
492         
493         // XXX: Should be configurable via preference, see https://bugs.eclipse.org/bugs/show_bug.cgi?id=81117
494
String JavaDoc[] javaExtensions= JavaCore.getJavaLikeExtensions();
495         for (int i= 0; i < javaExtensions.length; i++)
496             fileNamePatternStrings.add("*." + javaExtensions[i]); //$NON-NLS-1$
497
fileNamePatternStrings.add("*.xml"); //$NON-NLS-1$
498
fileNamePatternStrings.add("*.ini"); //$NON-NLS-1$
499

500         String JavaDoc[] allPatternStrings= (String JavaDoc[]) fileNamePatternStrings.toArray(new String JavaDoc[fileNamePatternStrings.size()]);
501         Pattern JavaDoc fileNamePattern= PatternConstructor.createPattern(allPatternStrings, false, false);
502         
503         return TextSearchScope.newSearchScope(new IResource[] { scope }, fileNamePattern, false);
504     }
505
506     /*
507      * @see org.eclipse.jdt.internal.ui.javaeditor.IHyperlink#getTypeLabel()
508      */

509     public String JavaDoc getTypeLabel() {
510         return null;
511     }
512
513     /*
514      * @see org.eclipse.jdt.internal.ui.javaeditor.IHyperlink#getHyperlinkText()
515      */

516     public String JavaDoc getHyperlinkText() {
517         return null;
518     }
519 }
520
Popular Tags