Bug 541190 - Generic Editor should support more input sources than files
Adapt the Generic Editor to handle opening files from further inputs
besides files in the workspace. For instance, the Generic Editor now
supports opening files from a local or Git history revision.
If an opened editor input does not allow to persist the loaded data
(e.g. in the history revision case), the editor is opened as read-only.
Concretely, this has the following implications:
* Drag and drop is disabled for the tree
* The tree's context menu is disabled
* The editor doesn't show toolbar actions
* All detail views are shown as read-only but the user can still select
different objects in the tree to view their detail views
To achieve the foregoing behavior, the TreeViewerCustomization was
extended by a read-only configuration which can be queried from a
customization implementation.
The DefaultTreeViewerCustomization was adapted to this by not returning
any menu and stating that drag and drop is disabled whenever read-only
is set to true.
Change-Id: I76972d2399c05fdd908ed45e5c713da7842a3fa9
Signed-off-by: Lucas Koehler <lkoehler@eclipsesource.com>
diff --git a/bundles/org.eclipse.emfforms.editor.ecore/src/org/eclipse/emfforms/internal/editor/ecore/EcoreEditor.java b/bundles/org.eclipse.emfforms.editor.ecore/src/org/eclipse/emfforms/internal/editor/ecore/EcoreEditor.java
index e253b41..c03f9ca 100644
--- a/bundles/org.eclipse.emfforms.editor.ecore/src/org/eclipse/emfforms/internal/editor/ecore/EcoreEditor.java
+++ b/bundles/org.eclipse.emfforms.editor.ecore/src/org/eclipse/emfforms/internal/editor/ecore/EcoreEditor.java
@@ -49,6 +49,7 @@
final EcoreEditorTMDCustomization buildBehaviour = new EcoreEditorTMDCustomization(createElementCallback,
(Notifier) editorInput, (EcoreDiagnosticCache) getDiagnosticCache());
buildBehaviour.setTree(createTreeViewerBuilder());
+ buildBehaviour.setReadOnly(!isEditable(getEditorInput()));
final TreeMasterDetailComposite result = TreeMasterDetailSWTFactory.createTreeMasterDetail(composite, SWT.NONE,
editorInput,
diff --git a/bundles/org.eclipse.emfforms.editor/META-INF/MANIFEST.MF b/bundles/org.eclipse.emfforms.editor/META-INF/MANIFEST.MF
index c463814..54b2ce5 100644
--- a/bundles/org.eclipse.emfforms.editor/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.emfforms.editor/META-INF/MANIFEST.MF
@@ -15,7 +15,7 @@
org.eclipse.emfforms.spi.editor.messages;version="1.22.0"
Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.1.0,4.0.0)",
org.eclipse.emf.ecp.ui.view.swt;bundle-version="[1.22.0,1.23.0)",
- org.eclipse.emf.edit.ui;bundle-version="[2.10.0,3.0.0)",
+ org.eclipse.emf.edit.ui;bundle-version="[2.11.0,3.0.0)",
org.eclipse.emf.ecp.view.template.model;bundle-version="[1.22.0,1.23.0)",
org.eclipse.ui.ide;bundle-version="[3.10.0,4.0.0)",
org.eclipse.emf.ecore.edit;bundle-version="[2.9.0,3.0.0)",
diff --git a/bundles/org.eclipse.emfforms.editor/src/org/eclipse/emfforms/spi/editor/GenericEditor.java b/bundles/org.eclipse.emfforms.editor/src/org/eclipse/emfforms/spi/editor/GenericEditor.java
index 52f08c1..635737c 100644
--- a/bundles/org.eclipse.emfforms.editor/src/org/eclipse/emfforms/spi/editor/GenericEditor.java
+++ b/bundles/org.eclipse.emfforms.editor/src/org/eclipse/emfforms/spi/editor/GenericEditor.java
@@ -511,7 +511,8 @@
}
})
- .customizeTree(createTreeViewerBuilder());
+ .customizeTree(createTreeViewerBuilder())
+ .customizeReadOnly(!isEditable(getEditorInput()));
if (enableValidation()) {
builder.customizeLabelDecorator(
@@ -569,9 +570,9 @@
* @throws PartInitException if the resource could not be loaded
*/
protected ResourceSet loadResource(IEditorInput editorInput) throws PartInitException {
- final URI resourceURI = EditUIUtil.getURI(editorInput, null);
-
ResourceSet resourceSet = ResourceSetHelpers.createResourceSet(getCommandStack());
+ final URI resourceURI = EditUIUtil.getURI(editorInput, resourceSet.getURIConverter());
+
try {
resourceSet = ResourceSetHelpers.loadResourceWithProxies(resourceURI, resourceSet,
getResourceLoadOptions());
@@ -585,6 +586,18 @@
}
/**
+ * Returns whether the editor input allows editing of its contents.
+ *
+ * @param editorInput the editor's {@link IEditorInput}
+ * @return <code>true</code> if the input source allows editing, <code>false</code> otherwise
+ * @since 1.22
+ */
+ protected boolean isEditable(IEditorInput editorInput) {
+ // Only allow editing data if it can be persisted
+ return editorInput.getPersistable() != null;
+ }
+
+ /**
* Check that the resource was loaded correctly and show any warnings to the user.
*
* @param resourceSet the resource set
@@ -683,6 +696,10 @@
*/
protected List<Action> getToolbarActions() {
final List<Action> result = new LinkedList<Action>();
+ if (!isEditable(getEditorInput())) {
+ // If the input isn't editable, toolbar actions are disabled
+ return result;
+ }
result.add(new LoadEcoreAction(resourceSet));
diff --git a/bundles/org.eclipse.emfforms.rulerepository.tooling/src/org/eclipse/emfforms/internal/rulerepository/tooling/RuleRepositoryEditor.java b/bundles/org.eclipse.emfforms.rulerepository.tooling/src/org/eclipse/emfforms/internal/rulerepository/tooling/RuleRepositoryEditor.java
index 2650a50..0b35ed3 100644
--- a/bundles/org.eclipse.emfforms.rulerepository.tooling/src/org/eclipse/emfforms/internal/rulerepository/tooling/RuleRepositoryEditor.java
+++ b/bundles/org.eclipse.emfforms.rulerepository.tooling/src/org/eclipse/emfforms/internal/rulerepository/tooling/RuleRepositoryEditor.java
@@ -49,7 +49,11 @@
*/
@Override
protected List<Action> getToolbarActions() {
- final List<Action> result = new LinkedList<Action>();
+ final List<Action> result = new LinkedList<>();
+ if (!isEditable(getEditorInput())) {
+ // If the input isn't editable, toolbar actions shouldn't be available
+ return result;
+ }
result.add(new LoadEcoreAction(getResourceSet(), "Load ViewModel")); //$NON-NLS-1$
diff --git a/bundles/org.eclipse.emfforms.swt.treemasterdetail/.settings/.api_filters b/bundles/org.eclipse.emfforms.swt.treemasterdetail/.settings/.api_filters
index d3c9b02..7875ebf 100644
--- a/bundles/org.eclipse.emfforms.swt.treemasterdetail/.settings/.api_filters
+++ b/bundles/org.eclipse.emfforms.swt.treemasterdetail/.settings/.api_filters
@@ -91,6 +91,13 @@
<message_argument value="getLabelDecorator(TreeViewer)"/>
</message_arguments>
</filter>
+ <filter comment="SPI Change 1.22.0: Added TreeReadOnlyProvider to TreeViewerCustomization" id="403984517">
+ <message_arguments>
+ <message_argument value="org.eclipse.emfforms.spi.swt.treemasterdetail.TreeMasterDetailSWTCustomization"/>
+ <message_argument value="org.eclipse.emfforms.spi.swt.treemasterdetail.TreeReadOnlyProvider"/>
+ <message_argument value="isReadOnly()"/>
+ </message_arguments>
+ </filter>
</resource>
<resource path="src/org/eclipse/emfforms/spi/swt/treemasterdetail/TreeViewerCustomization.java" type="org.eclipse.emfforms.spi.swt.treemasterdetail.TreeViewerCustomization">
<filter comment="SPI Change 1.9.0" id="403984517">
@@ -107,6 +114,13 @@
<message_argument value="getLabelDecorator(TreeViewer)"/>
</message_arguments>
</filter>
+ <filter comment="SPI Change 1.22.0: Added TreeReadOnlyProvider to TreeViewerCustomization" id="403984517">
+ <message_arguments>
+ <message_argument value="org.eclipse.emfforms.spi.swt.treemasterdetail.TreeViewerCustomization"/>
+ <message_argument value="org.eclipse.emfforms.spi.swt.treemasterdetail.TreeReadOnlyProvider"/>
+ <message_argument value="isReadOnly()"/>
+ </message_arguments>
+ </filter>
</resource>
<resource path="src/org/eclipse/emfforms/spi/swt/treemasterdetail/actions/MasterDetailAction.java" type="org.eclipse.emfforms.spi.swt.treemasterdetail.actions.MasterDetailAction">
<filter comment="SPI Change 1.10.0" id="336695337">
diff --git a/bundles/org.eclipse.emfforms.swt.treemasterdetail/src/org/eclipse/emfforms/internal/swt/treemasterdetail/DefaultTreeViewerCustomization.java b/bundles/org.eclipse.emfforms.swt.treemasterdetail/src/org/eclipse/emfforms/internal/swt/treemasterdetail/DefaultTreeViewerCustomization.java
index a65ef8c..8d67f7d 100644
--- a/bundles/org.eclipse.emfforms.swt.treemasterdetail/src/org/eclipse/emfforms/internal/swt/treemasterdetail/DefaultTreeViewerCustomization.java
+++ b/bundles/org.eclipse.emfforms.swt.treemasterdetail/src/org/eclipse/emfforms/internal/swt/treemasterdetail/DefaultTreeViewerCustomization.java
@@ -69,6 +69,7 @@
private ContentProviderProvider contentProvider;
private ComposedAdapterFactory adapterFactory;
private AdapterFactoryContentProvider adapterFactoryContentProvider;
+ private boolean readOnly;
/**
* Default constructor.
@@ -133,6 +134,9 @@
@Override
public boolean hasDND() {
+ if (readOnly) {
+ return false;
+ }
return dnd.hasDND();
}
@@ -193,6 +197,9 @@
@Override
public Menu getMenu(TreeViewer treeViewer, EditingDomain editingDomain) {
+ if (readOnly) {
+ return null;
+ }
return menu.getMenu(treeViewer, editingDomain);
}
@@ -320,6 +327,24 @@
this.filters = filters;
}
+ @Override
+ public boolean isReadOnly() {
+ return readOnly;
+ }
+
+ /**
+ * Allows to set the tree as read-only. Default is false. Setting the tree as read-only has two consequences:
+ * <ol>
+ * <li>The tree's context menu is disabled
+ * <li>Drag and drop is disabled</li>
+ * </ol>
+ *
+ * @param readOnly <code>true</code> to set as read-only
+ */
+ public void setReadOnly(boolean readOnly) {
+ this.readOnly = readOnly;
+ }
+
/**
* Provides no decorator.
*
diff --git a/bundles/org.eclipse.emfforms.swt.treemasterdetail/src/org/eclipse/emfforms/spi/swt/treemasterdetail/TreeMasterDetailComposite.java b/bundles/org.eclipse.emfforms.swt.treemasterdetail/src/org/eclipse/emfforms/spi/swt/treemasterdetail/TreeMasterDetailComposite.java
index 1001699..1509826 100644
--- a/bundles/org.eclipse.emfforms.swt.treemasterdetail/src/org/eclipse/emfforms/spi/swt/treemasterdetail/TreeMasterDetailComposite.java
+++ b/bundles/org.eclipse.emfforms.swt.treemasterdetail/src/org/eclipse/emfforms/spi/swt/treemasterdetail/TreeMasterDetailComposite.java
@@ -318,9 +318,13 @@
final VView view = detailManager.getDetailView(eObject);
if (view.getChildren().size() > 0 && view.getChildren().get(0) instanceof VTreeMasterDetail) {
// Yes, we need to render this node differently
- final VTreeMasterDetail vTreeMasterDetail = (VTreeMasterDetail) view.getChildren().get(0);
+ final VView treeDetailView = VTreeMasterDetail.class.cast(view.getChildren().get(0))
+ .getDetailView();
+ // Even if the TMD composite is not configured as read-only honor the effective read-only
+ // configuration of the loaded detail view
+ treeDetailView.setReadonly(treeDetailView.isEffectivelyReadonly() || customization.isReadOnly());
final ViewModelContext context = ViewModelContextFactory.INSTANCE.createViewModelContext(
- vTreeMasterDetail.getDetailView(), eObject);
+ treeDetailView, eObject);
detailManager.render(context, ECPSWTViewRenderer.INSTANCE::render);
} else {
// No, everything is fine
@@ -614,6 +618,17 @@
}
/**
+ * Returns whether I am read-only.
+ *
+ * @return <code>true</code> if read-only
+ * @since 1.22
+ * @see TreeMasterDetailSWTBuilder#customizeReadOnly(boolean)
+ */
+ public boolean isReadOnly() {
+ return customization.isReadOnly();
+ }
+
+ /**
* Adapter which listens to changes and delegates the notification to other EObjects.
*
* @author Eugen Neufeld
@@ -687,6 +702,9 @@
viewModelPropertiesUpdateCallback.updateViewModelProperties(detailManager.getDetailProperties());
}
final VView view = detailManager.getDetailView(eObject);
+ // Even if the TMD is not configured as read-only honor the effective read-only
+ // configuration of the loaded view
+ view.setReadonly(view.isEffectivelyReadonly() || customization.isReadOnly());
final ViewModelContext modelContext = ViewModelContextFactory.INSTANCE
.createViewModelContext(
view, eObject, customization.getViewModelServices(view, eObject));
diff --git a/bundles/org.eclipse.emfforms.swt.treemasterdetail/src/org/eclipse/emfforms/spi/swt/treemasterdetail/TreeMasterDetailSWTBuilder.java b/bundles/org.eclipse.emfforms.swt.treemasterdetail/src/org/eclipse/emfforms/spi/swt/treemasterdetail/TreeMasterDetailSWTBuilder.java
index ca26af0..af87750 100644
--- a/bundles/org.eclipse.emfforms.swt.treemasterdetail/src/org/eclipse/emfforms/spi/swt/treemasterdetail/TreeMasterDetailSWTBuilder.java
+++ b/bundles/org.eclipse.emfforms.swt.treemasterdetail/src/org/eclipse/emfforms/spi/swt/treemasterdetail/TreeMasterDetailSWTBuilder.java
@@ -339,6 +339,25 @@
}
/**
+ * Use this method to specify whether the tree and its details should be rendered as read-only. The default is
+ * false. Setting the tree master detail as read-only has the following implications:
+ * <ul>
+ * <li>Set all detail views as read-only</li>
+ * <li>Disable the tree's context menu</li>
+ * <li>Deactivate drag and drop in the tree</li>
+ * </ul>
+ * <strong>Note:</strong> Setting this to true voids all menu and DND customizations.
+ *
+ * @param readOnly <code>true</code> to make the tree master detail read-only.
+ * @return self
+ * @since 1.22
+ */
+ public TreeMasterDetailSWTBuilder customizeReadOnly(boolean readOnly) {
+ behaviour.setReadOnly(readOnly);
+ return this;
+ }
+
+ /**
* Call this method after all desired customizations have been passed to the builder. The will create a new
* {@link TreeMasterDetailComposite} with the desired customizations.
*
diff --git a/bundles/org.eclipse.emfforms.swt.treemasterdetail/src/org/eclipse/emfforms/spi/swt/treemasterdetail/TreeReadOnlyProvider.java b/bundles/org.eclipse.emfforms.swt.treemasterdetail/src/org/eclipse/emfforms/spi/swt/treemasterdetail/TreeReadOnlyProvider.java
new file mode 100644
index 0000000..63f8969
--- /dev/null
+++ b/bundles/org.eclipse.emfforms.swt.treemasterdetail/src/org/eclipse/emfforms/spi/swt/treemasterdetail/TreeReadOnlyProvider.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2019 EclipseSource Muenchen GmbH and others.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Lucas Koehler - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.emfforms.spi.swt.treemasterdetail;
+
+/**
+ * @author Lucas Koehler
+ * @since 1.22
+ *
+ */
+public interface TreeReadOnlyProvider {
+
+ /**
+ * Returns whether the tree should be read-only.
+ *
+ * @return <code>true</code> if the tree is read-only
+ */
+ boolean isReadOnly();
+}
diff --git a/bundles/org.eclipse.emfforms.swt.treemasterdetail/src/org/eclipse/emfforms/spi/swt/treemasterdetail/TreeViewerCustomization.java b/bundles/org.eclipse.emfforms.swt.treemasterdetail/src/org/eclipse/emfforms/spi/swt/treemasterdetail/TreeViewerCustomization.java
index 5a0ed2c..3033d40 100644
--- a/bundles/org.eclipse.emfforms.swt.treemasterdetail/src/org/eclipse/emfforms/spi/swt/treemasterdetail/TreeViewerCustomization.java
+++ b/bundles/org.eclipse.emfforms.swt.treemasterdetail/src/org/eclipse/emfforms/spi/swt/treemasterdetail/TreeViewerCustomization.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2011-2015 EclipseSource Muenchen GmbH and others.
+ * Copyright (c) 2011-2019 EclipseSource Muenchen GmbH and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -10,6 +10,7 @@
*
* Contributors:
* Johannes Faltermeier - initial API and implementation
+ * Lucas Koehler - Add read-only configuration for Bug 541190
******************************************************************************/
package org.eclipse.emfforms.spi.swt.treemasterdetail;
@@ -22,5 +23,6 @@
*
*/
public interface TreeViewerCustomization extends TreeViewerBuilder, ContentProviderProvider, DNDProvider,
- InitialSelectionProvider, LabelProviderProvider, ViewerFilterProvider, MenuProvider, LabelDecoratorProvider {
+ InitialSelectionProvider, LabelProviderProvider, ViewerFilterProvider, MenuProvider, LabelDecoratorProvider,
+ TreeReadOnlyProvider {
}
diff --git a/tests/ECPQ7Tests/EPPTests/update-site/project/EPPTestsSuite.suite b/tests/ECPQ7Tests/EPPTests/update-site/project/EPPTestsSuite.suite
index f7fc923..f88b289 100644
--- a/tests/ECPQ7Tests/EPPTests/update-site/project/EPPTestsSuite.suite
+++ b/tests/ECPQ7Tests/EPPTests/update-site/project/EPPTestsSuite.suite
@@ -6,7 +6,7 @@
Id: _MY-BIBiHEeiwib4PmrBZZQ
Manually-Ordered: true
Runtime-Version: 2.5.0.201907120000
-Save-Time: 7/12/19 5:23 PM
+Save-Time: 7/17/19 4:18 PM
------=_testcase-items-62c497da-4241-31f4-811a-6b453a3ecff8
Content-Type: text/testcase
@@ -34,5 +34,6 @@
_W4UMAPMcEeik6oWCgIASMQ // kind: 'test' name: 'View Model With Abstract Root EClass' path: 'View Model With Abstract Root EClass.test'
_g8ZkYKPGEemYVp7Ch3g4pw // kind: 'test' name: 'ViewModelRules' path: 'ViewModelRules.test'
_o1gAAKS1EemqHtyndiPQqQ // kind: 'test' name: 'ViewModelRules_nested' path: 'ViewModelRules_nested.test'
+_wk-EcKiXEemAyNs4iWgMTw // kind: 'test' name: 'EcoreEditor_OpenFromHistory' path: 'EcoreEditor_OpenFromHistory.test'
------=_testcase-items-62c497da-4241-31f4-811a-6b453a3ecff8--
diff --git a/tests/ECPQ7Tests/EPPTests/update-site/project/EcoreEditor_OpenFromHistory.test b/tests/ECPQ7Tests/EPPTests/update-site/project/EcoreEditor_OpenFromHistory.test
new file mode 100644
index 0000000..94a60bf
--- /dev/null
+++ b/tests/ECPQ7Tests/EPPTests/update-site/project/EcoreEditor_OpenFromHistory.test
@@ -0,0 +1,66 @@
+--- RCPTT testcase ---
+Format-Version: 1.0
+Contexts: _ihvnUC3mEeSwhO5Nwx0hPg,_ZOi4wZ77EeOm87IlbkWrfQ,_2bS8sTNtEeSiS7b7ptZeHw
+Element-Name: EcoreEditor_OpenFromHistory
+Element-Type: testcase
+Element-Version: 3.0
+External-Reference:
+Id: _wk-EcKiXEemAyNs4iWgMTw
+Runtime-Version: 2.5.0.201907120000
+Save-Time: 7/17/19 4:17 PM
+Testcase-Type: ecl
+
+------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa
+Content-Type: text/plain
+Entry-Name: .description
+
+Bug 541190:
+Tests that the Ecore Editor (and thereby indirectly the Generic Editor) are capable of opening a model which is not present as a file in the workspace but only as a revision in the history.
+Thereby, verify that the editor is in read-only mode because the opened revision can not be persisted.
+------=_.description-216f885c-d591-38ce-8ea2-e4f8cb4d6ffa--
+------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac
+Content-Type: text/ecl
+Entry-Name: .content
+
+get-view "Project Explorer" | get-tree | select "com.eclipsesource.makeithappen.model/model/task.ecore" | get-menu
+ -path "Open With/Ecore Editor" | click
+get-editor "task.ecore" | get-tree
+ | select "platform:\\/resource\\/com.eclipsesource.makeithappen.model\\/model\\/task.ecore/task" | get-menu
+ -path EEnum | click
+with [get-window "Create new EEnum"] {
+ get-editbox -after [get-label Name] | set-text V1
+ get-button OK | click
+}
+get-editor "task.ecore" | get-tree | get-item "platform:\\/resource\\/com.eclipsesource.makeithappen.model\\/model\\/task.ecore/task/V1" | get-menu -path Delete
+get-button "Save (M1+S)" | click
+with [get-editor "task.ecore" | get-editbox -after [get-label Name]] {
+ set-text V2
+ key-type "TRAVERSE_TAB_NEXT"
+}
+get-button "Save (M1+S)" | click
+get-editor "task.ecore" | close
+
+// Open second latest revision (with enum V1)
+get-view "Project Explorer" | get-tree | select "com.eclipsesource.makeithappen.model/model/task.ecore" | get-menu
+ -path "Show In/History" | click
+get-view History | get-tree | select [get-item -path ".*" -index 1] | get-menu
+ -path "Open With/Ecore Editor" | click
+
+// verify read-only in detail
+get-editor "task.ecore" | get-tree | select "file:\\/com.eclipsesource.makeithappen.model\\/model\\/task.ecore/task/V1"
+get-editor "task.ecore" | get-editbox -after [get-label Name] | get-property enablement | equals false | verify-true
+
+// verify no context menu by example: delete, cut, copy actions
+with [get-editor "task.ecore" | get-tree | get-item "file:\\/com.eclipsesource.makeithappen.model\\/model\\/task.ecore/task/V1"] {
+ verify-error { get-menu -path Delete }
+ verify-error { get-menu -path Cut }
+ verify-error { get-menu -path Copy }
+}
+
+// verify that the toolbar buttons are not shown
+with [get-editor "task.ecore"] {
+ verify-error { get-button "Load Ecore" }
+ verify-error { get-button "Generate All" }
+}
+
+------=_.content-0a7243a0-75d3-3d5f-9791-539de0e5b7ac--