blob: 493d58f9d45bd38b937cdfe2189bb32e212ed8f3 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012 Martin Reiterer, Alexej Strelzow.
* 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:
* Martin Reiterer - initial API and implementation
* Alexej Strelzow - seperation of ui/non-ui (methods moved from ASTUtils)
******************************************************************************/
package org.eclipse.babel.tapiji.tools.java.ui.util;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import org.eclipse.babel.core.configuration.DirtyHack;
import org.eclipse.babel.core.message.IMessagesBundle;
import org.eclipse.babel.core.message.IMessagesBundleGroup;
import org.eclipse.babel.core.message.manager.RBManager;
import org.eclipse.babel.tapiji.tools.core.Logger;
import org.eclipse.babel.tapiji.tools.core.ui.ResourceBundleManager;
import org.eclipse.babel.tapiji.tools.core.ui.dialogs.KeyRefactoringDialog;
import org.eclipse.babel.tapiji.tools.core.ui.dialogs.KeyRefactoringDialog.DialogConfiguration;
import org.eclipse.babel.tapiji.tools.core.ui.dialogs.KeyRefactoringSummaryDialog;
import org.eclipse.babel.tapiji.tools.core.ui.utils.LocaleUtils;
import org.eclipse.babel.tapiji.tools.java.ui.refactoring.Cal10nEnumRefactoringVisitor;
import org.eclipse.babel.tapiji.tools.java.ui.refactoring.Cal10nRefactoringVisitor;
import org.eclipse.babel.tapiji.tools.java.ui.refactoring.PrimitiveRefactoringVisitor;
import org.eclipse.babel.tapiji.tools.java.util.ASTutils;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IOpenable;
import org.eclipse.jdt.core.ITypeRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.ExpressionStatement;
import org.eclipse.jdt.core.dom.ImportDeclaration;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
import org.eclipse.jdt.ui.SharedASTProvider;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.swt.widgets.Display;
import org.eclipse.text.edits.MalformedTreeException;
import org.eclipse.text.edits.TextEdit;
public class ASTutilsUI {
public static CompilationUnit getCompilationUnit(IResource resource) {
IJavaElement je = JavaCore.create(resource,
JavaCore.create(resource.getProject()));
// get the type of the currently loaded resource
ITypeRoot typeRoot = ((ICompilationUnit) je);
if (typeRoot == null) {
return null;
}
return getCompilationUnit(typeRoot);
}
public static CompilationUnit getCompilationUnit(ITypeRoot typeRoot) {
// get a reference to the shared AST of the loaded CompilationUnit
CompilationUnit cu = SharedASTProvider.getAST(typeRoot,
// do not wait for AST creation
SharedASTProvider.WAIT_YES, null);
return cu;
}
public static String insertNewBundleRef(IDocument document,
IResource resource, int startPos, int endPos,
String resourceBundleId, String key) {
boolean createRBReference = false;
String reference = "";
CompilationUnit cu = getCompilationUnit(resource);
AST ast = cu.getAST();
ASTRewrite rewriter = ASTRewrite.create(ast);
String variableName = ASTutils.resolveRBReferenceVar(document,
resource, startPos, resourceBundleId, cu);
if (variableName == null) {
variableName = ASTutils.getNonExistingRBRefName(resourceBundleId, cu);
createRBReference = true;
}
//try {
reference = ASTutils.createResourceReference(resourceBundleId, key,
null, resource, startPos, variableName, ast, rewriter, cu);
if (startPos > 0 && document.get().charAt(startPos - 1) == '\"') {
startPos--;
endPos++;
}
if ((startPos + endPos) < document.getLength()
&& document.get().charAt(startPos + endPos) == '\"') {
endPos++;
}
if ((startPos + endPos) < document.getLength()
&& document.get().charAt(startPos + endPos - 1) == ';') {
endPos--;
}
//document.replace(startPos, endPos, reference);
// create non-internationalisation-comment
//ASTutils.createReplaceNonInternationalisationComment(cu, document,
// startPos);
//} catch (BadLocationException e) {
// e.printStackTrace();
//}
if (createRBReference) {
ASTutils.createResourceBundleReference(resource, startPos,
document, resourceBundleId, null, true, variableName, cu, ast, rewriter);
}
// computation of the text edits
TextEdit edits = rewriter.rewriteAST(document, null);
// computation of the new source code
try {
edits.apply(document);
} catch (MalformedTreeException e) {
Logger.logError(e);
} catch (BadLocationException e) {
Logger.logError(e);
}
return reference;
}
public static String insertExistingBundleRef(IDocument document,
IResource resource, int offset, int length,
String resourceBundleId, String key, Locale locale) {
boolean createRBReference = false;
String reference = "";
CompilationUnit cu = getCompilationUnit(resource);
AST ast = cu.getAST();
ASTRewrite rewriter = ASTRewrite.create(ast);
String variableName = ASTutils.resolveRBReferenceVar(document,
resource, offset, resourceBundleId, cu);
if (variableName == null) {
variableName = ASTutils.getNonExistingRBRefName(resourceBundleId, cu);
createRBReference = true;
}
reference = ASTutils.createResourceReference(resourceBundleId, key,
locale, resource, offset, variableName, ast, rewriter, cu);
//try {
// document.replace(offset, length, reference);
//} catch (BadLocationException e) {
// Logger.logError(e);
// return null;
//}
// create non-internationalisation-comment
//ASTutils.createReplaceNonInternationalisationComment(cu, document,
// offset);
// TODO retrieve cu in the same way as in createResourceReference
// the current version does not parse method bodies
if (createRBReference) {
ASTutils.createResourceBundleReference(resource, offset, document,
resourceBundleId, locale, true, variableName, cu, ast, rewriter);
}
// computation of the text edits
TextEdit edits = rewriter.rewriteAST(document, null);
// computation of the new source code
try {
edits.apply(document);
} catch (MalformedTreeException e) {
Logger.logError(e);
} catch (BadLocationException e) {
Logger.logError(e);
}
return reference;
}
/**
* Performs the refactoring of messages key. The key can be a {@link String}
* or an Enumeration! If it is an enumeration, then the enumPath needs to be
* provided!
*
* @param projectName
* The name of the project, where the resource bundle file is in
* @param resourceBundleId
* The Id of the resource bundle, which contains the old key
* @param selectedLocale
* The {@link Locale} to change
* @param oldKey
* The name of the key to change
* @param newKey
* The name of the key, which replaces the old one
* @param enumPath
* The path of the enum file (needs:
* {@link IPath#toPortableString()})
*/
public static void refactorKey(final String projectName,
final String resourceBundleId, final String selectedLocale,
final String oldKey, final String newKey, final String enumPath) {
// contains file and line
final List<String> changeSet = new ArrayList<String>();
ResourceBundleManager manager = ResourceBundleManager
.getManager(projectName);
IProject project = manager.getProject();
try {
project.accept(new IResourceVisitor() {
/**
* First step of filtering. Only classes, which import
* java.util.ResourceBundle or ch.qos.cal10n.MessageConveyor
* will be changed. An exception is the enum file, which gets
* referenced by the Cal10n framework.
*
* {@inheritDoc}
*/
@Override
public boolean visit(IResource resource) throws CoreException {
if (!(resource instanceof IFile)
|| !resource.getFileExtension().equals("java")) {
return true;
}
final CompilationUnit cu = getCompilationUnit(resource);
// step 1: import filter
for (Object obj : cu.imports()) {
ImportDeclaration imp = (ImportDeclaration) obj;
String importName = imp.getName().toString();
if ("java.util.ResourceBundle".equals(importName)) {
PrimitiveRefactoringVisitor prv = new PrimitiveRefactoringVisitor(
cu, resourceBundleId, oldKey, newKey,
changeSet);
cu.accept(prv);
prv.saveChanges();
break;
} else if ("ch.qos.cal10n.MessageConveyor"
.equals(importName)) { // Cal10n
Cal10nRefactoringVisitor crv = new Cal10nRefactoringVisitor(
cu, oldKey, newKey, enumPath, changeSet);
cu.accept(crv);
crv.saveChanges();
break;
}
}
return false;
}
});
} catch (CoreException e) {
Logger.logError(e);
}
if (enumPath != null) { // Cal10n support, change the enum file
IFile file = project.getFile(enumPath.substring(project.getName()
.length() + 1));
final CompilationUnit enumCu = getCompilationUnit(file);
Cal10nEnumRefactoringVisitor enumVisitor = new Cal10nEnumRefactoringVisitor(
enumCu, oldKey, newKey, changeSet);
enumCu.accept(enumVisitor);
}
// change backend
RBManager rbManager = RBManager.getInstance(projectName);
IMessagesBundleGroup messagesBundleGroup = rbManager
.getMessagesBundleGroup(resourceBundleId);
DirtyHack.setFireEnabled(false); // now the editor won't get dirty
// but with this change, we have to write it manually down ->
// rbManager.writeToFile
if (KeyRefactoringDialog.ALL_LOCALES.equals(selectedLocale)) {
messagesBundleGroup.renameMessageKeys(oldKey, newKey);
} else {
IMessagesBundle messagesBundle = messagesBundleGroup
.getMessagesBundle(LocaleUtils.getLocaleByDisplayName(
manager.getProvidedLocales(resourceBundleId),
selectedLocale));
messagesBundle.renameMessageKey(oldKey, newKey);
// rbManager.fireResourceChanged(messagesBundle); ??
}
DirtyHack.setFireEnabled(true);
rbManager.fireEditorChanged(); // notify Resource Bundle View
rbManager.writeToFile(rbManager
.getMessagesBundleGroup(resourceBundleId));
// show the summary dialog
KeyRefactoringSummaryDialog summaryDialog = new KeyRefactoringSummaryDialog(
Display.getDefault().getActiveShell());
DialogConfiguration config = summaryDialog.new DialogConfiguration();
config.setPreselectedKey(oldKey);
config.setNewKey(newKey);
config.setPreselectedBundle(resourceBundleId);
config.setProjectName(projectName);
summaryDialog.setDialogConfiguration(config);
summaryDialog.setChangeSet(changeSet);
summaryDialog.open();
}
}