/**
* Copyright (c) 2005-2012 IBM Corporation 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:
* IBM - Initial API and implementation
*/
package org.eclipse.emf.edit.ui.view;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
import org.eclipse.emf.edit.provider.IItemPropertySource;
import org.eclipse.emf.edit.provider.ItemPropertyDescriptor;
import org.eclipse.emf.edit.ui.EMFEditUIPlugin;
import org.eclipse.emf.edit.ui.provider.DiagnosticDecorator;
import org.eclipse.emf.edit.ui.provider.ExtendedImageRegistry;
import org.eclipse.emf.edit.ui.provider.PropertyDescriptor;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IStatusLineManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.views.properties.IPropertyDescriptor;
import org.eclipse.ui.views.properties.IPropertySourceProvider;
import org.eclipse.ui.views.properties.PropertySheetEntry;
import org.eclipse.ui.views.properties.PropertySheetPage;
/**
* This property sheet page has an additional button in its local toolbar that locates the value of the
* selected property in the editor.
* It also supports {@link #ExtendedPropertySheetPage(AdapterFactoryEditingDomain, Decoration) decorating} the property values to indicate bad values.
*/
public class ExtendedPropertySheetPage extends PropertySheetPage
{
/**
* @since 2.9
*/
public static enum Decoration
{
NONE, MANUAL, LIVE
}
protected List<Object> objectsToSelect = new ArrayList<Object>();
protected AdapterFactoryEditingDomain editingDomain;
/**
* @since 2.9
*/
protected DiagnosticDecorator diagnosticDecorator;
/**
* @since 2.9
*/
protected IDialogSettings dialogSettings;
/**
* @since 2.9
*/
protected List<?> input = Collections.emptyList();
/**
* @since 2.9
*/
protected IPropertySourceProvider propertySourceProvider;
protected IAction locateValueAction = new LocateValueAction();
protected class LocateValueAction extends Action
{
public LocateValueAction()
{
setText(EMFEditUIPlugin.INSTANCE.getString("_UI_LocateValue_action"));
setToolTipText(EMFEditUIPlugin.INSTANCE.getString("_UI_LocateValue_action_tool_tip"));
setImageDescriptor(ExtendedImageRegistry.INSTANCE.getImageDescriptor(EMFEditUIPlugin.INSTANCE.getImage("full/elcl16/LocateValue")));
setDisabledImageDescriptor(ExtendedImageRegistry.INSTANCE.getImageDescriptor(EMFEditUIPlugin.INSTANCE.getImage("full/dlcl16/LocateValue")));
}
@Override
public void run()
{
List<Object> selection = new ArrayList<Object>();
for (Object object : objectsToSelect)
{
selection.add(editingDomain.getWrapper(object));
}
setSelectionToViewer(selection);
}
}
public ExtendedPropertySheetPage(AdapterFactoryEditingDomain editingDomain)
{
super();
this.editingDomain = editingDomain;
}
/**
* @since 2.9
*/
public ExtendedPropertySheetPage(AdapterFactoryEditingDomain editingDomain, Decoration decoration)
{
this(editingDomain, decoration, null);
}
/**
* @since 2.9
*/
public ExtendedPropertySheetPage(AdapterFactoryEditingDomain editingDomain, Decoration decoration, IDialogSettings dialogSettings)
{
this(editingDomain);
this.dialogSettings = dialogSettings;
diagnosticDecorator = createDiagnosticDecorator(decoration);
}
/**
* @since 2.9
*/
protected DiagnosticDecorator createDiagnosticDecorator(Decoration decoration)
{
switch (decoration)
{
case MANUAL:
{
return new DiagnosticDecorator(editingDomain.getResourceSet(), this);
}
case LIVE:
{
return new DiagnosticDecorator(editingDomain, this, dialogSettings);
}
default:
{
return null;
}
}
}
@Override
public void setPropertySourceProvider(IPropertySourceProvider newProvider)
{
propertySourceProvider = newProvider;
super.setPropertySourceProvider(newProvider);
}
@Override
public void createControl(Composite parent)
{
super.createControl(parent);
if (diagnosticDecorator != null)
{
class DecoratingPropertySheetEntry extends PropertySheetEntry
{
@Override
protected PropertySheetEntry createChildEntry()
{
return new DecoratingPropertySheetEntry();
}
@Override
public Image getImage()
{
Image image = super.getImage();
if (image == null)
{
image = ExtendedImageRegistry.INSTANCE.getImage(ItemPropertyDescriptor.GENERIC_VALUE_IMAGE);
}
Diagnostic featureDiagnostic = findDiagnostic();
return featureDiagnostic != null ? diagnosticDecorator.decorate(image, featureDiagnostic) : image;
}
protected Diagnostic findDiagnostic()
{
IPropertyDescriptor descriptor = getDescriptor();
if (descriptor instanceof PropertyDescriptor)
{
Object feature = ((PropertyDescriptor)descriptor).getFeature();
Map<Object, ? extends Diagnostic> decorations = diagnosticDecorator.getDecorations();
if (!decorations.isEmpty() && feature != null)
{
for (Diagnostic diagnostic : decorations.values())
{
Diagnostic featureDiagnostic = find(diagnostic, feature);
if (featureDiagnostic != null)
{
return featureDiagnostic;
}
}
}
}
return null;
}
protected Diagnostic find(Diagnostic diagnostic, Object feature)
{
// Gather them all...
//
if (diagnostic.getData().contains(feature))
{
return diagnostic;
}
for (Diagnostic child : diagnostic.getChildren())
{
Diagnostic result = find(child, feature);
if (result != null)
{
return result;
}
}
return null;
}
@Override
public String getDescription()
{
String description = super.getDescription();
Diagnostic featureDiagnostic = findDiagnostic();
if (featureDiagnostic != null)
{
return description + " - " + DiagnosticDecorator.strip(featureDiagnostic.getMessage());
}
else
{
return description;
}
}
}
DecoratingPropertySheetEntry decoratingPropertySheetEntry = new DecoratingPropertySheetEntry();
decoratingPropertySheetEntry.setPropertySourceProvider(propertySourceProvider);
setRootEntry(decoratingPropertySheetEntry);
}
}
/**
* This method should be overridden to set the selection.
*/
protected void setSelectionToViewer(List<?> selection)
{
// Do nothing.
}
@Override
public void makeContributions(IMenuManager menuManager, IToolBarManager toolBarManager, IStatusLineManager statusLineManager)
{
super.makeContributions(menuManager, toolBarManager, statusLineManager);
toolBarManager.add(locateValueAction);
}
@Override
public void handleEntrySelection(ISelection selection)
{
super.handleEntrySelection(selection);
objectsToSelect.clear();
if (!selection.isEmpty() && selection instanceof IStructuredSelection)
{
IStructuredSelection structuredSelection = (IStructuredSelection)selection;
if (structuredSelection.size() == 1)
{
Object object = structuredSelection.getFirstElement();
if (object instanceof PropertySheetEntry)
{
PropertySheetEntry entry = (PropertySheetEntry)object;
Object [] values = entry.getValues();
if (values != null)
{
for (int i = 0; i < values.length; ++i)
{
Object value = values[i];
if (value instanceof IItemPropertySource)
{
Object realValue = ((IItemPropertySource)value).getEditableValue(null);
if (realValue instanceof Collection<?>)
{
for (Object o : (Collection<?>)realValue)
{
addObjectToSelect(o);
}
}
else
{
addObjectToSelect(realValue);
}
}
}
}
}
}
}
locateValueAction.setEnabled(!objectsToSelect.isEmpty());
}
protected void addObjectToSelect(Object object)
{
if (object instanceof EObject)
{
objectsToSelect.add(object);
}
}
@Override
public void selectionChanged(IWorkbenchPart part, ISelection selection)
{
if (selection instanceof IStructuredSelection)
{
input = ((IStructuredSelection)selection).toList();
}
else
{
input = Collections.emptyList();
}
super.selectionChanged(part, selection);
}
/**
* Provides access to the current input to the page.
*
* @since 2.9
*/
public List<?> getInput()
{
return input;
}
@Override
public void dispose()
{
if (diagnosticDecorator != null)
{
diagnosticDecorator.dispose();
}
super.dispose();
}
/**
* Refreshes only the labels of the property sheet viewer.
* It does not dismiss the cell editor, if there is one.
*
* @since 2.12
*/
public void refreshLabels()
{
try
{
Field viewerField = PropertySheetPage.class.getDeclaredField("viewer");
viewerField.setAccessible(true);
Viewer viewer = (Viewer)viewerField.get(this);
viewer.refresh();
return;
}
catch (Throwable throwable)
{
// Ignore.
}
refresh();
}
}