blob: 3bcbec196e28748348e0e245edab3754d86956fb [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2012, 2019 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.ecommons.emf.ui.forms;
import java.util.Collection;
import java.util.Iterator;
import org.eclipse.core.databinding.observable.IObserving;
import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.databinding.edit.EMFEditProperties;
import org.eclipse.emf.databinding.edit.IEMFEditListProperty;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.edit.command.CommandParameter;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.emf.edit.provider.IViewerNotification;
import org.eclipse.emf.edit.ui.dnd.EditingDomainViewerDropAdapter;
import org.eclipse.emf.edit.ui.dnd.LocalTransfer;
import org.eclipse.emf.edit.ui.dnd.ViewerDragAdapter;
import org.eclipse.emf.edit.ui.provider.AdapterFactoryContentProvider;
import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider;
import org.eclipse.jface.action.IContributionItem;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.databinding.viewers.ObservableListContentProvider;
import org.eclipse.jface.databinding.viewers.typed.ViewerProperties;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.statet.ecommons.emf.core.databinding.IEMFEditContext;
import org.eclipse.statet.ecommons.ui.components.ButtonGroup;
import org.eclipse.statet.ecommons.ui.content.ElementSourceSelectionProvider;
import org.eclipse.statet.ecommons.ui.util.MenuUtils;
import org.eclipse.statet.ecommons.ui.viewers.ViewerUtils;
import org.eclipse.statet.ecommons.ui.viewers.ViewerUtils.TableComposite;
public class EObjectListProperty<TProperty extends EObject> extends EFProperty {
private class LabelProvider extends AdapterFactoryLabelProvider {
protected Viewer viewer;
protected AdapterFactoryContentProvider.ViewerRefresh viewerRefresh;
public LabelProvider(final AdapterFactory adapterFactory, final Viewer viewer) {
super(adapterFactory);
this.viewer= viewer;
}
@Override
public void notifyChanged(final Notification notification) {
if (this.viewer != null && this.viewer.getControl() != null && !this.viewer.getControl().isDisposed()
&& notification instanceof IViewerNotification) {
final IViewerNotification viewerNotification= (IViewerNotification) notification;
if (viewerNotification.isLabelUpdate()) {
if (this.viewerRefresh == null) {
this.viewerRefresh= new AdapterFactoryContentProvider.ViewerRefresh(this.viewer);
}
if (this.viewerRefresh.addNotification(viewerNotification)) {
this.viewer.getControl().getDisplay().asyncExec(this.viewerRefresh);
}
}
}
super.notifyChanged(notification);
}
}
private class AddHandler extends ButtonGroup.AddHandler {
private MenuManager menuManager;
public AddHandler() {
}
@Override
public boolean run(final IStructuredSelection selection) {
if (this.menuManager == null) {
this.menuManager= new MenuManager();
}
else {
this.menuManager.removeAll();
}
fillMenu(this.menuManager);
final Menu menu= this.menuManager.createContextMenu(getControl());
MenuUtils.setPullDownPosition(menu, getControl());
menu.setVisible(true);
return false;
}
protected void fillMenu(final MenuManager menuManager) {
final EditingDomain editingDomain= getEditingDomain();
final EObject base= (EObject) getBaseObservable().getValue();
if (base == null) {
return;
}
final Collection<?> descriptors= editingDomain.getNewChildDescriptors(base, null);
for (final Object descriptor : descriptors) {
if (!(descriptor instanceof CommandParameter)) {
continue;
}
final CommandParameter parameter= (CommandParameter) descriptor;
if (parameter.getEStructuralFeature() != getEFeature()) {
continue;
}
final IContributionItem item= new EditCommandContributionItem(parameter,
editingDomain, getBaseObservable() ) {
@Override
protected void executed(final Collection<?> result) {
final Iterator<?> iter= result.iterator();
if (iter.hasNext()) {
final TProperty value= (TProperty) iter.next();
if (EObjectListProperty.this.modelObservable.contains(value)) {
EObjectListProperty.this.singleSelectionObservable.setValue(value);
}
}
}
};
menuManager.add(item);
}
}
@Override
public void widgetDisposed(final DisposeEvent e) {
if (this.menuManager != null) {
this.menuManager.dispose();
}
}
}
private TableComposite widget;
private ButtonGroup<TProperty> buttonGroup;
private IObservableList<TProperty> modelObservable;
private ElementSourceSelectionProvider selectionProvider;
private IObservableValue<TProperty> singleSelectionObservable;
public EObjectListProperty(final String label, final String tooltip,
final EClass eClass, final EStructuralFeature eFeature) {
super(label, tooltip, eClass, eFeature);
}
@Override
public void create(final Composite parent, final IEFFormPage page) {
this.widget= page.getToolkit().createPropSingleColumnTable(parent, 10, 25);
this.widget.viewer.setContentProvider(new ObservableListContentProvider());
this.widget.viewer.setLabelProvider(new LabelProvider(
page.getEditor().getAdapterFactory(), this.widget.viewer ));
this.buttonGroup= new ButtonGroup<>(parent);
this.buttonGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
customizeButtonGroup(this.buttonGroup);
}
protected void customizeButtonGroup(final ButtonGroup<TProperty> buttonGroup) {
buttonGroup.addAddButton(new AddHandler());
buttonGroup.addDeleteButton(null);
buttonGroup.addSeparator();
buttonGroup.addUpButton(null);
buttonGroup.addDownButton(null);
}
@Override
public Control getControl() {
return this.widget;
}
public TableViewer getViewer() {
return this.widget.viewer;
}
@Override
public void bind(final IEMFEditContext context) {
super.bind(context);
final IEMFEditListProperty emfProperty= EMFEditProperties.list(getEditingDomain(),
getEFeature() );
this.modelObservable= emfProperty.observeDetail(getBaseObservable());
((IObserving) this.modelObservable).getObserved();
this.widget.viewer.setInput(this.modelObservable);
this.buttonGroup.connectTo(this.widget.viewer, this.modelObservable, null);
register(this.widget.table, IEFPropertyExpressions.EOBJECT_LIST_ID);
this.selectionProvider= new ElementSourceSelectionProvider(this.widget.viewer, this);
ViewerUtils.setSelectionProvider(this.widget.table, this.selectionProvider);
{ final int operations= (DND.DROP_DEFAULT | DND.DROP_COPY | DND.DROP_MOVE);
final Transfer[] transfers= new Transfer[] { LocalTransfer.getInstance() };
this.widget.viewer.addDragSupport(operations, transfers, new ViewerDragAdapter(this.widget.viewer));
this.widget.viewer.addDropSupport(operations, transfers, new EditingDomainViewerDropAdapter(
getEditingDomain(), this.widget.viewer ));
}
this.singleSelectionObservable=
ViewerProperties.singlePostSelection((Class<TProperty>)this.modelObservable.getElementType())
.observe(this.widget.viewer);
this.buttonGroup.updateState();
}
@Override
public IObservableList<TProperty> getPropertyObservable() {
return this.modelObservable;
}
public IObservableValue<TProperty> getSingleSelectionObservable() {
return this.singleSelectionObservable;
}
public ISelectionProvider getSelectionProvider() {
return this.selectionProvider;
}
}