/**
* Copyright (c) 2013 Madhuranga Lakjeewa.
* 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:
* Madhuranga Lakjeewa - initial API and implementation.
* Olav Lenz - introduce ISnippetRepositoryConfiguration.
* Olav Lenz - add wizard support for creating snippet repositories.
*/
package org.eclipse.recommenders.internal.snipmatch.rcp;
import static java.text.MessageFormat.format;
import static org.eclipse.recommenders.internal.snipmatch.rcp.SnipmatchRcpModule.REPOSITORY_CONFIGURATION_FILE;
import static org.eclipse.recommenders.utils.Checks.cast;
import java.io.File;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import javax.inject.Inject;
import javax.inject.Named;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialogWithToggle;
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.window.Window;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.recommenders.internal.snipmatch.rcp.Repositories.SnippetRepositoryConfigurationChangedEvent;
import org.eclipse.recommenders.internal.snipmatch.rcp.l10n.Messages;
import org.eclipse.recommenders.snipmatch.ISnippetRepository;
import org.eclipse.recommenders.snipmatch.model.SnippetRepositoryConfiguration;
import org.eclipse.recommenders.snipmatch.rcp.ISnippetRepositoryWizard;
import org.eclipse.recommenders.snipmatch.rcp.model.SnippetRepositoryConfigurations;
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.collect.Collections2;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.eventbus.EventBus;
public class SnipmatchPreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage {
private final SnipmatchRcpPreferences prefs;
private final EventBus bus;
private final Repositories repos;
private final SnippetRepositoryConfigurations configuration;
private final File repositoryConfigurationFile;
private boolean dirty;
@Inject
public SnipmatchPreferencePage(EventBus bus, Repositories repos, SnippetRepositoryConfigurations configuration,
@Named(REPOSITORY_CONFIGURATION_FILE) File repositoryConfigurationFile, SnipmatchRcpPreferences prefs) {
super(GRID);
setDescription(Messages.PREFPAGE_DESCRIPTION);
this.bus = bus;
this.repos = repos;
this.configuration = configuration;
this.repositoryConfigurationFile = repositoryConfigurationFile;
this.prefs = prefs;
}
@Override
public void createFieldEditors() {
ConfigurationEditor configurationEditor = new ConfigurationEditor("", //$NON-NLS-1$
Messages.PREFPAGE_LABEL_REMOTE_SNIPPETS_REPOSITORY, getFieldEditorParent());
addField(configurationEditor);
Dialog.applyDialogFont(getControl());
dirty = false;
}
@Override
public void init(IWorkbench workbench) {
ScopedPreferenceStore store = new ScopedPreferenceStore(InstanceScope.INSTANCE, Constants.BUNDLE_ID);
setPreferenceStore(store);
}
private final class ConfigurationEditor extends FieldEditor {
private CheckboxTableViewer tableViewer;
private Composite buttonBox;
private Button newButton;
private Button editButton;
private Button removeButton;
private ConfigurationEditor(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) {
dirty = true;
}
updateButtonStatus();
}
});
tableViewer.getTable().addMouseListener(new MouseAdapter() {
@Override
public void mouseDoubleClick(MouseEvent e) {
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;
}
SnippetRepositoryConfiguration selectedConfiguration = cast(item.getData());
if (!selectedConfiguration.isDefaultConfiguration()) {
editConfiguration(selectedConfiguration);
}
updateButtonStatus();
}
});
buttonBox = getButtonControl(parent);
updateButtonStatus();
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.BEGINNING).applyTo(buttonBox);
}
private void updateButtonStatus() {
boolean selected = tableViewer.getTable().getSelectionIndex() != -1;
SnippetRepositoryConfiguration selectedConfiguration = getSelectedConfiguration();
if (selectedConfiguration == null) {
editButton.setEnabled(false);
removeButton.setEnabled(false);
return;
}
boolean wizardAvailable = WizardDescriptors.isWizardAvailable(selectedConfiguration);
boolean defaultConfiguration = selectedConfiguration.isDefaultConfiguration();
editButton.setEnabled(selected && wizardAvailable && !defaultConfiguration);
removeButton.setEnabled(selected && !defaultConfiguration);
}
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) {
addNewConfiguration();
updateButtonStatus();
}
});
editButton = createButton(box, Messages.PREFPAGE_BUTTON_EDIT);
editButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
editConfiguration(getSelectedConfiguration());
updateButtonStatus();
}
});
editButton.setEnabled(false);
removeButton = createButton(box, Messages.PREFPAGE_BUTTON_REMOVE);
removeButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
removeConfiguration(getSelectedConfiguration());
updateButtonStatus();
}
});
return box;
}
private SnippetRepositoryConfiguration getSelectedConfiguration() {
List<SnippetRepositoryConfiguration> tableInput = getTableInput();
int index = tableViewer.getTable().getSelectionIndex();
if (index != -1) {
return tableInput.get(index);
}
return null;
}
protected void removeConfiguration(SnippetRepositoryConfiguration configuration) {
List<SnippetRepositoryConfiguration> configurations = getTableInput();
MessageDialogWithToggle confirmDialog = MessageDialogWithToggle.openOkCancelConfirm(
SnipmatchPreferencePage.this.getShell(), Messages.CONFIRM_DIALOG_DELETE_REPOSITORY_TITLE,
format(Messages.CONFIRM_DIALOG_DELETE_REPOSITORY_MESSAGE, configuration.getName()),
Messages.CONFIRM_DIALOG_DELETE_REPOSITORY_TOGGLE_MESSAGE, true, null, null);
boolean confirmed = confirmDialog.getReturnCode() == Status.OK;
if (!confirmed) {
return;
}
boolean delete = confirmDialog.getToggleState();
if (delete) {
ISnippetRepository repo = repos.getRepository(configuration.getId()).orNull();
if (repo != null) {
repo.delete();
}
}
configurations.remove(configuration);
updateTableContent(configurations);
dirty = true;
}
protected void editConfiguration(SnippetRepositoryConfiguration oldConfiguration) {
List<WizardDescriptor> suitableWizardDescriptors = WizardDescriptors
.filterApplicableWizardDescriptors(WizardDescriptors.loadAvailableWizards(), oldConfiguration);
if (!suitableWizardDescriptors.isEmpty()) {
ISnippetRepositoryWizard wizard;
if (suitableWizardDescriptors.size() == 1) {
wizard = Iterables.getOnlyElement(suitableWizardDescriptors).getWizard();
wizard.setConfiguration(oldConfiguration);
} else {
wizard = new SnippetRepositoryTypeSelectionWizard(oldConfiguration);
}
WizardDialog dialog = new WizardDialog(this.getPage().getShell(), wizard);
dialog.setHelpAvailable(false);
if (dialog.open() == Window.OK) {
List<SnippetRepositoryConfiguration> configurations = getTableInput();
configurations.add(configurations.indexOf(oldConfiguration), wizard.getConfiguration());
configurations.remove(oldConfiguration);
updateTableContent(configurations);
dirty = true;
}
}
}
private List<SnippetRepositoryConfiguration> getTableInput() {
List<SnippetRepositoryConfiguration> configurations = cast(tableViewer.getInput());
if (configurations == null) {
return Lists.newArrayList();
}
return Lists.newArrayList(configurations);
}
protected void addNewConfiguration() {
List<WizardDescriptor> availableWizards = WizardDescriptors.loadAvailableWizards();
if (!availableWizards.isEmpty()) {
SnippetRepositoryTypeSelectionWizard newWizard = new SnippetRepositoryTypeSelectionWizard();
WizardDialog dialog = new WizardDialog(this.getPage().getShell(), newWizard);
dialog.setHelpAvailable(false);
if (dialog.open() == Window.OK) {
List<SnippetRepositoryConfiguration> configurations = getTableInput();
SnippetRepositoryConfiguration newConfiguration = newWizard.getConfiguration();
newConfiguration.setId(UUID.randomUUID().toString());
configurations.add(newConfiguration);
updateTableContent(configurations);
dirty = true;
}
}
}
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) {
final CheckboxTableViewer tableViewer = CheckboxTableViewer.newCheckList(parent,
SWT.BORDER | SWT.FULL_SELECTION);
tableViewer.setLabelProvider(new ColumnLabelProvider() {
@Override
public String getText(Object element) {
SnippetRepositoryConfiguration config = cast(element);
return config.getName();
}
@Override
public String getToolTipText(Object element) {
SnippetRepositoryConfiguration config = cast(element);
return config.getDescription();
}
});
ColumnViewerToolTipSupport.enableFor(tableViewer);
tableViewer.setContentProvider(new ArrayContentProvider());
return tableViewer;
}
@Override
protected void doLoad() {
updateTableContent(Lists.newArrayList(configuration.getRepos()));
}
public void updateTableContent(List<SnippetRepositoryConfiguration> configurations) {
final List<SnippetRepositoryConfiguration> oldConfigurations = getTableInput();
Collection<SnippetRepositoryConfiguration> checkedConfigurations = Collections2.filter(configurations,
new Predicate<SnippetRepositoryConfiguration>() {
@Override
public boolean apply(SnippetRepositoryConfiguration input) {
if (oldConfigurations != null && oldConfigurations.contains(input)) {
return tableViewer.getChecked(input);
}
return prefs.isRepositoryEnabled(input);
}
});
tableViewer.setInput(configurations);
tableViewer.setCheckedElements(checkedConfigurations.toArray());
}
@Override
public void loadDefault() {
super.loadDefault();
// Force storing of both provided and custom repositories
setPresentsDefaultValue(false);
}
@Override
protected void doLoadDefault() {
List<SnippetRepositoryConfiguration> defaultConfigurations = RepositoryConfigurations
.fetchDefaultConfigurations();
updateTableContent(defaultConfigurations);
tableViewer.setCheckedElements(defaultConfigurations.toArray());
dirty = true;
}
@Override
protected void doStore() {
if (!dirty) {
return;
}
List<SnippetRepositoryConfiguration> oldconfigs = getTableInput();
List<SnippetRepositoryConfiguration> newConfigs = Lists.newArrayList();
for (SnippetRepositoryConfiguration config : oldconfigs) {
prefs.setRepositoryEnabled(config, tableViewer.getChecked(config));
newConfigs.add(config);
}
configuration.getRepos().clear();
configuration.getRepos().addAll(newConfigs);
RepositoryConfigurations.storeConfigurations(configuration, repositoryConfigurationFile);
bus.post(new SnippetRepositoryConfigurationChangedEvent());
dirty = false;
}
@Override
public int getNumberOfControls() {
return 2;
}
}
}