blob: c16bb0b03a3b971ad9d0c3ee6225d3e610023141 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008-2014 Chair for Applied Software Engineering,
* Technische Universitaet Muenchen.
* 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:
* Maximilian Koegel, Edgar Mueller - initial API and implementation
******************************************************************************/
package org.eclipse.emf.emfstore.internal.client.model.impl;
import java.util.List;
import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.emfstore.client.changetracking.ESCommandObserver;
import org.eclipse.emf.emfstore.internal.client.model.CompositeOperationHandle;
import org.eclipse.emf.emfstore.internal.client.model.Configuration;
import org.eclipse.emf.emfstore.internal.client.model.ESWorkspaceProviderImpl;
import org.eclipse.emf.emfstore.internal.client.model.ProjectSpace;
import org.eclipse.emf.emfstore.internal.client.model.changeTracking.notification.recording.NotificationRecorder;
import org.eclipse.emf.emfstore.internal.client.observers.OperationObserver;
import org.eclipse.emf.emfstore.internal.common.ESDisposable;
import org.eclipse.emf.emfstore.internal.common.model.IdEObjectCollection;
import org.eclipse.emf.emfstore.internal.common.model.util.IdEObjectCollectionChangeObserver;
import org.eclipse.emf.emfstore.internal.server.model.versioning.operations.AbstractOperation;
import org.eclipse.emf.emfstore.internal.server.model.versioning.operations.semantic.SemanticCompositeOperation;
/**
* This class acts as a simple wrapper around the operation recorder and provides convenience methods
* for undoing operations and handling composite operations.
*
* @author koegel
* @author emueller
*/
public class OperationManager implements OperationRecorderListener, ESDisposable, ESCommandObserver,
IdEObjectCollectionChangeObserver {
private final OperationRecorder operationRecorder;
private final ProjectSpace projectSpace;
/**
* Constructor.
*
* @param projectSpace
* the project space the operation manager should be attached to
*/
public OperationManager(ProjectSpaceBase projectSpace) {
operationRecorder = new OperationRecorder(projectSpace);
ESWorkspaceProviderImpl.getObserverBus().register(operationRecorder);
operationRecorder.addOperationRecorderListener(this);
configureOperationRecorder();
this.projectSpace = operationRecorder.getProjectSpace();
}
private void configureOperationRecorder() {
final OperationRecorderConfig config = operationRecorder.getConfig();
// incoming cross-references are cut off by default
config.setCutOffIncomingCrossReferences(
Configuration.getClientBehavior().isCutOffIncomingCrossReferencesActivated());
// usage of commands is not forced by default
config
.setForceCommands(
Configuration.getClientBehavior().isForceCommandsActived());
// cut elements are added automatically as regular model elements by default
config.setDenyAddCutElementsToModelElements(
Configuration.getClientBehavior().isDenyAddCutElementsToModelElementsFeatureActived());
config.setOperationModifier(
Configuration.getClientBehavior().getOperationModifier());
}
/**
* Undo the last operation of the projectSpace.
*/
public void undoLastOperation() {
projectSpace.undoLastOperations(1);
}
/**
* Adds an operation observer that gets notified whenever an operation
* is either executed or undone.
*
* @param operationObserver
* the operation observer to be added
*/
public void addOperationObserver(OperationObserver operationObserver) {
ESWorkspaceProviderImpl
.getObserverBus()
.register(operationObserver);
}
/**
* Removed the given operation observer from the list of operation observers.
*
* @param operationObserver
* the operation observer to be removed
*/
public void removeOperationListener(OperationObserver operationObserver) {
ESWorkspaceProviderImpl
.getObserverBus()
.unregister(operationObserver);
}
/**
* Notifies all operations observer that an operation has been undone.
*
* @param operation
* the operation that has been undone
*/
public void notifyOperationUndone(AbstractOperation operation) {
ESWorkspaceProviderImpl
.getObserverBus()
.notify(OperationObserver.class)
.operationUndone(operation);
}
/**
* Notify the operation observer that an operation has just completed.
*
* @param operation
* the operation
*/
void notifyOperationExecuted(AbstractOperation operation) {
ESWorkspaceProviderImpl
.getObserverBus()
.notify(OperationObserver.class)
.operationExecuted(operation);
}
/**
* Aborts the current composite operation.
*/
public void abortCompositeOperation() {
undoLastOperation();
operationRecorder.abortCompositeOperation();
}
/**
* Complete the current composite operation.
*/
public void endCompositeOperation() {
notifyOperationExecuted(operationRecorder.getCompositeOperation());
operationRecorder.endCompositeOperation();
}
/**
* Replace and complete the current composite operation.
*
* @param semanticCompositeOperation
* the semantic operation that replaces the composite operation
*/
public void endCompositeOperation(SemanticCompositeOperation semanticCompositeOperation) {
projectSpace.getLocalChangePackage().removeAtEnd(1);
projectSpace.getLocalChangePackage().add(semanticCompositeOperation);
endCompositeOperation();
}
/**
* Opens up a handle for creating a composite operation.
*
* @return the handle for the composite operation
*/
public CompositeOperationHandle beginCompositeOperation() {
return operationRecorder.beginCompositeOperation();
}
/**
*
* {@inheritDoc}
*
* @see org.eclipse.emf.emfstore.internal.client.model.impl.OperationRecorderListener#operationsRecorded(java.util.List)
*/
public void operationsRecorded(List<? extends AbstractOperation> operations) {
projectSpace.addOperations(operations);
}
/**
* Clears all recorded operations.
*
* @return the cleared operations
*/
public List<AbstractOperation> clearOperations() {
return operationRecorder.clearOperations();
}
/**
*
* {@inheritDoc}
*
* @see org.eclipse.emf.emfstore.internal.common.ESDisposable#dispose()
*/
public void dispose() {
ESWorkspaceProviderImpl.getObserverBus().unregister(operationRecorder);
operationRecorder.removeOperationRecorderListener(this);
}
/**
* Returns the notification recorder.
*
* @return the notification recorder
*/
public NotificationRecorder getNotificationRecorder() {
return operationRecorder.getNotificationRecorder();
}
/**
*
* {@inheritDoc}
*
* @see org.eclipse.emf.emfstore.client.changetracking.ESCommandObserver#commandStarted(org.eclipse.emf.common.command.Command)
*/
public void commandStarted(Command command) {
operationRecorder.commandStarted(command);
}
/**
*
* {@inheritDoc}
*
* @see org.eclipse.emf.emfstore.client.changetracking.ESCommandObserver#commandCompleted(org.eclipse.emf.common.command.Command)
*/
public void commandCompleted(Command command) {
operationRecorder.commandCompleted(command);
}
/**
*
* {@inheritDoc}
*
* @see org.eclipse.emf.emfstore.client.changetracking.ESCommandObserver#commandFailed(org.eclipse.emf.common.command.Command,
* java.lang.Exception)
*/
public void commandFailed(Command command, Exception exception) {
operationRecorder.commandFailed(command, exception);
}
/**
*
* {@inheritDoc}
*
* @see org.eclipse.emf.emfstore.internal.common.model.util.IdEObjectCollectionChangeObserver#notify(org.eclipse.emf.common.notify.Notification,
* org.eclipse.emf.emfstore.internal.common.model.IdEObjectCollection, org.eclipse.emf.ecore.EObject)
*/
public void notify(Notification notification, IdEObjectCollection collection, EObject modelElement) {
operationRecorder.notify(notification, collection, modelElement);
}
/**
*
* {@inheritDoc}
*
* @see org.eclipse.emf.emfstore.internal.common.model.util.IdEObjectCollectionChangeObserver#modelElementAdded(org.eclipse.emf.emfstore.internal.common.model.IdEObjectCollection,
* org.eclipse.emf.ecore.EObject)
*/
public void modelElementAdded(IdEObjectCollection collection, EObject modelElement) {
operationRecorder.modelElementAdded(collection, modelElement);
}
/**
*
* {@inheritDoc}
*
* @see org.eclipse.emf.emfstore.internal.common.model.util.IdEObjectCollectionChangeObserver#modelElementRemoved(org.eclipse.emf.emfstore.internal.common.model.IdEObjectCollection,
* org.eclipse.emf.ecore.EObject)
*/
public void modelElementRemoved(IdEObjectCollection collection, EObject modelElement) {
operationRecorder.modelElementRemoved(collection, modelElement);
}
/**
*
* {@inheritDoc}
*
* @see org.eclipse.emf.emfstore.internal.common.model.util.IdEObjectCollectionChangeObserver#collectionDeleted(org.eclipse.emf.emfstore.internal.common.model.IdEObjectCollection)
*/
public void collectionDeleted(IdEObjectCollection collection) {
operationRecorder.collectionDeleted(collection);
}
/**
* Starts change recording.
*/
public void startChangeRecording() {
operationRecorder.startChangeRecording();
}
/**
* Stops change recording.
*/
public void stopChangeRecording() {
operationRecorder.stopChangeRecording();
}
/**
* Returns the configuration options for the operation recorder.
*
* @return the operation recorder configuration options
*/
public OperationRecorderConfig getRecorderConfig() {
return operationRecorder.getConfig();
}
/**
* Notifies the manager that a command has been completed.
*
* @param command
* the {@link Command} that has been completed
* @param isNestedCommand
* whether the completed command is a command inside another one.
* If the completed command is nested, the {@link OperationRecorder}'s
* internal state maintains the state of a command still being run
*/
public void commandCompleted(Command command, boolean isNestedCommand) {
operationRecorder.commandCompleted(command, isNestedCommand);
}
/**
* Whether the operation manager considers a command is being run.
*
* @return <code>true</code> if a command is being run, <code>false</code> otherwise
*/
public boolean isCommandRunning() {
return operationRecorder.isCommandRunning();
}
}