Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 957b7725680a8a9eebee052c5f962ec748379b25 (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
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
/*******************************************************************************
 * Copyright (c) 2012 Original authors 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:
 *     Vincent Lorenzo (CEA-LIST)  - duplicated and adapted code from nattable project.
 *     Nicolas FAUVERGUE (ALL4TEC) nicolas.fauvergue - Bug 482790, 481835
 *
 ******************************************************************************/
package org.eclipse.papyrus.uml.nattable.manager.cell.editor;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.jface.window.Window;
import org.eclipse.nebula.widgets.nattable.config.IConfigRegistry;
import org.eclipse.nebula.widgets.nattable.edit.DialogEditHandler;
import org.eclipse.nebula.widgets.nattable.edit.EditConfigAttributes;
import org.eclipse.nebula.widgets.nattable.edit.EditConfigHelper;
import org.eclipse.nebula.widgets.nattable.edit.ICellEditHandler;
import org.eclipse.nebula.widgets.nattable.edit.editor.ICellEditor;
import org.eclipse.nebula.widgets.nattable.edit.editor.IEditErrorHandler;
import org.eclipse.nebula.widgets.nattable.edit.gui.AbstractDialogCellEditor;
import org.eclipse.nebula.widgets.nattable.layer.cell.ILayerCell;
import org.eclipse.nebula.widgets.nattable.selection.SelectionLayer.MoveDirectionEnum;
import org.eclipse.nebula.widgets.nattable.style.DisplayMode;
import org.eclipse.nebula.widgets.nattable.widget.EditModeEnum;
import org.eclipse.papyrus.infra.nattable.celleditor.AbstractPapyrusStyledTextCellEditor;
import org.eclipse.papyrus.infra.nattable.converter.StringResolutionProblemPapyrusConverter;
import org.eclipse.papyrus.infra.nattable.manager.table.ITableAxisElementProvider;
import org.eclipse.papyrus.infra.nattable.model.nattable.Table;
import org.eclipse.papyrus.infra.nattable.utils.CrossAxisWrapper;
import org.eclipse.papyrus.infra.widgets.editors.StringEditorWithCompletionWrapper;
import org.eclipse.papyrus.infra.widgets.util.INameResolutionHelper;
import org.eclipse.papyrus.infra.widgets.util.IPapyrusConverter;
import org.eclipse.papyrus.infra.widgets.util.ISetPapyrusConverter;
import org.eclipse.papyrus.uml.nattable.editor.MultiReferenceCellEditor;
import org.eclipse.papyrus.uml.nattable.editor.SingleReferenceValueCellEditor;
import org.eclipse.papyrus.uml.nattable.utils.UMLTableUtils;
import org.eclipse.papyrus.uml.tools.util.UMLReferenceConverter;
import org.eclipse.papyrus.uml.tools.utils.NameResolutionHelper;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Text;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.NamedElement;

/**
 * {@link ICellEditor} implementation that wraps a SWT {@link Text} control to
 * support text editing. This is also the default editor in NatTable if you
 * didn't configure something else.
 *
 * duplicated and adapted code from nattable project. Add the method {@link #keyPressed(Composite, KeyEvent)} to allow to override it
 */
public class UMLReferenceTextWithCompletionCellEditor extends AbstractPapyrusStyledTextCellEditor {

	/**
	 * The Text control which is the editor wrapped by this TextCellEditor.
	 */
	private StringEditorWithCompletionWrapper textCompletion = null;

	/**
	 * The name resolution helper to use to find UML Element from a string
	 */
	private INameResolutionHelper helper;

	/**
	 * the papyrus parser to use
	 */
	private IPapyrusConverter parser;
	/**
	 * boolean indicating if we are editing a multivalued field
	 */
	private boolean isMultiValued = false;

	/**
	 * The cell editor which allow to use the dialog reference selection.
	 * It must be used when the text completion can't reach the value.
	 */
	protected AbstractDialogCellEditor referenceValueCellEditor;

	/**
	 * Constructor.
	 *
	 * @param table
	 *            The current table.
	 * @param axisElement
	 *            The axis element to manage.
	 * @param elementProvider
	 *            The element provider for the current axis to edit.
	 * @param commitOnUpDown
	 *            Flag to configure whether the editor should commit and move the selection in the corresponding way if the up or down key is pressed.
	 * @param moveSelectionOnEnter
	 *            Flag to configure whether the selection should move after a value was committed after pressing enter.
	 */
	public UMLReferenceTextWithCompletionCellEditor(final Table table, final Object axisElement, final ITableAxisElementProvider elementProvider, final boolean commitOnUpDown, final boolean moveSelectionOnEnter) {
		super(table, axisElement, elementProvider, commitOnUpDown, moveSelectionOnEnter);
	}

	/**
	 * Constructor.
	 *
	 * @param table
	 *            The current table.
	 * @param axisElement
	 *            The axis element to manage.
	 * @param elementProvider
	 *            The element provider for the current axis to edit.
	 * @param commitOnUpDown
	 *            Flag to configure whether the editor should commit and move the selection in the corresponding way if the up or down key is pressed.
	 */
	public UMLReferenceTextWithCompletionCellEditor(final Table table, final Object axisElement, final ITableAxisElementProvider elementProvider, final boolean commitOnUpDown) {
		super(table, axisElement, elementProvider, commitOnUpDown);
	}

	/**
	 * Constructor.
	 *
	 * @param table
	 *            The current table.
	 * @param axisElement
	 *            The axis element to manage.
	 * @param elementProvider
	 *            The element provider for the current axis to edit.
	 */
	public UMLReferenceTextWithCompletionCellEditor(final Table table, final Object axisElement, final ITableAxisElementProvider elementProvider) {
		super(table, axisElement, elementProvider);
	}

	/**
	 * Set the multi valued boolean value.
	 * 
	 * @param isMultivalued
	 *            The multi valued boolean value.
	 */
	public void setIsMultiValued(boolean isMultivalued) {
		this.isMultiValued = isMultivalued;
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see org.eclipse.papyrus.infra.nattable.celleditor.AbstractStyledTextCellEditor#activateCell(org.eclipse.swt.widgets.Composite, java.lang.Object)
	 */
	@Override
	protected Control activateCell(final Composite parent, final Object originalCanonicalValue) {
		final CrossAxisWrapper<EObject, EStructuralFeature> editedElement = UMLTableUtils.getRealEditedObject(layerCell, elementProvider);
		final EObject element = editedElement.getFirstAxis();

		boolean useSimpleDialog = true;

		Control control = null;

		// Bug 482790: Check if this is not an object with a null namespace
		if (!(element instanceof NamedElement && null == ((NamedElement) element).getNamespace())) {
			this.helper = createNameResolutionHelper();
			parser = new StringResolutionProblemPapyrusConverter(new UMLReferenceConverter(this.helper, isMultiValued));
			setPapyrusConverter(parser);

			// Get the display value
			Object displayValue = null;
			if (this.displayConverter != null) {
				displayValue = this.displayConverter.canonicalToDisplayValue(this.layerCell, this.configRegistry, originalCanonicalValue);
			} else {
				displayValue = originalCanonicalValue;
			}

			// Bug 481835 : If the display value is empty and the data value is not null,
			// this means the namespace of the object to edit cannot be resolved (same Objects name? other?).
			// In this case, use the simple reference dialog.
			// Bug 492989 : For the multi-valued feature, the value is not null but empty
			if (displayValue.toString().isEmpty()
					&& ((!isMultiValued && null != layerCell.getDataValue())
							|| (isMultiValued && layerCell.getDataValue() instanceof Collection && !((Collection<?>) layerCell.getDataValue()).isEmpty()))) {
				helper = null;
				parser = null;
				setPapyrusConverter(parser);
			} else {
				useSimpleDialog = false;
			}
		}

		if (useSimpleDialog) {
			// Bug 482790: The parse can't be used because no name resolution helper can't be created
			// So re-initialize the display converter to null
			this.displayConverter = null;

			// The reference dialog used is managed by the SingleReferenceValueCellEditor cell editor

			if (isMultiValued) {
				referenceValueCellEditor = new MultiReferenceCellEditor(axisElement, elementProvider) {

					@Override
					public Control activateCell(Composite parent, Object originalCanonicalValue, EditModeEnum editMode, ICellEditHandler editHandler, ILayerCell cell, IConfigRegistry configRegistry) {
						this.parent = parent;
						this.layerCell = cell;
						this.configRegistry = configRegistry;

						final List<String> configLabels = cell.getConfigLabels().getLabels();
						this.displayConverter = UMLReferenceTextWithCompletionCellEditor.this.displayConverter;
						this.dataValidator = configRegistry.getConfigAttribute(
								EditConfigAttributes.DATA_VALIDATOR,
								DisplayMode.EDIT,
								configLabels);

						this.conversionEditErrorHandler = EditConfigHelper.getEditErrorHandler(
								configRegistry,
								EditConfigAttributes.CONVERSION_ERROR_HANDLER,
								configLabels);
						this.validationEditErrorHandler = EditConfigHelper.getEditErrorHandler(
								configRegistry,
								EditConfigAttributes.VALIDATION_ERROR_HANDLER,
								configLabels);

						this.dialog = createDialogInstance();

						setCanonicalValue(originalCanonicalValue);

						// this method is only needed to initialize the dialog editor, there
						// will be no control to return
						return null;
					}

				};
			} else {
				referenceValueCellEditor = new SingleReferenceValueCellEditor(axisElement, elementProvider) {

					@Override
					public Control activateCell(Composite parent, Object originalCanonicalValue, EditModeEnum editMode, ICellEditHandler editHandler, ILayerCell cell, IConfigRegistry configRegistry) {
						this.parent = parent;
						this.layerCell = cell;
						this.configRegistry = configRegistry;

						final List<String> configLabels = cell.getConfigLabels().getLabels();
						this.displayConverter = UMLReferenceTextWithCompletionCellEditor.this.displayConverter;
						this.dataValidator = configRegistry.getConfigAttribute(
								EditConfigAttributes.DATA_VALIDATOR,
								DisplayMode.EDIT,
								configLabels);

						this.conversionEditErrorHandler = EditConfigHelper.getEditErrorHandler(
								configRegistry,
								EditConfigAttributes.CONVERSION_ERROR_HANDLER,
								configLabels);
						this.validationEditErrorHandler = EditConfigHelper.getEditErrorHandler(
								configRegistry,
								EditConfigAttributes.VALIDATION_ERROR_HANDLER,
								configLabels);

						this.dialog = createDialogInstance();

						setCanonicalValue(originalCanonicalValue);

						// this method is only needed to initialize the dialog editor, there
						// will be no control to return
						return null;
					}

				};
			}

			// Activate the cell of the single reference cell editor
			control = referenceValueCellEditor.activateCell(parent, originalCanonicalValue, EditModeEnum.DIALOG, new DialogEditHandler(), layerCell, configRegistry);
			// Manage the dialog return
			if (Window.OK == referenceValueCellEditor.open()) {
				// The user click on 'OK' button, so set the canonical value
				setCanonicalValue(referenceValueCellEditor.getEditorValue());
				// Commit the value
				commit(MoveDirectionEnum.NONE);
			} else {
				referenceValueCellEditor.close();
			}
		} else {
			control = super.activateCell(parent, originalCanonicalValue);
		}
		return control;
	}

	/**
	 * This allows to set the parser to the display converter.
	 * 
	 * @param parser
	 *            the parser to use to find the references.
	 */
	private void setPapyrusConverter(final IPapyrusConverter parser) {
		if (this.displayConverter instanceof ISetPapyrusConverter) {
			((ISetPapyrusConverter) this.displayConverter).setPapyrusConverter(parser);
		}
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see org.eclipse.papyrus.infra.nattable.celleditor.AbstractStyledTextCellEditor#createStyledText(org.eclipse.swt.widgets.Composite, int)
	 */
	@Override
	protected StyledText createStyledText(final Composite parent, final int style) {
		this.textCompletion = new StringEditorWithCompletionWrapper(parent, this.parser);
		return this.textCompletion.getTextViewer().getTextWidget();
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see org.eclipse.papyrus.infra.nattable.celleditor.AbstractStyledTextCellEditor#keyPressed(org.eclipse.swt.events.KeyEvent)
	 */
	@Override
	public void keyPressed(final KeyEvent event) {
		if (!(isMultiValued && textCompletion.isContentAssistOpened())) {
			super.keyPressed(event);
		}
	}


	/**
	 * This allows to create the name resolution helper managed by the namespace.
	 * 
	 * @return
	 * 		the created name resolution helper
	 */
	protected INameResolutionHelper createNameResolutionHelper() {
		final CrossAxisWrapper<EObject, EStructuralFeature> editedElement = UMLTableUtils.getRealEditedObject(layerCell, elementProvider);
		final EObject element = editedElement.getFirstAxis();
		Element scope;
		if (element instanceof Element) {
			scope = (Element) element;
		} else {
			// it could be a stereotype application
			scope = org.eclipse.uml2.uml.util.UMLUtil.getBaseElement(element);
		}

		INameResolutionHelper helper = null;

		final EStructuralFeature feature = editedElement.getSecondAxis();
		final EClassifier eType = feature.getEType();
		if (eType instanceof EClass) {
			helper = new NameResolutionHelper(scope, (EClass) eType);
		}
		return helper;
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see org.eclipse.nebula.widgets.nattable.edit.editor.AbstractCellEditor#getCanonicalValue(org.eclipse.nebula.widgets.nattable.edit.editor.IEditErrorHandler)
	 */
	@Override
	public Object getCanonicalValue(final IEditErrorHandler conversionErrorHandler) {
		Object canonnicalValue = super.getCanonicalValue(conversionErrorHandler);
		if (canonnicalValue instanceof Collection<?>) {
			return canonnicalValue;
		}
		if (isMultiValued) {
			Collection<Object> coll = new ArrayList<Object>();
			coll.add(canonnicalValue);
			return coll;
		} else {
			return canonnicalValue;
		}
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see org.eclipse.papyrus.infra.nattable.celleditor.AbstractStyledTextCellEditor#getEditorValue()
	 */
	@Override
	public Object getEditorValue() {
		Object result = null;
		if (null != referenceValueCellEditor) {
			result = referenceValueCellEditor.getEditorValue();
		}
		return null != result ? result : super.getEditorValue();
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see org.eclipse.papyrus.infra.nattable.celleditor.AbstractStyledTextCellEditor#close()
	 */
	@Override
	public void close() {
		if (null != this.textCompletion && null != this.textCompletion.getTextWidget() && !this.textCompletion.getTextWidget().isDisposed()) {
			this.textCompletion.getTextWidget().dispose();
		}
		super.close();
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see org.eclipse.papyrus.infra.nattable.celleditor.AbstractPapyrusStyledTextCellEditor#getEditedEObject()
	 */
	@Override
	protected EObject getEditedEObject() {
		return null;
	}
}

Back to the top