diff options
author | Benoit Maggi | 2017-11-24 10:23:46 +0000 |
---|---|---|
committer | Benoit Maggi | 2017-12-14 08:38:21 +0000 |
commit | ac3c027356a20993ee782d09486c33df0456c5a3 (patch) | |
tree | de44ac6d3f53fd9f3e0a7b23d5a5b3b902363b56 | |
parent | 9e0e11f6bf5ca4222f9eefcfd4f65b0307e18636 (diff) | |
download | org.eclipse.papyrus-ac3c027356a20993ee782d09486c33df0456c5a3.tar.gz org.eclipse.papyrus-ac3c027356a20993ee782d09486c33df0456c5a3.tar.xz org.eclipse.papyrus-ac3c027356a20993ee782d09486c33df0456c5a3.zip |
Bug 518317 - [UMLPropertiesView] Autocompletion for type of properties
- new auto-completion editor:
- no binding to uml element
- available in example for property type
- add a predicate filter for INameResolutionHelper
- add completion proposal and processor for UML NamedElements
- fix a bunch of quality warnings for Java 8
Change-Id: I38722b6782c13fb8de511c8d0e253ba491c27136
Signed-off-by: Benoit Maggi <benoit.maggi@cea.fr>
11 files changed, 896 insertions, 46 deletions
diff --git a/examples/uml/org.eclipse.papyrus.uml.textual.editors.example/model/UML/ui/PropertyExample.xwt b/examples/uml/org.eclipse.papyrus.uml.textual.editors.example/model/UML/ui/PropertyExample.xwt index 738b6f4c795..02e5037363e 100644 --- a/examples/uml/org.eclipse.papyrus.uml.textual.editors.example/model/UML/ui/PropertyExample.xwt +++ b/examples/uml/org.eclipse.papyrus.uml.textual.editors.example/model/UML/ui/PropertyExample.xwt @@ -2,6 +2,7 @@ <Composite xmlns:ppe="clr-namespace:org.eclipse.papyrus.infra.properties.ui.widgets" xmlns:ppel="clr-namespace:org.eclipse.papyrus.infra.properties.ui.widgets.layout" xmlns:xtexteditor="clr-namespace:org.eclipse.papyrus.uml.properties.xtext.widget.property" + xmlns:uml="clr-namespace:org.eclipse.papyrus.uml.properties.editors" xmlns="http://www.eclipse.org/xwt/presentation" xmlns:x="http://www.eclipse.org/xwt"> <Composite.layout> <ppel:PropertiesLayout></ppel:PropertiesLayout> @@ -30,15 +31,14 @@ <ppe:EnumCombo input="{Binding}" property="UML:NamedElement:visibility"></ppe:EnumCombo> <ppe:ReferenceDialog input="{Binding}" property="UML:TypedElement:type" customLabel="Classic Type"></ppe:ReferenceDialog> - <ppe:CompletionStyledTextReferenceDialog - input="{Binding}" property="UML:TypedElement:type" customLabel="Auto-fill Type"></ppe:CompletionStyledTextReferenceDialog> + <ppe:CompletionStyledTextReferenceDialog input="{Binding}" property="UML:TypedElement:type" customLabel="Auto-fill Type"></ppe:CompletionStyledTextReferenceDialog> + <uml:AutoCompletePropertyEditor input="{Binding}" property="UML:TypedElement:type" customLabel="Auto-fill Type 2"></uml:AutoCompletePropertyEditor> <xtexteditor:MultiplicityXTextDialog property="Multiplicity:multiplicity" input="{Binding}"></xtexteditor:MultiplicityXTextDialog> <ppe:ReferenceDialog input="{Binding}" property="UML:Property:defaultValue"></ppe:ReferenceDialog> <xtexteditor:UMLStyledTextReferenceDialog property="UML:Property:defaultValue" input="{Binding}" directEditorConfiguration="org.eclipse.papyrus.uml.textedit.valuespecification.xtext.ui.contribution.ValueSpecificationXtextDirectEditorConfiguration"></xtexteditor:UMLStyledTextReferenceDialog> - <ppe:EnumCombo input="{Binding}" property="UML:Property:aggregation"></ppe:EnumCombo> <ppe:MultiReference input="{Binding}" property="UML:Property:subsettedProperty"></ppe:MultiReference> <ppe:MultiReference input="{Binding}" diff --git a/plugins/infra/ui/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/StyledTextStringEditor.java b/plugins/infra/ui/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/StyledTextStringEditor.java index becc57dd823..439658d91e3 100644 --- a/plugins/infra/ui/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/StyledTextStringEditor.java +++ b/plugins/infra/ui/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/editors/StyledTextStringEditor.java @@ -206,8 +206,6 @@ public class StyledTextStringEditor extends AbstractValueEditor implements KeyLi controlDecoration.hide(); // we ignore the indentation - // data.horizontalIndent = FieldDecorationRegistry.getDefault().getMaximumDecorationWidth(); - // we remove the margin GridLayout layout = (GridLayout) this.getLayout(); layout.marginHeight = 0; diff --git a/plugins/infra/ui/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/util/INameResolutionHelper.java b/plugins/infra/ui/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/util/INameResolutionHelper.java index 6272fd11b9f..eabdb5de8e8 100644 --- a/plugins/infra/ui/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/util/INameResolutionHelper.java +++ b/plugins/infra/ui/org.eclipse.papyrus.infra.widgets/src/org/eclipse/papyrus/infra/widgets/util/INameResolutionHelper.java @@ -1,5 +1,5 @@ /***************************************************************************** - * Copyright (c) 2015 CEA LIST and others. + * Copyright (c) 2015, 2017 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 @@ -8,12 +8,13 @@ * * Contributors: * CEA LIST - Initial API and implementation - * + * Benoit Maggi (CEA LIST) - Bug 518317 Autocompletion for type of properties *****************************************************************************/ package org.eclipse.papyrus.infra.widgets.util; import java.util.List; +import java.util.function.Predicate; /** * Common interface to use to find elements from a given string @@ -30,6 +31,17 @@ public interface INameResolutionHelper { */ public List<?> getMatchingElements(final String aString); + + /** + * Use a {@link java.util.function.Predicate} to get matching elements. + * + * @param predicate to match the elements + * @return all elements whose match the predicate + */ + public default List<?> getMatchingElements(final Predicate<?> predicate){ + return getElementsByName(""); //$NON-NLS-1$ TODO: remove default when bumping plugin to 4.0.0 + } + /** * * @param aString @@ -65,4 +77,6 @@ public interface INameResolutionHelper { */ public List<String> getShortestQualifiedNames(final Object element, final boolean manageDuplicate); + + } diff --git a/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/editors/AutoCompletePropertyEditor.java b/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/editors/AutoCompletePropertyEditor.java new file mode 100644 index 00000000000..7d084774b8a --- /dev/null +++ b/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/editors/AutoCompletePropertyEditor.java @@ -0,0 +1,103 @@ +/***************************************************************************** + * Copyright (c) 2017 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: + * Benoit Maggi (CEA LIST) - Initial API and implementation + *****************************************************************************/ +package org.eclipse.papyrus.uml.properties.editors; + +import org.eclipse.jface.viewers.ILabelProvider; +import org.eclipse.papyrus.infra.properties.ui.widgets.AbstractPropertyEditor; +import org.eclipse.papyrus.infra.widgets.creation.ReferenceValueFactory; +import org.eclipse.papyrus.infra.widgets.providers.IStaticContentProvider; +import org.eclipse.papyrus.infra.widgets.util.INameResolutionHelper; +import org.eclipse.swt.widgets.Composite; + +/** + * A PropertyEditor for editing with auto-completion through a Dialog + * (not binded with Papyrus Properties fwk) + */ +public class AutoCompletePropertyEditor extends AbstractPropertyEditor { + + /** + * The ReferenceDialog widget + */ + protected org.eclipse.papyrus.uml.properties.widgets.AutoCompleteReferenceDialog editor; + + /** + * The ValueFactory used to create or edit Objects directly from + * this editor + */ + protected ReferenceValueFactory factory; + + /** + * Constructor. + * + * @param parent + * The composite in which the widget will be displayed + * @param style + * The style for the widget + */ + public AutoCompletePropertyEditor(Composite parent, int style) { + editor = createReferenceDialog(parent, style); + setEditor(editor); + } + + /** + * Creates the reference dialog. + * + * @param parent + * The composite in which the widget will be displayed + * @param style + * The style for the widget + * @return the reference dialog. + */ + protected org.eclipse.papyrus.uml.properties.widgets.AutoCompleteReferenceDialog createReferenceDialog(Composite parent, int style) { + return new org.eclipse.papyrus.uml.properties.widgets.AutoCompleteReferenceDialog(parent, style); + } + + @Override + protected void doBinding() { + IStaticContentProvider provider = input.getContentProvider(propertyPath); + ILabelProvider labelProvider = input.getLabelProvider(propertyPath); + editor.setLabelProvider(labelProvider); + editor.setContentProvider(provider); + editor.setDirectCreation(input.getDirectCreation(propertyPath)); + editor.setMandatory(input.isMandatory(propertyPath)); + if (factory == null) { // Use the default factory from the DataSource + editor.setValueFactory(input.getValueFactory(propertyPath)); + } else { // Use the factory explicitly specified + editor.setValueFactory(factory); + } + INameResolutionHelper nameResolutionHelper = input.getNameResolutionHelper(propertyPath); + if (nameResolutionHelper != null) { + editor.setNameResolutionHelper(nameResolutionHelper); + } + super.doBinding(); + } + + /** + * Sets the ValueFactory used to create or edit Objects directly from + * this editor + * + * @param factory + */ + public void setFactory(ReferenceValueFactory factory) { + this.factory = factory; + editor.setValueFactory(factory); + } + + /** + * @return The ValueFactory used to create or edit Objects directly from + * this editor + */ + public ReferenceValueFactory getFactory() { + return factory; + } + +} diff --git a/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/editors/AutoCompleteReferenceDialogObservableValue.java b/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/editors/AutoCompleteReferenceDialogObservableValue.java new file mode 100644 index 00000000000..83bf4af26d0 --- /dev/null +++ b/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/editors/AutoCompleteReferenceDialogObservableValue.java @@ -0,0 +1,63 @@ +/***************************************************************************** + * Copyright (c) 2017 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: + * Benoit Maggi (CEA LIST) - Initial API and implementation + *****************************************************************************/ + +package org.eclipse.papyrus.uml.properties.editors; + +import org.eclipse.core.databinding.observable.value.IObservableValue; +import org.eclipse.papyrus.infra.widgets.databinding.StyledTextObservableValue; +import org.eclipse.papyrus.uml.properties.widgets.AutoCompleteReferenceDialog; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.uml2.uml.NamedElement; + +/** + * Observable for AutoCompleteReferenceDialog + */ +public class AutoCompleteReferenceDialogObservableValue extends StyledTextObservableValue { + + /** + * the styled text with completion reference dialog + */ + private AutoCompleteReferenceDialog referenceDialog; + + /** + * @param dialog + * The observed AutoCompleteReferenceDialog + * @param styledText + * The observed StyledText + * @param modelObservable + * The Model IObservable + * @param eventType + * The eventType to listen to. When the event is fired by the Text + * widget, this IObservableValue will fire a ChangeEvent + */ + public AutoCompleteReferenceDialogObservableValue(AutoCompleteReferenceDialog dialog, StyledText styledText, IObservableValue modelObservable, int eventType) { + super(styledText, modelObservable, eventType); + this.referenceDialog = dialog; + } + + /** + * + * @see org.eclipse.papyrus.infra.widgets.databinding.StyledTextObservableValue#doSetValue(java.lang.Object) + * + * @param value + */ + @Override + protected void doSetValue(Object value) { + if (value instanceof NamedElement) { + NamedElement namedElement = (NamedElement) value; + super.doSetValue(namedElement.getName()); + } else { + super.doSetValue(value); + } + referenceDialog.update(); + } +} diff --git a/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/editors/AutoCompleteStyledTextStringEditor.java b/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/editors/AutoCompleteStyledTextStringEditor.java new file mode 100644 index 00000000000..5dedeaad7b1 --- /dev/null +++ b/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/editors/AutoCompleteStyledTextStringEditor.java @@ -0,0 +1,200 @@ +/***************************************************************************** + * Copyright (c) 2017 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: + * Benoit Maggi (CEA LIST) - Initial API and implementation + *****************************************************************************/ + +package org.eclipse.papyrus.uml.properties.editors; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.text.Document; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.TextViewer; +import org.eclipse.jface.text.contentassist.ContentAssistEvent; +import org.eclipse.jface.text.contentassist.ContentAssistant; +import org.eclipse.jface.text.contentassist.ICompletionListener; +import org.eclipse.jface.text.contentassist.ICompletionProposal; +import org.eclipse.jface.text.contentassist.ICompletionProposalSorter; +import org.eclipse.papyrus.infra.widgets.editors.CompletionStyledTextStringEditor; +import org.eclipse.papyrus.infra.widgets.editors.StyledTextStringEditor; +import org.eclipse.papyrus.infra.widgets.util.INameResolutionHelper; +import org.eclipse.papyrus.infra.widgets.util.PlatformUIUtils; +import org.eclipse.papyrus.infra.widgets.validator.AbstractValidator; +import org.eclipse.papyrus.uml.tools.utils.NameResolutionHelper; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.uml2.uml.NamedElement; +import org.eclipse.uml2.uml.UMLPackage; + +/** + * Auto-completion styled text + * The main difference with {@link CompletionStyledTextStringEditor} is that + * this editor isn't intended to binded in Papyrus Properties framework + */ +public class AutoCompleteStyledTextStringEditor extends StyledTextStringEditor { + + private static final String CONTENT_ASSIST_COMMAND_ID = "org.eclipse.ui.edit.text.contentAssist.proposals"; //$NON-NLS-1$ + + /** + * This wrapper provides a text field with completion + */ + private TextViewer wrapper; + + protected INameResolutionHelper nameResolutionHelper; + + private ContentAssistant assistant; + + private UMLReferenceContentAssistProcessor processor; + + /** + * @return the nameResolutionHelper + */ + public INameResolutionHelper getNameResolutionHelper() { + return nameResolutionHelper; + } + + /** + * Initial value for text + * + * @param value + */ + @Override + public void setValue(Object value) { + if (value instanceof NamedElement) { + super.setValue(((NamedElement) value).getName()); + } + super.setValue(value); + } + + /** + * + * Constructor. + * + * @param parent + * @param style + */ + public AutoCompleteStyledTextStringEditor(Composite parent, int style) { + super(parent, style); + createReferenceTargetValidator(); + } + + @Override + protected void notifyChange() { + text.notifyListeners(SWT.FocusOut, new Event()); + + // added to update the status when we use the completion + if (targetValidator != null) { + IStatus status = targetValidator.validate(text.getText()); + updateStatus(status); + } + commit(); + changeColorField(); + } + + /** + * create the validator for the text field + */ + protected void createReferenceTargetValidator() { + targetValidator = new AbstractValidator() { + @Override + public IStatus validate(Object value) { + return Status.OK_STATUS; + } + }; + } + + /** + * + * @see org.eclipse.papyrus.infra.widgets.editors.StyledTextStringEditor#createStyledText(org.eclipse.swt.widgets.Composite, java.lang.String, int) + * + * @param parent + * @param value + * @param style + * @return + */ + @Override + public StyledText createStyledText(Composite parent, String value, int style) { + this.wrapper = buildControls(parent, style); + return wrapper.getTextWidget(); + } + + private TextViewer buildControls(Composite parent, int style) { + TextViewer textViewer = new TextViewer(parent, SWT.SINGLE | SWT.V_SCROLL | style); + textViewer.setDocument(new Document()); + this.assistant = new ContentAssistant(); + processor = new UMLReferenceContentAssistProcessor(UMLPackage.eINSTANCE.getTypedElement_Type(), (NameResolutionHelper) nameResolutionHelper, this); + assistant.setContentAssistProcessor(processor, IDocument.DEFAULT_CONTENT_TYPE); + + // Manage the sorter for the completion proposal + assistant.setSorter(new ICompletionProposalSorter() { + + @Override + public int compare(final ICompletionProposal p1, final ICompletionProposal p2) { + return p1.getDisplayString().compareTo(p2.getDisplayString()); + } + }); + + assistant.install(textViewer); + assistant.addCompletionListener(new ICompletionListener() { + + private boolean delayedIsOpen = false; + + @Override + public void selectionChanged(ICompletionProposal proposal, boolean smartToggle) { + + } + + @Override + public void assistSessionStarted(ContentAssistEvent event) { + // reset open status asynchronously. + Display.getDefault().asyncExec(new Runnable() { + @Override + public void run() { + delayedIsOpen = true; + } + }); + } + + @Override + public void assistSessionEnded(ContentAssistEvent event) { + // reset open status asynchronously. + Display.getDefault().asyncExec(new Runnable() { + @Override + public void run() { + delayedIsOpen = false; + } + }); + + } + }); + + // Hook up the user's preferred key binding for content assist + PlatformUIUtils.handleCommand(textViewer.getControl(), CONTENT_ASSIST_COMMAND_ID, + "CTRL+SPACE", //$NON-NLS-1$ // The default on all platforms + assistant::showPossibleCompletions); + return textViewer; + } + + public void setNameResolutionHelper(INameResolutionHelper nameResolutionHelper) { + this.nameResolutionHelper = nameResolutionHelper; + if (nameResolutionHelper instanceof NameResolutionHelper) { + processor.setNameResolutionHelper((NameResolutionHelper) nameResolutionHelper); + } + } + + @Override + public Object getContextElement() { + return super.getContextElement(); // we need a public api + } + +} diff --git a/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/editors/NamedElementCompletionProposal.java b/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/editors/NamedElementCompletionProposal.java new file mode 100644 index 00000000000..5f3e4c56abc --- /dev/null +++ b/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/editors/NamedElementCompletionProposal.java @@ -0,0 +1,144 @@ +/***************************************************************************** + * Copyright (c) 2017 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: + * Benoit Maggi (CEA LIST) - Initial API and implementation + *****************************************************************************/ + +package org.eclipse.papyrus.uml.properties.editors; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.transaction.RecordingCommand; +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.emf.transaction.util.TransactionUtil; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.contentassist.ICompletionProposal; +import org.eclipse.jface.text.contentassist.IContextInformation; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.uml2.uml.NamedElement; + + +/** + * The standard implementation of the <code>ICompletionProposal</code> interface. + */ +public final class NamedElementCompletionProposal implements ICompletionProposal { + + /** The string to be displayed in the completion proposal popup. */ + private String displayString; + /** The replacement string. */ + private String replacementString; + /** The replacement offset. */ + private int replacementOffset; + /** The replacement length. */ + private int replacementLength; + /** The cursor position after this proposal has been applied. */ + private int cursorPosition; + /** The image to be displayed in the completion proposal popup. */ + private Image image; + /** The context information of this proposal. */ + private IContextInformation contextInformation; + /** The additional info of this proposal. */ + private String additionalProposalInfo; + + private EStructuralFeature eStructuralFeature; + + private NamedElement namedElement; + + private EObject context; + + public NamedElementCompletionProposal(EStructuralFeature eStructuralFeature, NamedElement namedElement,EObject context, int replacementOffset, int replacementLength, int cursorPosition) { + this(eStructuralFeature,namedElement,context, namedElement.getName(), replacementOffset, replacementLength, cursorPosition, null, + namedElement.getName()+ " - "+ namedElement.getNamespace().getQualifiedName(), //$NON-NLS-1$ + null, + "help?"); //$NON-NLS-1$ + } + + /** + * Creates a new completion proposal. All fields are initialized based on the provided information. + * + * @param replacementString the actual string to be inserted into the document + * @param replacementOffset the offset of the text to be replaced + * @param replacementLength the length of the text to be replaced + * @param cursorPosition the position of the cursor following the insert relative to replacementOffset + * @param image the image to display for this proposal + * @param displayString the string to be displayed for the proposal + * @param contextInformation the context information associated with this proposal + * @param additionalProposalInfo the additional information associated with this proposal + */ + public NamedElementCompletionProposal(EStructuralFeature eStructuralFeature, NamedElement namedElement,EObject context,String replacementString, int replacementOffset, int replacementLength, int cursorPosition, Image image, String displayString, IContextInformation contextInformation, String additionalProposalInfo) { + Assert.isNotNull(replacementString); + Assert.isTrue(replacementOffset >= 0); + Assert.isTrue(replacementLength >= 0); + Assert.isTrue(cursorPosition >= 0); + + this.eStructuralFeature = eStructuralFeature; + this.namedElement = namedElement; + this.context = context; + this.replacementString= replacementString; + this.replacementOffset= replacementOffset; + this.replacementLength= replacementLength; + this.cursorPosition= cursorPosition; + this.image= image; + this.displayString= displayString; + this.contextInformation= contextInformation; + this.additionalProposalInfo= additionalProposalInfo; + } + + /** + * Set the text in the widget and update the reference with the selected value. + * + * @param document + */ + @Override + public void apply(IDocument document) { + try { + document.replace(replacementOffset, replacementLength, replacementString); + TransactionalEditingDomain editingDomain = TransactionUtil.getEditingDomain(context); + RecordingCommand cc = new RecordingCommand(editingDomain) { + @Override + protected void doExecute() { + context.eSet(eStructuralFeature , namedElement); + } + }; + editingDomain.getCommandStack().execute(cc); + } catch (BadLocationException x) { + // ignore since we replace in a non-binded widget + } + } + + @Override + public Point getSelection(IDocument document) { + return new Point(replacementOffset + cursorPosition, 0); + } + + @Override + public IContextInformation getContextInformation() { + return contextInformation; + } + + @Override + public Image getImage() { + return image; + } + + @Override + public String getDisplayString() { + if (displayString != null) + return displayString; + return replacementString; + } + + @Override + public String getAdditionalProposalInfo() { + return additionalProposalInfo; + } +} diff --git a/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/editors/UMLReferenceContentAssistProcessor.java b/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/editors/UMLReferenceContentAssistProcessor.java new file mode 100644 index 00000000000..961260722ea --- /dev/null +++ b/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/editors/UMLReferenceContentAssistProcessor.java @@ -0,0 +1,207 @@ +/***************************************************************************** + * Copyright (c) 2017 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: + * Benoit Maggi (CEA LIST) - Initial API and implementation + *****************************************************************************/ + +package org.eclipse.papyrus.uml.properties.editors; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.function.Predicate; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.contentassist.ICompletionProposal; +import org.eclipse.jface.text.contentassist.IContentAssistProcessor; +import org.eclipse.jface.text.contentassist.IContextInformation; +import org.eclipse.jface.text.contentassist.IContextInformationValidator; +import org.eclipse.papyrus.infra.widgets.util.DoNothingCompletionProposal; +import org.eclipse.papyrus.infra.widgets.util.INameResolutionHelper; +import org.eclipse.papyrus.infra.widgets.util.IPapyrusConverter; +import org.eclipse.papyrus.uml.tools.utils.NameResolutionHelper; +import org.eclipse.uml2.uml.NamedElement; + +/** + * Provide assistance for auto completion on provided reference with named elements + */ +public class UMLReferenceContentAssistProcessor implements IContentAssistProcessor { + /** + * the maximum of elements to display in the completion + */ + private static int MAX_ELEMENTS_TO_DISPLAY = 15; + + /** + * add this string to the suggestions when there are more than {@link #MAX_ELEMENTS_TO_DISPLAY} + */ + public static final String MORE_ELEMENTS = IPapyrusConverter.MORE_ELEMENTS; //$NON-NLS-1$ + + + private String lastError = null; + + private IContextInformationValidator contextInfoValidator; + + private NameResolutionHelper nameResolutionHelper; + + private AutoCompleteStyledTextStringEditor autoCompleteStyledTextStringEditor; + + private EReference eReference ; + + /** + * Constructor. + * + * @param nameResolutionHelper + * @param autoCompleteStyledTextStringEditor + */ + public UMLReferenceContentAssistProcessor(EReference eReference, NameResolutionHelper nameResolutionHelper, AutoCompleteStyledTextStringEditor autoCompleteStyledTextStringEditor) { + this.eReference = eReference; + this.nameResolutionHelper = nameResolutionHelper; + this.autoCompleteStyledTextStringEditor = autoCompleteStyledTextStringEditor; + } + + /** + * @return the nameResolutionHelper + */ + public INameResolutionHelper getNameResolutionHelper() { + return nameResolutionHelper; + } + + /** + * @param nameResolutionHelper the nameResolutionHelper to set + */ + public void setNameResolutionHelper(NameResolutionHelper nameResolutionHelper) { + this.nameResolutionHelper = nameResolutionHelper; + } + + /** + * + * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#computeCompletionProposals(org.eclipse.jface.text.ITextViewer, int) + * + * @param textViewer + * @param documentOffset + * @return + */ + public ICompletionProposal[] computeCompletionProposals(ITextViewer textViewer, int documentOffset) { + IDocument document = textViewer.getDocument(); + int currOffset = documentOffset - 1; + String stringToComplete = textViewer.getTextWidget().getText(); + + try { + String currWord = IPapyrusConverter.EMPTY_STRING; + char currChar; + while (currOffset > 0 && !Character.isWhitespace(currChar = document.getChar(currOffset))) { + currWord = currChar + currWord; + currOffset--; + } + + currWord = textViewer.getTextWidget().getText(); + ICompletionProposal[] proposals = buildProposals(stringToComplete, documentOffset - stringToComplete.length()); + if (proposals.length > 0) { + lastError = null; + } else { + lastError = "There is no suggestion for you."; //$NON-NLS-1$ + } + return proposals; + } catch (Exception e) { + org.eclipse.papyrus.infra.widgets.Activator.log.error(e); + lastError = e.getMessage(); + return null; + } + } + + + + /** + * List available completion list from user entry + * + * @param entry + * the word to complete + * @param offset + * the offset + * @return + * an array with the completion proposal + */ + private ICompletionProposal[] buildProposals(final String entry, int offset) { + List<ICompletionProposal> proposalList = new ArrayList<>(); + + List<NamedElement> matchingElements = (List<NamedElement>) nameResolutionHelper.getMatchingElements(new Predicate<NamedElement>() { + @Override + public boolean test(NamedElement namedElement) { //check startwith without case + return namedElement.getName().regionMatches(true, 0, entry, 0, entry.length()); + } + }); + + // We order the list to provide "equal" name first (best option would to have smart suggestion like in jdt) + //This comparator should be in API + Collections.sort(matchingElements, new Comparator<NamedElement>() { + @Override + public int compare(NamedElement o1, NamedElement o2) { + return o1.getName().compareTo(o2.getName()); + } + }); + + + Object contextElement = autoCompleteStyledTextStringEditor.getContextElement(); + + + for (int i = 0; i < matchingElements.size() && i < MAX_ELEMENTS_TO_DISPLAY; i++) { + NamedElement suggestedNamedElement = matchingElements.get(i); + + ICompletionProposal ccc = new NamedElementCompletionProposal(eReference,suggestedNamedElement, + (EObject) contextElement, + offset, entry.length(), suggestedNamedElement.getName().length()); + proposalList.add(ccc); + } + + // add undefined + ICompletionProposal resetProposal = new NamedElementCompletionProposal(eReference, null, (EObject) contextElement, "", 0, entry.length() + offset, IPapyrusConverter.UNDEFINED_VALUE.length(), null, IPapyrusConverter.UNDEFINED_VALUE, null, null); + proposalList.add(0, resetProposal); + // add more if required + if (matchingElements.size() > MAX_ELEMENTS_TO_DISPLAY) { + DoNothingCompletionProposal doNothingCompletionProposal = new DoNothingCompletionProposal(IPapyrusConverter.EMPTY_STRING, 0, entry.length() + offset, IPapyrusConverter.MORE_ELEMENTS.length(), null, IPapyrusConverter.MORE_ELEMENTS, null, null); + proposalList.add(doNothingCompletionProposal); + } + return proposalList.toArray(new ICompletionProposal[0]); + } + + + + + public IContextInformation[] computeContextInformation(ITextViewer textViewer, int documentOffset) { + return null; + } + + /** + * + * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#getCompletionProposalAutoActivationCharacters() + * + * @return + */ + public char[] getCompletionProposalAutoActivationCharacters() { + // we always wait for the user to explicitly trigger completion + return null; + } + + public char[] getContextInformationAutoActivationCharacters() { + // we have no context information + return null; + } + + public String getErrorMessage() { + return lastError; + } + + public IContextInformationValidator getContextInformationValidator() { + return contextInfoValidator; + } +}
\ No newline at end of file diff --git a/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/widgets/AutoCompleteReferenceDialog.java b/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/widgets/AutoCompleteReferenceDialog.java new file mode 100644 index 00000000000..f7127ca7c09 --- /dev/null +++ b/plugins/uml/properties/org.eclipse.papyrus.uml.properties/src/org/eclipse/papyrus/uml/properties/widgets/AutoCompleteReferenceDialog.java @@ -0,0 +1,88 @@ +/***************************************************************************** + * Copyright (c) 2017 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: + * Benoit Maggi (CEA LIST) - Initial API and implementation + *****************************************************************************/ +package org.eclipse.papyrus.uml.properties.widgets; + +import java.util.Collections; + +import org.eclipse.core.databinding.observable.value.IObservableValue; +import org.eclipse.jface.window.Window; +import org.eclipse.papyrus.infra.widgets.editors.StyledTextReferenceDialog; +import org.eclipse.papyrus.infra.widgets.editors.StyledTextStringEditor; +import org.eclipse.papyrus.infra.widgets.providers.IAdaptableContentProvider; +import org.eclipse.papyrus.infra.widgets.util.INameResolutionHelper; +import org.eclipse.papyrus.uml.properties.editors.AutoCompleteReferenceDialogObservableValue; +import org.eclipse.papyrus.uml.properties.editors.AutoCompleteStyledTextStringEditor; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; + +/** + * Reference dialog for auto-completion + */ +public class AutoCompleteReferenceDialog extends StyledTextReferenceDialog { + + /** + * + * Constructor. + * + * @param parent + * @param style + */ + public AutoCompleteReferenceDialog(Composite parent, int style) { + super(parent, style); + } + + @Override + protected StyledTextStringEditor createStyledTextStringEditor(Composite parent, String initialValue, int style) { + StyledTextStringEditor editor = new AutoCompleteStyledTextStringEditor(parent, style); + editor.setValue(initialValue); + return editor; + } + + /** + * + * @see org.eclipse.papyrus.infra.widgets.editors.StyledTextReferenceDialog#createWidgetObservable(org.eclipse.core.databinding.observable.value.IObservableValue) + * + * @param modelProperty + * @return + */ + @Override + protected IObservableValue createWidgetObservable(IObservableValue modelProperty) { + AutoCompleteReferenceDialogObservableValue val = new AutoCompleteReferenceDialogObservableValue(this, this.styledTextStringEditor.getText(), modelProperty, SWT.FocusOut); + return val; + } + + public void setNameResolutionHelper(INameResolutionHelper nameResolutionHelper) { + ((AutoCompleteStyledTextStringEditor) styledTextStringEditor).setNameResolutionHelper(nameResolutionHelper); + } + + @Override + protected void browseAction() { + setInitialSelection(Collections.singletonList(getValue())); + int result = dialog.open(); + if (result == Window.OK) { + Object[] newValue = dialog.getResult(); + if (newValue == null) { + return; + } + + if (newValue.length == 0) { + setValue(null); + } else { + Object value = newValue[0]; + if (contentProvider instanceof IAdaptableContentProvider) { + value = ((IAdaptableContentProvider) contentProvider).getAdaptedValue(value); + } + setValue(value); + } + } + } +} diff --git a/plugins/uml/tools/org.eclipse.papyrus.uml.tools.utils/src/org/eclipse/papyrus/uml/tools/utils/NameResolutionHelper.java b/plugins/uml/tools/org.eclipse.papyrus.uml.tools.utils/src/org/eclipse/papyrus/uml/tools/utils/NameResolutionHelper.java index c7a3fc7745c..3064a6b2343 100644 --- a/plugins/uml/tools/org.eclipse.papyrus.uml.tools.utils/src/org/eclipse/papyrus/uml/tools/utils/NameResolutionHelper.java +++ b/plugins/uml/tools/org.eclipse.papyrus.uml.tools.utils/src/org/eclipse/papyrus/uml/tools/utils/NameResolutionHelper.java @@ -11,6 +11,7 @@ * Arnaud Cuccuru (CEA LIST) - Initial API and implementation * Vincent Lorenzo (CEA LIST) * Benoit Maggi (CEA LIST) - Bug 431629 Patch to avoid loop on imported packages + * Benoit Maggi (CEA LIST) - Bug 518317 Autocompletion for type of properties *****************************************************************************/ package org.eclipse.papyrus.uml.tools.utils; @@ -25,6 +26,8 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Collectors; import org.eclipse.core.runtime.Assert; import org.eclipse.emf.ecore.EClass; @@ -87,7 +90,6 @@ public class NameResolutionHelper implements INameResolutionHelper { init(space, filter); } - /** * * Constructor. @@ -102,6 +104,19 @@ public class NameResolutionHelper implements INameResolutionHelper { } /** + * A cached getter to all names structure + * @return all the names + */ + public Map<String, List<NamedElement>> getAllNames() { + if (allNames == null) { + allNames = new HashMap<>(); + computeAllNames(); + } + return allNames; + } + + + /** * * @param scope * @param filter @@ -126,7 +141,7 @@ public class NameResolutionHelper implements INameResolutionHelper { */ @Deprecated public List<NamedElement> getNamedElements(String name) { - List<NamedElement> returnedValues = new ArrayList<NamedElement>(); + List<NamedElement> returnedValues = new ArrayList<>(); List<Object> obj = getElementsByName(name); for (Object current : obj) { if (current instanceof NamedElement) { @@ -137,7 +152,7 @@ public class NameResolutionHelper implements INameResolutionHelper { } /** - * TODO + * Compute all name with all authorized namespace computation in UML */ protected void computeAllNames() { @@ -148,7 +163,6 @@ public class NameResolutionHelper implements INameResolutionHelper { Namespace enclosingNamespace = scope.getNamespace(); String prefix = EMPTY_STRING; while (enclosingNamespace != null) { - // prefix += enclosingNamespace.getName() + NamedElementUtil.QUALIFIED_NAME_SEPARATOR; prefix = EMPTY_STRING; computeNames(prefix, enclosingNamespace, false); enclosingNamespace = enclosingNamespace.getNamespace(); @@ -163,7 +177,7 @@ public class NameResolutionHelper implements INameResolutionHelper { if (filter.isSuperTypeOf(model.eClass())) { List<NamedElement> l = this.allNames.get(model.getName()); if (l == null) { // i.e. no names have already been resolved in enclosed namespaces - l = new ArrayList<NamedElement>(); + l = new ArrayList<>(); l.add(model); this.allNames.put(model.getName(), l); } @@ -173,7 +187,7 @@ public class NameResolutionHelper implements INameResolutionHelper { computeNames(builder.toString(), model, false); // Build names corresponding to other available UML resources in the workspace - List<Resource> resources = new ArrayList<Resource>(scope.eResource().getResourceSet().getResources());// we duplicate the resource to avoid concurrent modification + List<Resource> resources = new ArrayList<>(scope.eResource().getResourceSet().getResources());// we duplicate the resource to avoid concurrent modification for (Resource resource : resources) { if (resource != scope.eResource() && resource instanceof UMLResource) { UMLResource umlResource = (UMLResource) resource; @@ -189,7 +203,7 @@ public class NameResolutionHelper implements INameResolutionHelper { if (filter.isSuperTypeOf(root.eClass())) { List<NamedElement> l = this.allNames.get(root.getName()); if (l == null) { // i.e. no names have already been resolved in enclosed namespaces - l = new ArrayList<NamedElement>(); + l = new ArrayList<>(); l.add(root); this.allNames.put(root.getName(), l); } @@ -202,9 +216,6 @@ public class NameResolutionHelper implements INameResolutionHelper { } } - /** - * TODO - */ protected void computeNames(String prefix, Namespace scope, boolean ignoreAlreadyFoundNames) { computeNames(prefix, scope, ignoreAlreadyFoundNames, new HashSet<Namespace>()); } @@ -221,7 +232,7 @@ public class NameResolutionHelper implements INameResolutionHelper { alreadyComputedNamespace.add(scope); Set<String> preExistingKeys; if (ignoreAlreadyFoundNames) { - preExistingKeys = new HashSet<String>(); + preExistingKeys = new HashSet<>(); } else { preExistingKeys = this.allNames.keySet(); } @@ -292,11 +303,11 @@ public class NameResolutionHelper implements INameResolutionHelper { */ public List<Object> getMatchingElements(String aString) { if (this.allNames == null) { - this.allNames = new HashMap<String, List<NamedElement>>(); + this.allNames = new HashMap<>(); this.computeAllNames(); } - Collection<Object> elements = new HashSet<Object>(); + Collection<Object> elements = new HashSet<>(); for (Entry<String, List<NamedElement>> current : this.allNames.entrySet()) { if (aString == null || aString.isEmpty() || current.getKey().startsWith(aString)) { @@ -304,11 +315,30 @@ public class NameResolutionHelper implements INameResolutionHelper { } } // to avoid to found the same element several time - return new ArrayList<Object>(elements); + return new ArrayList<>(elements); } - /** + * Apply the predicate to get matching elements from all Name Elements + * + * @see org.eclipse.papyrus.infra.widgets.util.INameResolutionHelper#getMatchingElements(java.util.function.Predicate) + * + * @param p + * @return + */ + @Override + public List<?> getMatchingElements(Predicate predicate) { + // Since Predicate isn't generic we need to handle the exception in filter + Set<?> collect = (Set<?>) this.getAllNames().values().stream().flatMap(List::stream) + .filter(namedElement -> {try {return predicate.test(namedElement);} catch (Exception e){return false;}}).collect(Collectors.toSet()); + return new ArrayList<>(collect); + } + + + /** + * This method will return all named element that can be found in the given qualified name + * (should be named getNamedElementByQualifiedName() + * * @see org.eclipse.papyrus.infra.widgets.util.INameResolutionHelper#getElementsByName(java.lang.String) * * @param aString @@ -316,24 +346,26 @@ public class NameResolutionHelper implements INameResolutionHelper { */ public List<Object> getElementsByName(String aString) { if (this.allNames == null) { - this.allNames = new HashMap<String, List<NamedElement>>(); + this.allNames = new HashMap<>(); this.computeAllNames(); } List<NamedElement> namedElements = this.allNames.get(aString); List<Object> returnedValues = null; if (namedElements != null && namedElements.size() > 0) { - - returnedValues = new ArrayList<Object>(namedElements); + returnedValues = new ArrayList<>(namedElements); } return returnedValues != null ? returnedValues : Collections.emptyList(); } + + /** * {@inheritDoc} * * @see org.eclipse.papyrus.infra.widgets.util.INameResolutionHelper#getShortestQualifiedNames(java.lang.Object) * @deprecated since 1.2.0 */ + @Deprecated public List<String> getShortestQualifiedNames(final Object element) { return getShortestQualifiedNames(element, true); } @@ -349,4 +381,7 @@ public class NameResolutionHelper implements INameResolutionHelper { } return null; } + + + } diff --git a/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/util/UMLReferenceConverter.java b/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/util/UMLReferenceConverter.java index 57b30848c21..e3a25101d15 100644 --- a/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/util/UMLReferenceConverter.java +++ b/plugins/uml/tools/org.eclipse.papyrus.uml.tools/src/org/eclipse/papyrus/uml/tools/util/UMLReferenceConverter.java @@ -20,6 +20,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.TreeMap; +import java.util.function.Predicate; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -59,7 +60,7 @@ public class UMLReferenceConverter implements IPapyrusConverter { * @param helper * the name resolution helper to use * @param isMultiValued - * <code>true</code> if the edited property is multi valued + * <code>true</code> if the edited property is multi-valued */ public UMLReferenceConverter(INameResolutionHelper nameResolutionHelper, boolean isMultiValued) { this.sharedResolutionHelper = nameResolutionHelper; @@ -78,7 +79,7 @@ public class UMLReferenceConverter implements IPapyrusConverter { } -/** + /** * This method takes a string as parameter. This string can contains the name (qualified name) of several elements, separated by {@link IPapyrusConverter#STRING_SEPARATOR}. if the name of an element contains {@link IPapyrusParser#STRING_SEPARATOR, the name will be delimited by IPapyrusParser#STRING_DELIMITER * * This method return a map with the name of the subelement as keys. The values are the start and the end position of the key in the string parameter. @@ -90,10 +91,10 @@ public class UMLReferenceConverter implements IPapyrusConverter { public final Map<List<Integer>, String> getSubStringsWithTheirPositions(String listOfValueAsString) { final Pattern pattern = Pattern.compile(FIND_PART_NAME_REGEX); final Matcher matcher = pattern.matcher(listOfValueAsString); - final TreeMap<List<Integer>, String> path = new TreeMap<List<Integer>, String>(new TwoIntegerListTupleComparator()); + final TreeMap<List<Integer>, String> path = new TreeMap<>(new TwoIntegerListTupleComparator()); while (matcher.find()) { String current = matcher.group(); - List<Integer> indexes = new ArrayList<Integer>(); + List<Integer> indexes = new ArrayList<>(); int start = matcher.start(); int end = matcher.end(); if (current.startsWith(STRING_DELIMITER) && current.endsWith(STRING_DELIMITER)) { @@ -144,19 +145,7 @@ public class UMLReferenceConverter implements IPapyrusConverter { */ public List<String> splitFullStringToSubElementString(String multiValueAsString) { TreeMap<List<Integer>, String> res = (TreeMap<List<Integer>, String>) getSubStringsWithTheirPositions(multiValueAsString); - List<String> values = new ArrayList<String>(res.values()); - return values; - // final Pattern pattern = Pattern.compile(FIND_PART_NAME_REGEX); - // final Matcher matcher = pattern.matcher(multiValueAsString); - // final List<String> subString = new ArrayList<String>(); - // while (matcher.find()) { - // String current = matcher.group(); - // if (current.startsWith(STRING_DELIMITER) && current.endsWith(STRING_DELIMITER)) { - // current = current.substring(1, current.length() - 1); - // } - // subString.add(current); - // } - // return subString; + return new ArrayList<>(res.values()); } @@ -226,6 +215,19 @@ public class UMLReferenceConverter implements IPapyrusConverter { } /** + * Transfer the call to the wrapped shared helper + * + * @see org.eclipse.papyrus.infra.widgets.util.INameResolutionHelper#getMatchingElements(java.util.function.Predicate) + * + * @param p + * @return + */ + @Override + public List<?> getMatchingElements(Predicate p) { + return this.sharedResolutionHelper.getMatchingElements(p); + } + + /** * * @param aString * a string @@ -270,7 +272,6 @@ public class UMLReferenceConverter implements IPapyrusConverter { } if (object instanceof Collection<?>) { - // if (canonicalValue instanceof Collection<?>) { if (((Collection<?>) object).isEmpty()) { return EMPTY_STRING; } @@ -331,12 +332,10 @@ public class UMLReferenceConverter implements IPapyrusConverter { */ public String canonicalToEditValue(Object object, int flag) { if (object == null || EMPTY_STRING.equals(object)) { -// return NULL_VALUE; return EMPTY_STRING; } if (object instanceof Collection<?>) { - // if (canonicalValue instanceof Collection<?>) { if (((Collection<?>) object).isEmpty()) { return EMPTY_STRING; } @@ -441,7 +440,6 @@ public class UMLReferenceConverter implements IPapyrusConverter { */ private static final class TwoIntegerListTupleComparator implements Comparator<List<Integer>> { - /** * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) * |