From 2a2b368a86e064a82a767aa5498a9949aa93a159 Mon Sep 17 00:00:00 2001 From: Ansgar Radermacher Date: Tue, 4 Mar 2014 16:41:32 +0100 Subject: Bug 315231 - [All Diagrams] Direct Edit : Xtext / Papyrus integration Enable validation without showing a progress bar Avoid focus lost for editor in properties tab after control assist ends Simple undo/redo support for editor in progress tab --- .../commands/AbstractValidateCommand.java | 26 ++++- .../sheet/AdvancedEditingPropertySection.java | 126 +++++++++++++++++++-- .../uml/properties/xtext/sheet/UndoRedoStack.java | 48 ++++++++ .../xtext/EssentialOCLEditorConfiguration.java | 4 +- .../DefaultXtextDirectEditorConfiguration.java | 4 +- .../validation/ExistsAnnotationConstraint.java | 4 +- 6 files changed, 197 insertions(+), 15 deletions(-) create mode 100644 plugins/uml/properties/org.eclipse.papyrus.uml.properties.xtext/src/org/eclipse/papyrus/uml/properties/xtext/sheet/UndoRedoStack.java (limited to 'plugins') diff --git a/plugins/infra/services/org.eclipse.papyrus.infra.services.validation/src/org/eclipse/papyrus/infra/services/validation/commands/AbstractValidateCommand.java b/plugins/infra/services/org.eclipse.papyrus.infra.services.validation/src/org/eclipse/papyrus/infra/services/validation/commands/AbstractValidateCommand.java index 8918cea877b..dff5bbd8114 100644 --- a/plugins/infra/services/org.eclipse.papyrus.infra.services.validation/src/org/eclipse/papyrus/infra/services/validation/commands/AbstractValidateCommand.java +++ b/plugins/infra/services/org.eclipse.papyrus.infra.services.validation/src/org/eclipse/papyrus/infra/services/validation/commands/AbstractValidateCommand.java @@ -21,6 +21,7 @@ import java.util.Iterator; import java.util.Map; import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.emf.common.notify.AdapterFactory; import org.eclipse.emf.common.util.BasicDiagnostic; @@ -64,6 +65,8 @@ abstract public class AbstractValidateCommand extends AbstractTransactionalComma protected IPapyrusDiagnostician diagnostician; + protected boolean showUIfeedback; + /** * Creates a new ValidationCommand * @@ -94,8 +97,17 @@ abstract public class AbstractValidateCommand extends AbstractTransactionalComma this.domain = domain; this.selectedElement = selectedElement; this.diagnostician= diagnostician; + this.showUIfeedback = true; // default is true; } + /** + * don't use a progress monitor to show validation progress. This is quite useful + * for diagnostics that are executed on a (shallow) subtree and do not take much time. + */ + public void disableUIFeedback() { + this.showUIfeedback = false; + } + /** * @return The resource on which markers should be applied. */ @@ -141,7 +153,12 @@ abstract public class AbstractValidateCommand extends AbstractTransactionalComma try { // runs the operation, and shows progress. diagnostic = null; - new ProgressMonitorDialog(shell).run(true, true, runValidationWithProgress); + if (showUIfeedback) { + new ProgressMonitorDialog(shell).run(true, true, runValidationWithProgress); + } + else { + runValidationWithProgress.run(new NullProgressMonitor()); + } if(diagnostic != null) { int markersToCreate = diagnostic.getChildren().size(); if((markersToCreate > 0) && PreferenceUtils.getAutoShowValidation()) { @@ -154,7 +171,12 @@ abstract public class AbstractValidateCommand extends AbstractTransactionalComma } // don't fork this dialog, i.e. run it in the UI thread. This avoids that the diagrams are constantly refreshing *while* // markers/decorations are changing. This greatly enhances update performance. See also bug 400593 - new ProgressMonitorDialog(shell).run(false, true, createMarkersWithProgress); + if (showUIfeedback) { + new ProgressMonitorDialog(shell).run(false, true, createMarkersWithProgress); + } + else { + createMarkersWithProgress.run(new NullProgressMonitor()); + } } } catch (Exception exception) { EMFEditUIPlugin.INSTANCE.log(exception); diff --git a/plugins/uml/properties/org.eclipse.papyrus.uml.properties.xtext/src/org/eclipse/papyrus/uml/properties/xtext/sheet/AdvancedEditingPropertySection.java b/plugins/uml/properties/org.eclipse.papyrus.uml.properties.xtext/src/org/eclipse/papyrus/uml/properties/xtext/sheet/AdvancedEditingPropertySection.java index b1231c64632..12d2f87a082 100644 --- a/plugins/uml/properties/org.eclipse.papyrus.uml.properties.xtext/src/org/eclipse/papyrus/uml/properties/xtext/sheet/AdvancedEditingPropertySection.java +++ b/plugins/uml/properties/org.eclipse.papyrus.uml.properties.xtext/src/org/eclipse/papyrus/uml/properties/xtext/sheet/AdvancedEditingPropertySection.java @@ -1,3 +1,17 @@ +/***************************************************************************** + * Copyright (c) 2014 CEA LIST. + * + * 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: + * Itemis - Initial API and implementation + * Ansgar Radermacher - added undo/redo support (inspired by code from Petr Bodnar) + * + *****************************************************************************/ + package org.eclipse.papyrus.uml.properties.xtext.sheet; import org.eclipse.emf.ecore.EObject; @@ -19,9 +33,13 @@ import org.eclipse.papyrus.uml.xtext.integration.core.ContextElementAdapter; import org.eclipse.papyrus.uml.xtext.integration.core.ContextElementAdapter.IContextElementProvider; import org.eclipse.papyrus.uml.xtext.integration.core.ContextElementAdapter.IContextElementProviderWithInit; import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.ExtendedModifyEvent; +import org.eclipse.swt.custom.ExtendedModifyListener; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.events.FocusEvent; import org.eclipse.swt.events.FocusListener; +import org.eclipse.swt.events.KeyAdapter; +import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; @@ -45,6 +63,16 @@ public class AdvancedEditingPropertySection extends final private ContextElementAdapter contextElementAdapter = new ContextElementAdapter( this); + UndoRedoStack undoRedoStack; + + protected boolean isUndo; + + protected boolean isRedo; + + public AdvancedEditingPropertySection() { + undoRedoStack = new UndoRedoStack(); + } + @Override public void refresh() { updateXtextAdapters(textControl); @@ -88,14 +116,20 @@ public class AdvancedEditingPropertySection extends createTextControl(form.getBody()); } + protected void createTextControl(final Composite parent) { textControl = new StyledText(parent, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL | SWT.WRAP); + textControl.addFocusListener(new FocusListener() { public void focusLost(FocusEvent e) { IParser parser = getParser(); + if (xtextAdapter.getCompletionProposalAdapter().delayedIsPopupOpen()) { + // ignore focus lost + return; + } if (parser != null) { ICommand command = parser.getParseCommand( new EObjectAdapter(getEObject()), @@ -109,12 +143,74 @@ public class AdvancedEditingPropertySection extends public void focusGained(FocusEvent e) { } }); - ((StyledText) textControl).setAlwaysShowScrollBars(false); + + textControl.setAlwaysShowScrollBars(false); GridDataFactory.fillDefaults().grab(true, true).hint(parent.getSize()) .applyTo(textControl); + textControl.addExtendedModifyListener(new ExtendedModifyListener() { + + public void modifyText(ExtendedModifyEvent event) { + if (isUndo) { + undoRedoStack.pushRedo(event); + } else { // is Redo or a normal user action + undoRedoStack.pushUndo(event); + if (!isRedo) { + undoRedoStack.clearRedo(); + // TODO Switch to treat consecutive characters as one event? + } + } + } + }); + textControl.addKeyListener(new KeyAdapter() { + public void keyPressed(KeyEvent e) { + boolean isCtrl = (e.stateMask & SWT.CTRL) > 0; + boolean isAlt = (e.stateMask & SWT.ALT) > 0; + if (isCtrl && !isAlt) { + boolean isShift = (e.stateMask & SWT.SHIFT) > 0; + if (e.keyCode == 'z') { + if (isShift) { + redo(); + } + else { + undo(); + } + } + } + } + }); + } + + protected void undo() { + if (undoRedoStack.hasUndo()) { + isUndo = true; + revertEvent(undoRedoStack.popUndo()); + isUndo = false; + } + } + + protected void redo() { + if (undoRedoStack.hasRedo()) { + isRedo = true; + revertEvent(undoRedoStack.popRedo()); + isRedo = false; + } } + /** + * Reverts the given modify event, in the way as the Eclipse text editor + * does it. + * + * @param event + */ + private void revertEvent(ExtendedModifyEvent event) { + textControl.replaceTextRange(event.start, event.length, event.replacedText); + // (causes the modifyText() listener method to be called) + + textControl.setSelectionRange(event.start, event.replacedText.length()); + } + + protected DefaultXtextDirectEditorConfiguration getConfigurationFromSelection() { IGraphicalEditPart part = getEditPartFromSelection(); if (part != null) { @@ -131,15 +227,8 @@ public class AdvancedEditingPropertySection extends .findEditorConfiguration(languagePreferred, semanticClassName); if (configuration instanceof DefaultXtextDirectEditorConfiguration) { + DefaultXtextDirectEditorConfiguration xtextConfiguration = (DefaultXtextDirectEditorConfiguration) configuration; - IContextElementProvider provider = xtextConfiguration.getContextProvider(); - if (provider instanceof IContextElementProviderWithInit) { - // update resource, if required by text editor - if (xtextAdapter != null) { - ((IContextElementProviderWithInit) provider).initResource( - xtextAdapter.getFakeResourceContext().getFakeResource()); - } - } xtextConfiguration.preEditAction(part.resolveSemanticElement()); return xtextConfiguration; } @@ -165,6 +254,8 @@ public class AdvancedEditingPropertySection extends } protected void updateXtextAdapters(Control styledText) { + final Object oldObjectToEdit = configuration != null ? configuration.getObjectToEdit() : null; + final DefaultXtextDirectEditorConfiguration newConfiguration = getConfigurationFromSelection(); // Check if configuration has changed and update adapters if (newConfiguration != null && newConfiguration != configuration) { @@ -175,10 +266,27 @@ public class AdvancedEditingPropertySection extends configuration = newConfiguration; xtextAdapter = new StyledTextXtextAdapter( configuration.getInjector()); + + IGraphicalEditPart part = getEditPartFromSelection(); + if (part != null) { + // newConfiguration.preEditAction(part.resolveSemanticElement()); + } + xtextAdapter.getFakeResourceContext().getFakeResource().eAdapters() .add(contextElementAdapter); xtextAdapter.adapt((StyledText) styledText); } + + if (configuration.getObjectToEdit() != oldObjectToEdit) { + IContextElementProvider provider = configuration.getContextProvider(); + if (provider instanceof IContextElementProviderWithInit) { + // update resource, if required by text editor + if (xtextAdapter != null) { + ((IContextElementProviderWithInit) provider).initResource( + xtextAdapter.getFakeResourceContext().getFakeResource()); + } + } + } } public EObject getContextObject() { diff --git a/plugins/uml/properties/org.eclipse.papyrus.uml.properties.xtext/src/org/eclipse/papyrus/uml/properties/xtext/sheet/UndoRedoStack.java b/plugins/uml/properties/org.eclipse.papyrus.uml.properties.xtext/src/org/eclipse/papyrus/uml/properties/xtext/sheet/UndoRedoStack.java new file mode 100644 index 00000000000..556bd7aa562 --- /dev/null +++ b/plugins/uml/properties/org.eclipse.papyrus.uml.properties.xtext/src/org/eclipse/papyrus/uml/properties/xtext/sheet/UndoRedoStack.java @@ -0,0 +1,48 @@ +package org.eclipse.papyrus.uml.properties.xtext.sheet; + +import java.util.Stack; + +/** + * Encapsulation of the Undo and Redo stack(s) + * @author Petr Bodnar + */ +public class UndoRedoStack { + + private Stack undo; + private Stack redo; + + public UndoRedoStack() { + undo = new Stack(); + redo = new Stack(); + } + + public void pushUndo(T delta) { + undo.add(delta); + } + + public void pushRedo(T delta) { + redo.add(delta); + } + + public T popUndo() { + T res = undo.pop(); + return res; + } + + public T popRedo() { + T res = redo.pop(); + return res; + } + + public void clearRedo() { + redo.clear(); + } + + public boolean hasUndo() { + return !undo.isEmpty(); + } + + public boolean hasRedo() { + return !redo.isEmpty(); + } +} diff --git a/plugins/uml/textedit/org.eclipse.papyrus.uml.textedit.constraintwithessentialocl.xtext/src/org/eclipse/papyrus/uml/textedit/constraintwithessentialocl/xtext/EssentialOCLEditorConfiguration.java b/plugins/uml/textedit/org.eclipse.papyrus.uml.textedit.constraintwithessentialocl.xtext/src/org/eclipse/papyrus/uml/textedit/constraintwithessentialocl/xtext/EssentialOCLEditorConfiguration.java index 4b923246a18..b82cc201fd6 100644 --- a/plugins/uml/textedit/org.eclipse.papyrus.uml.textedit.constraintwithessentialocl.xtext/src/org/eclipse/papyrus/uml/textedit/constraintwithessentialocl/xtext/EssentialOCLEditorConfiguration.java +++ b/plugins/uml/textedit/org.eclipse.papyrus.uml.textedit.constraintwithessentialocl.xtext/src/org/eclipse/papyrus/uml/textedit/constraintwithessentialocl/xtext/EssentialOCLEditorConfiguration.java @@ -182,7 +182,9 @@ public class EssentialOCLEditorConfiguration extends DefaultXtextDirectEditorCon TransactionalEditingDomain editingDomain = TransactionUtil.getEditingDomain(semanticObject); if (semanticObject instanceof Constraint) { result.add(new UpdateConstraintCommand(editingDomain, (Constraint) semanticObject, newString)); - result.add(new ValidateSubtreeCommand(semanticObject, new EcoreDiagnostician())); + ValidateSubtreeCommand validationCommand = new ValidateSubtreeCommand(semanticObject, new EcoreDiagnostician()); + validationCommand.disableUIFeedback(); + result.add(validationCommand); } return result; } diff --git a/plugins/uml/xtext/org.eclipse.papyrus.uml.xtext.integration.ui/src/org/eclipse/papyrus/uml/xtext/integration/DefaultXtextDirectEditorConfiguration.java b/plugins/uml/xtext/org.eclipse.papyrus.uml.xtext.integration.ui/src/org/eclipse/papyrus/uml/xtext/integration/DefaultXtextDirectEditorConfiguration.java index 4fd2766bc9a..fd4850eecc2 100644 --- a/plugins/uml/xtext/org.eclipse.papyrus.uml.xtext.integration.ui/src/org/eclipse/papyrus/uml/xtext/integration/DefaultXtextDirectEditorConfiguration.java +++ b/plugins/uml/xtext/org.eclipse.papyrus.uml.xtext.integration.ui/src/org/eclipse/papyrus/uml/xtext/integration/DefaultXtextDirectEditorConfiguration.java @@ -163,7 +163,9 @@ public abstract class DefaultXtextDirectEditorConfiguration extends DefaultDirec } else { result.add(createInvalidStringCommand(newString, semanticObject)); } - result.add(new ValidateSubtreeCommand(semanticObject, new EcoreDiagnostician())); + ValidateSubtreeCommand validationCommand = new ValidateSubtreeCommand(semanticObject, new EcoreDiagnostician()); + validationCommand.disableUIFeedback(); + result.add(validationCommand); return result; } diff --git a/plugins/uml/xtext/org.eclipse.papyrus.uml.xtext.integration.validation/src/org/eclipse/papyrus/uml/xtext/integration/validation/ExistsAnnotationConstraint.java b/plugins/uml/xtext/org.eclipse.papyrus.uml.xtext.integration.validation/src/org/eclipse/papyrus/uml/xtext/integration/validation/ExistsAnnotationConstraint.java index 008439089cb..091aa7bbf2e 100644 --- a/plugins/uml/xtext/org.eclipse.papyrus.uml.xtext.integration.validation/src/org/eclipse/papyrus/uml/xtext/integration/validation/ExistsAnnotationConstraint.java +++ b/plugins/uml/xtext/org.eclipse.papyrus.uml.xtext.integration.validation/src/org/eclipse/papyrus/uml/xtext/integration/validation/ExistsAnnotationConstraint.java @@ -13,7 +13,7 @@ import org.eclipse.uml2.uml.Element; * the xtext string couldn't be parsed and is out of sync with the UML model. * * - * @author Markus Mühlbrandt + * @author Markus M�hlbrandt * */ public class ExistsAnnotationConstraint extends AbstractModelConstraint { @@ -30,7 +30,7 @@ public class ExistsAnnotationConstraint extends AbstractModelConstraint { text = InvalidStringUtil.getTextualRepresentation(element); } - if (text != null && !"".equals(text)) { + if (text != null && !"".equals(text)) { //$NON-NLS-1$ return ctx.createFailureStatus(eObj.eClass().getName()); } } -- cgit v1.2.3