/*****************************************************************************
* Copyright (c) 2010 CEA LIST.
*
*
* 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:
* Patrick Tessier (CEA LIST) Patrick.tessier@cea.fr - Initial API and implementation
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Added graphic contributions for the filters
* Remi Schnekenburger (CEA LIST) remi.schnekenburger@cea.fr - Initial History implementation
* Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - History integration
*
*****************************************************************************/
package org.eclipse.papyrus.infra.emf.providers;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.papyrus.infra.emf.Activator;
import org.eclipse.papyrus.infra.widgets.editors.AbstractEditor;
import org.eclipse.papyrus.infra.widgets.editors.ICommitListener;
import org.eclipse.papyrus.infra.widgets.editors.StringEditor;
import org.eclipse.papyrus.infra.widgets.providers.EncapsulatedContentProvider;
import org.eclipse.papyrus.infra.widgets.providers.IDetailLabelProvider;
import org.eclipse.papyrus.infra.widgets.providers.PatternViewerFilter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Table;
/**
* This providers adds a text-filter and an History to EMF-based content providers
*/
//TODO : Extend (Abstract)FilteredContentProvider
public class EMFGraphicalContentProvider extends EncapsulatedContentProvider implements ISelectionChangedListener {
private static final String DIALOG_SETTINGS = EMFGraphicalContentProvider.class.getName();
protected String historyId;
//Unused (yet)
//TODO : Add a preference or a collapsible composite for this feature (Or both)
//
// /**
// * The current metaclass viewer filter
// */
// protected ViewerFilter currentMetaclassViewerFilter;
protected ViewerFilter patternFilter;
private static final String HISTORY_SETTINGS = "History"; //$NON-NLS-1$
private static final String PREVIOUS_SELECTION = "PreviousSelection";
protected List<EObject> selectionHistory;
protected CLabel detailLabel;
protected Object selectedObject;
protected StructuredViewer viewer;
protected ResourceSet resourceSet;
private static final int HISTORY_MAX_SIZE = 5;
private String currentFilterPattern = ""; //$NON-NLS-1$
/**
* the wanted root of the contentprovider
*/
/**
* the constructor
*/
public EMFGraphicalContentProvider(IStructuredContentProvider semanticProvider, ResourceSet resourceSet, String historyId) {
super(semanticProvider);
this.historyId = historyId;
this.resourceSet = resourceSet;
}
/**
* {@inheritDoc}
*/
@Override
public void createBefore(Composite parent) {
createPatternFilter(parent);
}
protected void createPatternFilter(Composite parent) {
StringEditor editor = new StringEditor(parent, SWT.NONE);
editor.setLabel("Filter:");
editor.setToolTipText("Enter the name of the element you're looking for. You can use * as a wildcard");
editor.setValidateOnDelay(true);
patternFilter = new PatternViewerFilter();
((PatternViewerFilter)patternFilter).setPattern(currentFilterPattern);
editor.addCommitListener(new ICommitListener() {
public void commit(AbstractEditor editor) {
String filterPattern = (String)((StringEditor)editor).getValue();
((PatternViewerFilter)patternFilter).setPattern(filterPattern);
viewer.refresh();
if(!("".equals(filterPattern) || currentFilterPattern.equals(filterPattern))) {
Object firstMatch = getFirstMatchingElement(null);
if(firstMatch != null) {
revealSemanticElement(Collections.singletonList(firstMatch));
}
currentFilterPattern = filterPattern;
}
}
});
List<ViewerFilter> filters = new LinkedList<ViewerFilter>(Arrays.asList(viewer.getFilters()));
filters.add(patternFilter);
viewer.setFilters(filters.toArray(new ViewerFilter[filters.size()]));
}
/**
* Returns the first (encapsulated) element matching the current filters
*
* @return
*/
protected Object getFirstMatchingElement(Object parent) {
//Browse from the root element
if(parent == null) {
for(Object parentElement : getElements(viewer.getInput())) {
Object firstMatch = getFirstMatchingElement(parentElement);
if(firstMatch != null) {
return firstMatch;
}
}
return null;
}
for(ViewerFilter filter : viewer.getFilters()) {
if(!filter.select(viewer, getParent(parent), parent)) {
return null;
}
}
//Test the current element
if(isValidValue(parent)) {
return parent;
}
//Browse the child elements
for(Object childElement : getChildren(parent)) {
Object firstMatch = getFirstMatchingElement(childElement);
if(firstMatch != null) {
return firstMatch;
}
}
//No match found
return null;
}
/**
* {@inheritDoc}
*/
@Override
public void createAfter(Composite parent) {
parent.setLayout(new GridLayout(1, false));
// createMetaclassFilter(parent); //Disabled
createHistory(parent);
createDetailArea(parent);
}
/**
* Creates a widget referencing the recently selected elements
*
* @param parent
* The composite in which the widget will be created
*/
protected void createHistory(Composite parent) {
initSelectionHistory();
Group historyGroup = new Group(parent, SWT.NONE);
historyGroup.setText("Recent selections");
historyGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1));
historyGroup.setLayout(new GridLayout(1, true));
// table
Table historyTable = new Table(historyGroup, SWT.BORDER | SWT.SINGLE);
GridData data = new GridData(SWT.FILL, SWT.FILL, true, false);
data.heightHint = 70;
historyTable.setLayoutData(data);
final TableViewer historyViewer = new TableViewer(historyTable);
historyViewer.setContentProvider(new HistoryContentProvider());
historyViewer.setLabelProvider(viewer.getLabelProvider());
historyViewer.setInput(selectionHistory);
historyViewer.addSelectionChangedListener(new ISelectionChangedListener() {
/**
* {@inheritDoc}
*/
public void selectionChanged(SelectionChangedEvent event) {
IStructuredSelection selection = (IStructuredSelection)historyViewer.getSelection();
Object selectedObject = selection.getFirstElement();
if(selectedObject instanceof EObject) {
EObject eObject = ((EObject)selectedObject);
revealSemanticElement(Collections.singletonList(eObject));
}
}
});
}
/**
* Inits the History
*/
protected void initSelectionHistory() {
selectionHistory = new ArrayList<EObject>(HISTORY_MAX_SIZE + 1);
IDialogSettings historySettings = getDialogSettings().getSection(HISTORY_SETTINGS);
if(historySettings != null && resourceSet != null) {
String[] uriHistory = historySettings.getArray(PREVIOUS_SELECTION);
// for each element in the list, try to get the EObject by its URI
if(uriHistory != null) {
for(String uri : uriHistory) {
try {
EObject object = resourceSet.getEObject(URI.createURI(uri), true);
if(object != null && !selectionHistory.contains(object)) {
selectionHistory.add(object);
}
} catch (Exception ex) {
//Ignore : if the resource doesn't exist anymore, we just skip it
}
}
}
}
}
/**
* Creates a widget to filter the tree according to the selected
* metaclass.
*
* @param parent
* The Composite in which the widgets will be created
* @deprecated
*/
@Deprecated
protected void createMetaclassFilter(Composite parent) {
// if(semanticRoot == null) {
// return;
// }
//
// Composite container = new Composite(parent, SWT.NONE);
// container.setLayout(new GridLayout(2, false));
// container.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
//
// ResourceSet resourceSet = semanticRoot.eResource().getResourceSet();
// EcoreUtil.resolveAll(resourceSet);
//
// Label metamodelLabel = new Label(container, SWT.NONE);
// metamodelLabel.setText("Metamodel:");
//
// ComboViewer metamodelViewer = new ComboViewer(container);
// metamodelViewer.setContentProvider(getMetamodelContentProvider());
// metamodelViewer.setLabelProvider(new EMFLabelProvider());
// metamodelViewer.setInput(semanticRoot);
// metamodelViewer.getCombo().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
//
// Label metaclassLabel = new Label(container, SWT.NONE);
// metaclassLabel.setText("Metaclass:");
//
// final ComboViewer metaclassViewer = new ComboViewer(container);
// IStructuredContentProvider metaclassProvider = getMetaclassContentProvider();
// metaclassViewer.setContentProvider(metaclassProvider);
// metaclassViewer.setLabelProvider(new EMFLabelProvider());
// metaclassViewer.getCombo().setEnabled(false);
// metaclassViewer.getCombo().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
//
// metamodelViewer.setFilters(new ViewerFilter[]{ new MetamodelContentFilter(metaclassProvider) });
//
// metamodelViewer.addSelectionChangedListener(new ISelectionChangedListener() {
//
// public void selectionChanged(SelectionChangedEvent event) {
// metaclassViewer.setInput(((IStructuredSelection)event.getSelection()).getFirstElement());
// metaclassViewer.getCombo().setEnabled(true);
// }
// });
//
// metaclassViewer.addSelectionChangedListener(new ISelectionChangedListener() {
//
// public void selectionChanged(SelectionChangedEvent event) {
// if(!event.getSelection().isEmpty()) {
// Object selectedObject = ((IStructuredSelection)event.getSelection()).getFirstElement();
// List<ViewerFilter> filters = new LinkedList<ViewerFilter>(Arrays.asList(viewer.getFilters()));
// filters.remove(currentMetaclassViewerFilter);
// currentMetaclassViewerFilter = getMetaclassViewerFilter(selectedObject);
// filters.add(currentMetaclassViewerFilter);
// viewer.setFilters(filters.toArray(new ViewerFilter[filters.size()]));
// viewer.refresh();
// }
// }
// });
}
/**
* Creates a label widget to display detailed information on the
* current value (Such as fully qualified name, ...)
*
* @param parent
* The composite in which the widget will be created
*/
protected void createDetailArea(Composite parent) {
detailLabel = new CLabel(parent, SWT.BORDER);
detailLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
updateDetailLabel();
}
// @Deprecated
// protected IStructuredContentProvider getMetamodelContentProvider() {
// return new MetamodelContentProvider();
// }
//
// @Deprecated
// protected IStructuredContentProvider getMetaclassContentProvider() {
// return new MetaclassContentProvider((EClass)this.metaClassWanted, this.metaClassNotWantedList);
// }
//
// @Deprecated
// protected ILabelProvider getLabelProvider() {
// return new EMFObjectLabelProvider();
// }
//
// @Deprecated
// protected ViewerFilter getMetaclassViewerFilter(Object selectedMetaClass) {
// return new MetaclassViewerFilter(selectedMetaClass);
// }
/**
* Returns the dialog settings. Returned object can't be null.
*
* @return dialog settings for this dialog
*/
protected IDialogSettings getDialogSettings() {
IDialogSettings settings = Activator.getDefault().getDialogSettings().getSection(getDialogSettingsIdentifier());
if(settings == null) {
settings = Activator.getDefault().getDialogSettings().addNewSection(getDialogSettingsIdentifier());
}
return settings;
}
private String getDialogSettingsIdentifier() {
return DIALOG_SETTINGS + "_" + historyId;
}
/**
* Stores dialog settings.
*
* @param settings
* settings used to store dialog
*/
protected void storeDialog(IDialogSettings settings, EObject currentValue) {
if(selectionHistory.contains(currentValue)) {
selectionHistory.remove(currentValue);
}
selectionHistory.add(0, currentValue);
//This should loop only once, unless the history was already oversized
while(selectionHistory.size() > HISTORY_MAX_SIZE) {
selectionHistory.remove(HISTORY_MAX_SIZE);
}
List<String> uriList = new ArrayList<String>();
// convert list of EObject into URI string list
for(EObject object : selectionHistory) {
URI uri = EcoreUtil.getURI(object);
uriList.add(uri.toString());
}
IDialogSettings historySettings = settings.getSection(HISTORY_SETTINGS);
if(historySettings == null) {
historySettings = settings.addNewSection(HISTORY_SETTINGS);
}
historySettings.put(PREVIOUS_SELECTION, uriList.toArray(new String[uriList.size()]));
}
@Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
encapsulated.inputChanged(viewer, oldInput, newInput);
if(viewer instanceof StructuredViewer) {
this.viewer = (StructuredViewer)viewer;
if(newInput != null && viewer.getControl() != null && !viewer.getControl().isDisposed()) {
this.viewer.addSelectionChangedListener(this);
}
} else {
this.viewer = null;
}
}
public void selectionChanged(SelectionChangedEvent event) {
selectedObject = ((IStructuredSelection)event.getSelection()).getFirstElement();
updateDetailLabel();
}
private void updateDetailLabel() {
if(detailLabel == null || detailLabel.isDisposed()) {
return;
}
if(selectedObject == null) {
detailLabel.setText("");
detailLabel.setImage(null);
} else {
ILabelProvider labelProvider = (ILabelProvider)viewer.getLabelProvider();
String description;
if(labelProvider instanceof IDetailLabelProvider) {
description = ((IDetailLabelProvider)labelProvider).getDetail(selectedObject);
} else {
description = labelProvider.getText(selectedObject);
}
detailLabel.setText(description);
detailLabel.setImage(labelProvider.getImage(selectedObject));
}
detailLabel.getParent().getParent().layout();
}
@Override
public void commit(AbstractEditor editor) {
Object semanticElement = getAdaptedValue(selectedObject);
if(semanticElement instanceof EObject) {
storeDialog(getDialogSettings(), (EObject)semanticElement);
}
}
@Override
public void dispose() {
super.dispose();
viewer.removeSelectionChangedListener(this);
}
}