blob: b94a8d872719ed5802c8f4b77c18b35fe1639db0 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2014, 2016 Obeo 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:
* Obeo - initial API and implementation
* Simon Delisle - bug 495753
*******************************************************************************/
package org.eclipse.emf.compare.rcp.ui.internal.preferences;
import static org.eclipse.jface.dialogs.MessageDialogWithToggle.ALWAYS;
import static org.eclipse.jface.dialogs.MessageDialogWithToggle.NEVER;
import static org.eclipse.jface.dialogs.MessageDialogWithToggle.PROMPT;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.collect.Sets.SetView;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.beans.PojoProperties;
import org.eclipse.core.databinding.observable.set.IObservableSet;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.emf.compare.rcp.internal.extension.IItemDescriptor;
import org.eclipse.emf.compare.rcp.internal.tracer.TracingConstant;
import org.eclipse.emf.compare.rcp.ui.EMFCompareRCPUIPlugin;
import org.eclipse.emf.compare.rcp.ui.internal.EMFCompareRCPUIMessages;
import org.eclipse.emf.compare.rcp.ui.internal.structuremergeviewer.filters.impl.DifferenceFilterManager;
import org.eclipse.emf.compare.rcp.ui.structuremergeviewer.filters.IDifferenceFilter;
import org.eclipse.jface.databinding.viewers.IViewerObservableSet;
import org.eclipse.jface.databinding.viewers.ViewersObservables;
import org.eclipse.jface.dialogs.MessageDialogWithToggle;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.preference.PreferencePage;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.CheckboxTableViewer;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPreferencePage;
/**
* Preference page for {@link IDifferenceFilter}.
*
* @author <a href="mailto:arthur.daussy@obeo.fr">Arthur Daussy</a>
*/
public class FiltersPreferencePage extends PreferencePage implements IWorkbenchPreferencePage {
/** Preference page ID. */
public static final String PAGE_ID = "org.eclipse.emf.compare.rcp.ui.preferencePage.filters"; //$NON-NLS-1$
/** Preference key holding synchronization behavior value. */
public static final String SYNCHRONIZATION_BEHAVIOR = "org.eclipse.emf.compare.rcp.ui.filters.syncbehavior"; //$NON-NLS-1$
/** Width hint for introduction label. */
private static final int INTRO_TEXT_WIDTH_HINT = 400;
/** Values used for the combobox. */
private static final List<String> SYNC_VALUES = ImmutableList.of(ALWAYS, NEVER, PROMPT);
/** Filter manager. Used to retrieve current and default configuration. */
private DifferenceFilterManager filterManager = null;
/** Interactive content holding UI components for enabled/disabled filters. */
private InteractiveFilterUIContent defaultFilterInteractiveContent;
/** Interactive content holding UI components for activated/deactivated filters. */
private InteractiveFilterUIContent activateFilterInteractiveContent;
/** The tab used to choose enabled filters. */
private Composite enabledFilterTabComposite;
/** The tab used to choose active filters. */
private Composite activateFilterTabComposite;
/** Combo holding synchronization behavior preferences. */
private Combo combo;
/** Field holding {@link SynchronizationBehavior} */
private String synchronizationBehaviorValue;
public void init(IWorkbench workbench) {
setPreferenceStore(EMFCompareRCPUIPlugin.getDefault().getPreferenceStore());
}
@Override
protected Control createContents(Composite parent) {
Composite container = new Composite(parent, SWT.NONE);
GridLayoutFactory.fillDefaults().applyTo(container);
GridDataFactory.fillDefaults().grab(true, true).applyTo(container);
createSynchronizationBehaviorContent(container);
setComboInput(getCurrentSynchronizationBehavior());
TabFolder tabFolder = new TabFolder(container, SWT.NONE);
GridDataFactory.fillDefaults().grab(true, true).applyTo(tabFolder);
// Create tab to choose filters that are enabled by default
createDefaultEnabledFilterTab(tabFolder);
// Create tab to activate or deactivate totally filters
createActivateFilterTab(tabFolder);
return container;
}
/**
* Create a tab to choose which filters to enable by default.
*
* @param tabFolder
*/
private void createDefaultEnabledFilterTab(TabFolder tabFolder) {
enabledFilterTabComposite = createTabSkeleton(tabFolder,
EMFCompareRCPUIMessages.getString("FiltersPreferencePage.select.tab.label"), //$NON-NLS-1$
EMFCompareRCPUIMessages.getString("FiltersPreferencePage.selectIntro.text")); //$NON-NLS-1$
if (filterManager == null) {
filterManager = EMFCompareRCPUIPlugin.getDefault().getDifferenceFilterManager();
}
defaultFilterInteractiveContent = new InteractiveFilterUIContent(enabledFilterTabComposite,
filterManager.getAllFilters(), filterManager.getCurrentByDefaultFilters(), false);
}
/**
* Create a tab to select which filters to activate or deactivate.
*
* @param tabFolder
*/
private void createActivateFilterTab(TabFolder tabFolder) {
activateFilterTabComposite = createTabSkeleton(tabFolder,
EMFCompareRCPUIMessages.getString("FiltersPreferencePage.activate.tab.label"), //$NON-NLS-1$
EMFCompareRCPUIMessages.getString("FiltersPreferencePage.activateIntro.text")); //$NON-NLS-1$
if (filterManager == null) {
filterManager = EMFCompareRCPUIPlugin.getDefault().getDifferenceFilterManager();
}
activateFilterInteractiveContent = new InteractiveFilterUIContent(activateFilterTabComposite,
filterManager.getAllFilters(), filterManager.getCurrentInactiveFilters(), true);
}
/**
* Create skeleton of a tab.
*
* @param tabFolder
* @param tabLabel
* @param introText
* Text use as description a tab
* @return Main composite of the tab
*/
private Composite createTabSkeleton(TabFolder tabFolder, String tabLabel, String introText) {
TabItem tbtmMain = new TabItem(tabFolder, SWT.NONE);
tbtmMain.setText(tabLabel);
Composite tabComposite = new Composite(tabFolder, SWT.NONE);
tbtmMain.setControl(tabComposite);
GridLayout layout = new GridLayout(1, true);
tabComposite.setLayout(layout);
GridData layoutData = new GridData(SWT.FILL, SWT.FILL, false, false, 1, 1);
tabComposite.setLayoutData(layoutData);
// Description text
Label introductionText = new Label(tabComposite, SWT.WRAP);
GridDataFactory.fillDefaults().grab(true, false).hint(INTRO_TEXT_WIDTH_HINT, SWT.DEFAULT)
.applyTo(introductionText);
introductionText.setText(introText);
return tabComposite;
}
/**
* Content for synchronization behavior preferences.
*
* @param parent
*/
private void createSynchronizationBehaviorContent(Composite parent) {
Composite synchronizationComposite = new Composite(parent, SWT.NONE);
GridLayoutFactory.fillDefaults().numColumns(2).applyTo(synchronizationComposite);
Label label = new Label(synchronizationComposite, SWT.WRAP);
label.setText(EMFCompareRCPUIMessages.getString("InteractiveFilterUIContent.sync.behavior.label")); //$NON-NLS-1$
label.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
combo = new Combo(synchronizationComposite, SWT.DROP_DOWN | SWT.READ_ONLY);
for (String comboLabel : SYNC_VALUES) {
combo.add(comboLabel);
}
combo.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, true));
combo.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if (combo.equals(e.getSource())) {
synchronizationBehaviorValue = combo.getItem(combo.getSelectionIndex());
}
}
});
}
/**
* Select the correct behavior in the interactive UI.
*
* @param behavior
*/
public void setComboInput(String behavior) {
int index = 0;
for (String value : SYNC_VALUES) {
if (value.equals(behavior)) {
combo.select(index);
synchronizationBehaviorValue = behavior;
}
index++;
}
}
/**
* Gets the current value of the filter synchronization behavior.
* <p>
* This value can only be one of the following:
* <ul>
* <li>{@link MessageDialogWithToggle#PROMPT}</li>
* <li>{@link MessageDialogWithToggle#ALWAYS}</li>
* <li>{@link MessageDialogWithToggle#NEVER}</li>
* </ul>
* </p>
*
* @return String.
*/
public String getCurrentSynchronizationBehavior() {
String value = getPreferenceStore().getString(SYNCHRONIZATION_BEHAVIOR);
if (value == null || !SYNC_VALUES.contains(value)) {
value = getDefaultSynchronizationBehavior();
}
return value;
}
/**
* @return The default value of filter synchronization behavior.
*/
public String getDefaultSynchronizationBehavior() {
return MessageDialogWithToggle.PROMPT;
}
/**
* Set the current value of the filter synchronization behavior.
*
* @param newBehavior
* New value.
*/
public void setCurrentSynchronizationBehavior(String newBehavior) {
if (getDefaultSynchronizationBehavior().equals(newBehavior)) {
getPreferenceStore().setToDefault(SYNCHRONIZATION_BEHAVIOR);
} else {
getPreferenceStore().setValue(SYNCHRONIZATION_BEHAVIOR, newBehavior);
}
// Trace preferences values
if (TracingConstant.CONFIGURATION_TRACING_ACTIVATED) {
StringBuilder builder = new StringBuilder();
// Print each preferences
builder.append("Preference ").append(SYNCHRONIZATION_BEHAVIOR).append(":\n"); //$NON-NLS-1$ //$NON-NLS-2$
String preferenceValue = getPreferenceStore().getString(SYNCHRONIZATION_BEHAVIOR);
builder.append(preferenceValue);
EMFCompareRCPUIPlugin.getDefault().log(IStatus.INFO, builder.toString());
}
}
/**
* {@inheritDoc}
*/
@Override
public boolean performOk() {
filterManager.setCurrentByDefaultFilters(defaultFilterInteractiveContent.getCheckedFilter());
filterManager.setCurrentActiveFilters(activateFilterInteractiveContent.getCheckedFilter());
setCurrentSynchronizationBehavior(synchronizationBehaviorValue);
return super.performOk();
}
/**
* {@inheritDoc}
*/
@Override
protected void performDefaults() {
if (activateFilterTabComposite.isVisible()) {
activateFilterInteractiveContent.checkElements(filterManager.getAllFilters());
}
if (enabledFilterTabComposite.isVisible()) {
defaultFilterInteractiveContent.checkElements(filterManager.getInitialByDefaultFilters());
setComboInput(getDefaultSynchronizationBehavior());
}
super.performDefaults();
}
/**
* Interactive UI for filter preference page.
*
* @author <a href="mailto:arthur.daussy@obeo.fr">Arthur Daussy</a>
*/
private static class InteractiveFilterUIContent {
/** Height hint for the description label. */
private static final int DESCRIPTION_LABEL_HEIGHT_HINT = 50;
/** Width hint for configuration composite. */
private static final int DESCRIPTION_LABEL_WIDTH_HINT = 400;
/** Text that will be updated with the description of the viewer. */
private final Label descriptionText;
/** Viewer of {@link IDifferenceFilter}. */
private CheckboxTableViewer viewer;
/** DataHolder for enabled/disabled {@link IDifferenceFilter}. */
private FilterDataHolder dataHolder = new FilterDataHolder();
/** DataHolder for activated/deactivated {@link IDifferenceFilter}. */
private FilterDataHolder allFilters = new FilterDataHolder();
private InteractiveFilterUIContent(Composite parent, Collection<? extends IDifferenceFilter> filters,
Collection<? extends IDifferenceFilter> defaultCheck, boolean isDeactivateTab) {
super();
Composite contentComposite = new Composite(parent, SWT.NONE);
GridLayoutFactory.fillDefaults().extendedMargins(0, 0, 10, 0).applyTo(contentComposite);
contentComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
Label introductionText = new Label(contentComposite, SWT.WRAP);
if (isDeactivateTab) {
introductionText.setText(
EMFCompareRCPUIMessages.getString("FiltersPreferencePage.INTRO_DEACTIVATE_TEXT")); //$NON-NLS-1$
} else {
introductionText.setText(
EMFCompareRCPUIMessages.getString("FiltersPreferencePage.INTRO_SELECT_TEXT")); //$NON-NLS-1$
}
introductionText.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 1, 1));
// Engine chooser composite
Composite viewerComposite = new Composite(contentComposite, SWT.NONE);
GridLayoutFactory.fillDefaults().applyTo(viewerComposite);
viewerComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
viewer = createViewer(viewerComposite);
// Descriptor engine Text
this.descriptionText = createDescriptionComposite(contentComposite);
setViewerInput(Lists.newArrayList(filters));
if (isDeactivateTab) {
SetView<IDifferenceFilter> activatedFilters = Sets.difference(Sets.newLinkedHashSet(filters),
Sets.newLinkedHashSet(defaultCheck));
bindAndInit(activatedFilters);
} else {
bindAndInit(Sets.newLinkedHashSet(defaultCheck));
}
allFilters.setFilters(Sets.newLinkedHashSet(filters));
}
/**
* @return All checked {@link IDifferenceFilter}.
*/
public Set<IDifferenceFilter> getCheckedFilter() {
return dataHolder.getFilters();
}
private void setViewerInput(List<IDifferenceFilter> filters) {
Collections.sort(filters, new Comparator<IDifferenceFilter>() {
public int compare(IDifferenceFilter o1, IDifferenceFilter o2) {
if (o1 == o2) {
return 0;
} else if (o1 == null || o1.getLabel() == null) {
return -1;
} else if (o2 == null || o2.getLabel() == null) {
return 1;
}
return o1.getLabel().compareTo(o2.getLabel());
}
});
viewer.setInput(filters);
select(filters.iterator().next());
}
private CheckboxTableViewer createViewer(Composite viewerCompsite) {
CheckboxTableViewer descriptorViewer = CheckboxTableViewer.newCheckList(viewerCompsite,
SWT.BORDER | SWT.V_SCROLL | SWT.FULL_SELECTION);
descriptorViewer.setContentProvider(ArrayContentProvider.getInstance());
descriptorViewer.setLabelProvider(new FilterLabelProvider());
GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1);
descriptorViewer.getControl().setLayoutData(gd);
setViewer(descriptorViewer);
return descriptorViewer;
}
private void bindAndInit(Set<IDifferenceFilter> defaultCheck) {
if (dataHolder != null) {
if (defaultCheck != null) {
dataHolder.setFilters(defaultCheck);
}
// Bind data
bindMultipleData(viewer, dataHolder);
}
}
/**
* Bind UI to data object.
*
* @param engineBindingProperty
* @param descriptorViewer
* @param dataObject
*/
private void bindMultipleData(CheckboxTableViewer descriptorViewer, FilterDataHolder dataObject) {
DataBindingContext ctx = new DataBindingContext();
// Bind the button with the corresponding field in data
IViewerObservableSet target = ViewersObservables.observeCheckedElements(descriptorViewer,
IDifferenceFilter.class);
IObservableSet model = PojoProperties.set(FilterDataHolder.class, FilterDataHolder.FIELD_NAME)
.observe(dataObject);
ctx.bindSet(target, model);
}
/**
* Check element in the viewer.
*
* @param checkedFilter
* Element to check.
*/
public void checkElements(Set<IDifferenceFilter> checkedFilter) {
viewer.setCheckedElements(checkedFilter.toArray());
dataHolder.setFilters(checkedFilter);
}
/**
* Composite for description. This composite hold the text widget that will update with the current
* selection
*
* @param composite
* @return
*/
private Label createDescriptionComposite(Composite composite) {
Group descriptionComposite = new Group(composite, SWT.NONE);
descriptionComposite.setText(
EMFCompareRCPUIMessages.getString("InteractiveUIContent.descriptionComposite.label")); //$NON-NLS-1$
GridLayoutFactory.swtDefaults().applyTo(descriptionComposite);
descriptionComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1));
Label engineDescriptionLabel = new Label(descriptionComposite, SWT.WRAP);
GridDataFactory.fillDefaults().grab(true, false)
.hint(DESCRIPTION_LABEL_WIDTH_HINT, DESCRIPTION_LABEL_HEIGHT_HINT)
.applyTo(engineDescriptionLabel);
return engineDescriptionLabel;
}
/**
* Handle a selection in the viewer. Update related components.
*
* @param descriptor
*/
public void select(IDifferenceFilter descriptor) {
// Update viewer
viewer.setSelection(new StructuredSelection(descriptor), true);
String description = descriptor.getDescription();
if (description != null) {
descriptionText.setText(description);
} else {
descriptionText.setText(""); //$NON-NLS-1$
}
}
/**
* @param viewer
* A {@link StructuredViewer} of {@link IItemDescriptor}
*/
public void setViewer(CheckboxTableViewer inputViewer) {
this.viewer = inputViewer;
viewer.addSelectionChangedListener(new DescriptionListener());
}
/**
* Listener to update description text
*
* @author <a href="mailto:arthur.daussy@obeo.fr">Arthur Daussy</a>
*/
private final class DescriptionListener implements ISelectionChangedListener {
public void selectionChanged(SelectionChangedEvent event) {
ISelection selection = event.getSelection();
if (selection instanceof IStructuredSelection) {
IStructuredSelection structSelection = (IStructuredSelection)selection;
Object selected = structSelection.getFirstElement();
if (selected instanceof IDifferenceFilter) {
IDifferenceFilter desc = (IDifferenceFilter)selected;
String description = desc.getDescription();
if (description != null) {
descriptionText.setText(description);
} else {
descriptionText.setText(""); //$NON-NLS-1$
}
}
}
}
}
/**
* Label provider for {@link IDifferenceFilter}.
*
* @author <a href="mailto:arthur.daussy@obeo.fr">Arthur Daussy</a>
*/
private static final class FilterLabelProvider extends LabelProvider {
/**
* {@inheritDoc}
*/
@Override
public String getText(Object element) {
if (element instanceof IDifferenceFilter) {
return ((IDifferenceFilter)element).getLabel();
}
return super.getText(element);
}
}
/**
* Data holder for checked {@link IDifferenceFilter}.
*
* @author <a href="mailto:arthur.daussy@obeo.fr">Arthur Daussy</a>
*/
private static final class FilterDataHolder {
private static final String FIELD_NAME = "filters"; //$NON-NLS-1$
private Set<IDifferenceFilter> filters;
public Set<IDifferenceFilter> getFilters() {
return filters;
}
public void setFilters(Set<IDifferenceFilter> filters) {
this.filters = filters;
}
}
}
}