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 |
Parsa Pourali 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 #1785470 is a reply to message #1785458] |
Sat, 14 April 2018 16:06 |
Parsa Pourali 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 #1785480 is a reply to message #1785476] |
Sat, 14 April 2018 22:36 |
Parsa Pourali 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 #1785497 is a reply to message #1785484] |
Sun, 15 April 2018 17:29 |
Parsa Pourali 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
|
|
| |
Goto Forum:
Current Time: Wed Sep 25 23:31:20 GMT 2024
Powered by FUDForum. Page generated in 0.07950 seconds
|