/*******************************************************************************
* Copyright (c) 2005 - 2007 committers of openArchitectureWare and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* committers of openArchitectureWare - initial API and implementation
*******************************************************************************/
package org.eclipse.xpand.ui.refactoring.renamedefine;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
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.RefactoringParticipant;
import org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor;
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.xpand.ui.Messages;
import org.eclipse.xpand.ui.editor.XpandEditor;
import org.eclipse.xtend.shared.ui.Activator;
import org.eclipse.xtend.shared.ui.core.IXtendXpandProject;
import org.eclipse.xtend.shared.ui.core.search.SearchMatch;
import org.eclipse.xtend.shared.ui.core.search.XtendXpandSearchEngine;
/**
* RenameDefineProcessor creates the refactoring changes for rename
* refactorings.
*
* @author Peter Friese
* @author Dennis H�bner
*/
public class RenameDefineProcessor extends RefactoringProcessor {
private final XpandEditor editor;
private final ITextSelection selection;
private String newName;
/**
* Creates a new <code>RenameDefineProcessor</code>.
*
* @param selection
* @param editor
*/
public RenameDefineProcessor(XpandEditor editor, ITextSelection selection) {
this.editor = editor;
this.selection = selection;
}
/**
* {@inheritDoc}
*/
@Override
public RefactoringStatus checkFinalConditions(IProgressMonitor pm,
CheckConditionsContext context) throws CoreException,
OperationCanceledException {
return new RefactoringStatus();
}
/**
* {@inheritDoc}
*/
@Override
public RefactoringStatus checkInitialConditions(IProgressMonitor pm)
throws CoreException, OperationCanceledException {
IFile sourceFile = getSourceFile();
RefactoringStatus result = new RefactoringStatus();
if (sourceFile == null || !sourceFile.exists()) {
result.addFatalError(Messages.RenameDefineProcessor_NoSuchFile);
} else if (sourceFile.isReadOnly()) {
result.addFatalError(Messages.RenameDefineProcessor_FileReadonly);
} else if (findXtendXpandProject() == null) {
result
.addFatalError(Messages.RenameDefineProcessor_NotXpandXtendProject);
}
return result;
}
private IFile getSourceFile() {
IFile sourceFile = (IFile) editor.getEditorInput().getAdapter(
IFile.class);
return sourceFile;
}
private IXtendXpandProject findXtendXpandProject() {
return Activator.getExtXptModelManager().findProject(getSourceFile());
}
/**
* {@inheritDoc}
*/
@Override
public Change createChange(IProgressMonitor pm) throws CoreException,
OperationCanceledException {
CompositeChange result = new CompositeChange(
Messages.RenameDefineProcessor_CompositeChangeName);
IXtendXpandProject project = findXtendXpandProject();
String selectedText = selection.getText();
List<SearchMatch> references = XtendXpandSearchEngine
.findAllOccurrences(project, selectedText);
Map<IFile, TextFileChange> fileChanges = new HashMap<IFile, TextFileChange>();
for (SearchMatch match : references) {
TextFileChange fileChange = null;
if (fileChanges.containsKey(match.getFile())) {
fileChange = fileChanges.get(match.getFile());
} else {
fileChange = new TextFileChange(
Messages.RenameDefineProcessor_TextFileChangeName,
match.getFile());
MultiTextEdit fileChangeRootEdit = new MultiTextEdit();
fileChange.setEdit(fileChangeRootEdit);
fileChanges.put(match.getFile(), fileChange);
result.add(fileChange);
}
ReplaceEdit replaceSelectionEdit = new ReplaceEdit(match
.getOffSet() + 1, match.getLength(), newName);
fileChange.addEdit(replaceSelectionEdit);
TextEditGroup teg2 = new TextEditGroup(
Messages.RenameDefineProcessor_GroupDescription);
fileChange.addTextEditGroup(teg2);
teg2.addTextEdit(replaceSelectionEdit);
}
return result;
}
/**
* Returns <code>true</code> if the given character is a line delimiter
* character.
*
* @param ch
* the given character
* @return Returns <code>true</code> if this the character is a line
* delimiter character, <code>false</code> otherwise
*/
public static boolean isLineDelimiterChar(char ch) {
return ch == '\n' || ch == '\r';
}
/**
* {@inheritDoc}
*/
@Override
public Object[] getElements() {
return new Object[] { getSourceFile() };
}
/**
* {@inheritDoc}
*/
@Override
public String getIdentifier() {
return Messages.RenameDefineProcessor_ID;
}
/**
* {@inheritDoc}
*/
@Override
public String getProcessorName() {
return Messages.RenameDefineProcessor_ProcessorName;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isApplicable() throws CoreException {
return true;
}
public boolean validateNewName() {
// TODO (dennis) check if newName is a valid define name
return newName != null && !newName.trim().equals("")
&& !selection.getText().equals(newName);
}
/**
* {@inheritDoc}
*/
@Override
public RefactoringParticipant[] loadParticipants(RefactoringStatus status,
SharableParticipants sharedParticipants) throws CoreException {
return new RefactoringParticipant[0];
}
public void setNewName(String newName) {
this.newName = newName;
}
public ITextSelection getSelection() {
return selection;
}
}