From 7726e19ca0834ab1117003e08d35deea2c7ff020 Mon Sep 17 00:00:00 2001 From: Eike Stepper Date: Wed, 7 Nov 2007 15:09:13 +0000 Subject: [209036] Offer RollbackTransactionDialog on save conflict https://bugs.eclipse.org/bugs/show_bug.cgi?id=209036 --- plugins/org.eclipse.emf.cdo.ui/CDOClient1.launch | 72 ++++----- .../ui/actions/RollbackTransactionAction.java | 74 ++------- .../ui/dialogs/RollbackTransactionDialog.java | 178 +++++++++++++++++++++ .../emf/cdo/internal/ui/editor/CDOEditor.java | 16 +- .../src/org/eclipse/emf/cdo/CDOObject.java | 2 + .../src/org/eclipse/emf/cdo/CDOTransaction.java | 8 +- .../eclipse/emf/internal/cdo/CDOAdapterImpl.java | 1 + .../eclipse/emf/internal/cdo/CDOLegacyImpl.java | 10 ++ .../org/eclipse/emf/internal/cdo/CDOMetaImpl.java | 5 + .../eclipse/emf/internal/cdo/CDOObjectImpl.java | 11 +- .../eclipse/emf/internal/cdo/CDOStateMachine.java | 77 +++++++-- .../emf/internal/cdo/CDOTransactionImpl.java | 4 +- 12 files changed, 334 insertions(+), 124 deletions(-) create mode 100644 plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/dialogs/RollbackTransactionDialog.java diff --git a/plugins/org.eclipse.emf.cdo.ui/CDOClient1.launch b/plugins/org.eclipse.emf.cdo.ui/CDOClient1.launch index 14101303f4..8f627f5aa8 100644 --- a/plugins/org.eclipse.emf.cdo.ui/CDOClient1.launch +++ b/plugins/org.eclipse.emf.cdo.ui/CDOClient1.launch @@ -14,8 +14,8 @@ - + @@ -24,7 +24,7 @@ - + @@ -39,8 +39,8 @@ - + @@ -53,8 +53,8 @@ - + @@ -64,11 +64,11 @@ - + - + @@ -78,15 +78,15 @@ - + - + @@ -98,8 +98,8 @@ - + @@ -113,11 +113,11 @@ - + - + @@ -126,17 +126,17 @@ - - + + - - + + @@ -147,26 +147,26 @@ - + - + - + - + - + @@ -177,11 +177,11 @@ - + - + @@ -207,8 +207,8 @@ - + @@ -220,12 +220,12 @@ - + - + @@ -246,11 +246,11 @@ - + - + @@ -266,16 +266,16 @@ - + - + - + @@ -293,16 +293,16 @@ - + - + - + @@ -313,10 +313,10 @@ - - + + @@ -334,8 +334,8 @@ - + diff --git a/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/actions/RollbackTransactionAction.java b/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/actions/RollbackTransactionAction.java index 948367a88d..5fc3ca5b57 100644 --- a/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/actions/RollbackTransactionAction.java +++ b/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/actions/RollbackTransactionAction.java @@ -2,8 +2,9 @@ package org.eclipse.emf.cdo.internal.ui.actions; import org.eclipse.emf.cdo.CDOTransaction; import org.eclipse.emf.cdo.CDOView; +import org.eclipse.emf.cdo.internal.ui.dialogs.RollbackTransactionDialog; -import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.dialogs.Dialog; import org.eclipse.ui.IWorkbenchPage; /** @@ -15,6 +16,8 @@ public final class RollbackTransactionAction extends ViewAction private static final String TOOL_TIP = "Rollback this transaction"; + private boolean remote; + public RollbackTransactionAction(IWorkbenchPage page, CDOView view) { super(page, TITLE + INTERACTIVE, TOOL_TIP, null, view); @@ -25,70 +28,25 @@ public final class RollbackTransactionAction extends ViewAction protected void preRun() throws Exception { CDOTransaction transaction = (CDOTransaction)getView(); - int newResources = transaction.getNewResources().size(); - int newObjects = transaction.getNewObjects().size(); - int dirtyObjects = transaction.getDirtyObjects().size(); - int count = (newResources > 0 ? 1 : 0) + (newObjects > 0 ? 1 : 0) + (dirtyObjects > 0 ? 1 : 0); - - StringBuilder builder = new StringBuilder(); - builder.append("This transaction contains "); - if (newResources > 0) - { - builder.append(newResources); - builder.append(" new resource"); - if (newResources > 1) - { - builder.append("s"); - } - } - - if (newObjects > 0) - { - if (newResources > 0) - { - if (count > 2) - { - builder.append(", "); - } - else - { - builder.append(" and "); - } - } - - builder.append(newObjects); - builder.append(" new object"); - if (newObjects > 1) - { - builder.append("s"); - } - } - - if (dirtyObjects > 0) - { - if (count > 1) - { - builder.append(" and "); - } - - builder.append(dirtyObjects); - builder.append(" dirty object"); - if (dirtyObjects > 1) - { - builder.append("s"); - } - } - - builder.append(".\nAre you sure to rollback this transaction?"); - if (!MessageDialog.openQuestion(getShell(), TITLE, builder.toString())) + Dialog dialog = new RollbackTransactionDialog(getPage(), TITLE, "Choose how to rollback this transaction.", + transaction); + switch (dialog.open()) { + case RollbackTransactionDialog.REMOTE: + remote = true; + break; + case RollbackTransactionDialog.LOCAL: + remote = false; + break; + default: cancel(); + break; } } @Override protected void doRun() throws Exception { - getTransaction().rollback(); + getTransaction().rollback(remote); } } \ No newline at end of file diff --git a/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/dialogs/RollbackTransactionDialog.java b/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/dialogs/RollbackTransactionDialog.java new file mode 100644 index 0000000000..b626b0ab40 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/dialogs/RollbackTransactionDialog.java @@ -0,0 +1,178 @@ +/*************************************************************************** + * Copyright (c) 2004 - 2007 Eike Stepper, Germany. + * 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: + * Eike Stepper - initial API and implementation + **************************************************************************/ +package org.eclipse.emf.cdo.internal.ui.dialogs; + +import org.eclipse.emf.cdo.CDOTransaction; + +import org.eclipse.net4j.util.ui.UIUtil; + +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.TitleAreaDialog; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IWorkbenchPage; + +/** + * @author Eike Stepper + */ +public class RollbackTransactionDialog extends TitleAreaDialog +{ + // public static final String TITLE = "Rollback Transaction"; + + public static final int REMOTE = CANCEL + 1; + + public static final int LOCAL = CANCEL + 2; + + private static final int REMOTE_ID = IDialogConstants.CLIENT_ID + REMOTE; + + private static final int LOCAL_ID = IDialogConstants.CLIENT_ID + LOCAL; + + private IWorkbenchPage page; + + private String title; + + private String description; + + private CDOTransaction transaction; + + public RollbackTransactionDialog(IWorkbenchPage page, String title, String description, CDOTransaction transaction) + { + super(new Shell(page.getWorkbenchWindow().getShell())); + this.page = page; + this.title = title; + this.description = description; + this.transaction = transaction; + setShellStyle(getShellStyle() | SWT.APPLICATION_MODAL | SWT.MAX | SWT.TITLE | SWT.RESIZE); + } + + public IWorkbenchPage getPage() + { + return page; + } + + @Override + protected void configureShell(Shell newShell) + { + super.configureShell(newShell); + newShell.setText(title); + } + + @Override + protected Control createDialogArea(Composite parent) + { + Composite composite = new Composite((Composite)super.createDialogArea(parent), SWT.NONE); + composite.setLayoutData(UIUtil.createGridData()); + composite.setLayout(new GridLayout(1, false)); + + setTitle(description); + setTitleImage(getShell().getDisplay().getSystemImage(SWT.ICON_QUESTION)); + + Label label = new Label(composite, SWT.NONE); + label.setText(formatMessage()); + label.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true)); + + return composite; + } + + @Override + protected void createButtonsForButtonBar(Composite parent) + { + createButton(parent, REMOTE_ID, "Remote Rollback", true); + createButton(parent, LOCAL_ID, "Local Rollback", false); + createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false); + } + + @Override + protected void buttonPressed(int buttonId) + { + if (buttonId == REMOTE_ID) + { + setReturnCode(REMOTE); + close(); + } + else if (buttonId == LOCAL_ID) + { + setReturnCode(LOCAL); + close(); + } + else + { + super.buttonPressed(buttonId); + } + } + + protected String formatMessage() + { + int newResources = transaction.getNewResources().size(); + int newObjects = transaction.getNewObjects().size(); + int dirtyObjects = transaction.getDirtyObjects().size(); + int count = (newResources > 0 ? 1 : 0) + (newObjects > 0 ? 1 : 0) + (dirtyObjects > 0 ? 1 : 0); + + StringBuilder builder = new StringBuilder(); + builder.append("This transaction contains "); + if (newResources > 0) + { + builder.append(newResources); + builder.append(" new resource"); + if (newResources > 1) + { + builder.append("s"); + } + } + + if (newObjects > 0) + { + if (newResources > 0) + { + if (count > 2) + { + builder.append(", "); + } + else + { + builder.append(" and "); + } + } + + builder.append(newObjects); + builder.append(" new object"); + if (newObjects > 1) + { + builder.append("s"); + } + } + + if (dirtyObjects > 0) + { + if (count > 1) + { + builder.append(" and "); + } + + builder.append(dirtyObjects); + builder.append(" dirty object"); + if (dirtyObjects > 1) + { + builder.append("s"); + } + } + + builder.append(".\nBe careful, rolling back to local state can result\n" + + "in visible state that is different from the remote state!"); + builder.append("\n\nAre you sure to rollback this transaction?"); + return builder.toString(); + } +} diff --git a/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/editor/CDOEditor.java b/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/editor/CDOEditor.java index 0129734d6f..30c8ecc133 100644 --- a/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/editor/CDOEditor.java +++ b/plugins/org.eclipse.emf.cdo.ui/src/org/eclipse/emf/cdo/internal/ui/editor/CDOEditor.java @@ -12,6 +12,7 @@ import org.eclipse.emf.cdo.CDOView; import org.eclipse.emf.cdo.eresource.CDOResource; import org.eclipse.emf.cdo.internal.ui.SharedIcons; import org.eclipse.emf.cdo.internal.ui.bundle.OM; +import org.eclipse.emf.cdo.internal.ui.dialogs.RollbackTransactionDialog; import org.eclipse.emf.cdo.internal.ui.views.CDOEventHandler; import org.eclipse.emf.cdo.protocol.model.CDOClass; import org.eclipse.emf.cdo.protocol.model.CDOPackage; @@ -82,6 +83,7 @@ import org.eclipse.jface.action.IStatusLineManager; import org.eclipse.jface.action.IToolBarManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.action.Separator; +import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.viewers.ISelection; @@ -1586,13 +1588,23 @@ public class CDOEditor extends MultiPageEditorPart implements IEditingDomainProv } catch (final TransactionException exception) { - OM.LOG.error(exception); final Shell shell = getSite().getShell(); shell.getDisplay().syncExec(new Runnable() { public void run() { - MessageDialog.openError(shell, "Transaction Error", exception.getMessage()); + CDOTransaction transaction = (CDOTransaction)view; + Dialog dialog = new RollbackTransactionDialog(getEditorSite().getPage(), "Transaction Error", + exception.getMessage(), transaction); + switch (dialog.open()) + { + case RollbackTransactionDialog.REMOTE: + transaction.rollback(true); + break; + case RollbackTransactionDialog.LOCAL: + transaction.rollback(false); + break; + } } }); } diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/CDOObject.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/CDOObject.java index 567b0dc153..f38fbe42a2 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/CDOObject.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/CDOObject.java @@ -33,4 +33,6 @@ public interface CDOObject extends EObject public CDOResource cdoResource(); public CDORevision cdoRevision(); + + public boolean cdoRefresh(boolean force); } diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/CDOTransaction.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/CDOTransaction.java index d869e63fc6..ee4a56bdae 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/CDOTransaction.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/CDOTransaction.java @@ -38,15 +38,9 @@ public interface CDOTransaction extends CDOView public CDOObject newInstance(CDOClass cdoClass); - /** - * @see CDOTransaction#commit() - */ public void commit() throws TransactionException; - /** - * @see CDOTransaction#rollback() - */ - public void rollback(); + public void rollback(boolean remote); public void addHandler(CDOTransactionHandler handler); diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOAdapterImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOAdapterImpl.java index 0de8c82b2d..703cc18cb3 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOAdapterImpl.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOAdapterImpl.java @@ -22,6 +22,7 @@ public class CDOAdapterImpl extends CDOLegacyImpl { } + @Override public boolean isAdapterForType(Object type) { return type == CDOAdapterImpl.class; diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOLegacyImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOLegacyImpl.java index fcf62e68d8..0a79ec6950 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOLegacyImpl.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOLegacyImpl.java @@ -101,6 +101,16 @@ public abstract class CDOLegacyImpl extends CDOWrapperImpl implements Adapter.In return view; } + public boolean cdoRefresh(boolean force) + { + return CDOStateMachine.INSTANCE.refresh(this, force); + } + + public boolean isAdapterForType(Object type) + { + return false; + } + public CDOState cdoInternalSetState(CDOState state) { if (this.state != state) diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOMetaImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOMetaImpl.java index 2efa0676a2..4aa4a5de4e 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOMetaImpl.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOMetaImpl.java @@ -50,6 +50,11 @@ public class CDOMetaImpl extends CDOWrapperImpl throw new UnsupportedOperationException(); } + public boolean cdoRefresh(boolean force) + { + throw new UnsupportedOperationException(); + } + public boolean cdoTransient() { return false; diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOObjectImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOObjectImpl.java index c3ea214032..c5f47a9a70 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOObjectImpl.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOObjectImpl.java @@ -20,9 +20,6 @@ import org.eclipse.emf.cdo.internal.protocol.revision.CDORevisionImpl; import org.eclipse.emf.cdo.protocol.CDOID; import org.eclipse.emf.cdo.protocol.revision.CDORevision; -import org.eclipse.net4j.internal.util.om.trace.ContextTracer; -import org.eclipse.net4j.util.ImplementationError; - import org.eclipse.emf.common.util.BasicEMap; import org.eclipse.emf.common.util.ECollections; import org.eclipse.emf.common.util.EList; @@ -43,6 +40,9 @@ import org.eclipse.emf.internal.cdo.bundle.OM; import org.eclipse.emf.internal.cdo.util.FSMUtil; import org.eclipse.emf.internal.cdo.util.ModelUtil; +import org.eclipse.net4j.internal.util.om.trace.ContextTracer; +import org.eclipse.net4j.util.ImplementationError; + import java.util.Collection; import java.util.Iterator; import java.util.List; @@ -104,6 +104,11 @@ public class CDOObjectImpl extends EStoreEObjectImpl implements InternalCDOObjec return resource; } + public boolean cdoRefresh(boolean force) + { + return CDOStateMachine.INSTANCE.refresh(this, force); + } + public void cdoInternalSetID(CDOID id) { if (id == null) diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOStateMachine.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOStateMachine.java index 74889bd408..f5a50793aa 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOStateMachine.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/CDOStateMachine.java @@ -48,63 +48,70 @@ public final class CDOStateMachine extends FiniteStateMachine + private final class RollbackTransition implements ITransition { - public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Object NULL) + public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Boolean remote) { CDOViewImpl view = (CDOViewImpl)object.cdoView(); @@ -323,7 +338,7 @@ public final class CDOStateMachine extends FiniteStateMachine + private final class RefreshTransition implements ITransition + { + public void execute(InternalCDOObject object, CDOState state, CDOEvent event, boolean[] forceAndResult) + { + if (forceAndResult[0]) + { + } + + changeState(object, CDOState.CLEAN); + } + } + + /** + * @author Eike Stepper + */ + private class InvalidateTransition implements ITransition { public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Long timeStamp) { - ((CDORevisionImpl)object.cdoRevision()).setRevised(timeStamp - 1); + reviseObject(object, timeStamp); changeState(object, CDOState.PROXY); } + + protected void reviseObject(InternalCDOObject object, Long timeStamp) + { + CDORevisionImpl revision = (CDORevisionImpl)object.cdoRevision(); + revision.setRevised(timeStamp - 1); + + if (revision.isTransactional()) + { + CDOViewImpl view = (CDOViewImpl)object.cdoView(); + revision = view.getRevision(object.cdoID()); + revision.setRevised(timeStamp - 1); + } + } } /** * @author Eike Stepper */ - private final class ConflictTransition implements ITransition + private final class ConflictTransition extends InvalidateTransition { + @Override public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Long timeStamp) { + reviseObject(object, timeStamp); CDOViewImpl view = (CDOViewImpl)object.cdoView(); CDOTransactionImpl transaction = view.toTransaction(); transaction.setConflict(object); @@ -452,5 +497,5 @@ public final class CDOStateMachine extends FiniteStateMachine