/******************************************************************************* * Copyright © 2011, 2013 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * *******************************************************************************/ package org.eclipse.edt.ide.ui.internal.contentassist; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IContributor; import org.eclipse.core.runtime.IExtensionRegistry; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.InvalidRegistryObjectException; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.edt.ide.ui.EDTUIPlugin; import org.eclipse.edt.ide.ui.EDTUIPreferenceConstants; import org.eclipse.edt.ide.ui.internal.preferences.Messages; import org.eclipse.jdt.ui.PreferenceConstants; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Link; import org.eclipse.ui.dialogs.PreferencesUtil; public final class EGLCompletionProposalComputerRegistry { private static final String EXTENSION_POINT = "eglCompletionProposalComputer"; //$NON-NLS-1$ private static final String NUM_COMPUTERS_PREF_KEY= "content_assist_number_of_computers"; //$NON-NLS-1$ /** The singleton instance. */ private static EGLCompletionProposalComputerRegistry eglCplProposalRegistrySingleton= null; public static synchronized EGLCompletionProposalComputerRegistry getDefault() { if (null == eglCplProposalRegistrySingleton) { eglCplProposalRegistrySingleton= new EGLCompletionProposalComputerRegistry(); } return eglCplProposalRegistrySingleton; } private final Map fDescriptorsByPartition= new HashMap(); private final Map fPublicDescriptorsByPartition= new HashMap(); private final List fDescriptors= new ArrayList(); private final List fPublicDescriptors= Collections.unmodifiableList(fDescriptors); private final List fCategories= new ArrayList(); private final List fPublicCategories= Collections.unmodifiableList(fCategories); /** * <code>true</code> if this registry has been loaded. */ private boolean fLoaded= false; private boolean fHasUninstalledComputers= false; /** * Creates a new instance. */ public EGLCompletionProposalComputerRegistry() { } List getProposalComputerDescriptors() { ensureExtensionPointRead(); return fPublicDescriptors; } List getProposalComputerDescriptors(String partition) { ensureExtensionPointRead(); List result= (List) fPublicDescriptorsByPartition.get(partition); return result != null ? result : Collections.EMPTY_LIST; } public List getProposalCategories() { ensureExtensionPointRead(); return fPublicCategories; } /** * Ensures that the extensions are read and stored in * <code>fDescriptorsByPartition</code>. */ private void ensureExtensionPointRead() { boolean reload; synchronized (this) { reload= !fLoaded; fLoaded= true; } if (reload) { reload(); updateUninstalledComputerCount(); } } private void updateUninstalledComputerCount() { IPreferenceStore preferenceStore= EDTUIPreferenceConstants.getPreferenceStore(); int lastNumberOfComputers= preferenceStore.getInt(NUM_COMPUTERS_PREF_KEY); int currNumber= fDescriptors.size(); fHasUninstalledComputers= lastNumberOfComputers > currNumber; preferenceStore.putValue(NUM_COMPUTERS_PREF_KEY, Integer.toString(currNumber)); EDTUIPlugin.getDefault().savePluginPreferences(); } public void reload() { IExtensionRegistry registry= Platform.getExtensionRegistry(); List elements= new ArrayList(Arrays.asList(registry.getConfigurationElementsFor(EDTUIPlugin.getPluginId(), EXTENSION_POINT))); Map map= new HashMap(); List all= new ArrayList(); List categories= getCategories(elements); for (Iterator iter= elements.iterator(); iter.hasNext();) { IConfigurationElement element= (IConfigurationElement) iter.next(); try { EGLCompletionProposalComputerDescriptor desc= new EGLCompletionProposalComputerDescriptor(element, this, categories); Set partitions= desc.getPartitions(); for (Iterator it= partitions.iterator(); it.hasNext();) { String partition= (String) it.next(); List list= (List) map.get(partition); if (list == null) { list= new ArrayList(); map.put(partition, list); } list.add(desc); } all.add(desc); } catch (InvalidRegistryObjectException x) { } catch (CoreException x) { } } synchronized (this) { fCategories.clear(); fCategories.addAll(categories); Set partitions= map.keySet(); fDescriptorsByPartition.keySet().retainAll(partitions); fPublicDescriptorsByPartition.keySet().retainAll(partitions); for (Iterator it= partitions.iterator(); it.hasNext();) { String partition= (String) it.next(); List old= (List) fDescriptorsByPartition.get(partition); List current= (List) map.get(partition); if (old != null) { old.clear(); old.addAll(current); } else { fDescriptorsByPartition.put(partition, current); fPublicDescriptorsByPartition.put(partition, Collections.unmodifiableList(current)); } } fDescriptors.clear(); fDescriptors.addAll(all); } } boolean hasUninstalledComputers(String partition, List included) { return(fHasUninstalledComputers); } private List getCategories(List elements) { IPreferenceStore store= EDTUIPlugin.getDefault().getPreferenceStore(); String preference= store.getString(EDTUIPreferenceConstants.CODEASSIST_EXCLUDED_CATEGORIES); Set disabled= new HashSet(); StringTokenizer tok= new StringTokenizer(preference, "\0"); //$NON-NLS-1$ while (tok.hasMoreTokens()) disabled.add(tok.nextToken()); Map ordered= new HashMap(); preference= store.getString(EDTUIPreferenceConstants.CODEASSIST_CATEGORY_ORDER); tok= new StringTokenizer(preference, "\0"); //$NON-NLS-1$ while (tok.hasMoreTokens()) { StringTokenizer inner= new StringTokenizer(tok.nextToken(), ":"); //$NON-NLS-1$ String id= inner.nextToken(); int rank= Integer.parseInt(inner.nextToken()); ordered.put(id, new Integer(rank)); } EGLCompletionProposalCategory allProposals= null; List categories= new ArrayList(); for (Iterator iter= elements.iterator(); iter.hasNext();) { IConfigurationElement element= (IConfigurationElement) iter.next(); try { if (element.getName().equals("proposalCategory")) { //$NON-NLS-1$ iter.remove(); // remove from list to leave only computers EGLCompletionProposalCategory category= new EGLCompletionProposalCategory(element, this); categories.add(category); category.setIncluded(!disabled.contains(category.getId())); Integer rank= (Integer) ordered.get(category.getId()); if (rank != null) { int r= rank.intValue(); boolean separate= r < 0xffff; if (!separate) r= r - 0xffff; category.setSeparateCommand(separate); category.setSortOrder(r); } } } catch (InvalidRegistryObjectException x) { Object[] args= {element.toString()}; String message= Messages.format(EGLTextMessages.CompletionProposalComputerRegistry_invalid_message, args); IStatus status= new Status(IStatus.WARNING, EDTUIPlugin.getPluginId(), IStatus.OK, message, x); informUser(status); } catch (CoreException x) { informUser(x.getStatus()); } } preventDuplicateCategories(store, disabled, allProposals); return categories; } private void preventDuplicateCategories(IPreferenceStore store, Set disabled, EGLCompletionProposalCategory allProposals) { if (allProposals == null || !allProposals.isIncluded()) return; StringBuffer buf= new StringBuffer(50 * disabled.size()); Iterator iter= disabled.iterator(); while (iter.hasNext()) { buf.append(iter.next()); buf.append('\0'); } store.putValue(PreferenceConstants.CODEASSIST_EXCLUDED_CATEGORIES, buf.toString()); } void resetUnistalledComputers() { fHasUninstalledComputers= false; } private void informUser(IStatus status) { EDTUIPlugin.log(status); String title= EGLTextMessages.CompletionProposalComputerRegistry_error_dialog_title; String message= status.getMessage(); MessageDialog.openError(EDTUIPlugin.getActiveWorkbenchShell(), title, message); } void informUser(EGLCompletionProposalComputerDescriptor descriptor, IStatus status) { EDTUIPlugin.log(status); String title= EGLTextMessages.CompletionProposalComputerRegistry_error_dialog_title; EGLCompletionProposalCategory category= descriptor.getCategory(); IContributor culprit= descriptor.getContributor(); Set affectedPlugins= getAffectedContributors(category, culprit); final String avoidHint; final String culpritName= culprit == null ? null : culprit.getName(); if (affectedPlugins.isEmpty()) avoidHint= Messages.format(EGLTextMessages.CompletionProposalComputerRegistry_messageAvoidanceHint, new Object[] {culpritName, category.getDisplayName()}); else avoidHint= Messages.format(EGLTextMessages.CompletionProposalComputerRegistry_messageAvoidanceHintWithWarning, new Object[] {culpritName, category.getDisplayName(), toString(affectedPlugins)}); String message= status.getMessage(); // inlined from MessageDialog.openError MessageDialog dialog = new MessageDialog(EDTUIPlugin.getActiveWorkbenchShell(), title, null /* default image */, message, MessageDialog.ERROR, new String[] { IDialogConstants.OK_LABEL }, 0) { protected Control createCustomArea(Composite parent) { Link link= new Link(parent, SWT.NONE); link.setText(avoidHint); link.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { PreferencesUtil.createPreferenceDialogOn(getShell(), "org.eclipse.edt.ide.ui.ContentAssistAdvancedPreferences", null, null).open(); //$NON-NLS-1$ } }); GridData gridData= new GridData(SWT.FILL, SWT.BEGINNING, true, false); gridData.widthHint= this.getMinimumMessageWidth(); link.setLayoutData(gridData); return link; } }; dialog.open(); } private Set getAffectedContributors(EGLCompletionProposalCategory category, IContributor culprit) { Set affectedPlugins= new HashSet(); for (Iterator it= getProposalComputerDescriptors().iterator(); it.hasNext();) { EGLCompletionProposalComputerDescriptor desc= (EGLCompletionProposalComputerDescriptor) it.next(); EGLCompletionProposalCategory cat= desc.getCategory(); if (cat.equals(category)) { IContributor contributor= desc.getContributor(); if (contributor != null && !culprit.equals(contributor)) affectedPlugins.add(contributor.getName()); } } return affectedPlugins; } private Object toString(Collection collection) { // strip brackets off AbstractCollection.toString() String string= collection.toString(); return string.substring(1, string.length() - 1); } }