Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » TMF (Xtext) » issue with findActualNodeFor and what it returns from an old version of the Resource
issue with findActualNodeFor and what it returns from an old version of the Resource [message #1785452] Fri, 13 April 2018 22:55 Go to next message
Parsa Pourali is currently offline Parsa PouraliFriend
Messages: 210
Registered: February 2014
Senior Member
Hi,

Currently, I am trying to add a Xtext Embedded editor in the properties page of my graphical tool (using Sirius Custom Widgets).

Here is a sample story:
1) I click on the model element in the graphical diagram/view.
2) The xtext editor for that element will be shown in the properties view and actually works well (content assist and every thing...). And it works very good when I change the element's text/value from the xtext editor and save it. It will be immediately reflected in the graphical editor and my model file (original xtext textual file/editor).

e.g., [ Entity1 = Association1 ] ->>CHANGED TO -->> [ Entity1 = F2.att2 ]

3) However, when I click again on that element, and use findActualNodeFor (element), it does NOT show the exact text from the model. The reason is that the model has recently changed but still refers back to the previous version of the model.

For instance in the example above, if I click again on the element, this is what I get in the editor: "[ Entity1 = F2.att2 ] / a2" where "/ a2" is actually the rest of the text that should not be shown !

My guess is that since the text was edited to a shorter text , then when clicking back it is still getting the same length and returns extra characters.

I hope I could convey the message.

Thanks,
Parsa

Here is my Code:

public final class CustomEditorHelper {

	private CustomEditorHelper() {
	}

	public static EmbeddedEditor editor;
	public static EmbeddedEditorModelAccess partialEditorModelAccess;
	public static Resource originalResource;
	public static XtextResource xTextResource;
	public static CLabel lblUserShiftEnter;
	public static CLabel lblSavedOrStillErroneous;

	public static EmbeddedEditor createEditor(Composite parent, EObject semanticElement) throws CoreException {

		TransactionalEditingDomain editingDomain = TransactionUtil.getEditingDomain(semanticElement);

		if (!(semanticElement instanceof Transition))
			return null;

		Transition trans = (Transition) semanticElement;

		final CommandStack commandStack = editingDomain.getCommandStack();
		commandStack.execute(new RecordingCommand(editingDomain) {

			@Override
			protected void doExecute() {

				Composite top = new Composite(parent, SWT.NONE);
				top.setLayout(new GridLayout());

				GridData data = new GridData(GridData.FILL_HORIZONTAL);
				data.heightHint = 100;
				top.setLayoutData(data);

				Injector injector = FormlActivator.getInstance().getInjector(FormlActivator.UW_CS_WATFORM_FORML_FORML);

				CustomEmbeddedEditorResourceProvider resourceProvider = injector
						.getInstance(CustomEmbeddedEditorResourceProvider.class);
				// EmbeddedEditorFactory factory =
				// injector.getInstance(EmbeddedEditorFactory.class);
				CustomEmbeddedEditorFactory factory = injector.getInstance(CustomEmbeddedEditorFactory.class);

				editor = factory.newEditor(resourceProvider).showErrorAndWarningAnnotations().withParent(top);
				editor.getViewer().getTextWidget().setLayoutData(data);

				if (trans.getGuard() == null) {
					Guard guard = FormlFactory.eINSTANCE.createGuard();
					trans.setGuard(guard);
				}

				xTextResource = resourceProvider.createResource(trans.getGuard());
				ICompositeNode rootNode = xTextResource.getParseResult().getRootNode();
				originalResource = trans.getGuard().eResource();

				String[] pre_editable_suff_Fixes = findPartsForNode(rootNode, trans.getGuard());

				partialEditorModelAccess = editor.createPartialEditor(pre_editable_suff_Fixes[0],
						pre_editable_suff_Fixes[1], pre_editable_suff_Fixes[2], true);

				// CREATES TOOLTIPS AND ETC.
				lblUserShiftEnter = new CLabel(top, SWT.SHADOW_NONE);
				lblUserShiftEnter.setForeground(SWTResourceManager.getColor(64, 64, 64));
				lblUserShiftEnter.setSize(SWT.DEFAULT, 100);
				lblUserShiftEnter.setText("Please use Shift+Enter to save the modifications in the textual editor.");
				lblUserShiftEnter.pack();

				lblSavedOrStillErroneous = new CLabel(top, SWT.SHADOW_NONE);
				lblSavedOrStillErroneous.setForeground(SWTResourceManager.getColor(0, 255, 0));

				editor.getViewer().getTextWidget().setBackground(SWTResourceManager.getColor(228, 246, 253));
				
			}
		});

		addKeyVerifyListener();

		return editor;
	}

	protected static String[] findPartsForNode(ICompositeNode rootNode, EObject semanticElementInDocument) {
		String[] parts = new String[3];

		try {
			String allText = rootNode.getText();
			ICompositeNode elementNode = NodeModelUtils.findActualNodeFor((semanticElementInDocument));

			String prefix = allText.substring(0, elementNode.getOffset() - 1);
			String editablePart = allText.substring(elementNode.getOffset(), elementNode.getEndOffset());

			String suffix = allText.substring(elementNode.getEndOffset());

			parts[0] = prefix;
			parts[1] = editablePart;
			parts[2] = suffix;
		} catch (Exception e) {
			parts[0] = "";
			parts[1] = "[]";
			parts[2] = "";
		}
		return parts;
	}

	private static void addKeyVerifyListener() {
		final StyledText xtextTextWidget = editor.getViewer().getTextWidget();
		xtextTextWidget.addVerifyKeyListener(new VerifyKeyListener() {
			public void verifyKey(VerifyEvent e) {
				int keyCode = e.keyCode;
				// if ((e.stateMask & SWT.CTRL) != 0 && ((keyCode == SWT.KEYPAD_CR) || (keyCode
				// == SWT.CR))) {
				if ((e.stateMask & SWT.SHIFT) != 0 && ((keyCode == SWT.KEYPAD_CR) || (keyCode == SWT.CR))) {
					e.doit = false;
					saveEditor(true);
				}
				// if (keyCode == SWT.ESC) {
				if ((e.stateMask & SWT.SHIFT) != 0 && keyCode == SWT.ESC) {
					e.doit = false;
					saveEditor(false);
				}

			}
		});
	}

	/**
	 * Close this editor.
	 * 
	 * @param isReconcile
	 */
	public static void saveEditor(boolean isReconcile) {
		if (partialEditorModelAccess != null) {
			if (isReconcile) {
				try {
					updateXtextResource();
				} catch (Exception exc) {
					Activator.logError(exc);
				}
			}

		}
	}

	protected static void updateXtextResource() throws IOException, BadLocationException {
		String newText = partialEditorModelAccess.getSerializedModel();
		xTextResource.reparse(newText);
		EcoreUtil.resolveAll(xTextResource);
		final IParseResult parseResult = xTextResource.getParseResult();
		if (!parseResult.hasSyntaxErrors() && !hasDanglingRefs(xTextResource)) {
			if (reconcile(originalResource, xTextResource)) {
				lblSavedOrStillErroneous.setForeground(SWTResourceManager.getColor(0, 102, 0));
				lblSavedOrStillErroneous.setText("Successfully saved.");
				lblSavedOrStillErroneous.pack();
			} else {
				lblSavedOrStillErroneous.setForeground(SWTResourceManager.getColor(255, 0, 0));
				lblSavedOrStillErroneous.setText("Guard value contains error and cannot be saved.");
				lblSavedOrStillErroneous.pack();
			}
		} else {
			lblSavedOrStillErroneous.setForeground(SWTResourceManager.getColor(255, 0, 0));
			lblSavedOrStillErroneous.setText("Guard value contains error and cannot be saved.");
			lblSavedOrStillErroneous.pack();
		}
	}

	private static boolean hasDanglingRefs(XtextResource xtextResource2) {
		return EcoreUtil.UnresolvedProxyCrossReferencer.find(xtextResource2).size() > 0;
	}

	private static boolean reconcile(Resource resourceInSirius, XtextResource resourceInEmbeddedEditor) {
		try {

			IComparisonScope scope = new DefaultComparisonScope(resourceInSirius, resourceInEmbeddedEditor, null);
			final Comparison comparison = EMFCompare.builder().build().compare(scope);

			IMerger.Registry mergerRegistry = EMFCompareRCPPlugin.getDefault().getMergerRegistry();
			final IBatchMerger merger = new BatchMerger(mergerRegistry);

			final TransactionalEditingDomain editingDomain = TransactionUtil.getEditingDomain(originalResource);
			editingDomain.getCommandStack()
					.execute(new RecordingCommand(editingDomain, "update resource after direct text edit") {

						@Override
						protected void doExecute() {
							merger.copyAllRightToLeft(comparison.getDifferences(), new BasicMonitor());
						}
					});
		} catch (Exception e) {
			Activator.logError(e);
			return false;
		}
		return true;
	}

}

Re: issue with findActualNodeFor and what it returns from an old version of the Resource [message #1785456 is a reply to message #1785452] Sat, 14 April 2018 05:20 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14665
Registered: July 2009
Senior Member
I don't know anything about Sirius but two questions

There does the trans object come from and is it updated with a newly parsed one after saving?
What does the custom edited resource provider do
Why do you use the edited resources rootnode to find stuff from trans that does not come from that? Or does it?


Twitter : @chrdietrich
Blog : https://www.dietrich-it.de

[Updated on: Sat, 14 April 2018 05:23]

Report message to a moderator

Re: issue with findActualNodeFor and what it returns from an old version of the Resource [message #1785458 is a reply to message #1785456] Sat, 14 April 2018 05:39 Go to previous messageGo to next message
Ed Willink is currently offline Ed WillinkFriend
Messages: 7655
Registered: July 2009
Senior Member
Hi

Your title says "an old version of a Resource" and I see no IUnitOfWork. After an update Xtext churns EObjects, so if you hang on to old ones that is exactly what you do. It is usually necessary to use an IUnitOfWork to locate the resource, and URIs to locate content across changes.

I suggest that you instrument/set a breakpoint on ILinker.linkModel to check whether updates are occurring and what Resources are live/stale.

Regards

Ed Willink
Re: issue with findActualNodeFor and what it returns from an old version of the Resource [message #1785470 is a reply to message #1785458] Sat, 14 April 2018 16:06 Go to previous messageGo to next message
Parsa Pourali is currently offline Parsa PouraliFriend
Messages: 210
Registered: February 2014
Senior Member
Thanks Christian and Ed,

Christian:
The trans object is a transition (state machine) object in my diagram. When I click on a transition, the semantic element (trans) of that selected part is passed to here.
The CustomResourceProvide implements IEditedResourceProvider and creates a virtual xtext resource and loads it in the memory.
The rootnode is where the trans is coming from.

Ed: I'm not sure how to use IUnitOfWork and where to put it :( The issue as you pointed is that Sirius has its own version which is not updated. I tried the following solution but got a new problem.

In my recouncil method which finds the diffs and merges the changes on the XText file, I added a few lines to also update the resource in the Sirius as well (See below). It fixed the previous issue, but now the new problem is when I edit the model element using the embedded editor multiple times, the CTRL+SPACE key combination for content assist stops responding. It does not throw any error but I can see that in console it says the following warning which says about handlers (maybe key handlers). I'm not even sure if this is relevant to the problem of Control+Space not working though. Do you have any idea on the reasons why the Content Assist might not work ? Note that if I write the text without assistant the editor works.
!ENTRY org.eclipse.ui 4 4 2018-04-14 11:43:33.806
!MESSAGE Conflicting handlers for org.eclipse.ui.edit.text.select.columnNext: {ActionHandler(org.eclipse.ui.texteditor.TextNavigationAction@1da308)} vs {ActionHandler(org.eclipse.ui.texteditor.TextNavigationAction@5ef5757f)}

!ENTRY org.eclipse.ui 4 4 2018-04-14 11:43:33.807
!MESSAGE Conflicting handlers for org.eclipse.ui.edit.text.select.textEnd: {ActionHandler(org.eclipse.ui.texteditor.TextNavigationAction@1097a31c)} vs {ActionHandler(org.eclipse.ui.texteditor.TextNavigationAction@52f5f5eb)}

!ENTRY org.eclipse.ui 4 4 2018-04-14 11:43:33.808
!MESSAGE Conflicting handlers for org.eclipse.ui.edit.text.deleteNextWord: {ActionHandler(org.eclipse.ui.texteditor.TextNavigationAction@74a756fd)} vs {ActionHandler(org.eclipse.ui.texteditor.TextNavigationAction@4efd6b61)}

!ENTRY org.eclipse.ui 4 4 2018-04-14 11:43:33.808
!MESSAGE Conflicting handlers for org.eclipse.ui.edit.text.swap.mark: {ActionHandler(org.eclipse.xtext.ui.editor.embedded.TextViewerMarkAction@47d6101)} vs {ActionHandler(org.eclipse.xtext.ui.editor.embedded.TextViewerMarkAction@5b8e6e09)}


private boolean reconcile(Resource resourceInSirius, XtextResource resourceInEmbeddedEditor) {
		try {

			IComparisonScope scope = new DefaultComparisonScope(resourceInSirius, resourceInEmbeddedEditor, null);
			final Comparison comparison = EMFCompare.builder().build().compare(scope);

			IMerger.Registry mergerRegistry = EMFCompareRCPPlugin.getDefault().getMergerRegistry();
			final IBatchMerger merger = new BatchMerger(mergerRegistry);

			final TransactionalEditingDomain editingDomain = TransactionUtil.getEditingDomain(originalResource);
			editingDomain.getCommandStack()
					.execute(new RecordingCommand(editingDomain, "update resource after direct text edit") {

						@Override
						protected void doExecute() {

							
									merger.copyAllRightToLeft(comparison.getDifferences(), new BasicMonitor());
                                                                         /******************THIS TRY BLOCK BELOW IS WHAT I ADDED ********************/
									try {
										resourceInSirius.save(SaveOptions.newBuilder().format().getOptions().toOptionsMap());
									} catch (IOException e) {
										e.printStackTrace();
									}
						}
					});
		} catch (Exception e) {
			Activator.logError(e);
			return false;
		}
		return true;
	}
Re: issue with findActualNodeFor and what it returns from an old version of the Resource [message #1785472 is a reply to message #1785470] Sat, 14 April 2018 16:29 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14665
Registered: July 2009
Senior Member
i still dont understand how this like can work:

ICompositeNode elementNode = NodeModelUtils.findActualNodeFor((semanticElementInDocument));

if the object does not come from xtext or is old.


Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: issue with findActualNodeFor and what it returns from an old version of the Resource [message #1785476 is a reply to message #1785472] Sat, 14 April 2018 18:32 Go to previous messageGo to next message
Ed Willink is currently offline Ed WillinkFriend
Messages: 7655
Registered: July 2009
Senior Member
Hi

If you have an Xtext editor managing your resource, you must obtin the prevailing resource from the editor using IUnitOfWork. There is no alternative since the resource field is pr9vate.

You do

originalResource = trans.getGuard().eResource()

which is just about guaranteed to give bad results since the original resource is stale.

Regards

Ed Willink
Re: issue with findActualNodeFor and what it returns from an old version of the Resource [message #1785480 is a reply to message #1785476] Sat, 14 April 2018 22:36 Go to previous messageGo to next message
Parsa Pourali is currently offline Parsa PouraliFriend
Messages: 210
Registered: February 2014
Senior Member
Hi Ed and Christian,

Thanks for replying so fast AAAANNNDD during the weekend :)

Christian: This is also what surprises me. The object that is being passed from sirius editor seems to be the right one and updated !!! I tested it using breakpoints. I THINK, the resource in the memory is still old. So, when I look for an object by its uri, the FindNode method actually finds it by searching through the old resource because the uri is actually correct, but the element's children's value has only changed. Don't know really, I am confused, cuz both the xtext file and the graphical editors show the correct thing meaning that the change has been reflected to the model correctly. So confusing ...

Ed: Thanks Ed for the hint, I changed my recouncil method to the following, and added an IUnitOfWork. But the issue still exists. Should I use it anywhere else ?

private boolean reconcile(Resource resourceInSirius, XtextResource resourceInEmbeddedEditor) {
		try {

			IComparisonScope scope = new DefaultComparisonScope(resourceInSirius, resourceInEmbeddedEditor, null);
			final Comparison comparison = EMFCompare.builder().build().compare(scope);

			IMerger.Registry mergerRegistry = EMFCompareRCPPlugin.getDefault().getMergerRegistry();
			final IBatchMerger merger = new BatchMerger(mergerRegistry);

			final TransactionalEditingDomain editingDomain = TransactionUtil.getEditingDomain(originalResource);
			editingDomain.getCommandStack()
					.execute(new RecordingCommand(editingDomain, "update resource after direct text edit") {
						@Override
						protected void doExecute() {
							IXtextDocument xTextDoc = editor.getDocument();
							xTextDoc.modify(new IUnitOfWork.Void<XtextResource>() {

								@Override
								public void process(XtextResource state) throws Exception {
									merger.copyAllRightToLeft(comparison.getDifferences(), new BasicMonitor());
								}
							});					
					    }
					});
		} catch (Exception e) {
			Activator.logError(e);
			return false;
		}
		return true;
	}
Re: issue with findActualNodeFor and what it returns from an old version of the Resource [message #1785484 is a reply to message #1785480] Sun, 15 April 2018 05:40 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14665
Registered: July 2009
Senior Member
Which resource are you talking about.
And which text is wrong.
The alltext
Or the element nodes text

And still the question. Where do you update the
Trans.getGuard object

(I really don't understand what your logic does there since the code has no comments)


And how did you implement thenedited resource provider


Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: issue with findActualNodeFor and what it returns from an old version of the Resource [message #1785485 is a reply to message #1785484] Sun, 15 April 2018 05:42 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14665
Registered: July 2009
Senior Member
And are the editors dirty on the first change or not

Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: issue with findActualNodeFor and what it returns from an old version of the Resource [message #1785486 is a reply to message #1785485] Sun, 15 April 2018 07:26 Go to previous messageGo to next message
Ed Willink is currently offline Ed WillinkFriend
Messages: 7655
Registered: July 2009
Senior Member
Hi

"Should I use it anywhere else"

In your code that needs to use the prevailing editor state, all accesses to the prevailing model should be a consequence of, preferably within, just one use of IUnitOfWork to lock out concurrent evolution. It is very important that you do not have any fields that persist a previous model across executions.

Regards

Ed Willink
Re: issue with findActualNodeFor and what it returns from an old version of the Resource [message #1785497 is a reply to message #1785484] Sun, 15 April 2018 17:29 Go to previous messageGo to next message
Parsa Pourali is currently offline Parsa PouraliFriend
Messages: 210
Registered: February 2014
Senior Member
Hi Christian and Ed,

You can see what I'm talking about in this video (please turn on subtitles): https://youtu.be/F1K3h48Itvs

Yes, the editors become dirty when I change the model from my embedded editor.

I'm talking about the Node text. Let's say the previous node text started from position 100, to 105 of the model text. But when I change the text and try to get the new position of the node, it still returns from 100 to 105 ! The question is if the Sirius resource is not updated , then why it is all reflected to the model both in graphical editor and textual editor.

The thing that I found is problematic is that, I have XTextResource and OriginalResource in my code which I later recouncil and merge.

When I select the model element to modify it again for the second time, I see that the xtextresource is updated and correct, BUT the originalResouce is still old. This originalResouce comes from the graphical editor which is showing the correct element text but apparently in the background it has another version in the memory. So, Ed is totally right when he says that "originalResource = trans.getGuard().eResource() is guaranteed to give bad results since the original resource is stale." And I tried IUnitOfWork but didn't help :( So far only adding resourceInSirius.save(SaveOptions.newBuilder().format().getOptions().toOptionsMap()); in the recouncil method worked but as I for some reasons the Ctrl+Space for content assist stops responding after a few times.


Christian, this is my resouceProvider implementation. I got it from Sirius Xtext Integration link that is on git and it actually works well I believe.
public static final String SYNTHETIC_SCHEME = "synthetic";
	XtextResource xtextResouce = null;

	@Inject
	private IResourceSetProvider resourceSetProvider;

	@Inject
	private FileExtensionProvider ext;

	public XtextResource createResource(EObject element) {
		ResourceSet resourceSet = resourceSetProvider.get(null);

		Resource originalResource = element.eResource();

		EObject semanticElement = EcoreUtil.copy(originalResource.getContents().get(0));

		try {
			xtextResouce = createVirtualXtextResource(originalResource.getURI(), semanticElement);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		resourceSet.getResources().add(xtextResouce);
		return xtextResouce;

	}

	public EObject getObject(EObject element) {
		// ResourceSet resourceSet = resourceSetProvider.get(null);
		System.out.println(ModelUtils.getTextForModelObjects(element).trim());
		return this.xtextResouce.getEObject(element.eResource().getURI().toString());

	}

	protected XtextResource createVirtualXtextResource(URI uri, EObject semanticElement) throws IOException {
		IResourceFactory resourceFactory = ModelUtils.getInjector().getInstance(IResourceFactory.class);
		// TODO use the synthetic scheme.
		XtextResourceSet rs = ModelUtils.getInjector().getInstance(XtextResourceSet.class);
		rs.setClasspathURIContext(getClass());
		// Create virtual resource
		XtextResource xtextVirtualResource = (XtextResource) resourceFactory
				.createResource(URI.createURI(uri.toString()));
		rs.getResources().add(xtextVirtualResource);

		// Populate virtual resource with the given semantic element to edit
		xtextVirtualResource.getContents().add(semanticElement);

		// Save and reparse in order to initialize virtual Xtext resource
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		xtextVirtualResource.save(out, SaveOptions.newBuilder().format().getOptions().toOptionsMap());
		xtextVirtualResource.reparse(new String(out.toByteArray()));

		return xtextVirtualResource;
	}

[Updated on: Sun, 15 April 2018 17:32]

Report message to a moderator

Re: issue with findActualNodeFor and what it returns from an old version of the Resource [message #1785502 is a reply to message #1785497] Mon, 16 April 2018 01:33 Go to previous message
Parsa Pourali is currently offline Parsa PouraliFriend
Messages: 210
Registered: February 2014
Senior Member
Thanks to you guys. I thought about Christian's question on "Which resource are you talking about." and found that somewhere in my code these two resources do not represent the same EObject/Resource. So, I found that, in my findPartsForNode(ICompositeNode rootNode, EObject semanticElementInDocument) method, I am passing the rootNode from my xTextResource but the semanticElementInDocument comes from the graphical editor (SiriusResource) !!! and that 's where the discrepancy happens! I then used the following two lines to get the equivalent object from the xtextResouce. And it worked :D Hopefully :)))

So, I changed:
String[] pre_editable_suff_Fixes = findPartsForNode(rootNode, trans.getGuard());

to:
String semanticElementFragment = originalResource.getURIFragment(trans.getGuard());
EObject semanticElementInDocument = xTextResource.getEObject(semanticElementFragment);
String[] pre_editable_suff_Fixes = findPartsForNode(rootNode,semanticElementInDocument);

Thanks for helping me through this :)
Previous Topic:Embed Editor
Next Topic:QualifiedNameProvider ends up in cyclic resolution, when referring to object of other resource
Goto Forum:
  


Current Time: Tue Apr 23 15:39:49 GMT 2024

Powered by FUDForum. Page generated in 0.03940 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top