First, there is the rename processor "RenameProcessor.java":
package mysomething.refactoring.rename;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.jface.text.ITextSelection;
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.TextFileChange;
import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
import org.eclipse.ltk.core.refactoring.participants.ProcessorBasedRefactoring;
import org.eclipse.ltk.core.refactoring.participants.RefactoringParticipant;
import org.eclipse.ltk.core.refactoring.participants.SharableParticipants;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.ReplaceEdit;
import org.eclipse.text.edits.TextEditGroup;
import org.eclipse.xtext.parsetree.CompositeNode;
import org.eclipse.xtext.parsetree.NodeAdapter;
import org.eclipse.xtext.parsetree.NodeUtil;
import org.eclipse.xtext.resource.EObjectAtOffsetHelper;
import org.eclipse.xtext.resource.IEObjectDescription;
import org.eclipse.xtext.resource.IReferenceDescription;
import org.eclipse.xtext.resource.IResourceDescription;
import org.eclipse.xtext.resource.IResourceDescriptions;
import org.eclipse.xtext.resource.XtextResource;
import org.eclipse.xtext.ui.core.editor.XtextEditor;
import org.eclipse.xtext.util.concurrent.IUnitOfWork;
import mysomething.Rule;
import mysomething.RuleReference;
import mysomething.utils.EObjectResolver;
import mysomething.utils.URIFragmentResolver;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
public class RenameProcessor extends
org.eclipse.ltk.core.refactoring.participants.RenameProcessor {
private XtextEditor editor;
private IResourceDescriptions resourceDescriptions;
private List<CompositeNode> references = null;
private String currentName;
private CompositeNode declaration;
private IFile file;
public RenameProcessor(XtextEditor editor,
IResourceDescriptions resourceDescriptions) {
this.editor = editor;
this.resourceDescriptions = resourceDescriptions;
final ITextSelection selection = (ITextSelection) editor
.getSelectionProvider().getSelection();
final IEObjectDescription eObjectDescription = editor.getDocument()
.readOnly(new EObjectResolver(selection, resourceDescriptions));
declaration = editor.getDocument().readOnly(
new URIFragmentResolver(eObjectDescription.getEObjectURI()
.fragment()));
if (declaration.getElement() instanceof Rule) {
Rule r = (Rule) declaration.getElement();
currentName = r.getName();
}
file = (IFile) editor.getEditorInput().getAdapter(IFile.class);
if (eObjectDescription != null) {
references = findReferenceDescriptions(eObjectDescription);
}
}
@Override
public Object[] getElements() {
return null;
}
@Override
public String getIdentifier() {
return "Rename Processor Identifier";
}
@Override
public String getProcessorName() {
return "Rename Processor";
}
@Override
public boolean isApplicable() throws CoreException {
return (references != null);
}
@Override
public RefactoringStatus checkInitialConditions(IProgressMonitor pm)
throws CoreException, OperationCanceledException {
RefactoringStatus status = new RefactoringStatus();
if (references == null)
status.addFatalError("Could not obtain references!");
return status;
}
@Override
public RefactoringStatus checkFinalConditions(IProgressMonitor pm,
CheckConditionsContext context) throws CoreException,
OperationCanceledException {
RefactoringStatus status = new RefactoringStatus();
RenameRefactoring refactoring = (RenameRefactoring) getRefactoring();
if (currentName.equals(refactoring.getRenameText())) {
status.addFatalError("Name unchanged!");
} else if (refactoring.getRenameText().length() <= 0) {
status.addFatalError("name must not be empty!");
}
return status;
}
@Override
public Change createChange(IProgressMonitor pm) throws CoreException,
OperationCanceledException {
CompositeChange compositeChange = new CompositeChange("Rename");
pm.beginTask("Rename Refactoring", references.size());
MultiTextEdit multiEdit = new MultiTextEdit();
TextFileChange fileChange = new TextFileChange("Declaraction Renaming", file);
fileChange.setEdit(multiEdit);
fileChange.setTextType("bnf");
compositeChange.add(fileChange);
RenameRefactoring refactoring = (RenameRefactoring) getRefactoring();
String replaceText = refactoring.getRenameText();
ReplaceEdit replaceEdit = new ReplaceEdit(declaration.getOffset(), ((Rule)declaration.getElement()).getName().length(), replaceText);
multiEdit.addChild(replaceEdit);
TextEditGroup editGroup = new TextEditGroup("declaration update", replaceEdit);
fileChange.addTextEditGroup(editGroup);
pm.worked(1);
for (int i=0; i < references.size(); i++) {
CompositeNode reference = references.get(i);
replaceEdit = new ReplaceEdit(reference.getOffset(), ((Rule)declaration.getElement()).getName().length(), replaceText);
multiEdit.addChild(replaceEdit);
editGroup = new TextEditGroup("reference update", replaceEdit);
fileChange.addTextEditGroup(editGroup);
pm.worked(1);
}
return compositeChange;
}
@Override
public RefactoringParticipant[] loadParticipants(RefactoringStatus status,
SharableParticipants sharedParticipants) throws CoreException {
return null;
}
private List<CompositeNode> findReferenceDescriptions(
final IEObjectDescription eObjectDescription) {
List<CompositeNode> references = new ArrayList<CompositeNode>();
for (IResourceDescription resourceDescription : resourceDescriptions
.getAllResourceDescriptions()) {
Iterable<IReferenceDescription> matchingReferenceDescriptors = Iterables
.filter(resourceDescription.getReferenceDescriptions(),
new Predicate<IReferenceDescription>() {
public boolean apply(IReferenceDescription input) {
return eObjectDescription
.getEObjectURI()
.equals(input.getTargetEObjectUri());
}
});
for (IReferenceDescription matchingReferenceDescription : matchingReferenceDescriptors) {
CompositeNode node = editor.getDocument().readOnly(
new URIFragmentResolver(matchingReferenceDescription
.getSourceEObjectUri().fragment()));
references.add(node);
}
}
return references;
}
private IFile getProjectFile(String filename) {
IWorkspace ws = ResourcesPlugin.getWorkspace();
IWorkspaceRoot root = ws.getRoot();
IProject project = root.getProject();
IFile file = null;
if (project == null) {
IPath path = ws.getRoot().findMember(filename).getFullPath();
file = ws.getRoot().getFile(path);
} else {
file = project.getFile(filename);
}
return file;
}
}
The handler called from the command "RenameRefactoringHandler.java":
package mysomething.refactoring.rename;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.ltk.ui.refactoring.RefactoringWizard;
import org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.handlers.HandlerUtil;
import org.eclipse.xtext.parsetree.CompositeNode;
import org.eclipse.xtext.resource.IEObjectDescription;
import org.eclipse.xtext.resource.IResourceDescriptions;
import org.eclipse.xtext.ui.core.editor.XtextEditor;
import mysomething.Rule;
import mysomething.utils.EObjectResolver;
import mysomething.utils.URIFragmentResolver;
import com.google.inject.Inject;
public class RenameRefactoringHandler extends AbstractHandler {
@Inject
private IResourceDescriptions resourceDescriptions;
@Override
public Object execute(ExecutionEvent event) throws ExecutionException {
try {
String currentName = "";
XtextEditor editor = (XtextEditor) HandlerUtil
.getActiveEditor(event);
final ITextSelection selection = (ITextSelection) editor
.getSelectionProvider().getSelection();
final IEObjectDescription eObjectDescription = editor
.getDocument()
.readOnly(
new EObjectResolver(selection, resourceDescriptions));
CompositeNode o = editor.getDocument().readOnly(
new URIFragmentResolver(eObjectDescription.getEObjectURI()
.fragment()));
if (o.getElement() instanceof Rule) {
Rule r = (Rule) o.getElement();
currentName = r.getName();
}
RenameProcessor processor = new RenameProcessor(editor,
resourceDescriptions);
RenameRefactoring refactoring = new RenameRefactoring(processor);
RenameRefactoringWizard wizard = new RenameRefactoringWizard(
refactoring, RefactoringWizard.WIZARD_BASED_USER_INTERFACE);
wizard.setRenameText(currentName);
RefactoringWizardOpenOperation openOperation = new RefactoringWizardOpenOperation(
wizard);
openOperation.run(Display.getCurrent().getActiveShell(),
"Refactoring not possible!");
} catch (Exception e) {
MessageDialog.openInformation(
Display.getDefault().getActiveShell(),
"Rename Refactoring",
"Error while applying refactoring to workbench/wizard: "
+ e.getMessage());
e.printStackTrace();
}
return null;
}
}
and we have the two gui classes "RenameRefactoringWizard.java" and "RenamePageComposite.java":
package mysomething.refactoring.rename;
import org.eclipse.jface.wizard.IWizardPage;
import org.eclipse.ltk.core.refactoring.Refactoring;
import org.eclipse.ltk.ui.refactoring.RefactoringWizard;
import org.eclipse.ltk.ui.refactoring.UserInputWizardPage;
import org.eclipse.swt.widgets.Composite;
public class RenameRefactoringWizard extends RefactoringWizard {
private RenameInputWizardPage wizardPage;
private String renameText = "";
public RenameRefactoringWizard(Refactoring refactoring, int flags) {
super(refactoring, flags);
}
@Override
protected void addUserInputPages() {
wizardPage = new RenameInputWizardPage("Refactoring");
wizardPage.setRenameText(renameText);
addPage(wizardPage);
}
public void setRenameText(String s) {
renameText = s;
if (wizardPage != null)
wizardPage.setRenameText(s);
}
static class RenameInputWizardPage extends UserInputWizardPage {
private RenamePageComposite composite;
private String renameText;
public RenameInputWizardPage(String name) {
super(name);
setTitle("Rename Refactoring");
setDescription("Automated Refactoring to rename rule names, rule references etc."
+ " with the possibility to automatically update references");
}
public void createControl(Composite parent) {
composite = new RenamePageComposite(parent, 0);
composite.getRenameText().setText(renameText);
composite.getRenameText().selectAll();
setControl(composite);
}
public String getRenameText() {
return composite.getRenameText().getText();
}
public void setRenameText(String s) {
renameText = s;
if (composite != null)
composite.getRenameText().setText(renameText);
}
@Override
public IWizardPage getNextPage() {
RenameRefactoring refactoring = (RenameRefactoring) getRefactoring();
if (refactoring != null) {
refactoring.setRenameText(getRenameText());
}
return super.getNextPage();
}
@Override
protected boolean performFinish() {
RenameRefactoring refactoring = (RenameRefactoring) getRefactoring();
if (refactoring != null) {
refactoring.setRenameText(getRenameText());
}
return super.performFinish();
}
}
}
package mysomething.refactoring.rename;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
public class RenamePageComposite extends Composite {
private Text renameText;
public RenamePageComposite(Composite parent, int style) {
super(parent, style);
final GridLayout gridLayout = new GridLayout();
setLayout(gridLayout);
final Composite composite = new Composite(this, SWT.NONE);
composite.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING,
true, false));
final GridLayout gridLayout_1 = new GridLayout();
gridLayout_1.numColumns = 2;
composite.setLayout(gridLayout_1);
final Label renameLabel = new Label(composite, SWT.NONE);
renameLabel.setLayoutData(new GridData(GridData.BEGINNING,
GridData.CENTER, false, true));
renameLabel.setText("New Name:");
renameText = new Text(composite, SWT.BORDER);
renameText.setLayoutData(new GridData(GridData.FILL, GridData.CENTER,
true, true));
}
@Override
public void dispose() {
super.dispose();
}
public Text getRenameText() {
return renameText;
}
}
Finally, two helper classes that deal with the EObject stuff:
package mysomething.utils;
import java.util.Iterator;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.xtext.resource.EObjectAtOffsetHelper;
import org.eclipse.xtext.resource.IEObjectDescription;
import org.eclipse.xtext.resource.IResourceDescription;
import org.eclipse.xtext.resource.IResourceDescriptions;
import org.eclipse.xtext.resource.XtextResource;
import org.eclipse.xtext.util.concurrent.IUnitOfWork;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
public class EObjectResolver implements
IUnitOfWork<IEObjectDescription, XtextResource> {
private final ITextSelection selection;
private IResourceDescriptions resourceDescriptions;
public EObjectResolver(ITextSelection selection,
IResourceDescriptions resourceDescriptions) {
this.selection = selection;
this.resourceDescriptions = resourceDescriptions;
}
public IEObjectDescription exec(XtextResource state) throws Exception {
EObject element = EObjectAtOffsetHelper.resolveElementAt(state,
selection.getOffset(), null);
if (element != null) {
final URI eObjectURI = EcoreUtil.getURI(element);
IResourceDescription resourceDescription = resourceDescriptions
.getResourceDescription(eObjectURI.trimFragment());
if (resourceDescription != null) {
Iterator<IEObjectDescription> eObjectDescriptions = Iterables
.filter(resourceDescription.getExportedObjects(),
new Predicate<IEObjectDescription>() {
public boolean apply(
IEObjectDescription input) {
return input.getEObjectURI().equals(
eObjectURI);
}
}).iterator();
if (eObjectDescriptions.hasNext()) {
return eObjectDescriptions.next();
}
}
}
return null;
}
}
package mysomething.utils;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.parsetree.CompositeNode;
import org.eclipse.xtext.parsetree.NodeAdapter;
import org.eclipse.xtext.parsetree.NodeUtil;
import org.eclipse.xtext.resource.XtextResource;
import org.eclipse.xtext.util.concurrent.IUnitOfWork;
public class URIFragmentResolver implements
IUnitOfWork<CompositeNode, XtextResource> {
private String uriFragment;
public URIFragmentResolver(String uriFragment) {
this.uriFragment = uriFragment;
}
@Override
public CompositeNode exec(XtextResource state) throws Exception {
EObject o = state.getEObject(uriFragment);
NodeAdapter node = NodeUtil.getNodeAdapter(o);
return node.getParserNode();
}
}