blob: a9586926637a0c46ecc806ea6b8a9da83b0c91ad [file] [log] [blame]
/***************************************************************************
* Copyright (c) 2008 Conselleria de Infraestructuras y Transporte,
* Generalitat de la Comunitat Valenciana and ohers.
*
* 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:
* Mario Cervera Ubeda (Integranova) - initial API and implementation
*
* $Id: AbstractCollectionPropertySection.java,v 1.3 2009/06/02 12:46:54 jlescot Exp $
******************************************************************************/
package org.eclipse.emf.ecoretools.tabbedproperties.sections;
import java.util.Iterator;
import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.provider.EcoreItemProviderAdapterFactory;
import org.eclipse.emf.ecoretools.tabbedproperties.internal.Messages;
import org.eclipse.emf.ecoretools.tabbedproperties.providers.TabbedPropertiesLabelProvider;
import org.eclipse.emf.edit.command.AddCommand;
import org.eclipse.emf.edit.command.RemoveCommand;
import org.eclipse.emf.edit.command.SetCommand;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.jface.viewers.IBaseLabelProvider;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Group;
import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage;
/**
* An abstract implementation of a section prepared to deal with collections.
*
* Creation 3 apr. 2008
*
* @author Mario Cervera Ubeda (Integranova)
*
*/
public abstract class AbstractCollectionPropertySection extends AbstractTabbedPropertySection {
/** Widgets */
/** The Group hosting the whole section */
private Group groupMembers;
/** Three composites to arrange the user interface */
private Composite compositeListElements;
private Composite compositeButtons;
private Composite compositeListMembers;
/** List widget with the elements that may be part of the collection. */
private TableViewer listElements = null;
/** List widget with the members of the collection. */
private TableViewer listMembers = null;
/** Add / Remove buttons. */
private Button buttonAdd = null;
private Button buttonRemove = null;
/** Up / Down buttons. */
private Button buttonUp = null;
private Button buttonDown = null;
/**
* @see org.eclipse.emf.tabbedproperties.sections.AbstractTabbedPropertySection#createControls(org.eclipse.swt.widgets.Composite,
* org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage)
*/
public void createControls(Composite parent, TabbedPropertySheetPage tabbedPropertySheetPage) {
super.createControls(parent, tabbedPropertySheetPage);
}
/**
* @see org.eclipse.emf.tabbedproperties.sections.AbstractTabbedPropertySection#createWidgets(org.eclipse.swt.widgets.Composite)
*/
protected void createWidgets(Composite composite) {
groupMembers = getWidgetFactory().createGroup(composite, getLabelText());
GridLayout gl = new GridLayout(3, false);
groupMembers.setLayout(gl);
compositeListElements = getWidgetFactory().createComposite(groupMembers);
compositeListElements.setLayout(new GridLayout());
compositeButtons = getWidgetFactory().createComposite(groupMembers);
compositeButtons.setLayout(new GridLayout());
compositeListMembers = getWidgetFactory().createComposite(groupMembers);
compositeListMembers.setLayout(new GridLayout());
listElements = new TableViewer(compositeListElements);
listElements.setLabelProvider(getLabelProvider());
listMembers = new TableViewer(compositeListMembers);
listMembers.setLabelProvider(getLabelProvider());
buttonAdd = getWidgetFactory().createButton(compositeButtons, Messages.AbstractCollectionPropertySection_Add, SWT.PUSH);
buttonRemove = getWidgetFactory().createButton(compositeButtons, Messages.AbstractCollectionPropertySection_Remove, SWT.PUSH);
getWidgetFactory().createLabel(compositeButtons, " "); // A hidden Label //$NON-NLS-1$
buttonUp = getWidgetFactory().createButton(compositeButtons, Messages.AbstractCollectionPropertySection_Up, SWT.PUSH);
buttonDown = getWidgetFactory().createButton(compositeButtons, Messages.AbstractCollectionPropertySection_Down, SWT.PUSH);
}
/**
* @see org.eclipse.emf.tabbedproperties.sections.AbstractTabbedPropertySection#setSectionData(org.eclipse.swt.widgets.Composite)
*/
protected void setSectionData(Composite composite) {
FormData fdata;
GridData gdata;
fdata = new FormData();
fdata.top = new FormAttachment(0, 0);
fdata.left = new FormAttachment(0, 0);
fdata.right = new FormAttachment(100, 0);
fdata.bottom = new FormAttachment(100, 0);
groupMembers.setLayoutData(fdata);
gdata = new GridData(GridData.FILL_BOTH);
compositeListElements.setLayoutData(gdata);
gdata = new GridData();
compositeButtons.setLayoutData(gdata);
gdata = new GridData(GridData.FILL_BOTH);
compositeListMembers.setLayoutData(gdata);
gdata = new GridData(GridData.FILL_BOTH);
listElements.getTable().setLayoutData(gdata);
listMembers.getTable().setLayoutData(gdata);
buttonAdd.setLayoutData(gdata);
buttonRemove.setLayoutData(gdata);
buttonUp.setLayoutData(gdata);
buttonDown.setLayoutData(gdata);
}
/**
* @see org.eclipse.emf.tabbedproperties.sections.AbstractTabbedPropertySection#hookListeners()
*/
protected void hookListeners() {
buttonAdd.addSelectionListener(new SelectionListener() {
public void widgetDefaultSelected(SelectionEvent e) {
return; // should never be invoked
}
public void widgetSelected(SelectionEvent e) {
handleAddButtonSelected();
}
});
buttonRemove.addSelectionListener(new SelectionListener() {
public void widgetDefaultSelected(SelectionEvent e) {
return; // should never be invoked
}
public void widgetSelected(SelectionEvent e) {
handleRemoveButtonSelected();
}
});
buttonUp.addSelectionListener(new SelectionListener() {
public void widgetDefaultSelected(SelectionEvent e) {
return; // should never be invoked
}
public void widgetSelected(SelectionEvent e) {
handleUpButtonSelected();
}
});
buttonDown.addSelectionListener(new SelectionListener() {
public void widgetDefaultSelected(SelectionEvent e) {
return; // should never be invoked
}
public void widgetSelected(SelectionEvent e) {
handleDownButtonSelected();
}
});
}
/**
* @see org.eclipse.emf.tabbedproperties.sections.AbstractListPropertySection#getLabelProvider()
*/
protected IBaseLabelProvider getLabelProvider() {
return new TabbedPropertiesLabelProvider(new EcoreItemProviderAdapterFactory());
}
/**
* @see org.eclipse.ui.views.properties.tabbed.AbstractPropertySection#refresh()
*/
public void refresh() {
fillListElements();
fillListMembers();
}
private void fillListElements() {
EList<EObject> elements = getElements();
listElements.getTable().removeAll();
for (EObject object : elements) {
listElements.add(object);
}
}
private void fillListMembers() {
EList<EObject> elements = getFeatureAsList();
listMembers.getTable().removeAll();
for (EObject object : elements) {
listMembers.add(object);
}
}
private void handleAddButtonSelected() {
if (listElements.getSelection() instanceof StructuredSelection) {
StructuredSelection selection = (StructuredSelection) listElements.getSelection();
if (!selection.isEmpty()) {
Iterator<?> iterator = selection.iterator();
while (iterator.hasNext()) {
executeAddCommand(iterator.next());
}
}
}
}
private void handleRemoveButtonSelected() {
if (listMembers.getSelection() instanceof StructuredSelection) {
StructuredSelection selection = (StructuredSelection) listMembers.getSelection();
if (!selection.isEmpty()) {
Iterator<?> iterator = selection.iterator();
while (iterator.hasNext()) {
executeRemoveCommand(iterator.next());
}
}
}
}
private void handleUpButtonSelected() {
executeMovement(true);
}
private void handleDownButtonSelected() {
executeMovement(false);
}
private void executeMovement(boolean up) {
if (listMembers.getSelection() instanceof StructuredSelection) {
StructuredSelection selection = (StructuredSelection) listMembers.getSelection();
if (!selection.isEmpty()) {
EList<EObject> membersToMove = new BasicEList<EObject>();
Iterator<?> iterator = selection.iterator();
while (iterator.hasNext()) {
membersToMove.add((EObject) iterator.next());
}
int[] indexes = new int[membersToMove.size()];
for (int k = 0; k < indexes.length; k++) {
indexes[k] = -1;
}
EList<EObject> members = getFeatureAsList();
EList<EObject> movedMembers = moveMembers(members, membersToMove, up, indexes);
if (!movedMembers.equals(members)) {
executeEmptyListCommand();
executeAddAllCommand(movedMembers);
listMembers.getTable().setSelection(indexes);
}
}
}
return;
}
/*
* Moves the columns contained in membersToMove one position up or down
* (depending on the boolean variable up) in the collection members
*/
private EList<EObject> moveMembers(EList<EObject> members, EList<EObject> membersToMove, boolean up, int[] indexes) {
EList<EObject> result = new BasicEList<EObject>();
if (firstOrLastElements(members, membersToMove, up, indexes)) {
// Don't move the elements
result.addAll(members);
} else {
// Copy the elements that won't be moved
for (Object o : members) {
if (o instanceof EObject) {
EObject c = (EObject) o;
if (!membersToMove.contains(c)) {
result.add(c);
}
}
}
// Calculate the indexes of the elements to move
if (up) { // Case movement upwards
for (int i = 0; i < membersToMove.size(); i++) {
EObject eobject = membersToMove.get(i);
int index = members.indexOf(eobject);
int newIndex = -1;
if (index == 0) {
newIndex = index;
} else {
if (!containsIndex(index - 1, indexes)) {
newIndex = index - 1;
} else {
newIndex = index;
}
}
result.add(newIndex, eobject);
indexes[i] = newIndex;
}
} else { // Case movement downwards
for (int i = membersToMove.size() - 1; i >= 0; i--) {
EObject eobject = membersToMove.get(i);
// First get the new indexes for the elements to be moved
int index = members.indexOf(eobject);
int newIndex = -1;
if (index == members.size() - 1) {
newIndex = members.size() - 1;
} else {
if (!containsIndex(index + 1, indexes)) {
newIndex = index + 1;
} else {
newIndex = index;
}
}
indexes[i] = newIndex;
}
for (int i = 0; i < indexes.length; i++) {
result.add(indexes[i], membersToMove.get(i));
}
}
}
return result;
}
/*
* This method returns true if the selected members to move are together and
* in the beginning of the collection (in case up is true) or the end of the
* collection (in case up is false) This is important because if this method
* returns true the elements shouldn't be moved
*/
private boolean firstOrLastElements(EList<EObject> members, EList<EObject> membersToMove, boolean up, int[] indexes) {
if (membersToMove.size() == members.size()) {
return true;
}
int size = membersToMove.size();
int[] indexes2 = new int[size];
int i = 0;
for (EObject member : membersToMove) {
indexes2[i] = members.indexOf(member);
i++;
}
// If the first or last member are not in the first or last position we
// can stop here
if ((indexes2[0] != 0 && up) || (indexes2[size - 1] != size - 1 && !up)) {
return false;
}
// Are the members together?
for (int j = 0; j < indexes2.length - 1; j++) {
if (indexes2[j + 1] - indexes2[j] != 1) {
return false;
}
}
// Maybe the group of members is at the beginning or the end of the
// collection
// but we have to move them anyway because of the direction of the
// movement
if ((indexes2[0] == 0 && !up) || indexes2[size - 1] == size - 1 && up) {
return false;
}
indexes = indexes2;
return true;
}
private boolean containsIndex(int i, int[] indexes) {
for (int j = 0; j < indexes.length; j++) {
if (indexes[j] == i) {
return true;
}
}
return false;
}
private void executeAddCommand(Object objectToAdd) {
EditingDomain domain = getEditingDomain();
if (domain != null) {
Command command = AddCommand.create(domain, getEObject(), getFeature(), objectToAdd);
domain.getCommandStack().execute(command);
}
}
private void executeRemoveCommand(Object objectToRemove) {
EditingDomain domain = getEditingDomain();
if (domain != null) {
Command command = RemoveCommand.create(domain, getEObject(), getFeature(), objectToRemove);
domain.getCommandStack().execute(command);
}
}
private void executeEmptyListCommand() {
EditingDomain domain = getEditingDomain();
if (domain != null) {
Command command = SetCommand.create(domain, getEObject(), getFeature(), new BasicEList<EObject>());
domain.getCommandStack().execute(command);
}
}
private void executeAddAllCommand(EList<EObject> membersToAdd) {
EditingDomain domain = getEditingDomain();
if (domain != null) {
Command command = SetCommand.create(domain, getEObject(), getFeature(), membersToAdd);
domain.getCommandStack().execute(command);
}
}
protected EList<EObject> getFeatureAsList() {
EObject eobject = getEObject();
if (eobject != null) {
Object featureValue = eobject.eGet(getFeature());
if (featureValue instanceof EList) {
return (EList<EObject>) featureValue;
}
}
return null;
}
/**
* Return the candidates EObjects to be part of the collection
*
* @return the candidates to be part of the collection
*/
protected abstract EList<EObject> getElements();
}