blob: 011b3a07a25a7cff63f504a371586d511fc58e81 [file] [log] [blame]
/*
* Copyright (c) 2004 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM - Initial API and implementation
*
* $Id: ChangeCommand.java,v 1.3 2004/06/17 19:49:16 khussey Exp $
*/
package org.eclipse.uml2.edit.util;
import java.util.Collections;
import java.util.Iterator;
import java.util.ListIterator;
import org.eclipse.emf.common.command.AbstractCommand;
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.EStructuralFeature;
import org.eclipse.emf.ecore.change.ChangeDescription;
import org.eclipse.emf.ecore.change.ChangeKind;
import org.eclipse.emf.ecore.change.FeatureChange;
import org.eclipse.emf.ecore.change.ListChange;
import org.eclipse.emf.ecore.change.impl.ListChangeImpl;
import org.eclipse.emf.ecore.change.util.ChangeRecorder;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.edit.domain.EditingDomain;
/**
*
*/
public class ChangeCommand
extends AbstractCommand {
private static class UniqueListChangeImpl
extends ListChangeImpl {
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.ecore.change.ListChange#apply(org.eclipse.emf.common.util.EList)
*/
public void apply(EList originalList) {
switch (getKind().getValue()) {
case ChangeKind.ADD :
if (-1 == index) {
for (Iterator values = getValues().iterator(); values
.hasNext();) {
Object value = values.next();
if (!originalList.contains(value)) {
originalList.add(value);
}
}
} else {
for (ListIterator values = getValues().listIterator(
getValues().size()); values.hasPrevious();) {
Object value = values.previous();
if (!originalList.contains(value)) {
originalList.add(index, value);
}
}
}
break;
case ChangeKind.REMOVE :
for (Iterator values = getValues().iterator(); values
.hasNext();) {
originalList.remove(values.next());
}
break;
default :
super.apply(originalList);
}
}
}
private static final ChangeRecorder CHANGE_RECORDER = new ChangeRecorder() {
protected ListChange createUniqueListChange(EList changesList,
ChangeKind kind, int index) {
ListChange listChange = new UniqueListChangeImpl();
listChange.setKind(kind);
listChange.setIndex(index);
changesList.add(listChange);
return listChange;
}
protected void createUniqueListChanges(EList oldList, EList newList,
EList changesList) {
int index = 0;
for (Iterator objects = newList.iterator(); objects.hasNext(); ++index) {
Object newObject = objects.next();
if (oldList.size() <= index) {
ListChange listChange = createUniqueListChange(changesList,
ChangeKind.ADD_LITERAL, index);
listChange.getValues().add(newObject);
oldList.add(newObject);
} else {
boolean done;
do {
done = true;
Object targetObject = oldList.get(index);
if (null == targetObject
? null != newObject
: !targetObject.equals(newObject)) {
int position = EcoreUtil.indexOf(oldList,
newObject, index);
if (-1 != position) {
int targetIndex = EcoreUtil.indexOf(newList,
targetObject, index);
if (-1 == targetIndex) {
ListChange listChange = createUniqueListChange(
changesList, ChangeKind.REMOVE_LITERAL,
index);
listChange.getValues().add(
oldList.remove(index));
done = false;
} else if (targetIndex > position) {
if (oldList.size() <= targetIndex) {
targetIndex = oldList.size() - 1;
}
ListChange listChange = createUniqueListChange(
changesList, ChangeKind.MOVE_LITERAL,
index);
listChange.setMoveToIndex(targetIndex);
oldList.move(targetIndex, index);
done = false;
} else {
ListChange listChange = createUniqueListChange(
changesList, ChangeKind.MOVE_LITERAL,
position);
listChange.setMoveToIndex(index);
oldList.move(index, position);
}
} else {
ListChange listChange = createUniqueListChange(
changesList, ChangeKind.ADD_LITERAL, index);
listChange.getValues().add(newObject);
oldList.add(index, newObject);
}
}
} while (!done);
}
}
for (int i = oldList.size(); i > index;) {
ListChange listChange = createUniqueListChange(changesList,
ChangeKind.REMOVE_LITERAL, --i);
listChange.getValues().add(oldList.remove(i));
}
}
protected void finalizeChange(FeatureChange change, EObject eObject) {
if (change.isSet()) {
EStructuralFeature feature = change.getFeature();
if (feature.isMany()) {
EList oldList = new BasicEList((EList) eObject
.eGet(feature));
EList newList = (EList) change.getValue();
if (feature.isUnique()) {
createUniqueListChanges(oldList, newList, change
.getListChanges());
} else {
createListChanges(oldList, newList, change
.getListChanges());
}
}
}
}
};
private final EditingDomain editingDomain;
private final Runnable runnable;
private ChangeDescription changeDescription = null;
public ChangeCommand(EditingDomain editingDomain, Runnable runnable) {
this(editingDomain, runnable, null);
}
public ChangeCommand(EditingDomain editingDomain, Runnable runnable,
String label) {
this(editingDomain, runnable, label, null);
}
public ChangeCommand(EditingDomain editingDomain, Runnable runnable,
String label, String description) {
super(label, description);
if (null == editingDomain) {
throw new IllegalArgumentException(String.valueOf(editingDomain));
}
if (null == runnable) {
throw new IllegalArgumentException(String.valueOf(runnable));
}
this.editingDomain = editingDomain;
this.runnable = runnable;
}
public EditingDomain getEditingDomain() {
return editingDomain;
}
protected Runnable getRunnable() {
return runnable;
}
protected ChangeDescription getChangeDescription() {
return changeDescription;
}
protected void setChangeDescription(ChangeDescription changeDescription) {
this.changeDescription = changeDescription;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.common.command.AbstractCommand#prepare()
*/
protected boolean prepare() {
return null == getChangeDescription();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.common.command.Command#canUndo()
*/
public boolean canUndo() {
return null != getChangeDescription();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.common.command.Command#execute()
*/
public void execute() {
synchronized (CHANGE_RECORDER) {
CHANGE_RECORDER.beginRecording(Collections
.singleton(getEditingDomain().getResourceSet()));
try {
getRunnable().run();
} finally {
setChangeDescription(CHANGE_RECORDER.endRecording());
}
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.common.command.Command#undo()
*/
public void undo() {
synchronized (CHANGE_RECORDER) {
CHANGE_RECORDER.beginRecording(Collections
.singleton(getEditingDomain().getResourceSet()));
try {
getChangeDescription().apply();
} finally {
setChangeDescription(CHANGE_RECORDER.endRecording());
}
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.common.command.Command#redo()
*/
public void redo() {
synchronized (CHANGE_RECORDER) {
CHANGE_RECORDER.beginRecording(Collections
.singleton(getEditingDomain().getResourceSet()));
try {
getChangeDescription().apply();
} finally {
setChangeDescription(CHANGE_RECORDER.endRecording());
}
}
}
}