KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > ui > text > java > CompletionProposalComputerRegistry


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 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.text.java;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.Arrays JavaDoc;
15 import java.util.Collection JavaDoc;
16 import java.util.Collections JavaDoc;
17 import java.util.HashMap JavaDoc;
18 import java.util.HashSet JavaDoc;
19 import java.util.Iterator JavaDoc;
20 import java.util.List JavaDoc;
21 import java.util.Map JavaDoc;
22 import java.util.Set JavaDoc;
23 import java.util.StringTokenizer JavaDoc;
24
25 import org.eclipse.core.runtime.IConfigurationElement;
26 import org.eclipse.core.runtime.IContributor;
27 import org.eclipse.core.runtime.IExtensionRegistry;
28 import org.eclipse.core.runtime.IStatus;
29 import org.eclipse.core.runtime.InvalidRegistryObjectException;
30 import org.eclipse.core.runtime.Platform;
31 import org.eclipse.core.runtime.Status;
32
33 import org.eclipse.swt.SWT;
34 import org.eclipse.swt.events.SelectionAdapter;
35 import org.eclipse.swt.events.SelectionEvent;
36 import org.eclipse.swt.layout.GridData;
37 import org.eclipse.swt.widgets.Composite;
38 import org.eclipse.swt.widgets.Control;
39 import org.eclipse.swt.widgets.Link;
40
41 import org.eclipse.jface.dialogs.IDialogConstants;
42 import org.eclipse.jface.dialogs.MessageDialog;
43 import org.eclipse.jface.preference.IPreferenceStore;
44
45 import org.eclipse.ui.dialogs.PreferencesUtil;
46
47 import org.eclipse.jdt.internal.corext.util.Messages;
48
49 import org.eclipse.jdt.ui.PreferenceConstants;
50
51 import org.eclipse.jdt.internal.ui.JavaPlugin;
52
53 /**
54  * A registry for all extensions to the
55  * <code>org.eclipse.jdt.ui.javaCompletionProposalComputer</code>
56  * extension point.
57  *
58  * @since 3.2
59  */

60 public final class CompletionProposalComputerRegistry {
61
62     private static final String JavaDoc EXTENSION_POINT= "javaCompletionProposalComputer"; //$NON-NLS-1$
63

64     /** The singleton instance. */
65     private static CompletionProposalComputerRegistry fgSingleton= null;
66     
67     /**
68      * Returns the default computer registry.
69      * <p>
70      * TODO keep this or add some other singleton, e.g. JavaPlugin?
71      * </p>
72      *
73      * @return the singleton instance
74      */

75     public static synchronized CompletionProposalComputerRegistry getDefault() {
76         if (fgSingleton == null) {
77             fgSingleton= new CompletionProposalComputerRegistry();
78         }
79         
80         return fgSingleton;
81     }
82     
83     /**
84      * The sets of descriptors, grouped by partition type (key type:
85      * {@link String}, value type:
86      * {@linkplain List List&lt;CompletionProposalComputerDescriptor&gt;}).
87      */

88     private final Map JavaDoc fDescriptorsByPartition= new HashMap JavaDoc();
89     /**
90      * Unmodifiable versions of the sets stored in
91      * <code>fDescriptorsByPartition</code> (key type: {@link String},
92      * value type:
93      * {@linkplain List List&lt;CompletionProposalComputerDescriptor&gt;}).
94      */

95     private final Map JavaDoc fPublicDescriptorsByPartition= new HashMap JavaDoc();
96     /**
97      * All descriptors (element type:
98      * {@link CompletionProposalComputerDescriptor}).
99      */

100     private final List JavaDoc fDescriptors= new ArrayList JavaDoc();
101     /**
102      * Unmodifiable view of <code>fDescriptors</code>
103      */

104     private final List JavaDoc fPublicDescriptors= Collections.unmodifiableList(fDescriptors);
105     
106     private final List JavaDoc fCategories= new ArrayList JavaDoc();
107     private final List JavaDoc fPublicCategories= Collections.unmodifiableList(fCategories);
108     /**
109      * <code>true</code> if this registry has been loaded.
110      */

111     private boolean fLoaded= false;
112
113     /**
114      * Creates a new instance.
115      */

116     public CompletionProposalComputerRegistry() {
117     }
118
119     /**
120      * Returns the list of {@link CompletionProposalComputerDescriptor}s describing all extensions
121      * to the <code>javaCompletionProposalComputer</code> extension point for the given partition
122      * type.
123      * <p>
124      * A valid partition is either one of the constants defined in
125      * {@link org.eclipse.jdt.ui.text.IJavaPartitions} or
126      * {@link org.eclipse.jface.text.IDocument#DEFAULT_CONTENT_TYPE}. An empty list is returned if
127      * there are no extensions for the given partition.
128      * </p>
129      * <p>
130      * The returned list is read-only and is sorted in the order that the extensions were read in.
131      * There are no duplicate elements in the returned list. The returned list may change if plug-ins
132      * are loaded or unloaded while the application is running or if an extension violates the API
133      * contract of {@link org.eclipse.jdt.ui.text.java.IJavaCompletionProposalComputer}. When
134      * computing proposals, it is therefore imperative to copy the returned list before iterating
135      * over it.
136      * </p>
137      *
138      * @param partition
139      * the partition type for which to retrieve the computer descriptors
140      * @return the list of extensions to the <code>javaCompletionProposalComputer</code> extension
141      * point (element type: {@link CompletionProposalComputerDescriptor})
142      */

143     List JavaDoc getProposalComputerDescriptors(String JavaDoc partition) {
144         ensureExtensionPointRead();
145         List JavaDoc result= (List JavaDoc) fPublicDescriptorsByPartition.get(partition);
146         return result != null ? result : Collections.EMPTY_LIST;
147     }
148
149     /**
150      * Returns the list of {@link CompletionProposalComputerDescriptor}s describing all extensions
151      * to the <code>javaCompletionProposalComputer</code> extension point.
152      * <p>
153      * The returned list is read-only and is sorted in the order that the extensions were read in.
154      * There are no duplicate elements in the returned list. The returned list may change if plug-ins
155      * are loaded or unloaded while the application is running or if an extension violates the API
156      * contract of {@link org.eclipse.jdt.ui.text.java.IJavaCompletionProposalComputer}. When
157      * computing proposals, it is therefore imperative to copy the returned list before iterating
158      * over it.
159      * </p>
160      *
161      * @return the list of extensions to the <code>javaCompletionProposalComputer</code> extension
162      * point (element type: {@link CompletionProposalComputerDescriptor})
163      */

164     List JavaDoc getProposalComputerDescriptors() {
165         ensureExtensionPointRead();
166         return fPublicDescriptors;
167     }
168     
169     /**
170      * Returns the list of proposal categories contributed to the
171      * <code>javaCompletionProposalComputer</code> extension point.
172      * <p>
173      * <p>
174      * The returned list is read-only and is sorted in the order that the extensions were read in.
175      * There are no duplicate elements in the returned list. The returned list may change if
176      * plug-ins are loaded or unloaded while the application is running.
177      * </p>
178      *
179      * @return list of proposal categories contributed to the
180      * <code>javaCompletionProposalComputer</code> extension point (element type:
181      * {@link CompletionProposalCategory})
182      */

183     public List JavaDoc getProposalCategories() {
184         ensureExtensionPointRead();
185         return fPublicCategories;
186     }
187
188     /**
189      * Ensures that the extensions are read and stored in
190      * <code>fDescriptorsByPartition</code>.
191      */

192     private void ensureExtensionPointRead() {
193         boolean reload;
194         synchronized (this) {
195             reload= !fLoaded;
196             fLoaded= true;
197         }
198         if (reload)
199             reload();
200     }
201
202     /**
203      * Reloads the extensions to the extension point.
204      * <p>
205      * This method can be called more than once in order to reload from
206      * a changed extension registry.
207      * </p>
208      */

209     public void reload() {
210         IExtensionRegistry registry= Platform.getExtensionRegistry();
211         List JavaDoc elements= new ArrayList JavaDoc(Arrays.asList(registry.getConfigurationElementsFor(JavaPlugin.getPluginId(), EXTENSION_POINT)));
212         
213         Map JavaDoc map= new HashMap JavaDoc();
214         List JavaDoc all= new ArrayList JavaDoc();
215         
216         List JavaDoc categories= getCategories(elements);
217         for (Iterator JavaDoc iter= elements.iterator(); iter.hasNext();) {
218             IConfigurationElement element= (IConfigurationElement) iter.next();
219             try {
220                 CompletionProposalComputerDescriptor desc= new CompletionProposalComputerDescriptor(element, this, categories);
221                 Set JavaDoc partitions= desc.getPartitions();
222                 for (Iterator JavaDoc it= partitions.iterator(); it.hasNext();) {
223                     String JavaDoc partition= (String JavaDoc) it.next();
224                     List JavaDoc list= (List JavaDoc) map.get(partition);
225                     if (list == null) {
226                         list= new ArrayList JavaDoc();
227                         map.put(partition, list);
228                     }
229                     list.add(desc);
230                 }
231                 all.add(desc);
232                 
233             } catch (InvalidRegistryObjectException x) {
234                 /*
235                  * Element is not valid any longer as the contributing plug-in was unloaded or for
236                  * some other reason. Do not include the extension in the list and inform the user
237                  * about it.
238                  */

239                 Object JavaDoc[] args= {element.toString()};
240                 String JavaDoc message= Messages.format(JavaTextMessages.CompletionProposalComputerRegistry_invalid_message, args);
241                 IStatus status= new Status(IStatus.WARNING, JavaPlugin.getPluginId(), IStatus.OK, message, x);
242                 informUser(status);
243             }
244         }
245         
246         synchronized (this) {
247             fCategories.clear();
248             fCategories.addAll(categories);
249             
250             Set JavaDoc partitions= map.keySet();
251             fDescriptorsByPartition.keySet().retainAll(partitions);
252             fPublicDescriptorsByPartition.keySet().retainAll(partitions);
253             for (Iterator JavaDoc it= partitions.iterator(); it.hasNext();) {
254                 String JavaDoc partition= (String JavaDoc) it.next();
255                 List JavaDoc old= (List JavaDoc) fDescriptorsByPartition.get(partition);
256                 List JavaDoc current= (List JavaDoc) map.get(partition);
257                 if (old != null) {
258                     old.clear();
259                     old.addAll(current);
260                 } else {
261                     fDescriptorsByPartition.put(partition, current);
262                     fPublicDescriptorsByPartition.put(partition, Collections.unmodifiableList(current));
263                 }
264             }
265             
266             fDescriptors.clear();
267             fDescriptors.addAll(all);
268         }
269     }
270
271     private List JavaDoc getCategories(List JavaDoc elements) {
272         IPreferenceStore store= JavaPlugin.getDefault().getPreferenceStore();
273         String JavaDoc preference= store.getString(PreferenceConstants.CODEASSIST_EXCLUDED_CATEGORIES);
274         Set JavaDoc disabled= new HashSet JavaDoc();
275         StringTokenizer JavaDoc tok= new StringTokenizer JavaDoc(preference, "\0"); //$NON-NLS-1$
276
while (tok.hasMoreTokens())
277             disabled.add(tok.nextToken());
278         Map JavaDoc ordered= new HashMap JavaDoc();
279         preference= store.getString(PreferenceConstants.CODEASSIST_CATEGORY_ORDER);
280         tok= new StringTokenizer JavaDoc(preference, "\0"); //$NON-NLS-1$
281
while (tok.hasMoreTokens()) {
282             StringTokenizer JavaDoc inner= new StringTokenizer JavaDoc(tok.nextToken(), ":"); //$NON-NLS-1$
283
String JavaDoc id= inner.nextToken();
284             int rank= Integer.parseInt(inner.nextToken());
285             ordered.put(id, new Integer JavaDoc(rank));
286         }
287         
288         List JavaDoc categories= new ArrayList JavaDoc();
289         for (Iterator JavaDoc iter= elements.iterator(); iter.hasNext();) {
290             IConfigurationElement element= (IConfigurationElement) iter.next();
291             try {
292                 if (element.getName().equals("proposalCategory")) { //$NON-NLS-1$
293
iter.remove(); // remove from list to leave only computers
294

295                     CompletionProposalCategory category= new CompletionProposalCategory(element, this);
296                     categories.add(category);
297                     category.setIncluded(!disabled.contains(category.getId()));
298                     Integer JavaDoc rank= (Integer JavaDoc) ordered.get(category.getId());
299                     if (rank != null) {
300                         int r= rank.intValue();
301                         boolean separate= r < 0xffff;
302                         category.setSeparateCommand(separate);
303                         category.setSortOrder(r);
304                     }
305                 }
306             } catch (InvalidRegistryObjectException x) {
307                 /*
308                  * Element is not valid any longer as the contributing plug-in was unloaded or for
309                  * some other reason. Do not include the extension in the list and inform the user
310                  * about it.
311                  */

312                 Object JavaDoc[] args= {element.toString()};
313                 String JavaDoc message= Messages.format(JavaTextMessages.CompletionProposalComputerRegistry_invalid_message, args);
314                 IStatus status= new Status(IStatus.WARNING, JavaPlugin.getPluginId(), IStatus.OK, message, x);
315                 informUser(status);
316             }
317         }
318         return categories;
319     }
320
321     /**
322      * Log the status and inform the user about a misbehaving extension.
323      *
324      * @param descriptor the descriptor of the misbehaving extension
325      * @param status a status object that will be logged
326      */

327     void informUser(CompletionProposalComputerDescriptor descriptor, IStatus status) {
328         JavaPlugin.log(status);
329         String JavaDoc title= JavaTextMessages.CompletionProposalComputerRegistry_error_dialog_title;
330         CompletionProposalCategory category= descriptor.getCategory();
331         IContributor culprit= descriptor.getContributor();
332         Set JavaDoc affectedPlugins= getAffectedContributors(category, culprit);
333         
334         final String JavaDoc avoidHint;
335         final String JavaDoc culpritName= culprit == null ? null : culprit.getName();
336         if (affectedPlugins.isEmpty())
337             avoidHint= Messages.format(JavaTextMessages.CompletionProposalComputerRegistry_messageAvoidanceHint, new Object JavaDoc[] {culpritName, category.getDisplayName()});
338         else
339             avoidHint= Messages.format(JavaTextMessages.CompletionProposalComputerRegistry_messageAvoidanceHintWithWarning, new Object JavaDoc[] {culpritName, category.getDisplayName(), toString(affectedPlugins)});
340         
341         String JavaDoc message= status.getMessage();
342         // inlined from MessageDialog.openError
343
MessageDialog dialog = new MessageDialog(JavaPlugin.getActiveWorkbenchShell(), title, null /* default image */, message, MessageDialog.ERROR, new String JavaDoc[] { IDialogConstants.OK_LABEL }, 0) {
344             protected Control createCustomArea(Composite parent) {
345                 Link link= new Link(parent, SWT.NONE);
346                 link.setText(avoidHint);
347                 link.addSelectionListener(new SelectionAdapter() {
348                     public void widgetSelected(SelectionEvent e) {
349                         PreferencesUtil.createPreferenceDialogOn(getShell(), "org.eclipse.jdt.ui.preferences.CodeAssistPreferenceAdvanced", null, null).open(); //$NON-NLS-1$
350
}
351                 });
352                 GridData gridData= new GridData(SWT.FILL, SWT.BEGINNING, true, false);
353                 gridData.widthHint= this.getMinimumMessageWidth();
354                 link.setLayoutData(gridData);
355                 return link;
356             }
357         };
358         dialog.open();
359     }
360
361     /**
362      * Returns the names of contributors affected by disabling a category.
363      *
364      * @param category the category that would be disabled
365      * @param culprit the culprit plug-in, which is not included in the returned list
366      * @return the names of the contributors other than <code>culprit</code> that contribute to <code>category</code> (element type: {@link String})
367      */

368     private Set JavaDoc getAffectedContributors(CompletionProposalCategory category, IContributor culprit) {
369         Set JavaDoc affectedPlugins= new HashSet JavaDoc();
370         for (Iterator JavaDoc it= getProposalComputerDescriptors().iterator(); it.hasNext();) {
371             CompletionProposalComputerDescriptor desc= (CompletionProposalComputerDescriptor) it.next();
372             CompletionProposalCategory cat= desc.getCategory();
373             if (cat.equals(category)) {
374                 IContributor contributor= desc.getContributor();
375                 if (contributor != null && !culprit.equals(contributor))
376                     affectedPlugins.add(contributor.getName());
377             }
378         }
379         return affectedPlugins;
380     }
381
382     private Object JavaDoc toString(Collection JavaDoc collection) {
383         // strip brackets off AbstractCollection.toString()
384
String JavaDoc string= collection.toString();
385         return string.substring(1, string.length() - 1);
386     }
387
388     private void informUser(IStatus status) {
389         JavaPlugin.log(status);
390         String JavaDoc title= JavaTextMessages.CompletionProposalComputerRegistry_error_dialog_title;
391         String JavaDoc message= status.getMessage();
392         MessageDialog.openError(JavaPlugin.getActiveWorkbenchShell(), title, message);
393     }
394 }
395
Popular Tags