/** * Copyright (c) 2010, 2013 Darmstadt University of Technology. * 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: * Marcel Bruch - initial API and implementation. */ package org.eclipse.recommenders.internal.completion.rcp; import static org.eclipse.recommenders.internal.completion.rcp.Constants.PREF_SESSIONPROCESSORS; import static org.eclipse.recommenders.utils.Checks.cast; import java.util.List; import java.util.Set; import javax.inject.Inject; import org.apache.commons.lang3.ArrayUtils; import org.eclipse.core.runtime.preferences.InstanceScope; import org.eclipse.jdt.ui.PreferenceConstants; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.GridLayoutFactory; import org.eclipse.jface.preference.FieldEditor; import org.eclipse.jface.preference.FieldEditorPreferencePage; import org.eclipse.jface.viewers.ArrayContentProvider; import org.eclipse.jface.viewers.CheckboxTableViewer; import org.eclipse.jface.viewers.ColumnLabelProvider; import org.eclipse.jface.viewers.ColumnViewerToolTipSupport; import org.eclipse.jface.viewers.DoubleClickEvent; import org.eclipse.jface.viewers.IDoubleClickListener; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerSorter; import org.eclipse.recommenders.completion.rcp.processable.SessionProcessorDescriptor; import org.eclipse.recommenders.internal.completion.rcp.l10n.Messages; import org.eclipse.recommenders.utils.Checks; import org.eclipse.recommenders.utils.rcp.Selections; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Link; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchPreferencePage; import org.eclipse.ui.dialogs.PreferencesUtil; import org.eclipse.ui.preferences.ScopedPreferenceStore; import com.google.common.base.Optional; import com.google.common.base.Predicate; import com.google.common.collect.Collections2; import com.google.common.collect.Lists; public class CompletionsPreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage { private final CompletionRcpPreferences preferences; @Inject public CompletionsPreferencePage(CompletionRcpPreferences preferences) { super(GRID); this.preferences = preferences; } @Override public void init(IWorkbench workbench) { setPreferenceStore(new ScopedPreferenceStore(InstanceScope.INSTANCE, Constants.BUNDLE_NAME)); setMessage(Messages.PREFPAGE_TITLE_COMPLETIONS); setDescription(Messages.PREFPAGE_DESCRIPTION_COMPLETIONS); } @Override protected void createFieldEditors() { addField(new SessionProcessorEditor(PREF_SESSIONPROCESSORS, Messages.FIELD_LABEL_SESSION_PROCESSORS, getFieldEditorParent())); addField(new ContentAssistEnablementEditor(Constants.RECOMMENDERS_ALL_CATEGORY_ID, "enablement", //$NON-NLS-1$ getFieldEditorParent())); Dialog.applyDialogFont(getControl()); } private final class SessionProcessorEditor extends FieldEditor { private CheckboxTableViewer tableViewer; private Composite buttonBox; private Button configureBtn; private SessionProcessorEditor(String name, String labelText, Composite parent) { super(name, labelText, parent); } @Override protected void adjustForNumColumns(int numColumns) { } @Override protected void doFillIntoGrid(Composite parent, int numColumns) { Control control = getLabelControl(parent); GridDataFactory.swtDefaults().span(numColumns, 1).applyTo(control); tableViewer = getTableControl(parent); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.FILL).span(numColumns - 1, 1).grab(true, false) .applyTo(tableViewer.getTable()); tableViewer.getTable().addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { updateButtonStatus(); setPresentsDefaultValue(false); } }); buttonBox = getButtonControl(parent); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.BEGINNING).applyTo(buttonBox); } private CheckboxTableViewer getTableControl(Composite parent) { CheckboxTableViewer tableViewer = CheckboxTableViewer.newCheckList(parent, SWT.BORDER | SWT.FULL_SELECTION); tableViewer.setLabelProvider(new ColumnLabelProvider() { @Override public String getText(Object element) { SessionProcessorDescriptor descriptor = cast(element); return descriptor.getName(); } @Override public String getToolTipText(Object element) { SessionProcessorDescriptor descriptor = cast(element); return descriptor.getDescription(); } @Override public Image getImage(Object element) { SessionProcessorDescriptor descriptor = cast(element); return descriptor.getIcon(); } }); ColumnViewerToolTipSupport.enableFor(tableViewer); tableViewer.setContentProvider(new ArrayContentProvider()); tableViewer.addDoubleClickListener(new IDoubleClickListener() { @Override public void doubleClick(DoubleClickEvent event) { openSessionProcessorPreferencePage(event.getSelection()); } }); return tableViewer; } private Composite getButtonControl(Composite parent) { Composite box = new Composite(parent, SWT.NONE); GridLayoutFactory.fillDefaults().applyTo(box); configureBtn = createButton(box, Messages.BUTTON_LABEL_CONFIGURE); return box; } private Button createButton(Composite box, String text) { Button button = new Button(box, SWT.PUSH); button.setText(text); button.setEnabled(false); button.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { openSessionProcessorPreferencePage(tableViewer.getSelection()); } }); int widthHint = Math.max(convertHorizontalDLUsToPixels(button, IDialogConstants.BUTTON_WIDTH), button.computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x); GridDataFactory.swtDefaults().align(SWT.FILL, SWT.CENTER).hint(widthHint, SWT.DEFAULT).applyTo(button); return button; } private void updateButtonStatus() { int selectionIndex = tableViewer.getTable().getSelectionIndex(); if (selectionIndex == -1) { configureBtn.setEnabled(false); return; } IStructuredSelection selected = (IStructuredSelection) tableViewer.getSelection(); SessionProcessorDescriptor descriptor = cast(selected.getFirstElement()); configureBtn.setEnabled(descriptor.getPreferencePage().isPresent()); } private void openSessionProcessorPreferencePage(ISelection selection) { Optional<SessionProcessorDescriptor> optionalDescriptor = Selections .<SessionProcessorDescriptor>getFirstSelected(selection); if (!optionalDescriptor.isPresent()) { return; } SessionProcessorDescriptor descriptor = optionalDescriptor.get(); if (!descriptor.getPreferencePage().isPresent()) { return; } String id = descriptor.getPreferencePage().get(); PreferencesUtil.createPreferenceDialogOn(getShell(), id, null, null); } @Override protected void doLoad() { Set<SessionProcessorDescriptor> input = preferences.getAvailableSessionProcessors(); List<SessionProcessorDescriptor> checkedElements = Lists.newArrayList(); for (SessionProcessorDescriptor descriptor : input) { if (preferences.isEnabled(descriptor)) { checkedElements.add(descriptor); } } tableViewer.setInput(input); tableViewer.setSorter(new ViewerSorter() { @Override public int compare(Viewer viewer, Object e1, Object e2) { SessionProcessorDescriptor lhs = Checks.cast(e1); SessionProcessorDescriptor rhs = Checks.cast(e2); return lhs.getName().compareTo(rhs.getName()); } }); tableViewer.setCheckedElements(checkedElements.toArray()); } @Override protected void doLoadDefault() { Set<SessionProcessorDescriptor> input = preferences.getAvailableSessionProcessors(); List<SessionProcessorDescriptor> checkedElements = Lists.newArrayList(); for (SessionProcessorDescriptor descriptor : input) { if (descriptor.isEnabledByDefault()) { checkedElements.add(descriptor); } } tableViewer.setInput(input); tableViewer.setCheckedElements(checkedElements.toArray()); updateButtonStatus(); } @Override protected void doStore() { Set<SessionProcessorDescriptor> descriptors = cast(tableViewer.getInput()); preferences.setSessionProcessorEnabled(Collections2.filter(descriptors, new EnabledPredicate(true)), Collections2.filter(descriptors, new EnabledPredicate(false))); updateButtonStatus(); } private final class EnabledPredicate implements Predicate<SessionProcessorDescriptor> { private final boolean enabled; public EnabledPredicate(boolean enabled) { this.enabled = enabled; } @Override public boolean apply(SessionProcessorDescriptor descriptor) { return !(enabled ^ tableViewer.getChecked(descriptor)); } } @Override public int getNumberOfControls() { return 2; } } private final class ContentAssistEnablementEditor extends FieldEditor { public ContentAssistEnablementEditor(String recommendersAllCategoryId, String string, Composite fieldEditorParent) { super(recommendersAllCategoryId, string, fieldEditorParent); } @Override protected void adjustForNumColumns(int numColumns) { // TODO Auto-generated method stub } @Override protected void doFillIntoGrid(Composite parent, int numColumns) { ContentAssistEnablementBlock enable = new ContentAssistEnablementBlock(parent, Messages.FIELD_LABEL_ENABLE_COMPLETION, Constants.RECOMMENDERS_ALL_CATEGORY_ID) { @Override protected void additionalExcludedCompletionCategoriesUpdates(final boolean isEnabled, final Set<String> cats) { if (isEnabled) { // enable subwords - disable mylyn and jdt cats.add(JDT_ALL_CATEGORY); cats.add(MYLYN_ALL_CATEGORY); } else { // disable subwords - enable jdt -- or mylyn if installed. if (isMylynInstalled()) { cats.remove(MYLYN_ALL_CATEGORY); } else { cats.remove(JDT_ALL_CATEGORY); } } } @Override public void loadSelection() { String[] excluded = PreferenceConstants.getExcludedCompletionProposalCategories(); boolean deactivated = ArrayUtils.contains(excluded, Constants.RECOMMENDERS_ALL_CATEGORY_ID); boolean mylynActive = isMylynInstalled() && !ArrayUtils.contains(excluded, MYLYN_ALL_CATEGORY); boolean jdtActive = !ArrayUtils.contains(excluded, JDT_ALL_CATEGORY); enablement.setSelection(!(deactivated || mylynActive || jdtActive)); enablement.setToolTipText(Messages.FIELD_TOOLTIP_ENABLE_COMPLETION); } }; enable.loadSelection(); Link contentAssistLink = new Link(parent, SWT.NONE | SWT.WRAP); contentAssistLink.setLayoutData(GridDataFactory.swtDefaults().span(2, 1).align(SWT.FILL, SWT.BEGINNING) .grab(true, false).hint(super.convertHorizontalDLUsToPixels(contentAssistLink, IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH), SWT.DEFAULT) .create()); contentAssistLink.setText(Messages.PREFPAGE_FOOTER_COMPLETIONS); contentAssistLink.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent event) { PreferencesUtil.createPreferenceDialogOn(getShell(), "org.eclipse.jdt.ui.preferences.CodeAssistPreferenceAdvanced", null, null); //$NON-NLS-1$ } }); } @Override protected void doLoad() { // No-op - functionality provided by ContentAssistEnablementBlock } @Override protected void doLoadDefault() { // No-op } @Override protected void doStore() { // No-op - functionality provided by ContentAssistEnablementBlock } @Override public int getNumberOfControls() { return 0; } } }