/*************************************************************************** * 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(); }