Index: META-INF/MANIFEST.MF =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui/META-INF/MANIFEST.MF,v --- META-INF/MANIFEST.MF 4 Mar 2011 18:57:13 -0000 1.89 +++ META-INF/MANIFEST.MF 18 Jul 2011 13:26:50 -0000 @@ -2,7 +2,7 @@ Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.jdt.ui; singleton:=true -Bundle-Version: 3.7.0.qualifier +Bundle-Version: 3.7.1.qualifier Bundle-Activator: org.eclipse.jdt.internal.ui.JavaPlugin Bundle-ActivationPolicy: lazy Bundle-Vendor: %providerName Index: ui/org/eclipse/jdt/internal/ui/javaeditor/SpecificContentAssistExecutor.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/javaeditor/SpecificContentAssistExecutor.java,v --- ui/org/eclipse/jdt/internal/ui/javaeditor/SpecificContentAssistExecutor.java 27 Apr 2011 07:48:36 -0000 1.8 +++ ui/org/eclipse/jdt/internal/ui/javaeditor/SpecificContentAssistExecutor.java 18 Jul 2011 13:26:50 -0000 @@ -7,11 +7,15 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Thomas Schlosser - 340876 [preferences][content assist] Request for more flexible configuration of content assist lists - https://bugs.eclipse.org/bugs/show_bug.cgi?id=340876 *******************************************************************************/ package org.eclipse.jdt.internal.ui.javaeditor; +import java.util.ArrayList; import java.util.Collection; +import java.util.HashSet; import java.util.Iterator; +import java.util.Set; import org.eclipse.core.runtime.Assert; @@ -24,8 +28,9 @@ import org.eclipse.jdt.internal.ui.text.java.CompletionProposalComputerRegistry; /** - * A content assist executor can invoke content assist for a specific proposal category on an editor. - * + * A content assist executor can invoke content assist for a specific proposal category on an + * editor. + * * @since 3.2 */ public final class SpecificContentAssistExecutor { @@ -34,7 +39,7 @@ /** * Creates a new executor. - * + * * @param registry the computer registry to use for the enablement of proposal categories */ public SpecificContentAssistExecutor(CompletionProposalComputerRegistry registry) { @@ -45,21 +50,18 @@ /** * Invokes content assist on editor, showing only proposals computed by the * CompletionProposalCategory with the given categoryId. - * + * * @param editor the editor to invoke code assist on * @param categoryId the id of the proposal category to show proposals for */ public void invokeContentAssist(final ITextEditor editor, String categoryId) { Collection categories= fRegistry.getProposalCategories(); - boolean[] inclusionState= new boolean[categories.size()]; - boolean[] separateState= new boolean[categories.size()]; - int i= 0; - for (Iterator it= categories.iterator(); it.hasNext(); i++) { - CompletionProposalCategory cat= it.next(); - inclusionState[i]= cat.isIncluded(); - cat.setIncluded(cat.getId().equals(categoryId)); - separateState[i]= cat.isSeparateCommand(); - cat.setSeparateCommand(false); + ArrayList> categoriesState= new ArrayList>(categories.size()); + for (CompletionProposalCategory cat : categories) { + categoriesState.add(new HashSet(cat.getProposalListIndices())); + cat.clearProposalListIndices(); + if (cat.getId().equals(categoryId)) + cat.addProposalListIndex(Integer.valueOf(0)); } try { @@ -67,11 +69,11 @@ if (target != null && target.canDoOperation(ISourceViewer.CONTENTASSIST_PROPOSALS)) target.doOperation(ISourceViewer.CONTENTASSIST_PROPOSALS); } finally { - i= 0; + int i= 0; for (Iterator it= categories.iterator(); it.hasNext(); i++) { CompletionProposalCategory cat= it.next(); - cat.setIncluded(inclusionState[i]); - cat.setSeparateCommand(separateState[i]); + cat.clearProposalListIndices(); + cat.addAllProposalListIndices(categoriesState.get(i)); } } } Index: ui/org/eclipse/jdt/internal/ui/preferences/CodeAssistAdvancedConfigurationBlock.java =================================================================== RCS file: ui/org/eclipse/jdt/internal/ui/preferences/CodeAssistAdvancedConfigurationBlock.java --- ui/org/eclipse/jdt/internal/ui/preferences/CodeAssistAdvancedConfigurationBlock.java 1 Mar 2011 11:50:45 -0000 1.14 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,784 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2005, 2011 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.jdt.internal.ui.preferences; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.graphics.GC; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Link; -import org.eclipse.swt.widgets.Table; -import org.eclipse.swt.widgets.TableColumn; - -import org.eclipse.core.commands.Command; -import org.eclipse.core.commands.CommandManager; -import org.eclipse.core.commands.IParameter; -import org.eclipse.core.commands.Parameterization; -import org.eclipse.core.commands.ParameterizedCommand; -import org.eclipse.core.commands.common.NotDefinedException; -import org.eclipse.core.commands.contexts.ContextManager; - -import org.eclipse.core.runtime.Assert; - -import org.eclipse.jface.bindings.BindingManager; -import org.eclipse.jface.bindings.Scheme; -import org.eclipse.jface.bindings.TriggerSequence; -import org.eclipse.jface.layout.PixelConverter; -import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.jface.resource.JFaceResources; -import org.eclipse.jface.viewers.ArrayContentProvider; -import org.eclipse.jface.viewers.CheckStateChangedEvent; -import org.eclipse.jface.viewers.CheckboxTableViewer; -import org.eclipse.jface.viewers.ICheckStateListener; -import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.viewers.ITableLabelProvider; -import org.eclipse.jface.viewers.LabelProvider; -import org.eclipse.jface.viewers.ViewerComparator; - -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.commands.ICommandService; -import org.eclipse.ui.dialogs.PreferencesUtil; -import org.eclipse.ui.keys.IBindingService; -import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer; - -import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds; - -import org.eclipse.jdt.core.JavaCore; - -import org.eclipse.jdt.internal.corext.util.Messages; - -import org.eclipse.jdt.ui.PreferenceConstants; - -import org.eclipse.jdt.internal.ui.JavaPlugin; -import org.eclipse.jdt.internal.ui.dialogs.StatusInfo; -import org.eclipse.jdt.internal.ui.text.java.CompletionProposalCategory; -import org.eclipse.jdt.internal.ui.text.java.CompletionProposalComputerRegistry; -import org.eclipse.jdt.internal.ui.util.SWTUtil; -import org.eclipse.jdt.internal.ui.wizards.IStatusChangeListener; - - -/** - * - * @since 3.2 - */ -final class CodeAssistAdvancedConfigurationBlock extends OptionsConfigurationBlock { - - private static final Key PREF_EXCLUDED_CATEGORIES= getJDTUIKey(PreferenceConstants.CODEASSIST_EXCLUDED_CATEGORIES); - private static final Key PREF_CATEGORY_ORDER= getJDTUIKey(PreferenceConstants.CODEASSIST_CATEGORY_ORDER); - private static final Key PREF_CODEASSIST_TIMEOUT_FOR_PARAMETER_NAME_FROM_ATTACHED_JAVADOC= getJDTCoreKey(JavaCore.TIMEOUT_FOR_PARAMETER_NAME_FROM_ATTACHED_JAVADOC); - - private static Key[] getAllKeys() { - return new Key[] { - PREF_EXCLUDED_CATEGORIES, - PREF_CATEGORY_ORDER, - PREF_CODEASSIST_TIMEOUT_FOR_PARAMETER_NAME_FROM_ATTACHED_JAVADOC - }; - } - - private final class DefaultTableLabelProvider extends LabelProvider implements ITableLabelProvider { - - /* - * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java.lang.Object, int) - */ - public Image getColumnImage(Object element, int columnIndex) { - if (columnIndex == 0) - return ((ModelElement) element).getImage(); - return null; - } - - /* - * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(java.lang.Object, int) - */ - public String getColumnText(Object element, int columnIndex) { - switch (columnIndex) { - case 0: - return ((ModelElement) element).getName(); - case 1: - return ((ModelElement) element).getKeybindingAsString(); - default: - Assert.isTrue(false); - return null; - } - } - - /* - * @see org.eclipse.jface.viewers.LabelProvider#getText(java.lang.Object) - */ - @Override - public String getText(Object element) { - return getColumnText(element, 0); // needed to make the sorter work - } - } - - private final class SeparateTableLabelProvider extends LabelProvider implements ITableLabelProvider { - - /* - * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java.lang.Object, int) - */ - public Image getColumnImage(Object element, int columnIndex) { - if (columnIndex == 0) - return ((ModelElement) element).getImage(); - return null; - } - - /* - * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(java.lang.Object, int) - */ - public String getColumnText(Object element, int columnIndex) { - switch (columnIndex) { - case 0: - return ((ModelElement) element).getName(); - default: - Assert.isTrue(false); - return null; - } - } - } - - private final Comparator fCategoryComparator= new Comparator() { - private int getRank(ModelElement o) { - return o.getRank(); - } - - public int compare(ModelElement o1, ModelElement o2) { - return getRank(o1) - getRank(o2); - } - }; - - private final class PreferenceModel { - private static final int LIMIT= 65535; - private static final String COLON= ":"; //$NON-NLS-1$ - private static final String SEPARATOR= "\0"; //$NON-NLS-1$ - - private final List fElements; - /** - * The read-only list of elements. - */ - final List elements; - - public PreferenceModel(CompletionProposalComputerRegistry registry) { - List categories= registry.getProposalCategories(); - fElements= new ArrayList(); - for (Iterator it= categories.iterator(); it.hasNext();) { - CompletionProposalCategory category= it.next(); - if (category.hasComputers()) { - fElements.add(new ModelElement(category, this)); - } - } - Collections.sort(fElements, fCategoryComparator); - elements= Collections.unmodifiableList(fElements); - } - - public void moveUp(ModelElement category) { - int index= fElements.indexOf(category); - if (index > 0) { - ModelElement item= fElements.remove(index); - fElements.add(index - 1, item); - writeOrderPreference(null, false); - } - } - - public void moveDown(ModelElement category) { - int index= fElements.indexOf(category); - if (index < fElements.size() - 1) { - ModelElement item= fElements.remove(index); - fElements.add(index + 1, item); - writeOrderPreference(null, false); - } - } - - private void writeInclusionPreference(ModelElement changed, boolean isInDefaultCategory) { - StringBuffer buf= new StringBuffer(); - for (Iterator it= fElements.iterator(); it.hasNext();) { - ModelElement item= it.next(); - boolean included= changed == item ? isInDefaultCategory : item.isInDefaultCategory(); - if (!included) - buf.append(item.getId() + SEPARATOR); - } - - String newValue= buf.toString(); - String oldValue= setValue(PREF_EXCLUDED_CATEGORIES, newValue); - validateSettings(PREF_EXCLUDED_CATEGORIES, oldValue, newValue); - } - - private void writeOrderPreference(ModelElement changed, boolean isSeparate) { - StringBuffer buf= new StringBuffer(); - int i= 0; - for (Iterator it= fElements.iterator(); it.hasNext(); i++) { - ModelElement item= it.next(); - boolean separate= changed == item ? isSeparate : item.isSeparateCommand(); - int rank= separate ? i : i + LIMIT; - buf.append(item.getId() + COLON + rank + SEPARATOR); - } - - String newValue= buf.toString(); - String oldValue= setValue(PREF_CATEGORY_ORDER, newValue); - validateSettings(PREF_CATEGORY_ORDER, oldValue, newValue); - } - - - private boolean readInclusionPreference(CompletionProposalCategory cat) { - String[] ids= getTokens(getValue(PREF_EXCLUDED_CATEGORIES), SEPARATOR); - for (int i= 0; i < ids.length; i++) { - if (ids[i].equals(cat.getId())) - return false; - } - return true; - } - - private int readOrderPreference(CompletionProposalCategory cat) { - String[] sortOrderIds= getTokens(getValue(PREF_CATEGORY_ORDER), SEPARATOR); - for (int i= 0; i < sortOrderIds.length; i++) { - String[] idAndRank= getTokens(sortOrderIds[i], COLON); - if (idAndRank[0].equals(cat.getId())) - return Integer.parseInt(idAndRank[1]); - } - return LIMIT - 1; - } - - public void update() { - Collections.sort(fElements, fCategoryComparator); - } - } - - private final class ModelElement { - private final CompletionProposalCategory fCategory; - private final Command fCommand; - private final IParameter fParam; - private final PreferenceModel fPreferenceModel; - - ModelElement(CompletionProposalCategory category, PreferenceModel model) { - fCategory= category; - ICommandService commandSvc= (ICommandService) PlatformUI.getWorkbench().getAdapter(ICommandService.class); - fCommand= commandSvc.getCommand("org.eclipse.jdt.ui.specific_content_assist.command"); //$NON-NLS-1$ - IParameter type; - try { - type= fCommand.getParameters()[0]; - } catch (NotDefinedException x) { - Assert.isTrue(false); - type= null; - } - fParam= type; - fPreferenceModel= model; - } - Image getImage() { - return CodeAssistAdvancedConfigurationBlock.this.getImage(fCategory.getImageDescriptor()); - } - String getName() { - return fCategory.getDisplayName(); - } - String getKeybindingAsString() { - final Parameterization[] params= { new Parameterization(fParam, fCategory.getId()) }; - final ParameterizedCommand pCmd= new ParameterizedCommand(fCommand, params); - String key= getKeyboardShortcut(pCmd); - return key; - } - boolean isInDefaultCategory() { - return fPreferenceModel.readInclusionPreference(fCategory); - } - void setInDefaultCategory(boolean included) { - if (included != isInDefaultCategory()) - fPreferenceModel.writeInclusionPreference(this, included); - } - String getId() { - return fCategory.getId(); - } - int getRank() { - int rank= getInternalRank(); - if (rank > PreferenceModel.LIMIT) - return rank - PreferenceModel.LIMIT; - return rank; - } - void moveUp() { - fPreferenceModel.moveUp(this); - } - void moveDown() { - fPreferenceModel.moveDown(this); - } - private int getInternalRank() { - return fPreferenceModel.readOrderPreference(fCategory); - } - boolean isSeparateCommand() { - return getInternalRank() < PreferenceModel.LIMIT; - } - - void setSeparateCommand(boolean separate) { - if (separate != isSeparateCommand()) - fPreferenceModel.writeOrderPreference(this, separate); - } - - void update() { - fCategory.setIncluded(isInDefaultCategory()); - int rank= getInternalRank(); - fCategory.setSortOrder(rank); - fCategory.setSeparateCommand(rank < PreferenceModel.LIMIT); - } - } - - /** element type: {@link ModelElement}. */ - private final PreferenceModel fModel; - private final Map fImages= new HashMap(); - - private CheckboxTableViewer fDefaultViewer; - private CheckboxTableViewer fSeparateViewer; - private Button fUpButton; - private Button fDownButton; - - CodeAssistAdvancedConfigurationBlock(IStatusChangeListener statusListener, IWorkbenchPreferenceContainer container) { - super(statusListener, null, getAllKeys(), container); - fModel= new PreferenceModel(CompletionProposalComputerRegistry.getDefault()); - } - - /* - * @see org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock#createContents(org.eclipse.swt.widgets.Composite) - */ - @Override - protected Control createContents(Composite parent) { - - ScrolledPageContent scrolled= new ScrolledPageContent(parent, SWT.H_SCROLL | SWT.V_SCROLL); - - scrolled.setExpandHorizontal(true); - scrolled.setExpandVertical(true); - - Composite composite= new Composite(scrolled, SWT.NONE); - int columns= 2; - GridLayout layout= new GridLayout(columns, false); - layout.marginWidth= 0; - layout.marginHeight= 0; - composite.setLayout(layout); - - - createDefaultLabel(composite, columns); - createDefaultViewer(composite, columns); - createKeysLink(composite, columns); - - createFiller(composite, columns); - - createSeparateLabel(composite, columns); - createSeparateSection(composite); - - createFiller(composite, columns); - - createParameterTimeoutControl(composite, columns); - - updateControls(); - if (fModel.elements.size() > 0) { - fDefaultViewer.getTable().select(0); - fSeparateViewer.getTable().select(0); - handleTableSelection(); - } - - scrolled.setContent(composite); - scrolled.setMinSize(composite.computeSize(SWT.DEFAULT, SWT.DEFAULT)); - return scrolled; - } - - private void createDefaultLabel(Composite composite, int h_span) { - final ICommandService commandSvc= (ICommandService) PlatformUI.getWorkbench().getAdapter(ICommandService.class); - final Command command= commandSvc.getCommand(ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS); - ParameterizedCommand pCmd= new ParameterizedCommand(command, null); - String key= getKeyboardShortcut(pCmd); - if (key == null) - key= PreferencesMessages.CodeAssistAdvancedConfigurationBlock_no_shortcut; - - PixelConverter pixelConverter= new PixelConverter(composite); - int width= pixelConverter.convertWidthInCharsToPixels(40); - - Label label= new Label(composite, SWT.NONE | SWT.WRAP); - label.setText(Messages.format(PreferencesMessages.CodeAssistAdvancedConfigurationBlock_page_description, new Object[] { key })); - GridData gd= new GridData(GridData.FILL, GridData.FILL, true, false, h_span, 1); - gd.widthHint= width; - label.setLayoutData(gd); - - createFiller(composite, h_span); - - label= new Label(composite, SWT.NONE | SWT.WRAP); - label.setText(PreferencesMessages.CodeAssistAdvancedConfigurationBlock_default_table_description); - gd= new GridData(GridData.FILL, GridData.FILL, true, false, h_span, 1); - gd.widthHint= width; - label.setLayoutData(gd); - } - - private void createDefaultViewer(Composite composite, int h_span) { - fDefaultViewer= CheckboxTableViewer.newCheckList(composite, SWT.SINGLE | SWT.BORDER); - Table table= fDefaultViewer.getTable(); - table.setHeaderVisible(true); - table.setLinesVisible(false); - table.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, false, false, h_span, 1)); - - TableColumn nameColumn= new TableColumn(table, SWT.NONE); - nameColumn.setText(PreferencesMessages.CodeAssistAdvancedConfigurationBlock_default_table_category_column_title); - nameColumn.setResizable(false); - TableColumn keyColumn= new TableColumn(table, SWT.NONE); - keyColumn.setText(PreferencesMessages.CodeAssistAdvancedConfigurationBlock_default_table_keybinding_column_title); - keyColumn.setResizable(false); - - fDefaultViewer.addCheckStateListener(new ICheckStateListener() { - public void checkStateChanged(CheckStateChangedEvent event) { - boolean checked= event.getChecked(); - ModelElement element= (ModelElement) event.getElement(); - element.setInDefaultCategory(checked); - } - }); - - fDefaultViewer.setContentProvider(new ArrayContentProvider()); - - DefaultTableLabelProvider labelProvider= new DefaultTableLabelProvider(); - fDefaultViewer.setLabelProvider(labelProvider); - fDefaultViewer.setInput(fModel.elements); - fDefaultViewer.setComparator(new ViewerComparator()); // sort alphabetically - - final int ICON_AND_CHECKBOX_WITH= 50; - final int HEADER_MARGIN= 20; - int minNameWidth= computeWidth(table, nameColumn.getText()) + HEADER_MARGIN; - int minKeyWidth= computeWidth(table, keyColumn.getText()) + HEADER_MARGIN; - for (int i= 0; i < fModel.elements.size(); i++) { - minNameWidth= Math.max(minNameWidth, computeWidth(table, labelProvider.getColumnText(fModel.elements.get(i), 0)) + ICON_AND_CHECKBOX_WITH); - minKeyWidth= Math.max(minKeyWidth, computeWidth(table, labelProvider.getColumnText(fModel.elements.get(i), 1))); - } - - nameColumn.setWidth(minNameWidth); - keyColumn.setWidth(minKeyWidth); - } - - private void createKeysLink(Composite composite, int h_span) { - Link link= new Link(composite, SWT.NONE | SWT.WRAP); - link.setText(PreferencesMessages.CodeAssistAdvancedConfigurationBlock_key_binding_hint); - link.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - PreferencesUtil.createPreferenceDialogOn(getShell(), e.text, null, null); - } - }); - - PixelConverter pixelConverter= new PixelConverter(composite); - int width= pixelConverter.convertWidthInCharsToPixels(40); - - // limit the size of the Link as it would take all it can get - GridData gd= new GridData(GridData.FILL, GridData.FILL, false, false, h_span, 1); - gd.widthHint= width; - link.setLayoutData(gd); - } - - private void createFiller(Composite composite, int h_span) { - Label filler= new Label(composite, SWT.NONE); - filler.setVisible(false); - filler.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, h_span, 1)); - } - - private void createSeparateLabel(Composite composite, int h_span) { - PixelConverter pixelConverter= new PixelConverter(composite); - int width= pixelConverter.convertWidthInCharsToPixels(40); - - Label label= new Label(composite, SWT.NONE | SWT.WRAP); - label.setText(PreferencesMessages.CodeAssistAdvancedConfigurationBlock_separate_table_description); - GridData gd= new GridData(GridData.FILL, GridData.FILL, false, false, h_span, 1); - gd.widthHint= width; - label.setLayoutData(gd); - } - - private void createSeparateSection(Composite composite) { - createSeparateViewer(composite); - createButtonList(composite); - } - - private void createSeparateViewer(Composite composite) { - fSeparateViewer= CheckboxTableViewer.newCheckList(composite, SWT.SINGLE | SWT.BORDER); - Table table= fSeparateViewer.getTable(); - table.setHeaderVisible(false); - table.setLinesVisible(false); - table.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, true, false, 1, 1)); - - TableColumn nameColumn= new TableColumn(table, SWT.NONE); - nameColumn.setText(PreferencesMessages.CodeAssistAdvancedConfigurationBlock_separate_table_category_column_title); - nameColumn.setResizable(false); - - fSeparateViewer.setContentProvider(new ArrayContentProvider()); - - ITableLabelProvider labelProvider= new SeparateTableLabelProvider(); - fSeparateViewer.setLabelProvider(labelProvider); - fSeparateViewer.setInput(fModel.elements); - - final int ICON_AND_CHECKBOX_WITH= 50; - final int HEADER_MARGIN= 20; - int minNameWidth= computeWidth(table, nameColumn.getText()) + HEADER_MARGIN; - for (int i= 0; i < fModel.elements.size(); i++) { - minNameWidth= Math.max(minNameWidth, computeWidth(table, labelProvider.getColumnText(fModel.elements.get(i), 0)) + ICON_AND_CHECKBOX_WITH); - } - - nameColumn.setWidth(minNameWidth); - - fSeparateViewer.addCheckStateListener(new ICheckStateListener() { - public void checkStateChanged(CheckStateChangedEvent event) { - boolean checked= event.getChecked(); - ModelElement element= (ModelElement) event.getElement(); - element.setSeparateCommand(checked); - } - }); - - table.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - handleTableSelection(); - } - }); - - } - - private void createButtonList(Composite parent) { - Composite composite= new Composite(parent, SWT.NONE); - composite.setLayoutData(new GridData(SWT.BEGINNING, SWT.BEGINNING, false, false)); - - GridLayout layout= new GridLayout(); - layout.marginWidth= 0; - layout.marginHeight= 0; - composite.setLayout(layout); - - fUpButton= new Button(composite, SWT.PUSH | SWT.CENTER); - fUpButton.setText(PreferencesMessages.CodeAssistAdvancedConfigurationBlock_Up); - fUpButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - int index= getSelectionIndex(); - if (index != -1) { - fModel.elements.get(index).moveUp(); - fSeparateViewer.refresh(); - handleTableSelection(); - } - } - }); - fUpButton.setLayoutData(new GridData()); - SWTUtil.setButtonDimensionHint(fUpButton); - - fDownButton= new Button(composite, SWT.PUSH | SWT.CENTER); - fDownButton.setText(PreferencesMessages.CodeAssistAdvancedConfigurationBlock_Down); - fDownButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - int index= getSelectionIndex(); - if (index != -1) { - fModel.elements.get(index).moveDown(); - fSeparateViewer.refresh(); - handleTableSelection(); - } - } - }); - fDownButton.setLayoutData(new GridData()); - SWTUtil.setButtonDimensionHint(fDownButton); - } - - private void createParameterTimeoutControl(Composite composite, int h_span) { - Composite timeoutComposite= new Composite(composite, SWT.NONE); - GridLayout layout= new GridLayout(4, false); - layout.marginWidth= 0; - layout.marginHeight= 0; - timeoutComposite.setLayout(layout); - GridData gd= new GridData(GridData.FILL, GridData.FILL, true, false, h_span, 1); - timeoutComposite.setLayoutData(gd); - - PixelConverter pixelConverter= new PixelConverter(composite); - String str= PreferencesMessages.CodeAssistAdvancedConfigurationBlock_parameterNameFromAttachedJavadoc_timeout; - addTextField(timeoutComposite, str, PREF_CODEASSIST_TIMEOUT_FOR_PARAMETER_NAME_FROM_ATTACHED_JAVADOC, 0, pixelConverter.convertWidthInCharsToPixels(7)); - - } - - private void handleTableSelection() { - ModelElement item= getSelectedItem(); - if (item != null) { - int index= getSelectionIndex(); - fUpButton.setEnabled(index > 0); - fDownButton.setEnabled(index < fModel.elements.size() - 1); - } else { - fUpButton.setEnabled(false); - fDownButton.setEnabled(false); - } - } - - private ModelElement getSelectedItem() { - return (ModelElement) ((IStructuredSelection) fSeparateViewer.getSelection()).getFirstElement(); - } - - private int getSelectionIndex() { - return fSeparateViewer.getTable().getSelectionIndex(); - } - - /* - * @see org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock#updateControls() - */ - @Override - protected void updateControls() { - super.updateControls(); - - fModel.update(); - updateCheckedState(); - fDefaultViewer.refresh(); - fSeparateViewer.refresh(); - handleTableSelection(); - } - - private void updateCheckedState() { - final int size= fModel.elements.size(); - List defaultChecked= new ArrayList(size); - List separateChecked= new ArrayList(size); - - for (Iterator it= fModel.elements.iterator(); it.hasNext();) { - ModelElement element= it.next(); - if (element.isInDefaultCategory()) - defaultChecked.add(element); - if (element.isSeparateCommand()) - separateChecked.add(element); - } - - fDefaultViewer.setCheckedElements(defaultChecked.toArray(new Object[defaultChecked.size()])); - fSeparateViewer.setCheckedElements(separateChecked.toArray(new Object[separateChecked.size()])); - } - - /* - * @see org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock#processChanges(org.eclipse.ui.preferences.IWorkbenchPreferenceContainer) - */ - @Override - protected boolean processChanges(IWorkbenchPreferenceContainer container) { - for (Iterator it= fModel.elements.iterator(); it.hasNext();) { - ModelElement item= it.next(); - item.update(); - } - - return super.processChanges(container); - } - - /* - * @see org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock#validateSettings(org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock.Key, java.lang.String, java.lang.String) - */ - @Override - protected void validateSettings(Key changedKey, String oldValue, String newValue) { - if (changedKey == PREF_CODEASSIST_TIMEOUT_FOR_PARAMETER_NAME_FROM_ATTACHED_JAVADOC) { - final StatusInfo status= new StatusInfo(); - if (newValue.length() == 0) - status.setError(PreferencesMessages.CodeAssistAdvancedConfigurationBlock_parameterNameFromAttachedJavadoc_timeout_emptyInput); - else { - try { - int number= Integer.parseInt(newValue); - int min= 0; - int max= 5000; - if (number < min || number > max) { - String msgFormat= PreferencesMessages.CodeAssistAdvancedConfigurationBlock_parameterNameFromAttachedJavadoc_timeout_invalidRange; - String msg= Messages.format(msgFormat, new Object[] {new Integer(min), new Integer(max)}); - status.setError(msg); - } - } catch (NumberFormatException ex) { - String msgFormat= PreferencesMessages.CodeAssistAdvancedConfigurationBlock_parameterNameFromAttachedJavadoc_timeout_invalidInput; - String msg= Messages.format(msgFormat, newValue); - status.setError(msg); - } - } - fContext.statusChanged(status); - } - } - - /* - * @see org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock#getFullBuildDialogStrings(boolean) - */ - @Override - protected String[] getFullBuildDialogStrings(boolean workspaceSettings) { - // no builds triggered by our settings - return null; - } - - /* - * @see org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock#dispose() - */ - @Override - public void dispose() { - for (Iterator it= fImages.values().iterator(); it.hasNext();) { - Image image= it.next(); - image.dispose(); - } - - super.dispose(); - } - - private int computeWidth(Control control, String name) { - if (name == null) - return 0; - GC gc= new GC(control); - try { - gc.setFont(JFaceResources.getDialogFont()); - return gc.stringExtent(name).x + 10; - } finally { - gc.dispose(); - } - } - - private static BindingManager fgLocalBindingManager; - static { - fgLocalBindingManager= new BindingManager(new ContextManager(), new CommandManager()); - final IBindingService bindingService= (IBindingService)PlatformUI.getWorkbench().getService(IBindingService.class); - final Scheme[] definedSchemes= bindingService.getDefinedSchemes(); - if (definedSchemes != null) { - try { - for (int i = 0; i < definedSchemes.length; i++) { - final Scheme scheme= definedSchemes[i]; - final Scheme copy= fgLocalBindingManager.getScheme(scheme.getId()); - copy.define(scheme.getName(), scheme.getDescription(), scheme.getParentId()); - } - } catch (final NotDefinedException e) { - JavaPlugin.log(e); - } - } - fgLocalBindingManager.setLocale(bindingService.getLocale()); - fgLocalBindingManager.setPlatform(bindingService.getPlatform()); - } - - private static String getKeyboardShortcut(ParameterizedCommand command) { - IBindingService bindingService= (IBindingService) PlatformUI.getWorkbench().getAdapter(IBindingService.class); - fgLocalBindingManager.setBindings(bindingService.getBindings()); - try { - Scheme activeScheme= bindingService.getActiveScheme(); - if (activeScheme != null) - fgLocalBindingManager.setActiveScheme(activeScheme); - } catch (NotDefinedException e) { - JavaPlugin.log(e); - } - - TriggerSequence[] bindings= fgLocalBindingManager.getActiveBindingsDisregardingContextFor(command); - if (bindings.length > 0) - return bindings[0].format(); - return null; - } - - private Image getImage(ImageDescriptor imgDesc) { - if (imgDesc == null) - return null; - - Image img= fImages.get(imgDesc); - if (img == null) { - img= imgDesc.createImage(false); - fImages.put(imgDesc, img); - } - return img; - } - -} Index: ui/org/eclipse/jdt/internal/ui/preferences/CodeAssistAdvancedPreferencePage.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/CodeAssistAdvancedPreferencePage.java,v --- ui/org/eclipse/jdt/internal/ui/preferences/CodeAssistAdvancedPreferencePage.java 27 Apr 2011 07:51:28 -0000 1.6 +++ ui/org/eclipse/jdt/internal/ui/preferences/CodeAssistAdvancedPreferencePage.java 18 Jul 2011 13:26:50 -0000 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Thomas Schlosser - 340876 [preferences][content assist] Request for more flexible configuration of content assist lists - https://bugs.eclipse.org/bugs/show_bug.cgi?id=340876 *******************************************************************************/ package org.eclipse.jdt.internal.ui.preferences; @@ -19,6 +20,7 @@ import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer; import org.eclipse.jdt.internal.ui.IJavaHelpContextIds; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.CodeAssistAdvancedConfigurationBlock; public final class CodeAssistAdvancedPreferencePage extends PropertyAndPreferencePage { Index: ui/org/eclipse/jdt/internal/ui/preferences/PreferencesMessages.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/PreferencesMessages.java,v --- ui/org/eclipse/jdt/internal/ui/preferences/PreferencesMessages.java 27 Apr 2011 07:51:27 -0000 1.143 +++ ui/org/eclipse/jdt/internal/ui/preferences/PreferencesMessages.java 18 Jul 2011 13:26:52 -0000 @@ -11,6 +11,7 @@ * Sebastian Davids, sdavids@gmx.de - 187316 [preferences] Mark Occurences Pref Page; Link to * Benjamin Muskalla - [preferences] Add preference for new compiler warning: MissingSynchronizedModifierInInheritedMethod - https://bugs.eclipse.org/bugs/show_bug.cgi?id=245240 * Guven Demir - [package explorer] Alternative package name shortening: abbreviation - https://bugs.eclipse.org/bugs/show_bug.cgi?id=299514 + * Thomas Schlosser - 340876 [preferences][content assist] Request for more flexible configuration of content assist lists - https://bugs.eclipse.org/bugs/show_bug.cgi?id=340876 *******************************************************************************/ package org.eclipse.jdt.internal.ui.preferences; @@ -41,16 +42,13 @@ public static String ClasspathVariablesPreferencePage_savechanges_message; public static String CleanUpPreferencePage_Description; public static String CleanUpPreferencePage_Title; - public static String CodeAssistAdvancedConfigurationBlock_default_table_category_column_title; - public static String CodeAssistAdvancedConfigurationBlock_default_table_description; - public static String CodeAssistAdvancedConfigurationBlock_default_table_keybinding_column_title; + public static String CodeAssistAdvancedConfigurationBlock_provided_table_category_column_title; + public static String CodeAssistAdvancedConfigurationBlock_provided_table_description; + public static String CodeAssistAdvancedConfigurationBlock_provided_table_keybinding_column_title; public static String CodeAssistAdvancedConfigurationBlock_key_binding_hint; + public static String CodeAssistAdvancedConfigurationBlock_proposal_list_table_title; public static String CodeAssistAdvancedConfigurationBlock_page_description; - public static String CodeAssistAdvancedConfigurationBlock_separate_table_category_column_title; - public static String CodeAssistAdvancedConfigurationBlock_separate_table_description; public static String CodeAssistAdvancedConfigurationBlock_no_shortcut; - public static String CodeAssistAdvancedConfigurationBlock_Up; - public static String CodeAssistAdvancedConfigurationBlock_Down; public static String CodeAssistAdvancedConfigurationBlock_parameterNameFromAttachedJavadoc_timeout; public static String CodeAssistAdvancedConfigurationBlock_parameterNameFromAttachedJavadoc_timeout_emptyInput; public static String CodeAssistAdvancedConfigurationBlock_parameterNameFromAttachedJavadoc_timeout_invalidInput; Index: ui/org/eclipse/jdt/internal/ui/preferences/PreferencesMessages.properties =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/PreferencesMessages.properties,v --- ui/org/eclipse/jdt/internal/ui/preferences/PreferencesMessages.properties 4 May 2011 11:04:12 -0000 1.530 +++ ui/org/eclipse/jdt/internal/ui/preferences/PreferencesMessages.properties 18 Jul 2011 13:26:53 -0000 @@ -11,6 +11,7 @@ # Sebastian Davids, sdavids@gmx.de - 187316 [preferences] Mark Occurrences Pref Page; Link to # Benjamin Muskalla - [preferences] Add preference for new compiler warning: MissingSynchronizedModifierInInheritedMethod - https://bugs.eclipse.org/bugs/show_bug.cgi?id=245240 # Guven Demir - [package explorer] Alternative package name shortening: abbreviation - https://bugs.eclipse.org/bugs/show_bug.cgi?id=299514 +# Thomas Schlosser - 340876 [preferences][content assist] Request for more flexible configuration of content assist lists - https://bugs.eclipse.org/bugs/show_bug.cgi?id=340876 ############################################################################### BuildPathsPropertyPage_error_message=An error occurred while setting the build path. @@ -848,15 +849,12 @@ CodeAssistAdvancedConfigurationBlock_page_description=Configure the behavior of the content assist ({0}) command. # stand-in text if there is no keyboard shortcut in above statement CodeAssistAdvancedConfigurationBlock_no_shortcut=no shortcut -CodeAssistAdvancedConfigurationBlock_default_table_description=&Select the proposal kinds contained in the 'default' content assist list: -CodeAssistAdvancedConfigurationBlock_default_table_category_column_title=Default Proposal Kinds -CodeAssistAdvancedConfigurationBlock_default_table_keybinding_column_title=Key Binding +CodeAssistAdvancedConfigurationBlock_provided_table_description=Drag proposal kinds to lists on the right to configure which proposals you want to have on each position while repeatedly invoking content assist. +CodeAssistAdvancedConfigurationBlock_provided_table_category_column_title=Proposal Kinds +CodeAssistAdvancedConfigurationBlock_provided_table_keybinding_column_title=Key Binding # do not translate the href argument (org.eclipse.ui.preferencePages.Keys) CodeAssistAdvancedConfigurationBlock_key_binding_hint=Individual key bindings can be assigned to each proposal kind on the 'Keys' preference page. -CodeAssistAdvancedConfigurationBlock_separate_table_description=&Content assist cycling: Select the proposal kinds that are cycled through when repeatedly invoking content assist: -CodeAssistAdvancedConfigurationBlock_separate_table_category_column_title=Separate Proposal Kinds -CodeAssistAdvancedConfigurationBlock_Up=&Up -CodeAssistAdvancedConfigurationBlock_Down=D&own +CodeAssistAdvancedConfigurationBlock_proposal_list_table_title={0}. Proposal List CodeAssistAdvancedConfigurationBlock_parameterNameFromAttachedJavadoc_timeout=&Timeout for fetching a parameter name from attached Javadoc (ms): CodeAssistAdvancedConfigurationBlock_parameterNameFromAttachedJavadoc_timeout_emptyInput=Empty input. Index: ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/CodeAssistAdvancedConfigurationBlock.java =================================================================== RCS file: ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/CodeAssistAdvancedConfigurationBlock.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/CodeAssistAdvancedConfigurationBlock.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,459 @@ +/******************************************************************************* + * Copyright (c) 2005, 2011 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 + * Thomas Schlosser - 340876 [preferences][content assist] Request for more flexible configuration of content assist lists - https://bugs.eclipse.org/bugs/show_bug.cgi?id=340876 + *******************************************************************************/ +package org.eclipse.jdt.internal.ui.preferences.codeassist.advanced; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.dnd.Transfer; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Link; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; + +import org.eclipse.core.commands.Command; +import org.eclipse.core.commands.CommandManager; +import org.eclipse.core.commands.ParameterizedCommand; +import org.eclipse.core.commands.common.NotDefinedException; +import org.eclipse.core.commands.contexts.ContextManager; + +import org.eclipse.core.runtime.Assert; + +import org.eclipse.jface.bindings.BindingManager; +import org.eclipse.jface.bindings.Scheme; +import org.eclipse.jface.bindings.TriggerSequence; +import org.eclipse.jface.layout.PixelConverter; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.viewers.ArrayContentProvider; +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.TableViewer; + +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.commands.ICommandService; +import org.eclipse.ui.dialogs.PreferencesUtil; +import org.eclipse.ui.keys.IBindingService; +import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer; + +import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds; + +import org.eclipse.jdt.core.JavaCore; + +import org.eclipse.jdt.internal.corext.util.Messages; + +import org.eclipse.jdt.ui.PreferenceConstants; + +import org.eclipse.jdt.internal.ui.JavaPlugin; +import org.eclipse.jdt.internal.ui.dialogs.StatusInfo; +import org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock; +import org.eclipse.jdt.internal.ui.preferences.PreferencesMessages; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.dnd.DragProvidedCategoryListener; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.dnd.DropIntoProvidedListener; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.dnd.ProposalListCategoryTransfer; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.dnd.ProposalListTransfer; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.dnd.ProposalTransfer; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.dnd.ProvidedCategoryTransfer; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.model.ModelElement; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.model.PreferenceModel; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.widgets.ProposalListSection; +import org.eclipse.jdt.internal.ui.text.java.CompletionProposalComputerRegistry; +import org.eclipse.jdt.internal.ui.wizards.IStatusChangeListener; + + +/** + * + * @since 3.2 + */ +public final class CodeAssistAdvancedConfigurationBlock extends OptionsConfigurationBlock { + + protected static final Key PREF_PROPOSAL_LISTS= getJDTUIKey(PreferenceConstants.CODEASSIST_PROPOSAL_LISTS); + + private static final Key PREF_CODEASSIST_TIMEOUT_FOR_PARAMETER_NAME_FROM_ATTACHED_JAVADOC= getJDTCoreKey(JavaCore.TIMEOUT_FOR_PARAMETER_NAME_FROM_ATTACHED_JAVADOC); + + private static Key[] getAllKeys() { + return new Key[] { + PREF_PROPOSAL_LISTS, + PREF_CODEASSIST_TIMEOUT_FOR_PARAMETER_NAME_FROM_ATTACHED_JAVADOC + }; + } + + private static final int NUMBER_OF_PAGE_COLUMNS= 2; + + private final class ProvidedTableLabelProvider extends LabelProvider implements ITableLabelProvider { + + /* + * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java.lang.Object, int) + */ + public Image getColumnImage(Object element, int columnIndex) { + if (columnIndex == 0) + return ((ModelElement) element).getImage(); + return null; + } + + /* + * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(java.lang.Object, int) + */ + public String getColumnText(Object element, int columnIndex) { + switch (columnIndex) { + case 0: + return ((ModelElement) element).getName(); + case 1: + return ((ModelElement) element).getKeybindingAsString(); + default: + Assert.isTrue(false); + return null; + } + } + } + + private final PreferenceModel fModel; + + private final Map fImages= new HashMap(); + + private TableViewer fProvidedViewer; + + private ProposalListSection fProposalListSection; + + private final CodeAssistAdvancedUtilitiesProxy fUtilitiesProxy; + + public CodeAssistAdvancedConfigurationBlock(IStatusChangeListener statusListener, IWorkbenchPreferenceContainer container) { + super(statusListener, null, getAllKeys(), container); + fUtilitiesProxy= new CodeAssistAdvancedUtilitiesProxy(this); + fModel= new PreferenceModel(CompletionProposalComputerRegistry.getDefault(), fUtilitiesProxy); + } + + /* + * @see org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock#createContents(org.eclipse.swt.widgets.Composite) + */ + @Override + public Control createContents(Composite parent) { + Composite composite= createWrappingComposite(parent); + + createPageDescription(composite); + + createProvidedSection(composite); + fProposalListSection= new ProposalListSection(composite, fModel, fUtilitiesProxy); + + createFiller(composite); + + createParameterTimeoutControl(composite); + + updateControls(); + selectFirstProvidedCategory(); + + return composite; + } + + private Composite createWrappingComposite(Composite parent) { + Composite composite= new Composite(parent, SWT.NONE); + GridLayout layout= new GridLayout(NUMBER_OF_PAGE_COLUMNS, false); + layout.marginWidth= 0; + layout.marginHeight= 0; + composite.setLayout(layout); + return composite; + } + + private void createPageDescription(Composite composite) { + final ICommandService commandSvc= (ICommandService) PlatformUI.getWorkbench().getAdapter(ICommandService.class); + final Command command= commandSvc.getCommand(ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS); + ParameterizedCommand pCmd= new ParameterizedCommand(command, null); + String key= getKeyboardShortcut(pCmd); + if (key == null) + key= PreferencesMessages.CodeAssistAdvancedConfigurationBlock_no_shortcut; + + PixelConverter pixelConverter= new PixelConverter(composite); + int width= pixelConverter.convertWidthInCharsToPixels(40); + + Label label= new Label(composite, SWT.NONE | SWT.WRAP); + label.setText(Messages.format(PreferencesMessages.CodeAssistAdvancedConfigurationBlock_page_description, new Object[] { key })); + GridData gd= new GridData(GridData.FILL, GridData.FILL, true, false, NUMBER_OF_PAGE_COLUMNS, 1); + gd.widthHint= width; + label.setLayoutData(gd); + } + + private void createProvidedSection(Composite composite) { + Composite providedContainer= new Composite(composite, SWT.NONE); + GridLayout layout= new GridLayout(); + layout.marginWidth= 0; + layout.marginHeight= 0; + providedContainer.setLayout(layout); + providedContainer.setLayoutData(new GridData(GridData.FILL_BOTH)); + + createProvidedViewer(providedContainer); + createProvidedLabel(providedContainer); + createKeysLink(providedContainer); + } + + private void createProvidedViewer(Composite composite) { + fProvidedViewer= new TableViewer(composite, SWT.SINGLE | SWT.BORDER | SWT.V_SCROLL); + Table table= fProvidedViewer.getTable(); + table.setHeaderVisible(true); + table.setLinesVisible(false); + GridData gridData= new GridData(SWT.FILL, SWT.FILL, true, true); + gridData.heightHint= 0; + table.setLayoutData(gridData); + + TableColumn nameColumn= new TableColumn(table, SWT.NONE); + nameColumn.setText(PreferencesMessages.CodeAssistAdvancedConfigurationBlock_provided_table_category_column_title); + nameColumn.setResizable(false); + TableColumn keyColumn= new TableColumn(table, SWT.NONE); + keyColumn.setText(PreferencesMessages.CodeAssistAdvancedConfigurationBlock_provided_table_keybinding_column_title); + keyColumn.setResizable(false); + + fProvidedViewer.setContentProvider(new ArrayContentProvider()); + ProvidedTableLabelProvider labelProvider= new ProvidedTableLabelProvider(); + fProvidedViewer.setLabelProvider(labelProvider); + fProvidedViewer.setInput(fModel.elements); + fProvidedViewer.setComparator(new ModelElement.ModelElementViewerComparator()); // sort alphabetically + + final int ICON_WIDTH= 16; + final int HEADER_MARGIN= 20; + int minNameWidth= computeWidth(table, nameColumn.getText()) + HEADER_MARGIN; + int minKeyWidth= computeWidth(table, keyColumn.getText()) + HEADER_MARGIN; + for (int i= 0; i < fModel.elements.size(); i++) { + minNameWidth= Math.max(minNameWidth, computeWidth(table, labelProvider.getColumnText(fModel.elements.get(i), 0)) + ICON_WIDTH); + minKeyWidth= Math.max(minKeyWidth, computeWidth(table, labelProvider.getColumnText(fModel.elements.get(i), 1))); + } + nameColumn.setWidth(minNameWidth); + keyColumn.setWidth(minKeyWidth); + + // add drag support for provided categories + Transfer[] transferTypes= new Transfer[] { ProvidedCategoryTransfer.getInstance() }; + fProvidedViewer.addDragSupport(ProposalTransfer.ALL_DRAG_OPERATIONS, transferTypes, new DragProvidedCategoryListener(fProvidedViewer)); + + // add drop support for proposal lists and proposal list categories + transferTypes= new Transfer[] { ProposalListTransfer.getInstance(), ProposalListCategoryTransfer.getInstance() }; + fProvidedViewer.addDropSupport(ProposalTransfer.ALL_DRAG_OPERATIONS, transferTypes, new DropIntoProvidedListener(fProvidedViewer, fModel, fUtilitiesProxy)); + } + + private void createProvidedLabel(Composite composite) { + PixelConverter pixelConverter= new PixelConverter(composite); + int width= pixelConverter.convertWidthInCharsToPixels(40); + + Label label= new Label(composite, SWT.NONE | SWT.WRAP); + label.setText(PreferencesMessages.CodeAssistAdvancedConfigurationBlock_provided_table_description); + GridData gd= new GridData(GridData.FILL, GridData.FILL, true, false); + gd.widthHint= width; + label.setLayoutData(gd); + } + + private void createKeysLink(Composite composite) { + Link link= new Link(composite, SWT.NONE | SWT.WRAP); + link.setText(PreferencesMessages.CodeAssistAdvancedConfigurationBlock_key_binding_hint); + link.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + PreferencesUtil.createPreferenceDialogOn(getShell(), e.text, null, null); + } + }); + + PixelConverter pixelConverter= new PixelConverter(composite); + int width= pixelConverter.convertWidthInCharsToPixels(40); + + // limit the size of the Link as it would take all it can get + GridData gd= new GridData(GridData.FILL, GridData.FILL, false, false); + gd.widthHint= width; + link.setLayoutData(gd); + } + + private void createFiller(Composite composite) { + Label filler= new Label(composite, SWT.NONE); + filler.setVisible(false); + filler.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false, NUMBER_OF_PAGE_COLUMNS, 1)); + } + + private void createParameterTimeoutControl(Composite composite) { + Composite timeoutComposite= new Composite(composite, SWT.NONE); + GridLayout layout= new GridLayout(4, false); + layout.marginWidth= 0; + layout.marginHeight= 0; + timeoutComposite.setLayout(layout); + GridData gd= new GridData(GridData.FILL, GridData.FILL, true, false, NUMBER_OF_PAGE_COLUMNS, 1); + timeoutComposite.setLayoutData(gd); + + PixelConverter pixelConverter= new PixelConverter(composite); + String str= PreferencesMessages.CodeAssistAdvancedConfigurationBlock_parameterNameFromAttachedJavadoc_timeout; + addTextField(timeoutComposite, str, PREF_CODEASSIST_TIMEOUT_FOR_PARAMETER_NAME_FROM_ATTACHED_JAVADOC, 0, pixelConverter.convertWidthInCharsToPixels(7)); + } + + private void selectFirstProvidedCategory() { + if (fModel.elements.size() > 0) { + fProvidedViewer.getTable().select(0); + } + } + + /* + * @see org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock#settingsUpdated() + */ + @Override + protected void settingsUpdated() { + if (fModel != null) + fModel.updatePreferenceModel(); + } + + /* + * @see org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock#updateControls() + */ + @Override + protected void updateControls() { + super.updateControls(); + fProvidedViewer.refresh(); + fProposalListSection.updateControls(); + } + + /* + * @see org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock#processChanges(org.eclipse.ui.preferences.IWorkbenchPreferenceContainer) + */ + @Override + protected boolean processChanges(IWorkbenchPreferenceContainer container) { + fModel.updatePreferenceModel(); + return super.processChanges(container); + } + + /* + * @see org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock#setValue(Key, String) + */ + @Override + protected String setValue(Key key, String value) { + return super.setValue(key, value); + } + + /* + * @see org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock#getValue(Key) + */ + @Override + protected String getValue(Key key) { + return super.getValue(key); + } + + /* + * @see org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock#validateSettings(org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock.Key, java.lang.String, java.lang.String) + */ + @Override + protected void validateSettings(Key changedKey, String oldValue, String newValue) { + if (changedKey == PREF_CODEASSIST_TIMEOUT_FOR_PARAMETER_NAME_FROM_ATTACHED_JAVADOC) { + final StatusInfo status= new StatusInfo(); + if (newValue.length() == 0) + status.setError(PreferencesMessages.CodeAssistAdvancedConfigurationBlock_parameterNameFromAttachedJavadoc_timeout_emptyInput); + else { + try { + int number= Integer.parseInt(newValue); + int min= 0; + int max= 5000; + if (number < min || number > max) { + String msgFormat= PreferencesMessages.CodeAssistAdvancedConfigurationBlock_parameterNameFromAttachedJavadoc_timeout_invalidRange; + String msg= Messages.format(msgFormat, new Object[] { new Integer(min), new Integer(max) }); + status.setError(msg); + } + } catch (NumberFormatException ex) { + String msgFormat= PreferencesMessages.CodeAssistAdvancedConfigurationBlock_parameterNameFromAttachedJavadoc_timeout_invalidInput; + String msg= Messages.format(msgFormat, newValue); + status.setError(msg); + } + } + fContext.statusChanged(status); + } + } + + /* + * @see org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock#getFullBuildDialogStrings(boolean) + */ + @Override + protected String[] getFullBuildDialogStrings(boolean workspaceSettings) { + // no builds triggered by our settings + return null; + } + + /* + * @see org.eclipse.jdt.internal.ui.preferences.OptionsConfigurationBlock#dispose() + */ + @Override + public void dispose() { + for (Iterator it= fImages.values().iterator(); it.hasNext();) { + Image image= it.next(); + image.dispose(); + } + super.dispose(); + } + + protected int computeWidth(Control control, String name) { + if (name == null) + return 0; + GC gc= new GC(control); + try { + gc.setFont(JFaceResources.getDialogFont()); + return gc.stringExtent(name).x + 10; + } finally { + gc.dispose(); + } + } + + protected Image getImage(ImageDescriptor imgDesc) { + if (imgDesc == null) + return null; + + Image img= fImages.get(imgDesc); + if (img == null) { + img= imgDesc.createImage(false); + fImages.put(imgDesc, img); + } + return img; + } + + private static BindingManager fgLocalBindingManager; + static { + fgLocalBindingManager= new BindingManager(new ContextManager(), new CommandManager()); + final IBindingService bindingService= (IBindingService) PlatformUI.getWorkbench().getService(IBindingService.class); + final Scheme[] definedSchemes= bindingService.getDefinedSchemes(); + if (definedSchemes != null) { + try { + for (int i= 0; i < definedSchemes.length; i++) { + final Scheme scheme= definedSchemes[i]; + final Scheme copy= fgLocalBindingManager.getScheme(scheme.getId()); + copy.define(scheme.getName(), scheme.getDescription(), scheme.getParentId()); + } + } catch (final NotDefinedException e) { + JavaPlugin.log(e); + } + } + fgLocalBindingManager.setLocale(bindingService.getLocale()); + fgLocalBindingManager.setPlatform(bindingService.getPlatform()); + } + + protected static String getKeyboardShortcut(ParameterizedCommand command) { + IBindingService bindingService= (IBindingService) PlatformUI.getWorkbench().getAdapter(IBindingService.class); + fgLocalBindingManager.setBindings(bindingService.getBindings()); + try { + Scheme activeScheme= bindingService.getActiveScheme(); + if (activeScheme != null) + fgLocalBindingManager.setActiveScheme(activeScheme); + } catch (NotDefinedException e) { + JavaPlugin.log(e); + } + + TriggerSequence[] bindings= fgLocalBindingManager.getActiveBindingsDisregardingContextFor(command); + if (bindings.length > 0) + return bindings[0].format(); + return null; + } +} Index: ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/CodeAssistAdvancedUtilitiesProxy.java =================================================================== RCS file: ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/CodeAssistAdvancedUtilitiesProxy.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/CodeAssistAdvancedUtilitiesProxy.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,103 @@ +/** + * Copyright (c) 2011 Thomas Schlosser. + * 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: + * Thomas Schlosser - initial API and implementation. + */ +package org.eclipse.jdt.internal.ui.preferences.codeassist.advanced; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.dnd.DND; +import org.eclipse.swt.dnd.TransferData; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; + +import org.eclipse.core.commands.ParameterizedCommand; + +import org.eclipse.jface.resource.ImageDescriptor; + +import org.eclipse.ui.plugin.AbstractUIPlugin; + +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.dnd.ProposalListCategoryTransfer; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.dnd.ProposalListTransfer; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.dnd.ProvidedCategoryTransfer; + +/** + * + * @since 3.8 + */ +public class CodeAssistAdvancedUtilitiesProxy { + public static final Color SELECTED_COLOR= Display.getCurrent().getSystemColor(SWT.COLOR_LIST_SELECTION); + + public static final Color SELECTED_TEXT_COLOR= Display.getCurrent().getSystemColor(SWT.COLOR_LIST_SELECTION_TEXT); + + public static final Color UNSELECTED_COLOR= Display.getCurrent().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND); + + public static final Color UNSELECTED_TEXT_COLOR= Display.getCurrent().getSystemColor(SWT.COLOR_WIDGET_FOREGROUND); + + public static final Color UNSELECTED_BORDER_COLOR= Display.getCurrent().getSystemColor(SWT.COLOR_GRAY); + + private static final ImageDescriptor REMOVE_PROPOSAL_LIST_ICON_DESCRIPTOR= AbstractUIPlugin.imageDescriptorFromPlugin("org.eclipse.jdt.ui", "$nl$/icons/full/elcl16/remove_proposal_list.gif"); //$NON-NLS-1$ //$NON-NLS-2$ + + private static final ImageDescriptor REMOVE_PROPOSAL_LIST_OVER_ICON_DESCRIPTOR= AbstractUIPlugin.imageDescriptorFromPlugin( + "org.eclipse.jdt.ui", "$nl$/icons/full/elcl16/remove_proposal_list_over.gif"); //$NON-NLS-1$ //$NON-NLS-2$ + + private CodeAssistAdvancedConfigurationBlock fConfigurationBlock; + + public final Image fRemoveProposalListImage; + + public final Image fRemoveProposalListOverImage; + + public CodeAssistAdvancedUtilitiesProxy(CodeAssistAdvancedConfigurationBlock configurationBlock) { + this.fConfigurationBlock= configurationBlock; + fRemoveProposalListImage= getImage(REMOVE_PROPOSAL_LIST_ICON_DESCRIPTOR); + fRemoveProposalListOverImage= getImage(REMOVE_PROPOSAL_LIST_OVER_ICON_DESCRIPTOR); + } + + public void updateControls() { + fConfigurationBlock.updateControls(); + } + + public int computeWidth(Control control, String name) { + return fConfigurationBlock.computeWidth(control, name); + } + + public Image getImage(ImageDescriptor imgDesc) { + return fConfigurationBlock.getImage(imgDesc); + } + + public String getKeyboardShortcut(ParameterizedCommand command) { + return CodeAssistAdvancedConfigurationBlock.getKeyboardShortcut(command); + } + + public String setValue(String value) { + return fConfigurationBlock.setValue(CodeAssistAdvancedConfigurationBlock.PREF_PROPOSAL_LISTS, value); + } + + public String getValue() { + return fConfigurationBlock.getValue(CodeAssistAdvancedConfigurationBlock.PREF_PROPOSAL_LISTS); + } + + public void validateSettings(String oldValue, String newValue) { + fConfigurationBlock.validateSettings(CodeAssistAdvancedConfigurationBlock.PREF_PROPOSAL_LISTS, oldValue, newValue); + } + + public static int getCompatibleOperation(int operation, int supportedOperations, TransferData currentDataType) { + int result= ProvidedCategoryTransfer.getInstance().getCompatibleOperation(operation, supportedOperations, currentDataType); + if (result != -1) + return result; + result= ProposalListTransfer.getInstance().getCompatibleOperation(operation, supportedOperations, currentDataType); + if (result != -1) + return result; + result= ProposalListCategoryTransfer.getInstance().getCompatibleOperation(operation, supportedOperations, currentDataType); + if (result != -1) + return result; + return DND.DROP_NONE; + } +} Index: ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/dnd/AutoscrollDropTargetListener.java =================================================================== RCS file: ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/dnd/AutoscrollDropTargetListener.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/dnd/AutoscrollDropTargetListener.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2011 Thomas Schlosser. + * 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: + * Thomas Schlosser - initial API and implementation. + */ +package org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.dnd; + +import org.eclipse.swt.dnd.DND; +import org.eclipse.swt.dnd.DropTargetEvent; +import org.eclipse.swt.dnd.DropTargetListener; + +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.widgets.ProposalListSection; + +/** + * + * @since 3.8 + */ +public final class AutoscrollDropTargetListener implements DropTargetListener { + private ProposalListSection fProposalListSection; + + public AutoscrollDropTargetListener(ProposalListSection proposalListSection) { + this.fProposalListSection= proposalListSection; + } + + public void dragEnter(DropTargetEvent event) { + event.detail= DND.DROP_NONE; + } + + public void dragLeave(DropTargetEvent event) { + } + + public void dragOperationChanged(DropTargetEvent event) { + event.detail= DND.DROP_NONE; + } + + public void dragOver(DropTargetEvent event) { + fProposalListSection.autoScroll(event); + } + + public void drop(DropTargetEvent event) { + event.detail= DND.DROP_NONE; + } + + public void dropAccept(DropTargetEvent event) { + event.detail= DND.DROP_NONE; + } +} Index: ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/dnd/DragProposalListCategoryListener.java =================================================================== RCS file: ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/dnd/DragProposalListCategoryListener.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/dnd/DragProposalListCategoryListener.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2011 Thomas Schlosser. + * 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: + * Thomas Schlosser - initial API and implementation. + */ +package org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.dnd; + +import org.eclipse.swt.dnd.DragSourceEvent; +import org.eclipse.swt.dnd.DragSourceListener; + +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.TableViewer; + +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.model.ModelElement; + +/** + * + * @since 3.8 + */ +public final class DragProposalListCategoryListener implements DragSourceListener { + private final TableViewer fViewer; + + private final Integer fListIndex; + + public DragProposalListCategoryListener(TableViewer viewer, int listIndex) { + this.fViewer= viewer; + this.fListIndex= Integer.valueOf(listIndex); + } + + public void dragSetData(DragSourceEvent event) { + if (ProposalListCategoryTransfer.getInstance().isSupportedType(event.dataType)) { + IStructuredSelection selection= (IStructuredSelection) fViewer.getSelection(); + if (fViewer.getSelection() != null && !fViewer.getSelection().isEmpty()) { + ModelElement firstElement= (ModelElement) selection.getFirstElement(); + if (firstElement != null) + event.data= new ProposalTransferType[] { new ProposalTransferType(firstElement.getId(), fListIndex) }; + } + } + } + + public void dragStart(DragSourceEvent event) { + if (fViewer.getSelection() == null || fViewer.getSelection().isEmpty() || ((IStructuredSelection) fViewer.getSelection()).getFirstElement() == null) { + event.doit= false; + } + } + + public void dragFinished(DragSourceEvent event) { + } +} Index: ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/dnd/DragProposalListListener.java =================================================================== RCS file: ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/dnd/DragProposalListListener.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/dnd/DragProposalListListener.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2011 Thomas Schlosser. + * 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: + * Thomas Schlosser - initial API and implementation. + */ +package org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.dnd; + +import org.eclipse.swt.dnd.DragSourceEvent; +import org.eclipse.swt.dnd.DragSourceListener; + +/** + * + * @since 3.8 + */ +public final class DragProposalListListener implements DragSourceListener { + private final Integer fListIndex; + + public DragProposalListListener(int listIndex) { + this.fListIndex= Integer.valueOf(listIndex); + } + + public void dragSetData(DragSourceEvent event) { + if (ProposalListTransfer.getInstance().isSupportedType(event.dataType)) { + event.data= new ProposalTransferType[] { new ProposalTransferType(fListIndex) }; + } + } + + public void dragStart(DragSourceEvent event) { + } + + public void dragFinished(DragSourceEvent event) { + } +} Index: ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/dnd/DragProvidedCategoryListener.java =================================================================== RCS file: ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/dnd/DragProvidedCategoryListener.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/dnd/DragProvidedCategoryListener.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2011 Thomas Schlosser. + * 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: + * Thomas Schlosser - initial API and implementation. + */ +package org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.dnd; + +import org.eclipse.swt.dnd.DragSourceEvent; +import org.eclipse.swt.dnd.DragSourceListener; + +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.TableViewer; + +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.model.ModelElement; + +/** + * + * @since 3.8 + */ +public final class DragProvidedCategoryListener implements DragSourceListener { + private final TableViewer fViewer; + + public DragProvidedCategoryListener(TableViewer viewer) { + this.fViewer= viewer; + } + + public void dragSetData(DragSourceEvent event) { + if (ProvidedCategoryTransfer.getInstance().isSupportedType(event.dataType)) { + IStructuredSelection selection= (IStructuredSelection) fViewer.getSelection(); + if (fViewer.getSelection() != null && !fViewer.getSelection().isEmpty()) { + ModelElement firstElement= (ModelElement) selection.getFirstElement(); + if (firstElement != null) + event.data= new ProposalTransferType[] { new ProposalTransferType(firstElement.getId()) }; + } + } + } + + public void dragStart(DragSourceEvent event) { + if (fViewer.getSelection() == null || fViewer.getSelection().isEmpty() || ((IStructuredSelection) fViewer.getSelection()).getFirstElement() == null) { + event.doit= false; + } + } + + public void dragFinished(DragSourceEvent event) { + } +} Index: ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/dnd/DropIntoProposalListListener.java =================================================================== RCS file: ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/dnd/DropIntoProposalListListener.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/dnd/DropIntoProposalListListener.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,144 @@ +/** + * Copyright (c) 2011 Thomas Schlosser. + * 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: + * Thomas Schlosser - initial API and implementation. + */ +package org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.dnd; + +import org.eclipse.swt.dnd.DND; +import org.eclipse.swt.dnd.DropTargetEvent; +import org.eclipse.swt.dnd.TransferData; + +import org.eclipse.jface.viewers.ViewerDropAdapter; + +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.CodeAssistAdvancedUtilitiesProxy; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.model.PreferenceModel; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.widgets.ProposalList; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.widgets.ProposalListSection; + +/** + * + * @since 3.8 + */ +public final class DropIntoProposalListListener extends ViewerDropAdapter { + private final PreferenceModel fModel; + + private final CodeAssistAdvancedUtilitiesProxy fUtilitiesProxy; + + private final int fListIndex; + + private final ProposalListSection fProposalListSection; + + private final ProposalList fProposalList; + + public DropIntoProposalListListener(ProposalList proposalList, int listIndex, PreferenceModel model, CodeAssistAdvancedUtilitiesProxy utilitiesProxy, ProposalListSection proposalListSection) { + super(proposalList.getTableViewer()); + this.fListIndex= listIndex; + this.fProposalList= proposalList; + this.fModel= model; + this.fUtilitiesProxy= utilitiesProxy; + this.fProposalListSection= proposalListSection; + } + + @Override + public void dragEnter(DropTargetEvent event) { + event.detail= CodeAssistAdvancedUtilitiesProxy.getCompatibleOperation(event.detail, event.operations, event.currentDataType); + } + + @Override + public void drop(DropTargetEvent event) { + super.drop(event); + drop: { + if (event.data == null) + break drop; + ProposalTransferType data= ((ProposalTransferType[]) event.data)[0]; + if (data.getListIndex() == null && fModel.isValidCategoryId(data.getCategoryId())) { + // category dragged from provided list + switch (event.detail) { + case DND.DROP_COPY: + fModel.getElement(data.getCategoryId()).setInProposalList(fListIndex); + break; + default: + break drop; + } + fUtilitiesProxy.updateControls(); + return; + } + if (data.getListIndex() == null) + break drop; + int sourceListIndex= data.getListIndex().intValue(); + if (sourceListIndex == fListIndex) + break drop; + if (data.getCategoryId() == null) { + // proposal list has been dragged + switch (event.detail) { + case DND.DROP_COPY: + // COPY all elements from source list to this list + fModel.mergeLists(sourceListIndex, fListIndex, false); + break; + case DND.DROP_MOVE: + // MOVE all elements from source list to this list + fModel.mergeLists(sourceListIndex, fListIndex, true); + break; + default: + break drop; + } + fUtilitiesProxy.updateControls(); + return; + } + if (fModel.isValidCategoryId(data.getCategoryId())) { + // category dragged from proposal list + switch (event.detail) { + case DND.DROP_COPY: + fModel.getElement(data.getCategoryId()).setInProposalList(fListIndex); + break; + case DND.DROP_MOVE: + fModel.getElement(data.getCategoryId()).moveToProposalList(sourceListIndex, fListIndex); + break; + default: + break drop; + } + fUtilitiesProxy.updateControls(); + return; + } + } + event.detail= DND.DROP_NONE; + } + + @Override + public boolean performDrop(Object data) { + return true; // behavior completely implemented in drop-method + } + + @Override + public void dragOperationChanged(DropTargetEvent event) { + event.detail= CodeAssistAdvancedUtilitiesProxy.getCompatibleOperation(event.detail, event.operations, event.currentDataType); + if (event.detail == DND.DROP_NONE) + fProposalList.highlight(false); + } + + @Override + public boolean validateDrop(Object target, int operation, TransferData transferType) { + return ProvidedCategoryTransfer.getInstance().isSupportedType(transferType) || + ProposalListCategoryTransfer.getInstance().isSupportedType(transferType) || + ProposalListTransfer.getInstance().isSupportedType(transferType); + } + + @Override + public void dragOver(DropTargetEvent event) { + event.feedback= DND.FEEDBACK_NONE; + if (event.detail != DND.DROP_NONE) + fProposalList.highlight(true); + fProposalListSection.autoScroll(event); + } + + @Override + public void dragLeave(DropTargetEvent event) { + fProposalList.highlight(false); + } +} Index: ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/dnd/DropIntoProvidedListener.java =================================================================== RCS file: ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/dnd/DropIntoProvidedListener.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/dnd/DropIntoProvidedListener.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,82 @@ +/** + * Copyright (c) 2011 Thomas Schlosser. + * 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: + * Thomas Schlosser - initial API and implementation. + */ +package org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.dnd; + +import org.eclipse.swt.dnd.DND; +import org.eclipse.swt.dnd.DropTargetEvent; +import org.eclipse.swt.dnd.TransferData; + +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.ViewerDropAdapter; + +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.CodeAssistAdvancedUtilitiesProxy; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.model.PreferenceModel; + +/** + * + * @since 3.8 + */ +public final class DropIntoProvidedListener extends ViewerDropAdapter { + private final PreferenceModel fModel; + + private final CodeAssistAdvancedUtilitiesProxy fUtilitiesProxy; + + public DropIntoProvidedListener(TableViewer viewer, PreferenceModel model, CodeAssistAdvancedUtilitiesProxy utilitiesProxy) { + super(viewer); + this.fModel= model; + this.fUtilitiesProxy= utilitiesProxy; + } + + @Override + public boolean validateDrop(Object target, int operation, TransferData transferType) { + return ProposalListCategoryTransfer.getInstance().isSupportedType(transferType) || + ProposalListTransfer.getInstance().isSupportedType(transferType); + } + + @Override + public boolean performDrop(Object data) { + ProposalTransferType transferData= ((ProposalTransferType[]) data)[0]; + if (transferData.getListIndex() != null) { + int listIndex= transferData.getListIndex().intValue(); + if (fModel.isValidCategoryId(transferData.getCategoryId())) + // category dragged from proposal list + fModel.getElement(transferData.getCategoryId()).removeInProposalList(listIndex); + else if (transferData.getCategoryId() == null) + // proposal list has been dragged + fModel.removeList(listIndex); + fUtilitiesProxy.updateControls(); + return true; + } + return false; + } + + @Override + public void dragEnter(DropTargetEvent event) { + event.detail= this.getCompatibleOperation(event.detail, event.operations, event.currentDataType); + } + + @Override + public void dragOperationChanged(DropTargetEvent event) { + event.detail= this.getCompatibleOperation(event.detail, event.operations, event.currentDataType); + } + + @Override + public void dragOver(DropTargetEvent event) { + event.feedback= DND.FEEDBACK_NONE; + } + + private int getCompatibleOperation(int detail, int operations, TransferData currentDataType) { + int operation= CodeAssistAdvancedUtilitiesProxy.getCompatibleOperation(detail, operations, currentDataType); + if (operation != DND.DROP_MOVE) + return DND.DROP_NONE; + return operation; + } +} Index: ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/dnd/DropNewProposalListListener.java =================================================================== RCS file: ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/dnd/DropNewProposalListListener.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/dnd/DropNewProposalListListener.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,138 @@ +/** + * Copyright (c) 2011 Thomas Schlosser. + * 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: + * Thomas Schlosser - initial API and implementation. + */ +package org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.dnd; + +import java.util.Arrays; + +import org.eclipse.swt.dnd.DND; +import org.eclipse.swt.dnd.DropTargetEvent; +import org.eclipse.swt.dnd.DropTargetListener; +import org.eclipse.swt.widgets.Composite; + +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.CodeAssistAdvancedUtilitiesProxy; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.model.PreferenceModel; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.widgets.ProposalListSection; + +/** + * + * @since 3.8 + */ +public final class DropNewProposalListListener implements DropTargetListener { + + private final ProposalListSection fProposalListSection; + + private final Composite fHighlightComposite; + + private final int fListIndex; + + private final PreferenceModel fModel; + + private final CodeAssistAdvancedUtilitiesProxy fUtilitiesProxy; + + public DropNewProposalListListener(Composite highlightComposite, int listIndex, PreferenceModel model, CodeAssistAdvancedUtilitiesProxy utilitiesProxy, ProposalListSection proposalListSection) { + this.fHighlightComposite= highlightComposite; + this.fListIndex= listIndex; + this.fModel= model; + this.fUtilitiesProxy= utilitiesProxy; + this.fProposalListSection= proposalListSection; + } + + public void dragEnter(DropTargetEvent event) { + event.detail= CodeAssistAdvancedUtilitiesProxy.getCompatibleOperation(event.detail, event.operations, event.currentDataType); + } + + public void dragOperationChanged(DropTargetEvent event) { + event.detail= CodeAssistAdvancedUtilitiesProxy.getCompatibleOperation(event.detail, event.operations, event.currentDataType); + if (event.detail == DND.DROP_NONE) + highlight(false); + } + + public void dragOver(DropTargetEvent event) { + if (event.detail != DND.DROP_NONE) { + highlight(true); + } + fProposalListSection.autoScroll(event); + } + + public void dragLeave(DropTargetEvent event) { + highlight(false); + } + + private void highlight(boolean selected) { + if (selected) + fHighlightComposite.setBackground(CodeAssistAdvancedUtilitiesProxy.SELECTED_COLOR); + else + fHighlightComposite.setBackground(CodeAssistAdvancedUtilitiesProxy.UNSELECTED_COLOR); + fHighlightComposite.update(); + } + + public void drop(DropTargetEvent event) { + drop: { + if (event.data == null) + break drop; + ProposalTransferType data= ((ProposalTransferType[]) event.data)[0]; + if (data.getListIndex() == null && fModel.isValidCategoryId(data.getCategoryId())) { + // category dragged from provided list + switch (event.detail) { + case DND.DROP_COPY: + fModel.addNewList(fListIndex, Arrays.asList(data.getCategoryId())); + break; + default: + break drop; + } + fUtilitiesProxy.updateControls(); + return; + } + if (data.getListIndex() == null) + break drop; + int sourceListIndex= data.getListIndex().intValue(); + if (data.getCategoryId() == null) { + // proposal list has been dragged + switch (event.detail) { + case DND.DROP_COPY: + fModel.addNewList(fListIndex, fModel.getCategoryIds(sourceListIndex)); + break; + case DND.DROP_MOVE: + if (sourceListIndex != fListIndex && sourceListIndex + 1 != fListIndex) + fModel.moveList(sourceListIndex, fListIndex); + else + break drop; + break; + default: + break drop; + } + fUtilitiesProxy.updateControls(); + return; + } + if (fModel.isValidCategoryId(data.getCategoryId())) { + // category dragged from proposal list + switch (event.detail) { + case DND.DROP_MOVE: + fModel.addNewList(fListIndex, Arrays.asList(data.getCategoryId())); + int removeIndex= fListIndex > sourceListIndex ? sourceListIndex : sourceListIndex + 1; + fModel.getElement(data.getCategoryId()).removeInProposalList(removeIndex); + break; + case DND.DROP_COPY: + fModel.addNewList(fListIndex, Arrays.asList(data.getCategoryId())); + break; + default: + break drop; + } + fUtilitiesProxy.updateControls(); + return; + } + } + event.detail= DND.DROP_NONE; + } + + public void dropAccept(DropTargetEvent event) { + } +} Index: ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/dnd/ProposalListCategoryTransfer.java =================================================================== RCS file: ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/dnd/ProposalListCategoryTransfer.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/dnd/ProposalListCategoryTransfer.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2011 Thomas Schlosser. + * 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: + * Thomas Schlosser - initial API and implementation. + */ +package org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.dnd; + +import org.eclipse.swt.dnd.DND; + +/** + * + * @since 3.8 + */ +public final class ProposalListCategoryTransfer extends ProposalTransfer { + private static final String TRANSFER_NAME= "ProposalListCategoryTransfer"; //$NON-NLS-1$ + + private static final ProposalListCategoryTransfer instance= new ProposalListCategoryTransfer(); + + private ProposalListCategoryTransfer() { + super(TRANSFER_NAME); + } + + public static ProposalListCategoryTransfer getInstance() { + return instance; + } + + @Override + public int getDefaultOperation(int supportedOperations) { + if ((supportedOperations & DND.DROP_MOVE) != 0) + return DND.DROP_MOVE; + else if ((supportedOperations & DND.DROP_COPY) != 0) + return DND.DROP_COPY; + return DND.DROP_NONE; + } + + @Override + public boolean isSupportedOperation(int operation) { + return operation == DND.DROP_COPY || operation == DND.DROP_MOVE; + } +} Index: ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/dnd/ProposalListTransfer.java =================================================================== RCS file: ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/dnd/ProposalListTransfer.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/dnd/ProposalListTransfer.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2011 Thomas Schlosser. + * 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: + * Thomas Schlosser - initial API and implementation. + */ +package org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.dnd; + +import org.eclipse.swt.dnd.DND; + +/** + * + * @since 3.8 + */ +public final class ProposalListTransfer extends ProposalTransfer { + private static final String TRANSFER_NAME= "ProposalListTransfer"; //$NON-NLS-1$ + + private static final ProposalListTransfer instance= new ProposalListTransfer(); + + private ProposalListTransfer() { + super(TRANSFER_NAME); + } + + public static ProposalListTransfer getInstance() { + return instance; + } + + @Override + public int getDefaultOperation(int supportedOperations) { + if ((supportedOperations & DND.DROP_MOVE) != 0) + return DND.DROP_MOVE; + else if ((supportedOperations & DND.DROP_COPY) != 0) + return DND.DROP_COPY; + return DND.DROP_NONE; + } + + @Override + public boolean isSupportedOperation(int operation) { + return operation == DND.DROP_COPY || operation == DND.DROP_MOVE; + } +} Index: ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/dnd/ProposalTransfer.java =================================================================== RCS file: ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/dnd/ProposalTransfer.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/dnd/ProposalTransfer.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,148 @@ +/** + * Copyright (c) 2011 Thomas Schlosser. + * 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: + * Thomas Schlosser - initial API and implementation. + */ +package org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.dnd; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.swt.dnd.ByteArrayTransfer; +import org.eclipse.swt.dnd.DND; +import org.eclipse.swt.dnd.TransferData; + +/** + * + * @since 3.8 + */ +public abstract class ProposalTransfer extends ByteArrayTransfer { + public static final int ALL_DRAG_OPERATIONS= DND.DROP_COPY | DND.DROP_DEFAULT | DND.DROP_LINK | DND.DROP_MOVE | DND.DROP_TARGET_MOVE; + + private final String fTransferName; + + private final int fTransferId; + + protected ProposalTransfer(String transferName) { + this.fTransferName= transferName; + this.fTransferId= registerType(transferName); + } + + public abstract int getDefaultOperation(int supportedOperations); + + public abstract boolean isSupportedOperation(int operation); + + @Override + public void javaToNative(Object object, TransferData transferData) { + if (!checkProposalTransferType(object) || !isSupportedType(transferData)) + DND.error(DND.ERROR_INVALID_DATA); + ProposalTransferType[] props= (ProposalTransferType[]) object; + ByteArrayOutputStream out= new ByteArrayOutputStream(); + DataOutputStream writeOut= new DataOutputStream(out); + try { + for (int i= 0, length= props.length; i < length; i++) { + if (props[i].getCategoryId() != null) { + byte[] buffer= props[i].getCategoryId().getBytes(); + writeOut.writeInt(buffer.length); + writeOut.write(buffer); + } else + writeOut.writeInt(0); + Integer index= props[i].getListIndex(); + writeOut.writeInt(index == null ? -1 : index.intValue()); + } + byte[] buffer= out.toByteArray(); + super.javaToNative(buffer, transferData); + } catch (IOException e) { + } finally { + try { + writeOut.close(); + } catch (IOException e) { + } + } + } + + @Override + public Object nativeToJava(TransferData transferData) { + if (isSupportedType(transferData)) { + byte[] buffer= (byte[]) super.nativeToJava(transferData); + if (buffer == null) + return null; + + List props= new ArrayList(); + ByteArrayInputStream in= new ByteArrayInputStream(buffer); + DataInputStream readIn= new DataInputStream(in); + try { + while (readIn.available() > 0) { + ProposalTransferType proposal= new ProposalTransferType(); + int size= readIn.readInt(); + if (size == 0) + proposal.setCategoryId(null); + else { + byte[] id= new byte[size]; + readIn.read(id); + proposal.setCategoryId(new String(id)); + } + int index= readIn.readInt(); + proposal.setListIndex(index < 0 ? null : Integer.valueOf(index)); + props.add(proposal); + } + } catch (IOException ex) { + return null; + } finally { + try { + readIn.close(); + } catch (IOException e) { + return null; + } + } + return props.toArray(new ProposalTransferType[0]); + } + return null; + } + + @Override + protected int[] getTypeIds() { + return new int[] { fTransferId }; + } + + @Override + protected String[] getTypeNames() { + return new String[] { fTransferName }; + } + + @Override + protected boolean validate(Object object) { + return checkProposalTransferType(object); + } + + public int getCompatibleOperation(int operation, int supportedOperations, TransferData currentDataType) { + if (this.isSupportedType(currentDataType)) { + if (operation == DND.DROP_DEFAULT) + return this.getDefaultOperation(supportedOperations); + if (this.isSupportedOperation(operation) && (supportedOperations & operation) != 0) + return operation; + return DND.DROP_NONE; + } + return -1; + } + + private boolean checkProposalTransferType(Object object) { + if (object == null || !(object instanceof ProposalTransferType[]) || ((ProposalTransferType[]) object).length == 0) + return false; + ProposalTransferType[] cats= (ProposalTransferType[]) object; + for (ProposalTransferType category : cats) + if (category == null || ((category.getCategoryId() == null || category.getCategoryId().length() == 0) && category.getListIndex() == null)) + return false; + return true; + } +} Index: ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/dnd/ProposalTransferType.java =================================================================== RCS file: ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/dnd/ProposalTransferType.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/dnd/ProposalTransferType.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,53 @@ +/** + * Copyright (c) 2011 Thomas Schlosser. + * 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: + * Thomas Schlosser - initial API and implementation. + */ +package org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.dnd; + +/** + * + * @since 3.8 + */ +public final class ProposalTransferType { + private Integer fListIndex; + + private String fCategoryId; + + public ProposalTransferType() { + } + + public ProposalTransferType(String categoryId) { + this.fCategoryId= categoryId; + } + + public ProposalTransferType(Integer listIndex) { + this.fListIndex= listIndex; + } + + public ProposalTransferType(String categoryId, Integer listIndex) { + this.fCategoryId= categoryId; + this.fListIndex= listIndex; + } + + public Integer getListIndex() { + return fListIndex; + } + + public void setListIndex(Integer listIndex) { + fListIndex= listIndex; + } + + public String getCategoryId() { + return fCategoryId; + } + + public void setCategoryId(String categoryId) { + fCategoryId= categoryId; + } +} Index: ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/dnd/ProvidedCategoryTransfer.java =================================================================== RCS file: ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/dnd/ProvidedCategoryTransfer.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/dnd/ProvidedCategoryTransfer.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2011 Thomas Schlosser. + * 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: + * Thomas Schlosser - initial API and implementation. + */ +package org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.dnd; + +import org.eclipse.swt.dnd.DND; + +/** + * + * @since 3.8 + */ +public final class ProvidedCategoryTransfer extends ProposalTransfer { + private static final String TRANSFER_NAME= "ProvidedCategoryTransfer"; //$NON-NLS-1$ + + private static final ProvidedCategoryTransfer instance= new ProvidedCategoryTransfer(); + + private ProvidedCategoryTransfer() { + super(TRANSFER_NAME); + } + + public static ProvidedCategoryTransfer getInstance() { + return instance; + } + + @Override + public int getDefaultOperation(int supportedOperations) { + if ((supportedOperations & DND.DROP_COPY) != 0) + return DND.DROP_COPY; + return DND.DROP_NONE; + } + + @Override + public boolean isSupportedOperation(int operation) { + return operation == DND.DROP_COPY; + } +} Index: ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/model/ModelElement.java =================================================================== RCS file: ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/model/ModelElement.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/model/ModelElement.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,128 @@ +/** + * Copyright (c) 2011 Thomas Schlosser. + * 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: + * Thomas Schlosser - initial API and implementation. + */ +package org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.model; + +import java.util.Comparator; +import java.util.Set; + +import org.eclipse.swt.graphics.Image; + +import org.eclipse.core.commands.Command; +import org.eclipse.core.commands.IParameter; +import org.eclipse.core.commands.Parameterization; +import org.eclipse.core.commands.ParameterizedCommand; +import org.eclipse.core.commands.common.NotDefinedException; + +import org.eclipse.core.runtime.Assert; + +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerComparator; + +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.commands.ICommandService; + +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.CodeAssistAdvancedUtilitiesProxy; +import org.eclipse.jdt.internal.ui.text.java.CompletionProposalCategory; + +/** + * + * @since 3.8 + */ +public final class ModelElement { + + public static final class ModelElementComparator implements Comparator { + public int compare(ModelElement o1, ModelElement o2) { + return o1.getName().compareTo(o2.getName()); + } + } + + public static final class ModelElementViewerComparator extends ViewerComparator { + @Override + public int compare(Viewer viewer, Object e1, Object e2) { + ModelElement m1= (ModelElement) e1; + ModelElement m2= (ModelElement) e2; + return new ModelElementComparator().compare(m1, m2); + } + } + + private final CodeAssistAdvancedUtilitiesProxy fUtilitiesProxy; + + private final CompletionProposalCategory fCategory; + + private final Command fCommand; + + private final IParameter fParam; + + private final PreferenceModel fPreferenceModel; + + ModelElement(CompletionProposalCategory category, PreferenceModel model, CodeAssistAdvancedUtilitiesProxy utilitiesProxy) { + fCategory= category; + ICommandService commandSvc= (ICommandService) PlatformUI.getWorkbench().getAdapter(ICommandService.class); + fCommand= commandSvc.getCommand("org.eclipse.jdt.ui.specific_content_assist.command"); //$NON-NLS-1$ + IParameter type; + try { + type= fCommand.getParameters()[0]; + } catch (NotDefinedException x) { + Assert.isTrue(false); + type= null; + } + fParam= type; + fPreferenceModel= model; + fUtilitiesProxy= utilitiesProxy; + } + + public Image getImage() { + return fUtilitiesProxy.getImage(fCategory.getImageDescriptor()); + } + + public String getName() { + return fCategory.getDisplayName(); + } + + public String getKeybindingAsString() { + final Parameterization[] params= { new Parameterization(fParam, fCategory.getId()) }; + final ParameterizedCommand pCmd= new ParameterizedCommand(fCommand, params); + String key= fUtilitiesProxy.getKeyboardShortcut(pCmd); + return key; + } + + public Set getProposalListIndices() { + return fCategory.getProposalListIndices(); + } + + public boolean isInProposalList(int index) { + return getProposalListIndices().contains(Integer.valueOf(index)); + } + + public void setInProposalList(int index) { + if (!isInProposalList(index)) + fPreferenceModel.changeSingleCategory(this, Integer.valueOf(index), null); + } + + public void moveToProposalList(int sourceIndex, int targetIndex) { + if (!isInProposalList(targetIndex) || isInProposalList(sourceIndex)) + fPreferenceModel.changeSingleCategory(this, Integer.valueOf(targetIndex), Integer.valueOf(sourceIndex)); + } + + public void removeInProposalList(int index) { + if (isInProposalList(index)) + fPreferenceModel.changeSingleCategory(this, null, Integer.valueOf(index)); + } + + public String getId() { + return fCategory.getId(); + } + + void updateIndices(Set indices) { + fCategory.clearProposalListIndices(); + fCategory.addAllProposalListIndices(indices); + } +} Index: ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/model/PreferenceModel.java =================================================================== RCS file: ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/model/PreferenceModel.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/model/PreferenceModel.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,235 @@ +/** + * Copyright (c) 2011 Thomas Schlosser. + * 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: + * Thomas Schlosser - initial API and implementation. + */ +package org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.model; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.TreeMap; + +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.CodeAssistAdvancedUtilitiesProxy; +import org.eclipse.jdt.internal.ui.text.java.CompletionProposalCategory; +import org.eclipse.jdt.internal.ui.text.java.CompletionProposalComputerRegistry; + +/** + * + * @since 3.8 + */ +public final class PreferenceModel { + private static final String COLON= ":"; //$NON-NLS-1$ + + private static final String SEPARATOR= "\0"; //$NON-NLS-1$ + + private final CodeAssistAdvancedUtilitiesProxy fUtilitiesProxy; + + private final List fElements; + + /** + * The read-only list of elements. + */ + public final List elements; + + public PreferenceModel(CompletionProposalComputerRegistry registry, CodeAssistAdvancedUtilitiesProxy utilitiesProxy) { + fUtilitiesProxy= utilitiesProxy; + List categories= registry.getProposalCategories(); + fElements= new ArrayList(); + for (CompletionProposalCategory category : categories) + if (category.hasComputers()) + fElements.add(new ModelElement(category, this, fUtilitiesProxy)); + elements= Collections.unmodifiableList(fElements); + } + + public void changeSingleCategory(ModelElement changed, Integer addIndex, Integer removeIndex) { + int initialBufferSize= 50 * fElements.size(); + Map proposalListsCategories= new TreeMap(); + for (ModelElement item : fElements) { + Set indices= new HashSet(item.getProposalListIndices()); + if (changed == item) { + if (addIndex != null) + indices.add(addIndex); + if (removeIndex != null) + indices.remove(removeIndex); + } + for (Integer index : indices) { + StringBuffer buf= proposalListsCategories.get(index); + if (buf == null) { + buf= new StringBuffer(initialBufferSize); + proposalListsCategories.put(index, buf); + } + buf.append(item.getId()); + buf.append(COLON); + } + } + writeProposalListsPreferences(proposalListsCategories, initialBufferSize); + } + + public void removeList(int listIndex) { + int initialBufferSize= 50 * fElements.size(); + Map proposalListsCategories= new TreeMap(); + for (ModelElement item : fElements) { + for (int index : item.getProposalListIndices()) { + if (listIndex == index) + continue; + else if (index > listIndex) + index--; + StringBuffer buf= proposalListsCategories.get(Integer.valueOf(index)); + if (buf == null) { + buf= new StringBuffer(initialBufferSize); + proposalListsCategories.put(Integer.valueOf(index), buf); + } + buf.append(item.getId()); + buf.append(COLON); + } + } + writeProposalListsPreferences(proposalListsCategories, initialBufferSize); + } + + public void addNewList(int listIndex, List categoryIds) { + int initialBufferSize= 50 * fElements.size(); + Map proposalListsCategories= new TreeMap(); + for (ModelElement item : fElements) { + for (int index : item.getProposalListIndices()) { + if (index >= listIndex) + index++; + StringBuffer buf= proposalListsCategories.get(Integer.valueOf(index)); + if (buf == null) { + buf= new StringBuffer(initialBufferSize); + proposalListsCategories.put(Integer.valueOf(index), buf); + } + buf.append(item.getId()); + buf.append(COLON); + } + } + if (categoryIds != null && !categoryIds.isEmpty()) { + // add categories to new list + StringBuffer newListBuf= new StringBuffer(initialBufferSize); + proposalListsCategories.put(Integer.valueOf(listIndex), newListBuf); + for (String catId : categoryIds) { + newListBuf.append(catId); + newListBuf.append(COLON); + } + } + writeProposalListsPreferences(proposalListsCategories, initialBufferSize); + } + + public void moveList(int listIndex, int targetIndex) { + int initialBufferSize= 50 * fElements.size(); + Map proposalListsCategories= new TreeMap(); + for (ModelElement item : fElements) { + for (int index : item.getProposalListIndices()) { + if (index > listIndex && index < targetIndex) + index--; + else if (index >= targetIndex && index < listIndex) + index++; + else if (index == listIndex) + index= listIndex < targetIndex ? targetIndex - 1 : targetIndex; + StringBuffer buf= proposalListsCategories.get(Integer.valueOf(index)); + if (buf == null) { + buf= new StringBuffer(initialBufferSize); + proposalListsCategories.put(Integer.valueOf(index), buf); + } + buf.append(item.getId()); + buf.append(COLON); + } + } + writeProposalListsPreferences(proposalListsCategories, initialBufferSize); + } + + public void mergeLists(int sourceIndex, int targetIndex, boolean removeSource) { + int initialBufferSize= 50 * fElements.size(); + Map proposalListsCategories= new TreeMap(); + for (ModelElement item : fElements) { + Set indices= new HashSet(item.getProposalListIndices()); + if (indices.contains(Integer.valueOf(sourceIndex))) { + if (removeSource) + indices.remove(Integer.valueOf(sourceIndex)); + indices.add(Integer.valueOf(targetIndex)); + } + for (Integer index : indices) { + StringBuffer buf= proposalListsCategories.get(index); + if (buf == null) { + buf= new StringBuffer(initialBufferSize); + proposalListsCategories.put(index, buf); + } + buf.append(item.getId()); + buf.append(COLON); + } + } + writeProposalListsPreferences(proposalListsCategories, initialBufferSize); + } + + private void writeProposalListsPreferences(Map proposalListsCategories, int initialBufferSize) { + StringBuffer buf= new StringBuffer(initialBufferSize * proposalListsCategories.size()); + for (StringBuffer proposalList : proposalListsCategories.values()) { + buf.append(proposalList); + buf.append(SEPARATOR); + } + String newValue= buf.toString(); + String oldValue= fUtilitiesProxy.setValue(newValue); + fUtilitiesProxy.validateSettings(oldValue, newValue); + updatePreferenceModel(); + } + + public void updatePreferenceModel() { + Map> newConfig= new HashMap>(); + StringTokenizer tok= new StringTokenizer(fUtilitiesProxy.getValue(), SEPARATOR); + for (int listIndex= 0; tok.hasMoreTokens(); listIndex++) { + StringTokenizer inner= new StringTokenizer(tok.nextToken(), COLON); + if (inner.countTokens() == 0) + listIndex--; + while (inner.hasMoreTokens()) { + String categoryId= inner.nextToken(); + Set indices= newConfig.get(categoryId); + if (indices == null) { + indices= new HashSet(); + newConfig.put(categoryId, indices); + } + indices.add(Integer.valueOf(listIndex)); + } + } + for (ModelElement elem : fElements) + elem.updateIndices(newConfig.get(elem.getId())); + } + + public ModelElement getElement(String id) { + for (ModelElement el : fElements) + if (el.getId().equals(id)) + return el; + return null; + } + + public List getElements(int index) { + List result= new ArrayList(); + for (ModelElement el : fElements) + if (el.getProposalListIndices() != null && el.getProposalListIndices().contains(Integer.valueOf(index))) + result.add(el); + return result; + } + + public List getCategoryIds(int index) { + List result= new ArrayList(); + for (ModelElement el : fElements) + if (el.getProposalListIndices() != null && el.getProposalListIndices().contains(Integer.valueOf(index))) + result.add(el.getId()); + return result; + } + + public boolean isValidCategoryId(String id) { + if (id != null) + return getElement(id) != null; + return false; + } +} Index: ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/widgets/NewListDropSection.java =================================================================== RCS file: ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/widgets/NewListDropSection.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/widgets/NewListDropSection.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,93 @@ +/** + * Copyright (c) 2011 Thomas Schlosser. + * 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: + * Thomas Schlosser - initial API and implementation. + */ +package org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.widgets; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.dnd.DropTarget; +import org.eclipse.swt.dnd.Transfer; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; + +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.CodeAssistAdvancedUtilitiesProxy; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.dnd.DropNewProposalListListener; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.dnd.ProposalListCategoryTransfer; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.dnd.ProposalListTransfer; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.dnd.ProposalTransfer; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.dnd.ProvidedCategoryTransfer; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.model.PreferenceModel; + +/** + * + * @since 3.8 + */ +public final class NewListDropSection { + private final PreferenceModel fModel; + + private final CodeAssistAdvancedUtilitiesProxy fUtilitiesProxy; + + private final ProposalListSection fProposalListSection; + + private final Composite fPaddingComposite; + + private final Composite fHighlightComposite; + + public NewListDropSection(Composite wrappingComposite, int listIndex, PreferenceModel model, ProposalListSection proposalListSection, CodeAssistAdvancedUtilitiesProxy utilitiesProxy) { + this.fModel= model; + this.fUtilitiesProxy= utilitiesProxy; + this.fProposalListSection= proposalListSection; + + fPaddingComposite= createPaddingComposite(wrappingComposite); + fHighlightComposite= createHighlightComposite(fPaddingComposite); + + addDropSupport(fPaddingComposite, fHighlightComposite, listIndex); + } + + public void activateLastPositionSpaceBehavior(boolean last) { + GridData gd= new GridData(GridData.FILL, GridData.FILL, true, last); + gd.heightHint= 10; + fPaddingComposite.setLayoutData(gd); + } + + public void dispose() { + fPaddingComposite.dispose(); + fHighlightComposite.dispose(); + } + + private Composite createPaddingComposite(Composite wrappingComposite) { + Composite paddingComposite= new Composite(wrappingComposite, SWT.NONE); + GridData gd= new GridData(GridData.FILL, GridData.BEGINNING, true, false); + gd.heightHint= 10; + paddingComposite.setLayoutData(gd); + GridLayout layout= new GridLayout(); + layout.marginHeight= 0; + layout.verticalSpacing= 0; + layout.marginWidth= 0; + paddingComposite.setLayout(layout); + return paddingComposite; + } + + private Composite createHighlightComposite(Composite paddingComposite) { + Composite highlightComposite= new Composite(paddingComposite, SWT.NONE); + GridData gd= new GridData(SWT.FILL, SWT.BEGINNING, true, true); + gd.heightHint= 2; + gd.verticalIndent= 4; + highlightComposite.setLayoutData(gd); + return highlightComposite; + } + + private void addDropSupport(Composite paddingComposite, Composite highlightComposite, int listIndex) { + Transfer[] transferTypes= new Transfer[] { ProvidedCategoryTransfer.getInstance(), ProposalListCategoryTransfer.getInstance(), ProposalListTransfer.getInstance() }; + DropTarget dropTarget= new DropTarget(paddingComposite, ProposalTransfer.ALL_DRAG_OPERATIONS); + dropTarget.setTransfer(transferTypes); + dropTarget.addDropListener(new DropNewProposalListListener(highlightComposite, listIndex, fModel, fUtilitiesProxy, fProposalListSection)); + } +} Index: ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/widgets/ProposalList.java =================================================================== RCS file: ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/widgets/ProposalList.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/widgets/ProposalList.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,421 @@ +/** + * Copyright (c) 2011 Thomas Schlosser. + * 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: + * Thomas Schlosser - initial API and implementation. + */ +package org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.widgets; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.dnd.DropTarget; +import org.eclipse.swt.dnd.Transfer; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.events.PaintEvent; +import org.eclipse.swt.events.PaintListener; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.swt.widgets.TableItem; + +import org.eclipse.core.runtime.Assert; + +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.LabelProvider; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.Viewer; + +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.CodeAssistAdvancedUtilitiesProxy; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.dnd.DragProposalListCategoryListener; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.dnd.DropIntoProposalListListener; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.dnd.ProposalListCategoryTransfer; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.dnd.ProposalListTransfer; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.dnd.ProposalTransfer; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.dnd.ProvidedCategoryTransfer; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.model.ModelElement; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.model.PreferenceModel; + +/** + * + * @since 3.8 + */ +public final class ProposalList { + + private final class ProposalListTableLabelProvider extends LabelProvider implements ITableLabelProvider { + + /* + * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java.lang.Object, int) + */ + public Image getColumnImage(Object element, int columnIndex) { + if (columnIndex == 0) + return ((ModelElement) element).getImage(); + return null; + } + + /* + * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(java.lang.Object, int) + */ + public String getColumnText(Object element, int columnIndex) { + switch (columnIndex) { + case 0: + return ((ModelElement) element).getName(); + default: + Assert.isTrue(false); + return null; + } + } + } + + private final class ProposalListContentProvider implements IStructuredContentProvider { + private final int fListIndex; + + public ProposalListContentProvider(int listIndex) { + this.fListIndex= listIndex; + } + + public void dispose() { + } + + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + } + + public Object[] getElements(Object inputElement) { + return fModel.getElements(fListIndex).toArray(); + } + } + + private final PreferenceModel fModel; + + private final CodeAssistAdvancedUtilitiesProxy fUtilitiesProxy; + + private final ProposalListSection fProposalListSection; + + private final Composite fTableContainer; + + private final ProposalListHeader fHeader; + + private final TableViewer fTableViewer; + + private final NewListDropSection fNewListDropSection; + + private boolean fSelected; + + public ProposalList(Composite parent, int listIndex, ProposalListSection proposalListSection, PreferenceModel model, CodeAssistAdvancedUtilitiesProxy utilitiesProxy) { + this.fModel= model; + this.fUtilitiesProxy= utilitiesProxy; + this.fProposalListSection= proposalListSection; + + fTableContainer= createTableContainer(parent); + fHeader= new ProposalListHeader(fTableContainer, listIndex, fModel, fUtilitiesProxy); + fTableViewer= createTable(fTableContainer, listIndex); + + fNewListDropSection= new NewListDropSection(parent, listIndex + 1, fModel, fProposalListSection, fUtilitiesProxy); + + addDropSupport(fTableContainer, listIndex); + addRemoveIconVisibility(); + addBorderPainter(fTableContainer); + } + + @SuppressWarnings("unchecked") + public List getContent() { + Object obj= fTableViewer.getInput(); + if (obj == null) + return null; + return (List) obj; + } + + public void clearContent() { + fTableViewer.setInput(null); + } + + public void addContent(ModelElement element) { + List content= getContent(); + if (content == null) + content= new ArrayList(); + content.add(element); + setContent(content); + } + + public void setContent(List elements) { + fTableViewer.setInput(elements); + } + + public void activateLastListSpaceBehavior(boolean last) { + fNewListDropSection.activateLastPositionSpaceBehavior(last); + } + + public void dispose() { + fTableContainer.dispose(); + fHeader.dispose(); + fTableViewer.getTable().dispose(); + fNewListDropSection.dispose(); + } + + public void highlight(boolean highlight) { + if (fSelected == highlight) + return; + fSelected= highlight; + fTableContainer.redraw(); + + fHeader.highlight(highlight); + } + + private Composite createTableContainer(Composite parent) { + Composite tableContainer= new Composite(parent, SWT.NONE); + tableContainer.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + GridLayout layout= new GridLayout(); + layout.marginHeight= 1; + layout.marginWidth= 1; + layout.verticalSpacing= 0; + layout.horizontalSpacing= 0; + tableContainer.setLayout(layout); + return tableContainer; + } + + private TableViewer createTable(Composite tableContainer, final int listIndex) { + TableViewer tableViewer= createInitialTableViewer(tableContainer); + TableColumn nameColumn= addFirstColumn(tableViewer); + + ITableLabelProvider labelProvider= setProviderAndComparator(tableViewer, listIndex); + adjustFirstColumnWidth(nameColumn, tableViewer, labelProvider); + + addDragSupport(tableViewer, listIndex); + addFocusOutListener(tableViewer); + addProposalListCategoryRemoveIconCreator(tableViewer, listIndex); + + return tableViewer; + } + + private void addDropSupport(Composite tableContainer, int listIndex) { + Transfer[] transferTypes= new Transfer[] { ProvidedCategoryTransfer.getInstance(), ProposalListCategoryTransfer.getInstance(), ProposalListTransfer.getInstance() }; + DropTarget dropTarget= new DropTarget(tableContainer, ProposalTransfer.ALL_DRAG_OPERATIONS); + dropTarget.setTransfer(transferTypes); + dropTarget.addDropListener(new DropIntoProposalListListener(this, listIndex, fModel, fUtilitiesProxy, fProposalListSection)); + } + + private void addRemoveIconVisibility() { + Listener l= new Listener() { + public void handleEvent(Event e) { + fHeader.showRemoveIcon(); + } + }; + this.addListener(SWT.MouseEnter, l); + this.addListener(SWT.MouseMove, l); + this.addListener(SWT.MouseExit, new Listener() { + public void handleEvent(Event e) { + fHeader.hideRemoveIcon(); + } + }); + } + + private void addBorderPainter(final Composite tableContainer) { + tableContainer.addPaintListener(new PaintListener() { + public void paintControl(PaintEvent e) { + if (fSelected) + e.gc.setBackground(CodeAssistAdvancedUtilitiesProxy.SELECTED_COLOR); + else + e.gc.setBackground(CodeAssistAdvancedUtilitiesProxy.UNSELECTED_BORDER_COLOR); + Rectangle rect= tableContainer.getClientArea(); + e.gc.fillRectangle(rect); + } + }); + } + + private TableViewer createInitialTableViewer(Composite tableContainer) { + TableViewer listViewer= new TableViewer(tableContainer, SWT.SINGLE | SWT.NO_SCROLL); + final Table table= listViewer.getTable(); + table.setHeaderVisible(false); + table.setLinesVisible(false); + table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + return listViewer; + } + + private TableColumn addFirstColumn(TableViewer tableViewer) { + TableColumn nameColumn= new TableColumn(tableViewer.getTable(), SWT.NONE); + nameColumn.setResizable(false); + return nameColumn; + } + + private void adjustFirstColumnWidth(TableColumn column, TableViewer tableViewer, ITableLabelProvider labelProvider) { + final int ICON_WIDTH= 16; + final int HEADER_MARGIN= 20; + int minNameWidth= fUtilitiesProxy.computeWidth(tableViewer.getTable(), column.getText()) + HEADER_MARGIN; + for (int i= 0; i < fModel.elements.size(); i++) { + minNameWidth= Math.max(minNameWidth, fUtilitiesProxy.computeWidth(tableViewer.getTable(), labelProvider.getColumnText(fModel.elements.get(i), 0)) + 2 * ICON_WIDTH); + } + column.setWidth(minNameWidth); + } + + private ITableLabelProvider setProviderAndComparator(TableViewer tableViewer, int listIndex) { + tableViewer.setContentProvider(new ProposalListContentProvider(listIndex)); + tableViewer.setComparator(new ModelElement.ModelElementViewerComparator()); + ITableLabelProvider labelProvider= new ProposalListTableLabelProvider(); + tableViewer.setLabelProvider(labelProvider); + return labelProvider; + } + + private void addDragSupport(TableViewer tableViewer, int listIndex) { + Transfer[] transferTypes= new Transfer[] { ProposalListCategoryTransfer.getInstance() }; + tableViewer.addDragSupport(ProposalTransfer.ALL_DRAG_OPERATIONS, transferTypes, new DragProposalListCategoryListener(tableViewer, listIndex)); + } + + private void addFocusOutListener(TableViewer tableViewer) { + final Table table= tableViewer.getTable(); + table.addListener(SWT.FocusOut, new Listener() { + public void handleEvent(Event event) { + table.deselectAll(); + } + }); + } + + private void addListener(int eventType, Listener listener) { + fTableContainer.addListener(eventType, listener); + fHeader.addListener(eventType, listener); + fTableViewer.getTable().addListener(eventType, listener); + } + + private void addProposalListCategoryRemoveIconCreator(final TableViewer tableViewer, final int listIndex) { + Table table= tableViewer.getTable(); + Rectangle iconRect= addRemoveIconToItemsPainter(table); + addRemoveIconRedrawListener(table, iconRect); + addRemoveCategoryOnClickListener(table, iconRect, listIndex); + } + + private Rectangle addRemoveIconToItemsPainter(Table table) { + final Rectangle iconRect= new Rectangle(0, 0, 0, 0); + Listener paintListener= new Listener() { + public void handleEvent(Event event) { + Table tab= ((Table) event.widget); + Point tabLoc= getTableLocation(tab); + Point mouseLoc= getMouseLocation(tab, tabLoc); + if (isMouseOverCurrentRow(tab, mouseLoc, (TableItem) event.item)) { + updateIconRectangle(tab, event.height, event.y); + drawIcon(event.gc, mouseLoc); + } + } + + private Point getTableLocation(Table tab) { + return tab.toDisplay(tab.getClientArea().x, tab.getClientArea().y); + } + + private Point getMouseLocation(Table tab, Point tabLoc) { + Point mouseLoc= tab.getDisplay().getCursorLocation(); + mouseLoc= new Point(mouseLoc.x - tabLoc.x, mouseLoc.y - tabLoc.y); + return mouseLoc; + } + + private boolean isMouseOverCurrentRow(Table tab, Point mouseLoc, TableItem currentItem) { + return tab.getClientArea().contains(mouseLoc) && currentItem == getItem(tab, mouseLoc); + } + + private void updateIconRectangle(Table tab, int eventHeight, int eventY) { + ImageData imgData= fUtilitiesProxy.fRemoveProposalListImage.getImageData(); + int x= tab.getClientArea().width - imgData.width; + int offset= Math.max(0, (eventHeight - imgData.height) / 2); + + iconRect.height= imgData.height; + iconRect.width= imgData.width; + iconRect.x= x; + iconRect.y= eventY + offset; + } + + private void drawIcon(GC gc, Point mouseLoc) { + gc.setClipping(iconRect); + if (iconRect.contains(mouseLoc)) + gc.drawImage(fUtilitiesProxy.fRemoveProposalListOverImage, iconRect.x, iconRect.y); + else + gc.drawImage(fUtilitiesProxy.fRemoveProposalListImage, iconRect.x, iconRect.y); + } + }; + table.addListener(SWT.PaintItem, paintListener); + return iconRect; + } + + private void addRemoveIconRedrawListener(final Table table, final Rectangle iconRect) { + Listener mouseOverTableListener= new Listener() { + TableItem lastItem; + + boolean lastOverImg; + + public void handleEvent(Event e) { + TableItem item= getItem(table, new Point(e.x, e.y)); + boolean overImg= iconRect.contains(e.x, e.y); + if (lastItem != item || lastOverImg != overImg) { + lastItem= item; + lastOverImg= overImg; + table.redraw(); + } + } + }; + table.addListener(SWT.MouseEnter, mouseOverTableListener); + table.addListener(SWT.MouseMove, mouseOverTableListener); + table.addListener(SWT.MouseExit, mouseOverTableListener); + } + + private void addRemoveCategoryOnClickListener(final Table table, final Rectangle iconRect, final int listIndex) { + table.addMouseListener(new MouseListener() { + public void mouseUp(MouseEvent e) { + if (isSingleClick(e.count) && isUpOverIcon(e.x, e.y)) { + int elemIndex= table.indexOf(getItem(table, new Point(e.x, e.y))); + List categories= fModel.getElements(listIndex); + Collections.sort(categories, new ModelElement.ModelElementComparator()); + categories.get(elemIndex).removeInProposalList(listIndex); + fUtilitiesProxy.updateControls(); + } + } + + public void mouseDown(MouseEvent e) { + } + + public void mouseDoubleClick(MouseEvent e) { + } + + private boolean isSingleClick(int count) { + return count == 1; + } + + private boolean isUpOverIcon(int x, int y) { + return iconRect.contains(x, y); + } + }); + } + + private TableItem getItem(Table tab, Point p) { + for (int index= 0; index < tab.getItemCount(); index++) { + if (getItemBounds(tab, index).contains(p)) + return tab.getItem(index); + } + return null; + } + + private Rectangle getItemBounds(Table tab, int itemIndex) { + Rectangle tableBounds= tab.getBounds(); + int height= tab.getItemHeight(); + int width= tableBounds.width; + int x= tableBounds.x; + int y= itemIndex * height; + return new Rectangle(x, y, width, height); + } + + public TableViewer getTableViewer() { + return fTableViewer; + } +} Index: ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/widgets/ProposalListHeader.java =================================================================== RCS file: ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/widgets/ProposalListHeader.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/widgets/ProposalListHeader.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,197 @@ +/** + * Copyright (c) 2011 Thomas Schlosser. + * 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: + * Thomas Schlosser - initial API and implementation. + */ +package org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.widgets; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.dnd.DragSource; +import org.eclipse.swt.dnd.DragSourceListener; +import org.eclipse.swt.dnd.Transfer; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Listener; + +import org.eclipse.jdt.internal.corext.util.Messages; + +import org.eclipse.jdt.internal.ui.preferences.PreferencesMessages; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.CodeAssistAdvancedUtilitiesProxy; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.dnd.DragProposalListListener; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.dnd.ProposalListTransfer; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.dnd.ProposalTransfer; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.model.PreferenceModel; + +/** + * + * @since 3.8 + */ +public final class ProposalListHeader { + + private static final Color SELECTED_COLOR= Display.getCurrent().getSystemColor(SWT.COLOR_LIST_SELECTION); + + private static final Color SELECTED_TEXT_COLOR= Display.getCurrent().getSystemColor(SWT.COLOR_LIST_SELECTION_TEXT); + + private static final Color UNSELECTED_COLOR= Display.getCurrent().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND); + + private static final Color UNSELECTED_TEXT_COLOR= Display.getCurrent().getSystemColor(SWT.COLOR_WIDGET_FOREGROUND); + + private final PreferenceModel fModel; + + private final CodeAssistAdvancedUtilitiesProxy fUtilitiesProxy; + + private final Composite fPaddingComposite; + + private final Label fTitle; + + private final Label fRemoveLabel; + + public ProposalListHeader(Composite tableContainer, int listIndex, PreferenceModel model, CodeAssistAdvancedUtilitiesProxy utilitiesProxy) { + this.fModel= model; + this.fUtilitiesProxy= utilitiesProxy; + + fPaddingComposite= createPaddingComposite(tableContainer); + fTitle= createTitle(fPaddingComposite, listIndex); + fRemoveLabel= createRemoveIcon(fPaddingComposite, listIndex); + updateHeaderHeight(); + + addListDragSupport(fPaddingComposite, listIndex); + addListDragSupport(fTitle, listIndex); + } + + public void dispose() { + fPaddingComposite.dispose(); + fTitle.dispose(); + fRemoveLabel.dispose(); + } + + public void highlight(boolean highlight) { + Color backgroundColor= highlight ? SELECTED_COLOR : UNSELECTED_COLOR; + Color foregroundColor= highlight ? SELECTED_TEXT_COLOR : UNSELECTED_TEXT_COLOR; + fPaddingComposite.setBackground(backgroundColor); + fTitle.setBackground(backgroundColor); + fTitle.setForeground(foregroundColor); + fRemoveLabel.setBackground(backgroundColor); + } + + public void showRemoveIcon() { + fRemoveLabel.setVisible(true); + } + + public void hideRemoveIcon() { + fRemoveLabel.setVisible(false); + } + + public void addListener(int eventType, Listener listener) { + fPaddingComposite.addListener(eventType, listener); + fTitle.addListener(eventType, listener); + fRemoveLabel.addListener(eventType, listener); + } + + private Composite createPaddingComposite(Composite tableContainer) { + Composite paddingComposite= new Composite(tableContainer, SWT.NONE); + GridLayout layout= new GridLayout(2, false); + layout.marginHeight= 0; + layout.verticalSpacing= 0; + paddingComposite.setLayout(layout); + return paddingComposite; + } + + private Label createTitle(Composite paddingComposite, int listIndex) { + Label title= new Label(paddingComposite, SWT.NONE); + title.setText(getProposalListTitle(listIndex)); + title.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true)); + return title; + } + + private void updateHeaderHeight() { + GridData gd= new GridData(SWT.FILL, SWT.FILL, true, true); + gd.heightHint= getHeaderHeight(); + fPaddingComposite.setLayoutData(gd); + } + + private Label createRemoveIcon(final Composite paddingComposite, final int listIndex) { + final Label removeLabel= createRemoveLabel(paddingComposite); + addMouseOverIconListener(removeLabel); + addRemoveListOnClickListener(removeLabel, listIndex); + return removeLabel; + } + + private void addListDragSupport(Control control, int listIndex) { + DragSourceListener tableDragSourceListener= new DragProposalListListener(listIndex); + Transfer[] transferTypes= new Transfer[] { ProposalListTransfer.getInstance() }; + DragSource dragSource= new DragSource(control, ProposalTransfer.ALL_DRAG_OPERATIONS); + dragSource.setTransfer(transferTypes); + dragSource.addDragListener(tableDragSourceListener); + } + + private String getProposalListTitle(int index) { + return Messages.format(PreferencesMessages.CodeAssistAdvancedConfigurationBlock_proposal_list_table_title, Integer.valueOf(index + 1)); + } + + private int getHeaderHeight() { + return fTitle.computeSize(SWT.DEFAULT, SWT.DEFAULT).y + 8; + } + + private Label createRemoveLabel(Composite paddingComposite) { + final Label removeLabel= new Label(paddingComposite, SWT.NONE); + removeLabel.setVisible(false); + removeLabel.setImage(fUtilitiesProxy.fRemoveProposalListImage); + GridData gd= new GridData(SWT.RIGHT, SWT.CENTER, true, true); + gd.widthHint= fUtilitiesProxy.fRemoveProposalListImage.getImageData().width; + gd.minimumWidth= gd.widthHint; + removeLabel.setLayoutData(gd); + return removeLabel; + } + + private void addMouseOverIconListener(final Label removeLabel) { + removeLabel.addListener(SWT.MouseEnter, new Listener() { + public void handleEvent(Event e) { + removeLabel.setImage(fUtilitiesProxy.fRemoveProposalListOverImage); + } + }); + removeLabel.addListener(SWT.MouseExit, new Listener() { + public void handleEvent(Event e) { + removeLabel.setImage(fUtilitiesProxy.fRemoveProposalListImage); + } + }); + } + + private void addRemoveListOnClickListener(final Label removeLabel, final int listIndex) { + removeLabel.addMouseListener(new MouseListener() { + public void mouseUp(MouseEvent e) { + if (isSingleClick(e.count) && isUpOverIcon(e.x, e.y)) { + fModel.removeList(listIndex); + fUtilitiesProxy.updateControls(); + } + } + + public void mouseDown(MouseEvent e) { + } + + public void mouseDoubleClick(MouseEvent e) { + } + + private boolean isSingleClick(int count) { + return count == 1; + } + + private boolean isUpOverIcon(int x, int y) { + return x >= 0 && x < removeLabel.getBounds().width && y >= 0 && y < removeLabel.getBounds().height; + } + }); + } +} Index: ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/widgets/ProposalListSection.java =================================================================== RCS file: ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/widgets/ProposalListSection.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ ui/org/eclipse/jdt/internal/ui/preferences/codeassist/advanced/widgets/ProposalListSection.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,194 @@ +/** + * Copyright (c) 2011 Thomas Schlosser. + * 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: + * Thomas Schlosser - initial API and implementation. + */ +package org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.widgets; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.ScrolledComposite; +import org.eclipse.swt.dnd.DropTarget; +import org.eclipse.swt.dnd.DropTargetEvent; +import org.eclipse.swt.dnd.Transfer; +import org.eclipse.swt.events.ControlEvent; +import org.eclipse.swt.events.ControlListener; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; + +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.CodeAssistAdvancedUtilitiesProxy; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.dnd.AutoscrollDropTargetListener; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.dnd.ProposalListCategoryTransfer; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.dnd.ProposalListTransfer; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.dnd.ProposalTransfer; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.dnd.ProvidedCategoryTransfer; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.model.ModelElement; +import org.eclipse.jdt.internal.ui.preferences.codeassist.advanced.model.PreferenceModel; + +/** + * + * @since 3.8 + */ +public final class ProposalListSection { + private final PreferenceModel fModel; + + private final CodeAssistAdvancedUtilitiesProxy fUtilitiesProxy; + + private final ScrolledComposite fScrolledComposite; + + private final Composite fInnerWrappingComposite; + + private final List fProposalLists= new ArrayList(); + + public ProposalListSection(Composite parent, PreferenceModel model, CodeAssistAdvancedUtilitiesProxy utilitiesProxy) { + this.fModel= model; + this.fUtilitiesProxy= utilitiesProxy; + + fScrolledComposite= createOuterScrolledComposite(parent); + addDropAutoScroll(fScrolledComposite); + fInnerWrappingComposite= createInnerProposalListWrappingComposite(fScrolledComposite); + + addOuterSizeUpdater(fScrolledComposite, fInnerWrappingComposite); + + createFirstNewListDropSection(fInnerWrappingComposite); + } + + public void updateControls() { + //FIXME: This fixes the problem of refreshing the first list when first element (category) has been added. + // This bug only occurs when the configuration page has been opened indirectly. + // If the "Content Assist"->"Advanced" page is opened directly, it behaves as expected. + if (fProposalLists.size() == 1 && fProposalLists.get(0).getContent() == null) { + fProposalLists.get(0).dispose(); + fProposalLists.remove(0); + } + clearOldListState(); + Set filledLists= updateListStates(); + makeSureFirstListExists(); + adjustAndCleanUp(filledLists); + reLayoutInnerComposite(); + } + + public void autoScroll(DropTargetEvent event) { + Rectangle area= fScrolledComposite.getClientArea(); + Point absoluteLocation= fScrolledComposite.toDisplay(1, 1); + Point origin= fScrolledComposite.getOrigin(); + Rectangle bounds= fInnerWrappingComposite.getBounds(); + + int scrollDetectRange= 15; + int offset= 5; + if (absoluteLocation.y + scrollDetectRange > event.y) + origin.y= Math.max(0, origin.y - offset); + if (absoluteLocation.y + area.height - scrollDetectRange < event.y) + origin.y= Math.min(bounds.height - area.height, origin.y + offset); + fScrolledComposite.setOrigin(origin); + } + + private ScrolledComposite createOuterScrolledComposite(Composite parent) { + ScrolledComposite scrolledComposite= new ScrolledComposite(parent, SWT.V_SCROLL | SWT.BORDER); + scrolledComposite.setAlwaysShowScrollBars(true); + scrolledComposite.setExpandHorizontal(true); + scrolledComposite.setExpandVertical(true); + GridData gridData= new GridData(GridData.FILL, GridData.FILL, true, true); + gridData.heightHint= 0; + scrolledComposite.setLayoutData(gridData); + return scrolledComposite; + } + + private void addDropAutoScroll(Composite composite) { + Transfer[] transferTypes= new Transfer[] { ProvidedCategoryTransfer.getInstance(), ProposalListCategoryTransfer.getInstance(), ProposalListTransfer.getInstance() }; + DropTarget dropTarget= new DropTarget(composite, ProposalTransfer.ALL_DRAG_OPERATIONS); + dropTarget.setTransfer(transferTypes); + dropTarget.addDropListener(new AutoscrollDropTargetListener(this)); + } + + private Composite createInnerProposalListWrappingComposite(ScrolledComposite scrolledComposite) { + Composite wrappingComposite= new Composite(scrolledComposite, SWT.NONE); + scrolledComposite.setContent(wrappingComposite); + GridLayout layout= new GridLayout(); + layout.marginHeight= 0; + layout.verticalSpacing= 0; + wrappingComposite.setLayout(layout); + return wrappingComposite; + } + + private void addOuterSizeUpdater(final ScrolledComposite scrolledComposite, final Composite innerComposite) { + innerComposite.addControlListener(new ControlListener() { + public void controlResized(ControlEvent e) { + innerComposite.update(); + scrolledComposite.setMinSize(innerComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT)); + scrolledComposite.layout(true, true); + } + + public void controlMoved(ControlEvent e) { + } + }); + } + + private void createFirstNewListDropSection(Composite innerWrappingComposite) { + new NewListDropSection(innerWrappingComposite, 0, fModel, this, fUtilitiesProxy); + } + + private void clearOldListState() { + for (ProposalList list : fProposalLists) + list.clearContent(); + } + + private Set updateListStates() { + Set filledLists= new HashSet(); + for (ModelElement element : fModel.elements) { + Set indices= element.getProposalListIndices(); + if (indices != null) { + filledLists.addAll(indices); + for (int index : indices) { + makeSureListExists(index); + addElementToList(element, index); + } + } + } + return filledLists; + } + + private void makeSureFirstListExists() { + if (fProposalLists.size() == 0) + makeSureListExists(0); + } + + private void adjustAndCleanUp(Set filledLists) { + boolean last= true; + for (int i= fProposalLists.size() - 1; i >= 0; i--) + if (i > 0 && !filledLists.contains(Integer.valueOf(i))) { + fProposalLists.get(i).dispose(); + fProposalLists.remove(i); + } + else { + fProposalLists.get(i).activateLastListSpaceBehavior(last); + last= false; + } + } + + private void reLayoutInnerComposite() { + fInnerWrappingComposite.pack(true); + fInnerWrappingComposite.layout(false); + } + + private void addElementToList(ModelElement element, int listIndex) { + fProposalLists.get(listIndex).addContent(element); + } + + private void makeSureListExists(int listIndex) { + while (fProposalLists.size() < listIndex + 1) + fProposalLists.add(new ProposalList(fInnerWrappingComposite, fProposalLists.size(), this, fModel, fUtilitiesProxy)); + } +} Index: ui/org/eclipse/jdt/internal/ui/text/java/CompletionProposalCategory.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/CompletionProposalCategory.java,v --- ui/org/eclipse/jdt/internal/ui/text/java/CompletionProposalCategory.java 1 Mar 2011 11:50:36 -0000 1.19 +++ ui/org/eclipse/jdt/internal/ui/text/java/CompletionProposalCategory.java 18 Jul 2011 13:26:55 -0000 @@ -7,13 +7,18 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Thomas Schlosser - 340876 [preferences][content assist] Request for more flexible configuration of content assist lists - https://bugs.eclipse.org/bugs/show_bug.cgi?id=340876 *******************************************************************************/ package org.eclipse.jdt.internal.ui.text.java; import java.net.URL; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Set; import org.osgi.framework.Bundle; @@ -55,12 +60,11 @@ /** The image descriptor for this category, or null if none specified. */ private final ImageDescriptor fImage; - private boolean fIsSeparateCommand= true; + private final Set fProposalListIndices = new HashSet(); + private final Set fPublicProposalListIndices= Collections.unmodifiableSet(fProposalListIndices); private boolean fIsEnabled= true; - private boolean fIsIncluded= true; private final CompletionProposalComputerRegistry fRegistry; - private int fSortOrder= 0xffff - 1; private String fLastError= null; CompletionProposalCategory(IConfigurationElement element, CompletionProposalComputerRegistry registry) throws CoreException { @@ -158,35 +162,54 @@ } /** - * Sets the separate command state of the category. - * - * @param enabled the new enabled state. + * Adds the given proposal list index to the proposal list indices of this category. + * + * @param listIndex the index of the proposal list. */ - public void setSeparateCommand(boolean enabled) { - fIsSeparateCommand= enabled; + public void addProposalListIndex(Integer listIndex) { + fProposalListIndices.add(listIndex); } /** - * Returns the enablement state of the category. - * - * @return the enablement state of the category + * Adds all given proposal list indices to the proposal list indices of this category. + * + * @param listIndices the indices of the proposal lists. */ - public boolean isSeparateCommand() { - return fIsSeparateCommand; + public void addAllProposalListIndices(Collection listIndices) { + if (listIndices == null) + return; + fProposalListIndices.addAll(listIndices); } /** - * @param included the included + * Removes all given proposal list indices from the proposal list indices of this category. + * + * @param listIndices the indices of the proposal lists. */ - public void setIncluded(boolean included) { - fIsIncluded= included; + public void removeAllProposalListIndices(Collection listIndices) { + if (listIndices == null) + return; + fProposalListIndices.removeAll(listIndices); } /** - * @return included + * Clears the list of proposal list indices of this category. + * */ - public boolean isIncluded() { - return fIsIncluded; + public void clearProposalListIndices() { + fProposalListIndices.clear(); + } + + /** + * Returns the indices of the proposal lists of this category. + *

+ * The returned set is read-only. + *

+ * + * @return the indices of the proposal lists of this category + */ + public Set getProposalListIndices() { + return fPublicProposalListIndices; } public boolean isEnabled() { @@ -233,20 +256,6 @@ } /** - * @return sortOrder - */ - public int getSortOrder() { - return fSortOrder; - } - - /** - * @param sortOrder the sortOrder - */ - public void setSortOrder(int sortOrder) { - fSortOrder= sortOrder; - } - - /** * Safely computes completion proposals of all computers of this category through their * extension. If an extension is disabled, throws an exception or otherwise does not adhere to * the contract described in {@link IJavaCompletionProposalComputer}, it is disabled. @@ -288,7 +297,7 @@ List descriptors= new ArrayList(fRegistry.getProposalComputerDescriptors(partition)); for (Iterator it= descriptors.iterator(); it.hasNext();) { CompletionProposalComputerDescriptor desc= it.next(); - if (desc.getCategory() == this && (isIncluded() || isSeparateCommand())) + if (desc.getCategory() == this && !fProposalListIndices.isEmpty()) result.addAll(desc.computeContextInformation(context, monitor)); if (fLastError == null) fLastError= desc.getErrorMessage(); Index: ui/org/eclipse/jdt/internal/ui/text/java/CompletionProposalComputerRegistry.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/CompletionProposalComputerRegistry.java,v --- ui/org/eclipse/jdt/internal/ui/text/java/CompletionProposalComputerRegistry.java 1 Mar 2011 11:50:36 -0000 1.23 +++ ui/org/eclipse/jdt/internal/ui/text/java/CompletionProposalComputerRegistry.java 18 Jul 2011 13:26:55 -0000 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Thomas Schlosser - 340876 [preferences][content assist] Request for more flexible configuration of content assist lists - https://bugs.eclipse.org/bugs/show_bug.cgi?id=340876 *******************************************************************************/ package org.eclipse.jdt.internal.ui.text.java; @@ -21,6 +22,8 @@ import java.util.Map; import java.util.Set; import java.util.StringTokenizer; +import java.util.TreeMap; +import java.util.Map.Entry; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; @@ -330,25 +333,28 @@ private List getCategories(List elements) { IPreferenceStore store= JavaPlugin.getDefault().getPreferenceStore(); - String preference= store.getString(PreferenceConstants.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(PreferenceConstants.CODEASSIST_CATEGORY_ORDER); - tok= new StringTokenizer(preference, "\0"); //$NON-NLS-1$ - while (tok.hasMoreTokens()) { + String preference= store.getString(PreferenceConstants.CODEASSIST_PROPOSAL_LISTS); + Map> proposalLists= new HashMap>(); + StringTokenizer tok= new StringTokenizer(preference, "\0"); //$NON-NLS-1$ + for (int i= 0; tok.hasMoreTokens(); i++) { 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)); + if (inner.countTokens() == 0) + i--; + while (inner.hasMoreTokens()) { + String categoryId= inner.nextToken(); + Set set= proposalLists.get(categoryId); + if (set == null) { + set= new HashSet(); + proposalLists.put(categoryId, set); + } + set.add(Integer.valueOf(i)); + } } CompletionProposalCategory allProposals= null; CompletionProposalCategory typeProposals= null; CompletionProposalCategory allButTypeProposals= null; - + List categories= new ArrayList(); for (Iterator iter= elements.iterator(); iter.hasNext();) { IConfigurationElement element= iter.next(); @@ -358,17 +364,8 @@ CompletionProposalCategory category= new CompletionProposalCategory(element, this); categories.add(category); - category.setIncluded(!disabled.contains(category.getId())); - Integer rank= 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); - } - + category.addAllProposalListIndices(proposalLists.get(category.getId())); + String id= category.getId(); if ("org.eclipse.jdt.ui.javaAllProposalCategory".equals(id)) //$NON-NLS-1$ allProposals= category; @@ -383,7 +380,7 @@ * some other reason. Do not include the extension in the list and inform the user * about it. */ - Object[] args= {element.toString()}; + Object[] args= { element.toString() }; String message= Messages.format(JavaTextMessages.CompletionProposalComputerRegistry_invalid_message, args); IStatus status= new Status(IStatus.WARNING, JavaPlugin.getPluginId(), IStatus.OK, message, x); informUser(status); @@ -391,35 +388,47 @@ informUser(x.getStatus()); } } - preventDuplicateCategories(store, disabled, allProposals, typeProposals, allButTypeProposals); + preventDuplicateCategories(store, proposalLists, allProposals, typeProposals, allButTypeProposals, categories.size()); return categories; } - private void preventDuplicateCategories(IPreferenceStore store, Set disabled, CompletionProposalCategory allProposals, CompletionProposalCategory typeProposals, - CompletionProposalCategory allButTypeProposals) { + private void preventDuplicateCategories(IPreferenceStore store, Map> proposalLists, CompletionProposalCategory allProposals, CompletionProposalCategory typeProposals, + CompletionProposalCategory allButTypeProposals, int numberOfCategories) { boolean adjusted= false; - if (allProposals == null || !allProposals.isIncluded()) + if (allProposals == null || allProposals.getProposalListIndices().isEmpty()) return; - if (allButTypeProposals != null && allButTypeProposals.isIncluded()) { - allButTypeProposals.setIncluded(false); - disabled.add(allButTypeProposals.getId()); + if (allButTypeProposals != null && !allButTypeProposals.getProposalListIndices().isEmpty()) { + allButTypeProposals.removeAllProposalListIndices(allProposals.getProposalListIndices()); + proposalLists.put(allButTypeProposals.getId(), allButTypeProposals.getProposalListIndices()); adjusted= true; } - if (typeProposals != null && typeProposals.isIncluded()) { - typeProposals.setIncluded(false); - disabled.add(typeProposals.getId()); + if (typeProposals != null && !typeProposals.getProposalListIndices().isEmpty()) { + typeProposals.removeAllProposalListIndices(allProposals.getProposalListIndices()); + proposalLists.put(typeProposals.getId(), typeProposals.getProposalListIndices()); adjusted= true; } if (adjusted) { - StringBuffer buf= new StringBuffer(50 * disabled.size()); - Iterator iter= disabled.iterator(); - while (iter.hasNext()) { - buf.append(iter.next()); + int initialBufferSize= 50 * numberOfCategories; + Map proposalListsCategories= new TreeMap(); + for (Entry> category : proposalLists.entrySet()) { + for (Integer index : category.getValue()) { + StringBuffer buf= proposalListsCategories.get(index); + if (buf == null) { + buf= new StringBuffer(initialBufferSize); + proposalListsCategories.put(index, buf); + } + buf.append(category.getKey()); + buf.append(':'); + } + } + StringBuffer buf= new StringBuffer(initialBufferSize * proposalListsCategories.size()); + for (StringBuffer proposalList : proposalListsCategories.values()) { + buf.append(proposalList); buf.append('\0'); } - store.putValue(PreferenceConstants.CODEASSIST_EXCLUDED_CATEGORIES, buf.toString()); + store.putValue(PreferenceConstants.CODEASSIST_PROPOSAL_LISTS, buf.toString()); } } Index: ui/org/eclipse/jdt/internal/ui/text/java/ContentAssistProcessor.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/ContentAssistProcessor.java,v --- ui/org/eclipse/jdt/internal/ui/text/java/ContentAssistProcessor.java 1 Mar 2011 11:50:36 -0000 1.26 +++ ui/org/eclipse/jdt/internal/ui/text/java/ContentAssistProcessor.java 18 Jul 2011 13:26:56 -0000 @@ -7,14 +7,15 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Thomas Schlosser - 340876 [preferences][content assist] Request for more flexible configuration of content assist lists - https://bugs.eclipse.org/bugs/show_bug.cgi?id=340876 *******************************************************************************/ package org.eclipse.jdt.internal.ui.text.java; import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; import java.util.Iterator; import java.util.List; +import java.util.Map; +import java.util.TreeMap; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; @@ -186,14 +187,6 @@ */ private static final String PREF_WARN_ABOUT_EMPTY_ASSIST_CATEGORY= "EmptyDefaultAssistCategory"; //$NON-NLS-1$ - private static final Comparator ORDER_COMPARATOR= new Comparator() { - - public int compare(CompletionProposalCategory d1, CompletionProposalCategory d2) { - return d1.getSortOrder() - d2.getSortOrder(); - } - - }; - private final List fCategories; private final String fPartition; private final ContentAssistant fAssistant; @@ -444,47 +437,44 @@ } private List> getCategoryIteration() { - List> sequence= new ArrayList>(); - sequence.add(getDefaultCategories()); - for (Iterator it= getSeparateCategories().iterator(); it.hasNext();) { - CompletionProposalCategory cat= it.next(); - sequence.add(Collections.singletonList(cat)); - } - return sequence; - } - - private List getDefaultCategories() { - // default mix - enable all included computers - List included= getDefaultCategoriesUnchecked(); - - if (fComputerRegistry.hasUninstalledComputers(fPartition, included)) { - if (informUserAboutEmptyDefaultCategory()) - // preferences were restored - recompute the default categories - included= getDefaultCategoriesUnchecked(); + List> categories= getProposalCategoriesUnchecked(); + if (fComputerRegistry.hasUninstalledComputers(fPartition, categories.get(0))) { + if (informUserAboutEmptyFirstProposalCategory()) + // preferences were restored - recompute the categories in the first proposal list + categories= getProposalCategoriesUnchecked(); fComputerRegistry.resetUnistalledComputers(); } - - return included; + return categories; } - private List getDefaultCategoriesUnchecked() { - List included= new ArrayList(); - for (Iterator it= fCategories.iterator(); it.hasNext();) { - CompletionProposalCategory category= it.next(); - if (category.isIncluded() && category.hasComputers(fPartition)) - included.add(category); + private List> getProposalCategoriesUnchecked() { + Map> sorted= new TreeMap>(); + for (CompletionProposalCategory category : fCategories) { + if (!category.getProposalListIndices().isEmpty() && category.hasComputers(fPartition)) { + for (Integer index : category.getProposalListIndices()) { + List list= sorted.get(index); + if (list == null) { + list= new ArrayList(); + sorted.put(index, list); + } + list.add(category); + } + } } - return included; + // put at least an empty first list + if (sorted.isEmpty()) + sorted.put(Integer.valueOf(0), new ArrayList()); + return new ArrayList>(sorted.values()); } /** - * Informs the user about the fact that there are no enabled categories in the default content - * assist set and shows a link to the preferences. - * - * @return true if the default should be restored + * Informs the user about the fact that there are no enabled categories in the first content + * assist proposal list set and shows a link to the preferences. + * + * @return true if the default should be restored * @since 3.3 */ - private boolean informUserAboutEmptyDefaultCategory() { + private boolean informUserAboutEmptyFirstProposalCategory() { if (OptionalMessageDialog.isDialogEnabled(PREF_WARN_ABOUT_EMPTY_ASSIST_CATEGORY)) { final Shell shell= JavaPlugin.getActiveWorkbenchShell(); String title= JavaTextMessages.ContentAssistProcessor_all_disabled_title; @@ -549,8 +539,7 @@ if (restoreId == returnValue || settingsId == returnValue) { if (restoreId == returnValue) { IPreferenceStore store= JavaPlugin.getDefault().getPreferenceStore(); - store.setToDefault(PreferenceConstants.CODEASSIST_CATEGORY_ORDER); - store.setToDefault(PreferenceConstants.CODEASSIST_EXCLUDED_CATEGORIES); + store.setToDefault(PreferenceConstants.CODEASSIST_PROPOSAL_LISTS); } if (settingsId == returnValue) PreferencesUtil.createPreferenceDialogOn(shell, "org.eclipse.jdt.ui.preferences.CodeAssistPreferenceAdvanced", null, null).open(); //$NON-NLS-1$ @@ -561,17 +550,6 @@ return false; } - private List getSeparateCategories() { - ArrayList sorted= new ArrayList(); - for (Iterator it= fCategories.iterator(); it.hasNext();) { - CompletionProposalCategory category= it.next(); - if (category.isSeparateCommand() && category.hasComputers(fPartition)) - sorted.add(category); - } - Collections.sort(sorted, ORDER_COMPARATOR); - return sorted; - } - private String createEmptyMessage() { return Messages.format(JavaTextMessages.ContentAssistProcessor_empty_message, new String[]{getCategoryLabel(fRepetition)}); } @@ -582,13 +560,7 @@ private String getCategoryLabel(int repetition) { int iteration= repetition % fCategoryIteration.size(); - if (iteration == 0) - return JavaTextMessages.ContentAssistProcessor_defaultProposalCategory; - return toString(fCategoryIteration.get(iteration).get(0)); - } - - private String toString(CompletionProposalCategory category) { - return category.getDisplayName(); + return Messages.format(JavaTextMessages.ContentAssistProcessor_proposalList, Integer.valueOf(iteration + 1)); } private String getIterationGesture() { Index: ui/org/eclipse/jdt/internal/ui/text/java/JavaTextMessages.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/JavaTextMessages.java,v --- ui/org/eclipse/jdt/internal/ui/text/java/JavaTextMessages.java 16 Nov 2009 17:00:10 -0000 1.23 +++ ui/org/eclipse/jdt/internal/ui/text/java/JavaTextMessages.java 18 Jul 2011 13:26:56 -0000 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Thomas Schlosser - 340876 [preferences][content assist] Request for more flexible configuration of content assist lists - https://bugs.eclipse.org/bugs/show_bug.cgi?id=340876 *******************************************************************************/ package org.eclipse.jdt.internal.ui.text.java; @@ -59,7 +60,7 @@ public static String CompletionProposalComputerDescriptor_blame_message; public static String CompletionProposalComputerRegistry_invalid_message; public static String CompletionProposalComputerRegistry_error_dialog_title; - public static String ContentAssistProcessor_defaultProposalCategory; + public static String ContentAssistProcessor_proposalList; public static String ContentAssistProcessor_toggle_affordance_press_gesture; public static String ContentAssistProcessor_toggle_affordance_click_gesture; public static String ContentAssistProcessor_toggle_affordance_update_message; Index: ui/org/eclipse/jdt/internal/ui/text/java/JavaTextMessages.properties =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/java/JavaTextMessages.properties,v --- ui/org/eclipse/jdt/internal/ui/text/java/JavaTextMessages.properties 16 Nov 2009 17:00:10 -0000 1.35 +++ ui/org/eclipse/jdt/internal/ui/text/java/JavaTextMessages.properties 18 Jul 2011 13:26:56 -0000 @@ -7,6 +7,7 @@ # # Contributors: # IBM Corporation - initial API and implementation +# Thomas Schlosser - 340876 [preferences][content assist] Request for more flexible configuration of content assist lists - https://bugs.eclipse.org/bugs/show_bug.cgi?id=340876 ############################################################################### CompletionProcessor_error_accessing_title=Error Accessing Compilation Unit @@ -57,14 +58,14 @@ ContentAssistProcessor_all_disabled_preference_link=Change the settings on the Advanced Content Assist preference page or click ''{0}'' to restore the default behavior. ContentAssistProcessor_collecting_contexts=Collecting context information ContentAssistProcessor_sorting_contexts=Sorting -ContentAssistProcessor_defaultProposalCategory=Default Proposals +ContentAssistProcessor_proposalList={0}. Proposal List # {0} will be replaced by a keyboard shortcut (accelerator) ContentAssistProcessor_toggle_affordance_press_gesture=Press ''{0}'' ContentAssistProcessor_toggle_affordance_click_gesture=Click # {0} will be replaced by a title describing the displayed proposal category, {1} by either the press_gesture or click_gesture message above, {2} by the name of the next proposal category ContentAssistProcessor_toggle_affordance_update_message={1} to show {2} # {0} will be replaced by a title describing the displayed proposal category -ContentAssistProcessor_empty_message= No {0} +ContentAssistProcessor_empty_message= No proposals in {0} ContentAssistHistory_serialize_error=Problems writing content assist history to XML ContentAssistHistory_deserialize_error=Problems reading content assist history from XML Index: ui/org/eclipse/jdt/ui/PreferenceConstants.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/PreferenceConstants.java,v --- ui/org/eclipse/jdt/ui/PreferenceConstants.java 5 Jan 2011 10:18:40 -0000 1.259 +++ ui/org/eclipse/jdt/ui/PreferenceConstants.java 18 Jul 2011 13:26:57 -0000 @@ -8,12 +8,19 @@ * Contributors: * IBM Corporation - initial API and implementation * Guven Demir - [package explorer] Alternative package name shortening: abbreviation - https://bugs.eclipse.org/bugs/show_bug.cgi?id=299514 + * Thomas Schlosser - 340876 [preferences][content assist] Request for more flexible configuration of content assist lists - https://bugs.eclipse.org/bugs/show_bug.cgi?id=340876 *******************************************************************************/ package org.eclipse.jdt.ui; import java.util.Arrays; import java.util.Locale; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map.Entry; +import java.util.Map; +import java.util.Set; import java.util.StringTokenizer; +import java.util.TreeMap; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.RGB; @@ -3174,9 +3181,8 @@ * Value is of type String, a "\0"-separated list of identifiers. *

* - * @see #getExcludedCompletionProposalCategories() - * @see #setExcludedCompletionProposalCategories(String[]) * @since 3.2 + * @deprecated As of 3.8, use {@link #CODEASSIST_PROPOSAL_LISTS} instead */ public static final String CODEASSIST_EXCLUDED_CATEGORIES= "content_assist_disabled_computers"; //$NON-NLS-1$ @@ -3196,8 +3202,25 @@ *

* * @since 3.2 + * @deprecated As of 3.8, use {@link #CODEASSIST_PROPOSAL_LISTS} instead */ public static final String CODEASSIST_CATEGORY_ORDER= "content_assist_category_order"; //$NON-NLS-1$ + + /** + * A named preference that controls which completion proposal category is included in which proposal list. + *

+ * Value is of type String, a "\0"-separated list of "\1"-separated lists with categoryId where + *

    + *
  • categoryId is the String holding the category ID
  • + *
+ * + *

+ * + * @see #getProposalLists() + * @see #setProposalLists(Map) + * @since 3.8 + */ + public static final String CODEASSIST_PROPOSAL_LISTS= "content_assist_proposal_lists"; //$NON-NLS-1$ /** * A named preference that controls whether folding is enabled in the Java editor. @@ -3784,8 +3807,7 @@ store.setDefault(PreferenceConstants.CODEASSIST_FILL_ARGUMENT_NAMES, true); store.setDefault(PreferenceConstants.CODEASSIST_GUESS_METHOD_ARGUMENTS, false); store.setDefault(PreferenceConstants.CODEASSIST_PREFIX_COMPLETION, false); - store.setDefault(PreferenceConstants.CODEASSIST_EXCLUDED_CATEGORIES, "org.eclipse.jdt.ui.textProposalCategory\0org.eclipse.jdt.ui.javaTypeProposalCategory\0org.eclipse.jdt.ui.javaNoTypeProposalCategory\0"); //$NON-NLS-1$ - store.setDefault(PreferenceConstants.CODEASSIST_CATEGORY_ORDER, "org.eclipse.jdt.ui.spellingProposalCategory:65545\0org.eclipse.jdt.ui.javaTypeProposalCategory:65540\0org.eclipse.jdt.ui.javaNoTypeProposalCategory:65539\0org.eclipse.jdt.ui.textProposalCategory:65541\0org.eclipse.jdt.ui.javaAllProposalCategory:65542\0org.eclipse.jdt.ui.templateProposalCategory:2\0org.eclipse.jdt.ui.swtProposalCategory:3\0"); //$NON-NLS-1$ + store.setDefault(PreferenceConstants.CODEASSIST_PROPOSAL_LISTS, "org.eclipse.jdt.ui.templateProposalCategory:org.eclipse.jdt.ui.swtProposalCategory:org.eclipse.jdt.ui.javaAllProposalCategory:org.eclipse.pde.api.tools.ui.apitools_proposal_category:\0org.eclipse.jdt.ui.templateProposalCategory:\0org.eclipse.jdt.ui.swtProposalCategory:\0org.eclipse.pde.api.tools.ui.apitools_proposal_category:\0"); //$NON-NLS-1$ store.setDefault(PreferenceConstants.CODEASSIST_LRU_HISTORY, ""); //$NON-NLS-1$ store.setDefault(PreferenceConstants.CODEASSIST_SORTER, "org.eclipse.jdt.ui.RelevanceSorter"); //$NON-NLS-1$ store.setDefault(PreferenceConstants.CODEASSIST_FAVORITE_STATIC_MEMBERS, ""); //$NON-NLS-1$ @@ -4005,38 +4027,61 @@ } /** - * Returns the completion proposal categories which - * are excluded from the default proposal list. - * - * @return an array with the IDs of the excluded categories - * @see #CODEASSIST_EXCLUDED_CATEGORIES - * @since 3.4 - */ - public static String[] getExcludedCompletionProposalCategories() { - String encodedPreference= getPreference(CODEASSIST_EXCLUDED_CATEGORIES, null); - StringTokenizer tokenizer= new StringTokenizer(encodedPreference, "\0"); //$NON-NLS-1$ - String[] result= new String[tokenizer.countTokens()]; - for (int i= 0; i < result.length; i++) - result[i]= tokenizer.nextToken(); + * Returns the completion proposal categories with their corresponding proposal list indices. + * + * @return a map which maps the category IDs to a set of proposal list indices + * @see #CODEASSIST_PROPOSAL_LISTS + * @since 3.8 + */ + public static Map> getProposalLists() { + String encodedPreference= getPreference(CODEASSIST_PROPOSAL_LISTS, null); + Map> result= new HashMap>(); + StringTokenizer tok= new StringTokenizer(encodedPreference, "\0"); //$NON-NLS-1$ + for (int i= 0; tok.hasMoreTokens(); i++) { + StringTokenizer inner= new StringTokenizer(tok.nextToken(), ":"); //$NON-NLS-1$ + if (inner.countTokens() == 0) + i--; + while (inner.hasMoreTokens()) { + String category= inner.nextToken(); + Set set= result.get(category); + if (set == null) { + set= new HashSet(); + result.put(category, set); + } + set.add(Integer.valueOf(i)); + } + } return result; } /** - * Sets the completion proposal categories which are excluded from the - * default proposal list and reloads the registry. - * - * @param categories the array with the IDs of the excluded categories - * @see #CODEASSIST_EXCLUDED_CATEGORIES - * @since 3.4 - */ - public static void setExcludedCompletionProposalCategories(String[] categories) { - Assert.isLegal(categories != null); - StringBuffer buf= new StringBuffer(50 * categories.length); - for (int i= 0; i < categories.length; i++) { - buf.append(categories[i]); - buf.append('\0'); + * Sets the completion proposal categories for each proposal list and reloads the registry. + * + * @param proposalLists a map which maps the category IDs to a set of proposal list indices + * @see #CODEASSIST_PROPOSAL_LISTS + * @since 3.8 + */ + public static void setProposalLists(Map> proposalLists) { + Assert.isLegal(proposalLists != null); + int initialBufferSize= 250; + Map proposalListsCategories= new TreeMap(); + for (Entry> category : proposalLists.entrySet()) { + for (Integer index : category.getValue()) { + StringBuffer buf= proposalListsCategories.get(index); + if (buf == null) { + buf= new StringBuffer(initialBufferSize); + proposalListsCategories.put(index, buf); + } + buf.append(category.getKey()); + buf.append(":"); //$NON-NLS-1$ + } + } + StringBuffer buf= new StringBuffer(initialBufferSize * proposalListsCategories.size()); + for (StringBuffer proposalList : proposalListsCategories.values()) { + buf.append(proposalList); + buf.append("\0"); //$NON-NLS-1$ } - getPreferenceStore().setValue(CODEASSIST_EXCLUDED_CATEGORIES, buf.toString()); + getPreferenceStore().setValue(CODEASSIST_PROPOSAL_LISTS, buf.toString()); CompletionProposalComputerRegistry.getDefault().reload(); }