Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » TMF (Xtext) » IResourceDescription's URI sync
IResourceDescription's URI sync [message #1723220] Fri, 12 February 2016 14:55 Go to next message
aurel pestell is currently offline aurel pestellFriend
Messages: 90
Registered: October 2013
Location: Sweden
Member
Hi,

Within IResourceChangeListener that detects file moves, I get a handle on all the resource decriptions that way:

Iterable<IResourceDescription> descriptions = resourceDescriptions.getAllResourceDescriptions();


I iterate through each of them and extract the corresponding XtextResource given their URI, in such a way:

Resource currentResource = resourceSet.getResource(description.getURI(), true);


I was expecting description.getURI() to deliver the URI of the original file (before it moved) but it seems pretty unstable.
It randomly gives me the original or the new URI.
How can I ensure I always get the original URI ?
Thanks.

(small precision: the code above is executed in a WorkspaceJob context)
Re: IResourceDescription's URI sync [message #1723223 is a reply to message #1723220] Fri, 12 February 2016 15:08 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14664
Registered: July 2009
Senior Member
Hi what do you actually want to achieve. Why don't you listen to the
changes xtext provides to the listeners on the xtext index


Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: IResourceDescription's URI sync [message #1723228 is a reply to message #1723223] Fri, 12 February 2016 15:36 Go to previous messageGo to next message
Jan Koehnlein is currently offline Jan KoehnleinFriend
Messages: 760
Registered: July 2009
Location: Hamburg
Senior Member
There are different scopes of IResourceDescriptions (see org.eclipse.xtext.resource.impl.ResourceDescriptionsProvider). Which one you get depends on the context you provide to the ResourceDescriptionsProvider. Resource descriptions are updated by the builder, i.e. usually by the auto-build job in background. Depending on whether the auto-build has already run, you get the new or the old values.

I am not sure what you are trying to achieve, but when it is really only about detecting resource description changes, you should consider implementing an IXtextBuildParticipant.



---
Get professional support from the Xtext committers at www.typefox.io
Re: IResourceDescription's URI sync [message #1723235 is a reply to message #1723228] Fri, 12 February 2016 16:12 Go to previous messageGo to next message
aurel pestell is currently offline aurel pestellFriend
Messages: 90
Registered: October 2013
Location: Sweden
Member
I am trying to implement refactoring xtext resources through drag-and-drop (in the package explorer, from one package to another).
Because I read refactoring in Xtext works only within the associated editor, I directly modify the physical file that are moved by a drag-and-drop action instead.
It "seems" to work great excepting in some case where the URI is wrong (as described in my first comment).


@Jan Koenhnlein: I have never done that but I will give it a try. In our project we use the default implementation "ParallelBuilderParticipant", should I start from there ?
edit: I will read this extending-xtext-build-participants/

Thanks!

[Updated on: Fri, 12 February 2016 16:34]

Report message to a moderator

Re: IResourceDescription's URI sync [message #1723240 is a reply to message #1723235] Fri, 12 February 2016 16:33 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14664
Registered: July 2009
Senior Member
do you implement a moveparticipant and do something similar as xtext does in AbstractProcessorBasedRenameParticipant
with a potential subclass

@SuppressWarnings("restriction")
public class MyDslFileRenameParticipant extends AbstractProcessorBasedRenameParticipant {

@Inject
private IResourceSetProvider resourceSetProvider;

@Inject
private IRenameContextFactory renameContextFactory;

@Inject
private FileExtensionProvider fileExtensionProvider;



@Override
protected List<? extends IRenameElementContext> createRenameElementContexts(
Object element) {
if (super.getNewName().endsWith(
"." + fileExtensionProvider.getPrimaryFileExtension())) {
IFile file = (IFile) element;
final IPath filePath = file.getFullPath();
final IPath newPath = file
.getFullPath()
.removeLastSegments(1)
.append(getNewName() + "."
+ fileExtensionProvider.getPrimaryFileExtension());
String className = trimFileExtension(file.getName());

ResourceSet resourceSet = resourceSetProvider.get(file.getProject());
URI resourceURI = URI.createPlatformResourceURI(
file.getFullPath().toString(), true);
Resource resource = resourceSet.getResource(resourceURI, true);
if (resource != null && !resource.getContents().isEmpty()) {
for (Entity type : EcoreUtil2.eAllOfType(resource.getContents().get(0),
Entity.class)) {
if (equal(className, type.getName())) {
IRenameElementContext renameElementContext = renameContextFactory
.createRenameElementContext(type, null, null,
(XtextResource) resource);
if (renameElementContext instanceof IChangeRedirector.Aware) {
((IChangeRedirector.Aware) renameElementContext)
.setChangeRedirector(new IChangeRedirector() {
@Override
public IPath getRedirectedPath(IPath source) {
return source.equals(filePath) ? newPath
: source;
}

});
}
return singletonList(renameElementContext);
}
}
}

}
return super.createRenameElementContexts(element);
}

@Override
protected String getNewName() {
return trimFileExtension(super.getNewName());
}

private String trimFileExtension(String fileName) {
if (fileName.lastIndexOf('.') == -1) {
return fileName;
}
return fileName.substring(0, fileName.lastIndexOf('.'));
}

@Override
protected List<EObject> getRenamedElementsOrProxies(EObject originalTarget) {
return singletonList(originalTarget);
}

}


Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: IResourceDescription's URI sync [message #1723536 is a reply to message #1723240] Tue, 16 February 2016 13:23 Go to previous messageGo to next message
aurel pestell is currently offline aurel pestellFriend
Messages: 90
Registered: October 2013
Location: Sweden
Member
Thank you Christian,

Not sure I undertsand, I tried to follow your hints and I came up with this code:

public class DesagnMoveParticipant extends MoveParticipant {

	@Inject private IGlobalServiceProvider globalServiceProvider;
	@Inject private StatusWrapper status;
	@Inject @Named(Constants.LANGUAGE_NAME) private String languageName;

	private Set<Object> disabledTargets = newHashSet();
	@Inject private IRenameContextFactory renameContextFactory;
	@Inject private RefactoringResourceSetProvider resourceSetProvider;
	private static final Logger LOG = Logger.getLogger(AbstractProcessorBasedRenameParticipant.class);
	@Inject private RefactoringPreferences preferences;
	@Inject private SyncUtil syncUtil;
	@Inject private ProjectUtil projectUtil;
	private List<RenameProcessor> wrappedProcessors;

	File sourceFile;
	Folder destinationFolder;

	@Override
	protected boolean initialize(Object originalTargetElement) {
		RefactoringProcessor p = this.getProcessor();
		if (originalTargetElement instanceof File) {
			sourceFile = (File) originalTargetElement;
			MoveArguments mas = this.getArguments();
			if (mas.getDestination() instanceof Folder) {
				destinationFolder = (Folder) mas.getDestination();
			}
		}
		try {
			wrappedProcessors = getRenameProcessors(originalTargetElement);
			if (wrappedProcessors != null) {
				syncUtil.totalSync(preferences.isSaveAllBeforeRefactoring(), true, false);
				return true;
			}
		} catch (InterruptedException e) {
			return false;
		} catch (Exception exc) {
			status.add(ERROR, "Error initializing refactoring participant.", exc, LOG);
		}
		return false;

	}

	protected List<RenameProcessor> getRenameProcessors(Object originalTargetElement) {
		List<? extends IRenameElementContext> participantContexts = createRenameElementContexts(originalTargetElement);
		if (participantContexts != null) {
			List<RenameProcessor> processors = newArrayList();
			for (IRenameElementContext participantContext : participantContexts) {
				RenameProcessor renameProcessor = getRenameProcessor(participantContext);
				if (renameProcessor != null) {
					processors.add(renameProcessor);
				}
			}
			return processors;
		}
		return null;
	}

	protected RenameProcessor getRenameProcessor(IRenameElementContext participantContext) {
		IRenameRefactoringProvider renameRefactoringProvider = getRenameRefactoringProvider(participantContext);
		if (renameRefactoringProvider != null) {
			return renameRefactoringProvider.getRenameProcessor(participantContext);
		} else {
			return null;
		}
	}

	protected IRenameRefactoringProvider getRenameRefactoringProvider(IRenameElementContext renameElementContext) {
		return globalServiceProvider.findService(renameElementContext.getTargetElementURI(), IRenameRefactoringProvider.class);
	}

	private String trimFileExtension(String fileName) {
		if (fileName.lastIndexOf('.') == -1) {
			return fileName;
		}
		return fileName.substring(0, fileName.lastIndexOf('.'));
	}

	protected List<? extends IRenameElementContext> createRenameElementContexts(Object element) {

		IFile file = (IFile) element;
		final IPath filePath = file.getFullPath();
		String className = trimFileExtension(file.getName());

		ResourceSet resourceSet = resourceSetProvider.get(file.getProject());
		URI resourceURI = URI.createPlatformResourceURI(file.getFullPath().toString(), true);
		Resource resource = resourceSet.getResource(resourceURI, true);
		if (resource != null && !resource.getContents().isEmpty()) {
			for (ConceptDefinition type : EcoreUtil2.eAllOfType(resource.getContents().get(0), ConceptDefinition.class)) {
				if (className.equals(type.getName())) {
					IRenameElementContext renameElementContext = renameContextFactory.createRenameElementContext(type, null, null, (XtextResource) resource);
					if (renameElementContext instanceof IChangeRedirector.Aware) {
						((IChangeRedirector.Aware) renameElementContext).setChangeRedirector(new IChangeRedirector() {
							@Override
							public IPath getRedirectedPath(IPath source) {
								return source.equals(filePath) ? /*just4testing*/destinationFolder.getFullPath().append("/InsertSeat.concept") : source;
							}

						});
					}
					return java.util.Collections.singletonList(renameElementContext);
				}
			}
		}

		return java.util.Collections.emptyList();
	}

	@Override
	public String getName() {
		return languageName;
	}

	@Override
	public RefactoringStatus checkConditions(IProgressMonitor pm, CheckConditionsContext context) throws OperationCanceledException {
		SubMonitor progress = SubMonitor.convert(pm).setWorkRemaining(100 * wrappedProcessors.size());
		try {
			for (RenameProcessor wrappedProcessor : wrappedProcessors) {
				List<Object> targetElements = Arrays.asList(wrappedProcessor.getElements());
				if (!disabledTargets.containsAll(targetElements)) {
					setNewName(wrappedProcessor, getNewName());
					status.merge(wrappedProcessor.checkInitialConditions(progress.newChild(20)));
					if (!status.getRefactoringStatus().hasFatalError()) {
						status.merge(wrappedProcessor.checkFinalConditions(progress.newChild(80), context));
					}
				}
			}
		} catch (OperationCanceledException e) {
			throw e;
		} catch (Exception ce) {
			status.add(ERROR, "Error checking conditions in refactoring participant: {0}. See log for details", ce, LOG);
		}
		return status.getRefactoringStatus();
	}

	protected void setNewName(RenameProcessor processor, String newName) {
		((AbstractRenameProcessor) processor).setNewName(newName);
	}

	protected String getNewName() {
		return /*getArguments().getNewName()*/"Random_newname";
	}

	@Override
	public Change createChange(IProgressMonitor pm) throws CoreException, OperationCanceledException {
		CompositeChange compositeChange = null;
		try {
			SubMonitor subMonitor = SubMonitor.convert(pm, wrappedProcessors.size());
			for (RenameProcessor wrappedProcessor : wrappedProcessors) {
				if (!disabledTargets.containsAll(Arrays.asList(wrappedProcessor.getElements()))) {
					Change processorChange = wrappedProcessor.createChange(subMonitor.newChild(1));
					if (processorChange != null) {
						if (compositeChange == null) {
							compositeChange = new CompositeChange("Changes from participant: " + getName());
						}
						compositeChange.add(processorChange);
					}
				} else {
					subMonitor.worked(1);
				}
			}
		} catch (OperationCanceledException e) {
			throw e;
		} catch (Exception e) {
			throw new CoreException(new Status(IStatus.ERROR, YbaseActivator.YAPP_YBASE_YBASE, "Error creating change", e));
		} finally {
			dispose();
		}
		return compositeChange;
		/*RenameResourceChange rrc = new RenameResourceChange(sourceFile.getFullPath(), "SomeNAME");
		return rrc;*/
	}

	protected void dispose() {
		status = null;
		wrappedProcessors = null;
		disabledTargets.clear();
	}

}


When I try out that code by moving the file
"a90/desagn/insertseat/InsertSeat.concept"
to this package:
"a90/desagn/insertscrew/"
I get the following error message:
"End position lies outside document range"

Is it because of those ChangDirectors that might interfer with Eclipse's Move refactoring ?

[Updated on: Tue, 16 February 2016 13:40]

Report message to a moderator

Re: IResourceDescription's URI sync [message #1723542 is a reply to message #1723536] Tue, 16 February 2016 14:01 Go to previous messageGo to next message
aurel pestell is currently offline aurel pestellFriend
Messages: 90
Registered: October 2013
Location: Sweden
Member
It's a shame because it does perform very well the refactoring in the cross-references (like the import section in other files).
Re: IResourceDescription's URI sync [message #1723543 is a reply to message #1723542] Tue, 16 February 2016 14:05 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14664
Registered: July 2009
Senior Member
sry have no idea on that

Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: IResourceDescription's URI sync [message #1723548 is a reply to message #1723543] Tue, 16 February 2016 14:15 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14664
Registered: July 2009
Senior Member
p.s.:

can you share a minimal grammar as well so that i can try to reproduce


Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: IResourceDescription's URI sync [message #1723550 is a reply to message #1723548] Tue, 16 February 2016 14:44 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14664
Registered: July 2009
Senior Member
btw i asume you implemented the following false:

public IPath getRedirectedPath(IPath source) {
return source.equals(filePath) ? /*just4testing*/destinationFolder.getFullPath().append("/"+filePath.removeFileExtension().lastSegment()+ ".mydsl2") : source;
}

this should delived the moved file name


Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: IResourceDescription's URI sync [message #1723561 is a reply to message #1723550] Tue, 16 February 2016 15:02 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14664
Registered: July 2009
Senior Member
p.s.:

i asume you have something like a package in your dsl and the package in the project should be the same


Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: IResourceDescription's URI sync [message #1723563 is a reply to message #1723550] Tue, 16 February 2016 15:32 Go to previous messageGo to next message
aurel pestell is currently offline aurel pestellFriend
Messages: 90
Registered: October 2013
Location: Sweden
Member
Yes sorry it's just a temporaring implementation for a special testcase:
@Override
							public IPath getRedirectedPath(IPath source) {
								return source.equals(filePath) ? /*just4testing*/destinationFolder.getFullPath().append("/InsertSeat.concept") : source;
							}

I tried if I could reproduce in the domain example, but it works very well with that code:
public class DmodelMoveParticipant extends MoveParticipant {

	@Inject private IGlobalServiceProvider globalServiceProvider;
	@Inject private StatusWrapper status;
	@Inject @Named(Constants.LANGUAGE_NAME) private String languageName;

	private Set<Object> disabledTargets = newHashSet();
	@Inject private IRenameContextFactory renameContextFactory;
	@Inject private RefactoringResourceSetProvider resourceSetProvider;
	private static final Logger LOG = Logger.getLogger(AbstractProcessorBasedRenameParticipant.class);
	@Inject private RefactoringPreferences preferences;
	@Inject private SyncUtil syncUtil;
	@Inject private ProjectUtil projectUtil;
	private List<RenameProcessor> wrappedProcessors;

	File sourceFile;
	Folder destinationFolder;

	@Override
	protected boolean initialize(Object originalTargetElement) {
		RefactoringProcessor p = this.getProcessor();
		if (originalTargetElement instanceof File) {
			sourceFile = (File) originalTargetElement;
			MoveArguments mas = this.getArguments();
			if (mas.getDestination() instanceof Folder) {
				destinationFolder = (Folder) mas.getDestination();
			}
		}
		try {
			wrappedProcessors = getRenameProcessors(originalTargetElement);
			if (wrappedProcessors != null) {
				syncUtil.totalSync(preferences.isSaveAllBeforeRefactoring(), true, false);
				return true;
			}
		} catch (InterruptedException e) {
			return false;
		} catch (Exception exc) {
			status.add(ERROR, "Error initializing refactoring participant.", exc, LOG);
		}
		return false;

	}

	protected List<RenameProcessor> getRenameProcessors(Object originalTargetElement) {
		List<? extends IRenameElementContext> participantContexts = createRenameElementContexts(originalTargetElement);
		if (participantContexts != null) {
			List<RenameProcessor> processors = newArrayList();
			for (IRenameElementContext participantContext : participantContexts) {
				RenameProcessor renameProcessor = getRenameProcessor(participantContext);
				if (renameProcessor != null) {
					processors.add(renameProcessor);
				}
			}
			return processors;
		}
		return null;
	}

	protected RenameProcessor getRenameProcessor(IRenameElementContext participantContext) {
		IRenameRefactoringProvider renameRefactoringProvider = getRenameRefactoringProvider(participantContext);
		if (renameRefactoringProvider != null) {
			return renameRefactoringProvider.getRenameProcessor(participantContext);
		} else {
			return null;
		}
	}

	protected IRenameRefactoringProvider getRenameRefactoringProvider(IRenameElementContext renameElementContext) {
		return globalServiceProvider.findService(renameElementContext.getTargetElementURI(), IRenameRefactoringProvider.class);
	}

	private String trimFileExtension(String fileName) {
		if (fileName.lastIndexOf('.') == -1) {
			return fileName;
		}
		return fileName.substring(0, fileName.lastIndexOf('.'));
	}

	protected List<? extends IRenameElementContext> createRenameElementContexts(Object element) {

		IFile file = (IFile) element;
		final IPath filePath = file.getFullPath();
		String className = trimFileExtension(file.getName());

		ResourceSet resourceSet = resourceSetProvider.get(file.getProject());
		URI resourceURI = URI.createPlatformResourceURI(file.getFullPath().toString(), true);
		Resource resource = resourceSet.getResource(resourceURI, true);
		if (resource != null && !resource.getContents().isEmpty()) {
			for (Entity type : EcoreUtil2.eAllOfType(resource.getContents().get(0), Entity.class)) {
				if (className.equals(type.getName())) {
					IRenameElementContext renameElementContext = renameContextFactory.createRenameElementContext(type, null, null, (XtextResource) resource);
					if (renameElementContext instanceof IChangeRedirector.Aware) {
						((IChangeRedirector.Aware) renameElementContext).setChangeRedirector(new IChangeRedirector() {
							@Override
							public IPath getRedirectedPath(IPath source) {
								return source.equals(filePath) ? /*newPath*/destinationFolder.getFullPath().append("/MyEntity.dmodel") : source;
							}

						});
					}
					return java.util.Collections.singletonList(renameElementContext);
				}
			}
		}

		return java.util.Collections.emptyList();
	}

	@Override
	public String getName() {
		return languageName;
	}

	@Override
	public RefactoringStatus checkConditions(IProgressMonitor pm, CheckConditionsContext context) throws OperationCanceledException {
		SubMonitor progress = SubMonitor.convert(pm).setWorkRemaining(100 * wrappedProcessors.size());
		try {
			for (RenameProcessor wrappedProcessor : wrappedProcessors) {
				List<Object> targetElements = Arrays.asList(wrappedProcessor.getElements());
				if (!disabledTargets.containsAll(targetElements)) {
					setNewName(wrappedProcessor, getNewName());
					status.merge(wrappedProcessor.checkInitialConditions(progress.newChild(20)));
					if (!status.getRefactoringStatus().hasFatalError()) {
						status.merge(wrappedProcessor.checkFinalConditions(progress.newChild(80), context));
					}
				}
			}
		} catch (OperationCanceledException e) {
			throw e;
		} catch (Exception ce) {
			status.add(ERROR, "Error checking conditions in refactoring participant: {0}. See log for details", ce, LOG);
		}
		return status.getRefactoringStatus();
	}

	protected void setNewName(RenameProcessor processor, String newName) {
		((AbstractRenameProcessor) processor).setNewName(newName);
	}

	protected String getNewName() {
		return /*getArguments().getNewName()*/"InsertSeat2";
	}

	@Override
	public Change createChange(IProgressMonitor pm) throws CoreException, OperationCanceledException {
		CompositeChange compositeChange = null;
		try {
			SubMonitor subMonitor = SubMonitor.convert(pm, wrappedProcessors.size());
			for (RenameProcessor wrappedProcessor : wrappedProcessors) {
				if (!disabledTargets.containsAll(Arrays.asList(wrappedProcessor.getElements()))) {
					Change processorChange = wrappedProcessor.createChange(subMonitor.newChild(1));
					if (processorChange != null) {
						if (compositeChange == null) {
							compositeChange = new CompositeChange("Changes from participant: " + getName());
						}
						compositeChange.add(processorChange);
					}
				} else {
					subMonitor.worked(1);
				}
			}
		} catch (OperationCanceledException e) {
			throw e;
		} catch (Exception e) {
			throw new CoreException(new Status(IStatus.ERROR, DomainmodelActivator.ORG_ECLIPSE_XTEXT_EXAMPLE_DOMAINMODEL_DOMAINMODEL, "Error creating change", e));
		} finally {
			dispose();
		}
		return compositeChange;
		/*RenameResourceChange rrc = new RenameResourceChange(sourceFile.getFullPath(), "SomeNAME");
		return rrc;*/
	}

	protected void dispose() {
		status = null;
		wrappedProcessors = null;
		disabledTargets.clear();
	}

}


The file to be tested for the package to package drag-and-drop is named "MyEntity.dmodel":
package mypackage {
	entity MyEntity{
		
	}
}


Re: IResourceDescription's URI sync [message #1723564 is a reply to message #1723563] Tue, 16 February 2016 15:33 Go to previous messageGo to next message
aurel pestell is currently offline aurel pestellFriend
Messages: 90
Registered: October 2013
Location: Sweden
Member
So I think something could be wrong with our grammar,
I can try to make it minimal (but it inherits another grammar that itself inherits Xbase) and post a copy here.
Re: IResourceDescription's URI sync [message #1723566 is a reply to message #1723564] Tue, 16 February 2016 15:38 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14664
Registered: July 2009
Senior Member
can you please try without xbase as well

here is my grammar and impl

package org.xtext.example.mydsl2.ui;

import java.util.Arrays;
import java.util.List;
import java.util.Set;

import javax.inject.Inject;

import org.apache.log4j.Logger;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.ltk.core.refactoring.CompositeChange;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
import org.eclipse.ltk.core.refactoring.participants.MoveArguments;
import org.eclipse.ltk.core.refactoring.participants.MoveParticipant;
import org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor;
import org.eclipse.ltk.core.refactoring.participants.RenameProcessor;
import org.eclipse.xtext.Constants;
import org.eclipse.xtext.EcoreUtil2;
import org.eclipse.xtext.resource.IGlobalServiceProvider;
import org.eclipse.xtext.resource.XtextResource;
import org.eclipse.xtext.ui.refactoring.IChangeRedirector;
import org.eclipse.xtext.ui.refactoring.IRenameRefactoringProvider;
import org.eclipse.xtext.ui.refactoring.impl.AbstractProcessorBasedRenameParticipant;
import org.eclipse.xtext.ui.refactoring.impl.AbstractRenameProcessor;
import org.eclipse.xtext.ui.refactoring.impl.ProjectUtil;
import org.eclipse.xtext.ui.refactoring.impl.RefactoringResourceSetProvider;
import org.eclipse.xtext.ui.refactoring.impl.StatusWrapper;
import org.eclipse.xtext.ui.refactoring.ui.IRenameContextFactory;
import org.eclipse.xtext.ui.refactoring.ui.IRenameElementContext;
import org.eclipse.xtext.ui.refactoring.ui.RefactoringPreferences;
import org.eclipse.xtext.ui.refactoring.ui.SyncUtil;
import org.xtext.example.mydsl2.myDsl.Model;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.inject.name.Named;

public class DesagnMoveParticipant extends MoveParticipant {

	@Inject private IGlobalServiceProvider globalServiceProvider;
	@Inject private StatusWrapper status;
	@Inject @Named(Constants.LANGUAGE_NAME) private String languageName;

	private Set<Object> disabledTargets = Sets.newHashSet();
	@Inject private IRenameContextFactory renameContextFactory;
	@Inject private RefactoringResourceSetProvider resourceSetProvider;
	private static final Logger LOG = Logger.getLogger(AbstractProcessorBasedRenameParticipant.class);
	@Inject private RefactoringPreferences preferences;
	@Inject private SyncUtil syncUtil;
	@Inject private ProjectUtil projectUtil;
	private List<RenameProcessor> wrappedProcessors;

	IFile sourceFile;
	IFolder destinationFolder;

	@Override
	protected boolean initialize(Object originalTargetElement) {
		RefactoringProcessor p = this.getProcessor();
		if (originalTargetElement instanceof IFile) {
			sourceFile = (IFile) originalTargetElement;
			MoveArguments mas = this.getArguments();
			if (mas.getDestination() instanceof IFolder) {
				destinationFolder = (IFolder) mas.getDestination();
			}
		}
		try {
			wrappedProcessors = getRenameProcessors(originalTargetElement);
			if (wrappedProcessors != null) {
				syncUtil.totalSync(preferences.isSaveAllBeforeRefactoring(), true, false);
				return true;
			}
		} catch (InterruptedException e) {
			return false;
		} catch (Exception exc) {
			status.add(IStatus.ERROR, "Error initializing refactoring participant.", exc, LOG);
		}
		return false;

	}

	protected List<RenameProcessor> getRenameProcessors(Object originalTargetElement) {
		List<? extends IRenameElementContext> participantContexts = createRenameElementContexts(originalTargetElement);
		if (participantContexts != null) {
			List<RenameProcessor> processors = Lists.newArrayList();
			for (IRenameElementContext participantContext : participantContexts) {
				RenameProcessor renameProcessor = getRenameProcessor(participantContext);
				if (renameProcessor != null) {
					processors.add(renameProcessor);
				}
			}
			return processors;
		}
		return null;
	}

	protected RenameProcessor getRenameProcessor(IRenameElementContext participantContext) {
		IRenameRefactoringProvider renameRefactoringProvider = getRenameRefactoringProvider(participantContext);
		if (renameRefactoringProvider != null) {
			return renameRefactoringProvider.getRenameProcessor(participantContext);
		} else {
			return null;
		}
	}

	protected IRenameRefactoringProvider getRenameRefactoringProvider(IRenameElementContext renameElementContext) {
		return globalServiceProvider.findService(renameElementContext.getTargetElementURI(), IRenameRefactoringProvider.class);
	}

	private String trimFileExtension(String fileName) {
		if (fileName.lastIndexOf('.') == -1) {
			return fileName;
		}
		return fileName.substring(0, fileName.lastIndexOf('.'));
	}

	protected List<? extends IRenameElementContext> createRenameElementContexts(Object element) {

		IFile file = (IFile) element;
		final IPath filePath = file.getFullPath();
		String className = file.getLocation().removeFileExtension().removeLastSegments(1).lastSegment();

		ResourceSet resourceSet = resourceSetProvider.get(file.getProject());
		URI resourceURI = URI.createPlatformResourceURI(file.getFullPath().toString(), true);
		Resource resource = resourceSet.getResource(resourceURI, true);
		if (resource != null && !resource.getContents().isEmpty()) {
			for (org.xtext.example.mydsl2.myDsl.Package type : EcoreUtil2.eAllOfType(resource.getContents().get(0), org.xtext.example.mydsl2.myDsl.Package.class)) {
				if (className.equals(type.getName())) {
					IRenameElementContext renameElementContext = renameContextFactory.createRenameElementContext(type, null, null, (XtextResource) resource);
					if (renameElementContext instanceof IChangeRedirector.Aware) {
						((IChangeRedirector.Aware) renameElementContext).setChangeRedirector(new IChangeRedirector() {
							@Override
							public IPath getRedirectedPath(IPath source) {
								return source.equals(filePath) ? /*just4testing*/destinationFolder.getFullPath().append("/"+filePath.removeFileExtension().lastSegment()+ ".mydsl2") : source;
							}

						});
					}
					return java.util.Collections.singletonList(renameElementContext);
				}
			}
		}

		return java.util.Collections.emptyList();
	}

	@Override
	public String getName() {
		return languageName;
	}

	@Override
	public RefactoringStatus checkConditions(IProgressMonitor pm, CheckConditionsContext context) throws OperationCanceledException {
		SubMonitor progress = SubMonitor.convert(pm).setWorkRemaining(100 * wrappedProcessors.size());
		try {
			for (RenameProcessor wrappedProcessor : wrappedProcessors) {
				List<Object> targetElements = Arrays.asList(wrappedProcessor.getElements());
				if (!disabledTargets.containsAll(targetElements)) {
					setNewName(wrappedProcessor, getNewName());
					status.merge(wrappedProcessor.checkInitialConditions(progress.newChild(20)));
					if (!status.getRefactoringStatus().hasFatalError()) {
						status.merge(wrappedProcessor.checkFinalConditions(progress.newChild(80), context));
					}
				}
			}
		} catch (OperationCanceledException e) {
			throw e;
		} catch (Exception ce) {
			status.add(IStatus.ERROR, "Error checking conditions in refactoring participant: {0}. See log for details", ce, LOG);
		}
		return status.getRefactoringStatus();
	}

	protected void setNewName(RenameProcessor processor, String newName) {
		((AbstractRenameProcessor) processor).setNewName(newName);
	}

	protected String getNewName() {
		Object destination = getArguments().getDestination();
		if (destination instanceof IFolder) {
			return ((IFolder) destination).getLocation().lastSegment();
		}
		
		return /*getArguments().getNewName()*/"Random_newname";
	}

	@Override
	public Change createChange(IProgressMonitor pm) throws CoreException, OperationCanceledException {
		CompositeChange compositeChange = null;
		try {
			SubMonitor subMonitor = SubMonitor.convert(pm, wrappedProcessors.size());
			for (RenameProcessor wrappedProcessor : wrappedProcessors) {
				if (!disabledTargets.containsAll(Arrays.asList(wrappedProcessor.getElements()))) {
					Change processorChange = wrappedProcessor.createChange(subMonitor.newChild(1));
					if (processorChange != null) {
						if (compositeChange == null) {
							compositeChange = new CompositeChange("Changes from participant: " + getName());
						}
						compositeChange.add(processorChange);
					}
				} else {
					subMonitor.worked(1);
				}
			}
		} catch (OperationCanceledException e) {
			throw e;
		} catch (Exception e) {
			throw new CoreException(new Status(IStatus.ERROR, "org.xtext.example.mydsl2.ui", "Error creating change", e));
		} finally {
			dispose();
		}
		return compositeChange;
		/*RenameResourceChange rrc = new RenameResourceChange(sourceFile.getFullPath(), "SomeNAME");
		return rrc;*/
	}

	protected void dispose() {
		status = null;
		wrappedProcessors = null;
		disabledTargets.clear();
	}

}


Package:
	"package" name=ID";"
	model=Model
;

Model:
	"model" name=ID 
	"refs" refs+=Ref*
;

Ref:
	ref=[Model|FQN]
;



Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: IResourceDescription's URI sync [message #1723575 is a reply to message #1723566] Tue, 16 February 2016 16:30 Go to previous messageGo to next message
aurel pestell is currently offline aurel pestellFriend
Messages: 90
Registered: October 2013
Location: Sweden
Member
I did the test with your implementation and the grammar (just changed FQN to the QualifiedName rule)
and this is what happened with those two sample files:

in the package mydsl2.tests, there are 2 sample files:
1) MyModel.mydsl2:
package tests;

model MyModel
refs 


2) MyOtherModel.mydsl2:
package tests;

model MyOtherModel
refs tests.MyModel 


So I moved the 1st one into the package mydsl2.tests.target and got that result:

1) MyModel.mydsl2:
package target;

model MyModel
refs 


2) MyOtherModel.mydsl2:
package tests;

model MyOtherModel
refs target.MyModel 


==>No log in the console nor error message.



[Updated on: Tue, 16 February 2016 16:31]

Report message to a moderator

Re: IResourceDescription's URI sync [message #1723579 is a reply to message #1723575] Tue, 16 February 2016 16:33 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14664
Registered: July 2009
Senior Member
So it is what we intend?

Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: IResourceDescription's URI sync [message #1723581 is a reply to message #1723579] Tue, 16 February 2016 16:45 Go to previous messageGo to next message
aurel pestell is currently offline aurel pestellFriend
Messages: 90
Registered: October 2013
Location: Sweden
Member
Yes it's what I want thanks !
Just that I need to figure out why it does not work in my DSL ...
The grammar is quite big and I am not sure where to start Wink
Re: IResourceDescription's URI sync [message #1723584 is a reply to message #1723581] Tue, 16 February 2016 16:50 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14664
Registered: July 2009
Senior Member
i dont think it is a question of grammar
i had the same problem unless i fixed the participant


Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: IResourceDescription's URI sync [message #1723597 is a reply to message #1723584] Tue, 16 February 2016 17:26 Go to previous messageGo to next message
aurel pestell is currently offline aurel pestellFriend
Messages: 90
Registered: October 2013
Location: Sweden
Member
But I would like to change the namespace of my file and in the grammar it looks like that:

YbaseFile returns YbaseFile:
	syntheticName='namespace' namespace=QualifiedName 
	importSection=XImportSection?
	yclass=YbaseClass
;


If I understand correctly, in the participant, we give to the rename processor the new name of the target EObject that we want to modify:
protected void setNewName(RenameProcessor processor, String newName) {
		((AbstractRenameProcessor) processor).setNewName(newName);
	}


But in my grammar, the property is "namespace".
Re: IResourceDescription's URI sync [message #1723600 is a reply to message #1723597] Tue, 16 February 2016 17:33 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14664
Registered: July 2009
Senior Member
You have to subclass the currently bound rename strategy and override
getNameAttribute


Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: IResourceDescription's URI sync [message #1723607 is a reply to message #1723600] Tue, 16 February 2016 18:08 Go to previous messageGo to next message
aurel pestell is currently offline aurel pestellFriend
Messages: 90
Registered: October 2013
Location: Sweden
Member
So great it works very well now Smile

Here is how it looks in my rename strategy bound class:
	@Override
	protected org.eclipse.emf.ecore.EAttribute getNameAttribute(EObject targetElement) {
		if (targetElement instanceof YbaseFile) {
			SimpleAttributeResolver<EObject, String> propResolver = SimpleAttributeResolver.newResolver(String.class, "namespace");//.getAttribute(targetElement);
			return propResolver.getAttribute(targetElement);
		}
		return super.getNameAttribute(targetElement);
	};


Is it ok to do that ? Thanks !!
Re: IResourceDescription's URI sync [message #1723610 is a reply to message #1723607] Tue, 16 February 2016 18:23 Go to previous messageGo to next message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14664
Registered: July 2009
Senior Member
You can use the constants in yourdslpackage.litersls as well

Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Re: IResourceDescription's URI sync [message #1723666 is a reply to message #1723610] Wed, 17 February 2016 07:34 Go to previous messageGo to next message
aurel pestell is currently offline aurel pestellFriend
Messages: 90
Registered: October 2013
Location: Sweden
Member
Very last question, I have implicit imports in my DSL, so it means in some cases I need to add or remove some imports
in the impacted files. How could I introduce such a thing there ?

My grammar for imports:
YbaseFile returns YbaseFile:
	syntheticName='namespace' namespace=QualifiedName 
	importSection=XImportSection?
	yclass=YbaseClass
;

XImportDeclaration returns type::XImportDeclaration: 
	'import' importedType=[jvm::JvmDeclaredType|QualifiedName] 
;
Re: IResourceDescription's URI sync [message #1723667 is a reply to message #1723666] Wed, 17 February 2016 07:36 Go to previous message
Christian Dietrich is currently offline Christian DietrichFriend
Messages: 14664
Registered: July 2009
Senior Member
sry have no idea on this and not the time to digg

Twitter : @chrdietrich
Blog : https://www.dietrich-it.de
Previous Topic:Adding Additional Parameters to ContentAssistContext
Next Topic:remove referece from Content Assist
Goto Forum:
  


Current Time: Tue Apr 16 07:02:43 GMT 2024

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

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

Back to the top