/** * Copyright (c) 2015 Pawel Nowak. * 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 */ package org.eclipse.recommenders.internal.news.rcp.preferences; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.eclipse.core.runtime.preferences.InstanceScope; 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.BooleanFieldEditor; import org.eclipse.jface.preference.FieldEditor; import org.eclipse.jface.preference.FieldEditorPreferencePage; import org.eclipse.jface.preference.IntegerFieldEditor; 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.IStructuredSelection; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerComparator; import org.eclipse.jface.window.Window; import org.eclipse.recommenders.internal.news.rcp.Constants; import org.eclipse.recommenders.internal.news.rcp.FeedDescriptor; import org.eclipse.recommenders.internal.news.rcp.FeedDescriptors; import org.eclipse.recommenders.internal.news.rcp.PreferenceConstants; import org.eclipse.recommenders.internal.news.rcp.l10n.Messages; import org.eclipse.swt.SWT; import org.eclipse.swt.events.MouseAdapter; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.TableItem; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchPreferencePage; import org.eclipse.ui.preferences.ScopedPreferenceStore; import com.google.common.base.Predicate; import com.google.common.base.Strings; import com.google.common.collect.Collections2; import com.google.common.collect.ComparisonChain; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; public class NewsPreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage { private BooleanFieldEditor enabledEditor; private FeedEditor feedEditor; private IntegerFieldEditor startupEditor; public NewsPreferencePage() { super(GRID); } @Override public void init(IWorkbench workbench) { setPreferenceStore(new ScopedPreferenceStore(InstanceScope.INSTANCE, Constants.PLUGIN_ID)); setMessage(Messages.PREFPAGE_TITLE); setDescription(Messages.PREFPAGE_DESCRIPTION); } @Override protected void createFieldEditors() { enabledEditor = new BooleanFieldEditor(PreferenceConstants.NEWS_ENABLED, Messages.FIELD_LABEL_NEWS_ENABLED, 0, getFieldEditorParent()) { @Override protected void valueChanged(boolean oldValue, boolean newValue) { super.valueChanged(oldValue, newValue); startupEditor.setEnabled(enabledEditor.getBooleanValue(), getFieldEditorParent()); } }; addField(enabledEditor); startupEditor = new IntegerFieldEditor(PreferenceConstants.POLLING_DELAY, Messages.FIELD_LABEL_STARTUP_DELAY, getFieldEditorParent(), 4); startupEditor.setEnabled(getPreferenceStore().getBoolean(PreferenceConstants.NEWS_ENABLED), getFieldEditorParent()); addField(startupEditor); final Composite bottomGroup = new Composite(getFieldEditorParent(), SWT.NONE); GridDataFactory.fillDefaults().grab(true, true).span(2, 1).applyTo(bottomGroup); GridLayoutFactory.fillDefaults().numColumns(1).applyTo(bottomGroup); feedEditor = new FeedEditor(PreferenceConstants.FEED_LIST_SORTED, Messages.FIELD_LABEL_FEEDS, bottomGroup); addField(feedEditor); addField(new LinkEditor(Messages.PREFPAGE_NOTIFICATION_ENABLEMENT, "org.eclipse.mylyn.commons.notifications.preferencePages.Notifications", //$NON-NLS-1$ getFieldEditorParent())); addField(new LinkEditor(Messages.PREFPAGE_WEB_BROWSER_SETTINGS, "org.eclipse.ui.browser.preferencePage", //$NON-NLS-1$ getFieldEditorParent())); Dialog.applyDialogFont(getControl()); } private final class FeedEditor extends FieldEditor { private CheckboxTableViewer tableViewer; private Composite buttonBox; private Button newButton; private Button editButton; private Button removeButton; private FeedEditor(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, true) .applyTo(tableViewer.getTable()); tableViewer.getTable().addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { if (e.detail == SWT.CHECK) { } updateButtonStatus(); } }); tableViewer.getTable().addMouseListener(new MouseAdapter() { @Override public void mouseDoubleClick(MouseEvent e) { tableViewer.setSelection(new StructuredSelection(FeedDescriptor.class), true); TableItem item = tableViewer.getTable().getItem(new Point(e.x, e.y)); if (item == null) { return; } Rectangle bounds = item.getBounds(); boolean isClickOnCheckbox = e.x < bounds.x; if (isClickOnCheckbox) { return; } FeedDescriptor feed = (FeedDescriptor) item.getData(); if (!feed.isDefaultRepository()) { editFeed(feed); } updateButtonStatus(); } }); buttonBox = getButtonControl(parent); updateButtonStatus(); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.BEGINNING).applyTo(buttonBox); } private void updateButtonStatus() { boolean selected = tableViewer.getTable().getSelectionIndex() != -1; FeedDescriptor feed = getSelectedFeed(); if (feed == null) { editButton.setEnabled(false); removeButton.setEnabled(false); return; } editButton.setEnabled(selected && !feed.isDefaultRepository()); removeButton.setEnabled(selected && !feed.isDefaultRepository()); } private Composite getButtonControl(Composite parent) { Composite box = new Composite(parent, SWT.NONE); GridLayoutFactory.fillDefaults().applyTo(box); newButton = createButton(box, Messages.PREFPAGE_BUTTON_NEW); newButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { addNewFeed(); updateButtonStatus(); } }); editButton = createButton(box, Messages.PREFPAGE_BUTTON_EDIT); editButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { editFeed(getSelectedFeed()); updateButtonStatus(); } }); editButton.setEnabled(false); removeButton = createButton(box, Messages.PREFPAGE_BUTTON_REMOVE); removeButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { removeFeed(getSelectedFeed()); updateButtonStatus(); } }); return box; } private FeedDescriptor getSelectedFeed() { IStructuredSelection selected = (IStructuredSelection) tableViewer.getSelection(); return (FeedDescriptor) selected.getFirstElement(); } protected void removeFeed(FeedDescriptor feed) { List<FeedDescriptor> feeds = getTableInput(); feeds.remove(feed); updateTableContent(feeds); } protected void editFeed(FeedDescriptor oldFeed) { @SuppressWarnings("unchecked") List<FeedDescriptor> descriptors = (List<FeedDescriptor>) tableViewer.getInput(); FeedDialog dialog = new FeedDialog(getShell(), oldFeed, descriptors); List<FeedDescriptor> feeds = getTableInput(); if (dialog.open() == Window.OK) { int index = feeds.indexOf(oldFeed); feeds.remove(oldFeed); feeds.add(index, dialog.getFeed()); updateTableContent(feeds); } } private List<FeedDescriptor> getTableInput() { @SuppressWarnings("unchecked") List<FeedDescriptor> configurations = (List<FeedDescriptor>) tableViewer.getInput(); if (configurations == null) { return new ArrayList<>(); } else { return new ArrayList<>(configurations); } } protected void addNewFeed() { @SuppressWarnings("unchecked") List<FeedDescriptor> descriptors = (List<FeedDescriptor>) tableViewer.getInput(); FeedDialog dialog = new FeedDialog(getShell(), descriptors); List<FeedDescriptor> feeds = getTableInput(); if (dialog.open() == Window.OK) { feeds.add(dialog.getFeed()); updateTableContent(feeds); } } private Button createButton(Composite box, String text) { Button button = new Button(box, SWT.PUSH); button.setText(text); 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 CheckboxTableViewer getTableControl(Composite parent) { CheckboxTableViewer tableViewer = CheckboxTableViewer.newCheckList(parent, SWT.BORDER | SWT.FULL_SELECTION); tableViewer.setLabelProvider(new ColumnLabelProvider() { @Override public String getText(Object element) { FeedDescriptor feed = (FeedDescriptor) element; if (Strings.isNullOrEmpty(feed.getContributedBy())) { return feed.getName(); } return MessageFormat.format(Messages.FEED_CONTRIBUTED_BY, feed.getName(), feed.getContributedBy()); } @Override public String getToolTipText(Object element) { FeedDescriptor feed = (FeedDescriptor) element; return MessageFormat.format(Messages.FEED_TOOLTIP, feed.getUri(), feed.getPollingInterval()); } }); ColumnViewerToolTipSupport.enableFor(tableViewer); tableViewer.setContentProvider(new ArrayContentProvider()); return tableViewer; } @Override protected void doLoad() { String value = getPreferenceStore().getString(getPreferenceName()); load(value, false); } private void load(String value, boolean loadDefaults) { List<FeedDescriptor> input = FeedDescriptors.load(value, FeedDescriptors.getRegisteredFeeds()); if (!loadDefaults) { input.addAll(FeedDescriptors .getFeeds(getPreferenceStore().getString(PreferenceConstants.CUSTOM_FEED_LIST_SORTED))); } List<FeedDescriptor> checkedElements = Lists.newArrayList(); for (FeedDescriptor feed : input) { if (feed.isEnabled()) { checkedElements.add(feed); } } tableViewer.setInput(input); tableViewer.setComparator(new ViewerComparator() { @Override public int compare(Viewer viewer, Object e1, Object e2) { String feedName = Strings.nullToEmpty(((FeedDescriptor) e1).getName()); String otherFeedName = Strings.nullToEmpty(((FeedDescriptor) e2).getName()); return ComparisonChain.start().compare(feedName, otherFeedName, String.CASE_INSENSITIVE_ORDER) .compare(feedName, otherFeedName).result(); } }); tableViewer.setCheckedElements(checkedElements.toArray()); } public void updateTableContent(List<FeedDescriptor> feeds) { final List<FeedDescriptor> oldFeeds = getTableInput(); Collection<FeedDescriptor> checkedFeeds = Collections2.filter(feeds, new Predicate<FeedDescriptor>() { @Override public boolean apply(FeedDescriptor input) { if (oldFeeds != null && oldFeeds.contains(input)) { return tableViewer.getChecked(input); } return input.isEnabled(); } }); tableViewer.setInput(feeds); tableViewer.setCheckedElements(checkedFeeds.toArray()); } @Override public void loadDefault() { super.loadDefault(); // Force storing of both provided and custom feeds setPresentsDefaultValue(false); } @Override protected void doLoadDefault() { String value = getPreferenceStore().getDefaultString(getPreferenceName()); load(value, true); } @Override protected void doStore() { @SuppressWarnings("unchecked") List<FeedDescriptor> descriptors = (List<FeedDescriptor>) tableViewer.getInput(); for (FeedDescriptor descriptor : descriptors) { descriptor.setEnabled(tableViewer.getChecked(descriptor)); } List<FeedDescriptor> feeds = Lists .newArrayList(Iterables.filter(descriptors, new Predicate<FeedDescriptor>() { @Override public boolean apply(FeedDescriptor input) { return input.isDefaultRepository(); } })); List<FeedDescriptor> customFeeds = Lists .newArrayList(Iterables.filter(descriptors, new Predicate<FeedDescriptor>() { @Override public boolean apply(FeedDescriptor input) { return !input.isDefaultRepository(); } })); String newValue = FeedDescriptors.feedsToString(feeds); getPreferenceStore().setValue(getPreferenceName(), newValue); getPreferenceStore().setValue(PreferenceConstants.CUSTOM_FEED_LIST_SORTED, FeedDescriptors.customFeedsToString(customFeeds)); } @Override public int getNumberOfControls() { return 2; } public List<FeedDescriptor> getValue() { @SuppressWarnings("unchecked") List<FeedDescriptor> feeds = (List<FeedDescriptor>) tableViewer.getInput(); for (FeedDescriptor feed : feeds) { feed.setEnabled(tableViewer.getChecked(feed)); } return feeds; } } }