Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: b06af100c97f555f8d4015b7dfb5eb593c011f02 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
/*****************************************************************************
 * Copyright (c) 2010, 2014 CEA LIST and others.
 *
 * 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:
 *  Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Initial API and implementation
 *  Christian W. Damus (CEA) - bug 402525
 *  Christian W. Damus (CEA) - bug 430077
 *
 *****************************************************************************/
package org.eclipse.papyrus.infra.properties.ui.creation;

import java.util.Collection;
import java.util.Set;

import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.window.Window;
import org.eclipse.papyrus.infra.constraints.runtime.ConstraintEngine;
import org.eclipse.papyrus.infra.properties.contexts.View;
import org.eclipse.papyrus.infra.properties.internal.ui.messages.Messages;
import org.eclipse.papyrus.infra.properties.ui.runtime.PropertiesRuntime;
import org.eclipse.papyrus.infra.widgets.creation.IAtomicOperationExecutor;
import org.eclipse.papyrus.infra.widgets.creation.ReferenceValueFactory;
import org.eclipse.swt.widgets.Control;

/**
 * A generic ReferenceValueFactory, which uses the Property View configurations
 * to edit objects. For a given object, the factory uses the matching constraints
 * to find the property views associated to the object, and displays these views
 * in a Dialog.
 * This factory cannot instantiate new objects. However, subclasses should override {@link #createObject(Control)} and {@link #canCreateObject()} to
 * enable
 * this behavior.
 *
 * @see org.eclipse.papyrus.infra.properties.ui.creation.EditionDialog
 *
 * @author Camille Letavernier
 */
public class PropertyEditorFactory implements ReferenceValueFactory {

	/**
	 *
	 * Constructor.
	 *
	 */
	public PropertyEditorFactory() {
	}

	/**
	 * Return a null value. Implementors should override when object creation
	 * needs to be supported. Implementors may rely on {@link #createObject(Control, Object)}
	 *
	 * @param widget
	 *            The widget from which this method is called. May be used to retrieve the current shell
	 * @param context
	 *            The object being edited, in which context the new object is to be created and which will as a result have a reference to the new object.
	 *            If there is no context object (creation of a free-floating object) or it cannot be determined, this may be {@code null}
	 * @return
	 * 		The newly created object
	 *
	 * @see ReferenceValueFactory#createObject(Control, Object)
	 * @see #createObject(Control, Object, Object)
	 */
	@Override
	public Object createObject(Control widget, Object context) {
		return null;
	}

	/**
	 * This class cannot instantiate objects. However, this method provides
	 * a base implementation to be used by subclasses.
	 *
	 * Subclasses should instantiate the base object, which will then be
	 * editable via a property dialog.
	 *
	 * @param widget
	 *            The widget used to open the dialog
	 * @param context
	 *            The object being edited, in which context the new object is to be created and which will as a result have a reference to the new object.
	 *            If there is no context object (creation of a free-floating object) or it cannot be determined, this may be {@code null}
	 * @param source
	 *            The created EObject. If null, nothing will happen
	 * @return
	 * 		The source EObject, which potential in-place modifications
	 */
	protected Object createObject(Control widget, Object context, Object source) {
		if (source == null) {
			return null;
		}

		IStructuredSelection selection = new StructuredSelection(source);

		ConstraintEngine<View> constraintEngine = PropertiesRuntime.getConstraintEngine();
		Set<View> views = constraintEngine.getDisplayUnits(selection);
		if (!views.isEmpty()) {
			CreationContext creationContext = getCreationContext(context);
			creationContext.pushCreatedElement(source);
			try {
				return doEdit(widget, source, views, getCreationDialogTitle());
			} finally {
				creationContext.popCreatedElement(source);
			}
		}

		return source;
	}

	/**
	 * Get the creation context for the specified {@code element} in which we are creating a new model element.
	 * This default implementation simply returns the {@linkplain CreationContext#NULL null implementation}.
	 * Subclasses should provide implementation suitable to their data model.
	 *
	 * @param element
	 *            an element in which context we are creating a new model element
	 *
	 * @return the encapsulated creation context (never {@code null})
	 */
	protected CreationContext getCreationContext(Object element) {
		return CreationContext.NULL;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Collection<Object> validateObjects(Collection<Object> objectsToValidate) {
		return objectsToValidate;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean canEdit() {
		return true;
	}

	/**
	 * Edits the given object via the matching Property view, if any
	 * The editing Dialog is directly binded to the underlying object, which means that all modifications are applied
	 * in real time, and cannot be undone (Except via the "Undo" command). The "Cancel" button is thus disabled.
	 *
	 * @see org.eclipse.papyrus.infra.widgets.creation.ReferenceValueFactory#edit(org.eclipse.swt.widgets.Control, java.lang.Object)
	 *
	 * @param widget
	 *            The widget calling the factory. The Dialog for editing the object will open in this widget's shell
	 * @param source
	 *            The object to edit
	 */
	@Override
	public Object edit(Control widget, Object source) {
		IStructuredSelection selection = new StructuredSelection(source);

		ConstraintEngine<View> constraintEngine = PropertiesRuntime.getConstraintEngine();

		Set<View> views = constraintEngine.getDisplayUnits(selection);
		if (!views.isEmpty()) {
			return doEdit(widget, source, views, getEditionDialogTitle(source));
		}

		return source;
	}

	protected Object doEdit(Control widget, Object source, Set<View> views, String dialogTitle) {
		EditionDialog dialog = new EditionDialog(widget.getShell(), true);
		dialog.setTitle(dialogTitle);
		dialog.setViews(views);
		dialog.setInput(source);

		if (dialog.open() != Window.OK) {
			handleEditCancelled(widget, source);
			return null;
		}

		return source;
	}

	protected void handleEditCancelled(Control widget, Object source) {
		// Pass
	}

	/**
	 * The standard Property Editor Factory cannot instantiate new objects.
	 * However, subclasses may override this method to return true if they
	 * implement {@link #createObject(Control)}
	 *
	 * @see org.eclipse.papyrus.infra.widgets.creation.ReferenceValueFactory#canCreateObject()
	 *
	 * @return
	 * 		True if the factory can create a new instance
	 */
	@Override
	public boolean canCreateObject() {
		return false;
	}

	/**
	 * @return
	 * 		The title of the dialog used to edit the newly created instance
	 *
	 * @see #canCreateObject()
	 * @see #createObject(Control)
	 */
	public String getCreationDialogTitle() {
		return Messages.PropertyEditorFactory_CreateANewElement;
	}

	public String getEditionDialogTitle(Object objectToEdit) {
		return "Edit an element";
	}

	/**
	 * Obtains the most appropriate operation executor for the object being edited.
	 *
	 * @param context
	 *            the object being edited
	 * @return the executor to use to run operations (never {@code null})
	 */
	public IAtomicOperationExecutor getOperationExecutor(Object context) {
		IAtomicOperationExecutor result;
		if (context instanceof IAdaptable) {
			result = ((IAdaptable) context).getAdapter(IAtomicOperationExecutor.class);
		} else {
			result = Platform.getAdapterManager().getAdapter(context, IAtomicOperationExecutor.class);
		}

		if (result == null) {
			result = IAtomicOperationExecutor.DEFAULT;
		}

		return result;
	}
}

Back to the top