blob: 1994bc283166f877ad40ac0d3d55c0239de31057 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2006 IBM Corporation 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.ui.actions;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.runtime.CoreException;
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.SubProgressMonitor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.ui.IWorkbenchSite;
import org.eclipse.ui.PlatformUI;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.compiler.InvalidInputException;
import org.eclipse.jdt.internal.corext.refactoring.RefactoringAvailabilityTester;
import org.eclipse.jdt.internal.corext.refactoring.nls.NLSElement;
import org.eclipse.jdt.internal.corext.refactoring.nls.NLSLine;
import org.eclipse.jdt.internal.corext.refactoring.nls.NLSRefactoring;
import org.eclipse.jdt.internal.corext.refactoring.nls.NLSScanner;
import org.eclipse.jdt.internal.corext.refactoring.reorg.ReorgUtils;
import org.eclipse.jdt.internal.corext.refactoring.util.ResourceUtil;
import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
import org.eclipse.jdt.internal.corext.util.Messages;
import org.eclipse.jdt.ui.JavaElementLabelProvider;
import org.eclipse.jdt.internal.ui.IJavaHelpContextIds;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.internal.ui.actions.ActionMessages;
import org.eclipse.jdt.internal.ui.actions.ActionUtil;
import org.eclipse.jdt.internal.ui.actions.SelectionConverter;
import org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitEditor;
import org.eclipse.jdt.internal.ui.refactoring.actions.ListDialog;
import org.eclipse.jdt.internal.ui.refactoring.actions.RefactoringStarter;
import org.eclipse.jdt.internal.ui.refactoring.nls.ExternalizeWizard;
import org.eclipse.jdt.internal.ui.util.ExceptionHandler;
/**
* Externalizes the strings of a compilation unit or find all strings
* in a package or project that are not externalized yet. Opens a wizard that
* gathers additional information to externalize the strings.
* <p>
* The action is applicable to structured selections containing elements
* of type <code>ICompilationUnit</code>, <code>IType</code>, <code>IJavaProject</code>,
* <code>IPackageFragment</code>, and <code>IPackageFragmentRoot</code>
*
* <p>
* This class may be instantiated; it is not intended to be subclassed.
* </p>
*
* @since 2.0
*/
public class ExternalizeStringsAction extends SelectionDispatchAction {
private CompilationUnitEditor fEditor;
private NonNLSElement[] fElements;
/**
* Creates a new <code>ExternalizeStringsAction</code>. The action requires
* that the selection provided by the site's selection provider is of type <code>
* org.eclipse.jface.viewers.IStructuredSelection</code>.
*
* @param site the site providing context information for this action
*/
public ExternalizeStringsAction(IWorkbenchSite site) {
super(site);
setText(ActionMessages.ExternalizeStringsAction_label);
PlatformUI.getWorkbench().getHelpSystem().setHelp(this, IJavaHelpContextIds.EXTERNALIZE_STRINGS_ACTION);
}
/**
* Note: This constructor is for internal use only. Clients should not call this constructor.
* @param editor the compilation unit editor
*/
public ExternalizeStringsAction(CompilationUnitEditor editor) {
this(editor.getEditorSite());
fEditor= editor;
setEnabled(fEditor != null && SelectionConverter.canOperateOn(fEditor));
}
/* (non-Javadoc)
* Method declared on SelectionDispatchAction.
*/
public void selectionChanged(ITextSelection selection) {
}
/* (non-Javadoc)
* Method declared on SelectionDispatchAction.
*/
public void selectionChanged(IStructuredSelection selection) {
try {
setEnabled(RefactoringAvailabilityTester.isExternalizeStringsAvailable(selection));
} catch (JavaModelException e) {
if (JavaModelUtil.isExceptionToBeLogged(e))
JavaPlugin.log(e);
setEnabled(false);//no UI - happens on selection changes
}
}
/* (non-Javadoc)
* Method declared on SelectionDispatchAction.
*/
public void run(ITextSelection selection) {
IJavaElement element= SelectionConverter.getInput(fEditor);
if (!(element instanceof ICompilationUnit))
return;
run((ICompilationUnit)element);
}
/* (non-Javadoc)
* Method declared on SelectionDispatchAction.
*/
public void run(IStructuredSelection selection) {
ICompilationUnit unit= getCompilationUnit(selection);
if (unit != null) {//run on cu
run(unit);
} else {
//run on multiple
try {
PlatformUI.getWorkbench().getProgressService().run(true, true, createRunnable(selection));
} catch(InvocationTargetException e) {
ExceptionHandler.handle(e, getShell(),
ActionMessages.FindStringsToExternalizeAction_dialog_title,
ActionMessages.FindStringsToExternalizeAction_error_message);
return;
} catch(InterruptedException e) {
// OK
return;
}
showResults();
}
}
/**
* Note: this method is for internal use only. Clients should not call this method.
*/
public void run(final ICompilationUnit unit) {
if (!ActionUtil.isProcessable(getShell(), unit))
return;
BusyIndicator.showWhile(getShell().getDisplay(), new Runnable() {
public void run() {
try {
if (unit != null && unit.exists()) {
NLSRefactoring refactoring= NLSRefactoring.create(unit);
if (refactoring != null)
new RefactoringStarter().activate(refactoring, new ExternalizeWizard(refactoring), getShell(), ActionMessages.ExternalizeStringsAction_dialog_title, true);
}
} catch(JavaModelException e) {
ExceptionHandler.handle(e, getShell(), ActionMessages.ExternalizeStringsAction_dialog_title, ActionMessages.ExternalizeStringsAction_dialog_message);
}
}
});
}
private static ICompilationUnit getCompilationUnit(IStructuredSelection selection) {
if (selection.isEmpty() || selection.size() != 1)
return null;
Object first= selection.getFirstElement();
if (first instanceof ICompilationUnit)
return (ICompilationUnit) first;
if (first instanceof IType)
return ((IType) first).getCompilationUnit();
return null;
}
private IRunnableWithProgress createRunnable(final IStructuredSelection selection) {
return new IRunnableWithProgress() {
public void run(IProgressMonitor pm) throws InvocationTargetException {
try {
fElements= doRun(selection, pm);
} catch (CoreException e) {
throw new InvocationTargetException(e);
}
}
};
}
private NonNLSElement[] doRun(IStructuredSelection selection, IProgressMonitor pm) throws CoreException {
List elements= getSelectedElementList(selection);
if (elements == null || elements.isEmpty())
return new NonNLSElement[0];
pm.beginTask(ActionMessages.FindStringsToExternalizeAction_find_strings, elements.size());
try{
List result= new ArrayList();
for (Iterator iter= elements.iterator(); iter.hasNext();) {
Object obj= iter.next();
if (obj instanceof IJavaElement) {
IJavaElement element= (IJavaElement) obj;
int elementType= element.getElementType();
if (elementType == IJavaElement.PACKAGE_FRAGMENT) {
result.addAll(analyze((IPackageFragment) element, new SubProgressMonitor(pm, 1)));
} else if (elementType == IJavaElement.PACKAGE_FRAGMENT_ROOT) {
IPackageFragmentRoot root= (IPackageFragmentRoot)element;
if (!root.isExternal() && !ReorgUtils.isClassFolder(root)) {
result.addAll(analyze((IPackageFragmentRoot) element, new SubProgressMonitor(pm, 1)));
} else {
pm.worked(1);
}
} else if (elementType == IJavaElement.JAVA_PROJECT) {
result.addAll(analyze((IJavaProject) element, new SubProgressMonitor(pm, 1)));
} else if (elementType == IJavaElement.COMPILATION_UNIT) {
ICompilationUnit cu= (ICompilationUnit)element;
if (cu.exists()) {
NonNLSElement nlsElement= analyze(cu);
if (nlsElement != null) {
result.add(nlsElement);
}
}
pm.worked(1);
} else if (elementType == IJavaElement.TYPE) {
IType type= (IType)element;
ICompilationUnit cu= type.getCompilationUnit();
if (cu != null && cu.exists()) {
NonNLSElement nlsElement= analyze(cu);
if (nlsElement != null) {
result.add(nlsElement);
}
}
pm.worked(1);
} else {
pm.worked(1);
}
} else {
pm.worked(1);
}
}
return (NonNLSElement[]) result.toArray(new NonNLSElement[result.size()]);
} finally{
pm.done();
}
}
private void showResults() {
if (noStrings())
MessageDialog.openInformation(getShell(), getDialogTitle(), ActionMessages.FindStringsToExternalizeAction_noStrings);
else
new NonNLSListDialog(getShell(), fElements, countStrings()).open();
}
private boolean noStrings() {
if (fElements != null) {
for (int i= 0; i < fElements.length; i++) {
if (fElements[i].count != 0)
return false;
}
}
return true;
}
/*
* returns List of Strings
*/
private List analyze(IPackageFragment pack, IProgressMonitor pm) throws CoreException {
try{
if (pack == null)
return new ArrayList(0);
ICompilationUnit[] cus= pack.getCompilationUnits();
pm.beginTask("", cus.length); //$NON-NLS-1$
pm.setTaskName(pack.getElementName());
List l= new ArrayList(cus.length);
for (int i= 0; i < cus.length; i++){
pm.subTask(cus[i].getElementName());
NonNLSElement element= analyze(cus[i]);
if (element != null)
l.add(element);
pm.worked(1);
if (pm.isCanceled())
throw new OperationCanceledException();
}
return l;
} finally {
pm.done();
}
}
/*
* returns List of Strings
*/
private List analyze(IPackageFragmentRoot sourceFolder, IProgressMonitor pm) throws CoreException {
try{
IJavaElement[] children= sourceFolder.getChildren();
pm.beginTask("", children.length); //$NON-NLS-1$
pm.setTaskName(sourceFolder.getElementName());
List result= new ArrayList();
for (int i= 0; i < children.length; i++) {
IJavaElement iJavaElement= children[i];
if (iJavaElement.getElementType() == IJavaElement.PACKAGE_FRAGMENT){
IPackageFragment pack= (IPackageFragment)iJavaElement;
if (! pack.isReadOnly())
result.addAll(analyze(pack, new SubProgressMonitor(pm, 1)));
else
pm.worked(1);
} else
pm.worked(1);
}
return result;
} finally{
pm.done();
}
}
/*
* returns List of Strings
*/
private List analyze(IJavaProject project, IProgressMonitor pm) throws CoreException {
try{
IPackageFragment[] packs= project.getPackageFragments();
pm.beginTask("", packs.length); //$NON-NLS-1$
List result= new ArrayList();
for (int i= 0; i < packs.length; i++) {
if (! packs[i].isReadOnly())
result.addAll(analyze(packs[i], new SubProgressMonitor(pm, 1)));
else
pm.worked(1);
}
return result;
} finally{
pm.done();
}
}
private int countStrings() {
int found= 0;
if (fElements != null) {
for (int i= 0; i < fElements.length; i++)
found+= fElements[i].count;
}
return found;
}
private NonNLSElement analyze(ICompilationUnit cu) throws CoreException {
int count= countNonExternalizedStrings(cu);
if (count == 0)
return null;
else
return new NonNLSElement(cu, count);
}
private int countNonExternalizedStrings(ICompilationUnit cu) throws CoreException {
try{
NLSLine[] lines= NLSScanner.scan(cu);
int result= 0;
for (int i= 0; i < lines.length; i++) {
result += countNonExternalizedStrings(lines[i]);
}
return result;
} catch (InvalidInputException e) {
throw new CoreException(new Status(IStatus.ERROR, JavaPlugin.getPluginId(), IStatus.ERROR,
Messages.format(ActionMessages.FindStringsToExternalizeAction_error_cannotBeParsed, cu.getElementName()),
e));
}
}
private int countNonExternalizedStrings(NLSLine line){
int result= 0;
NLSElement[] elements= line.getElements();
for (int i= 0; i < elements.length; i++){
if (! elements[i].hasTag())
result++;
}
return result;
}
/**
* returns <code>List</code> of <code>IPackageFragments</code>, <code>IPackageFragmentRoots</code> or
* <code>IJavaProjects</code> (all entries are of the same kind)
*/
private static List getSelectedElementList(IStructuredSelection selection) {
if (selection == null)
return null;
return selection.toList();
}
//-------private classes --------------
private static class NonNLSListDialog extends ListDialog {
private static final int OPEN_BUTTON_ID= IDialogConstants.CLIENT_ID + 1;
private Button fOpenButton;
NonNLSListDialog(Shell parent, NonNLSElement[] input, int count) {
super(parent);
setInput(Arrays.asList(input));
setTitle(ActionMessages.ExternalizeStringsAction_dialog_title);
setMessage(Messages.format(ActionMessages.FindStringsToExternalizeAction_non_externalized, new Object[] {new Integer(count)} ));
setContentProvider(new ArrayContentProvider());
setLabelProvider(createLabelProvider());
}
public void create() {
setShellStyle(SWT.DIALOG_TRIM | SWT.RESIZE | SWT.MIN);
super.create();
}
protected Point getInitialSize() {
return getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
}
protected Control createDialogArea(Composite parent) {
Composite result= (Composite)super.createDialogArea(parent);
getTableViewer().addSelectionChangedListener(new ISelectionChangedListener(){
public void selectionChanged(SelectionChangedEvent event){
if (fOpenButton != null){
fOpenButton.setEnabled(! getTableViewer().getSelection().isEmpty());
}
}
});
getTableViewer().getTable().addSelectionListener(new SelectionAdapter(){
public void widgetDefaultSelected(SelectionEvent e) {
NonNLSElement element= (NonNLSElement)e.item.getData();
openWizard(element.cu);
}
});
getTableViewer().getTable().setFocus();
applyDialogFont(result);
return result;
}
protected void createButtonsForButtonBar(Composite parent) {
fOpenButton= createButton(parent, OPEN_BUTTON_ID, ActionMessages.FindStringsToExternalizeAction_button_label, true);
fOpenButton.setEnabled(false);
//looks like a 'close' but it a 'cancel'
createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CLOSE_LABEL, false);
}
protected void buttonPressed(int buttonId) {
if (buttonId != OPEN_BUTTON_ID){
super.buttonPressed(buttonId);
return;
}
ISelection s= getTableViewer().getSelection();
if (s instanceof IStructuredSelection){
IStructuredSelection ss= (IStructuredSelection)s;
if (ss.getFirstElement() instanceof NonNLSElement)
openWizard(((NonNLSElement)ss.getFirstElement()).cu);
}
}
private void openWizard(ICompilationUnit unit) {
try {
if (unit != null && unit.exists()) {
NLSRefactoring refactoring= NLSRefactoring.create(unit);
if (refactoring != null)
new RefactoringStarter().activate(refactoring, new ExternalizeWizard(refactoring), getShell(), ActionMessages.ExternalizeStringsAction_dialog_title, true);
}
} catch (JavaModelException e) {
ExceptionHandler.handle(e,
ActionMessages.FindStringsToExternalizeAction_dialog_title,
ActionMessages.FindStringsToExternalizeAction_error_message);
}
}
private static LabelProvider createLabelProvider() {
return new JavaElementLabelProvider(JavaElementLabelProvider.SHOW_DEFAULT){
public String getText(Object element) {
NonNLSElement nlsel= (NonNLSElement)element;
String elementName= ResourceUtil.getResource(nlsel.cu).getFullPath().toString();
return Messages.format(
ActionMessages.FindStringsToExternalizeAction_foundStrings,
new Object[] {new Integer(nlsel.count), elementName} );
}
public Image getImage(Object element) {
return super.getImage(((NonNLSElement)element).cu);
}
};
}
/*
* @see org.eclipse.jface.window.Window#configureShell(Shell)
*/
protected void configureShell(Shell newShell) {
super.configureShell(newShell);
PlatformUI.getWorkbench().getHelpSystem().setHelp(newShell, IJavaHelpContextIds.NONNLS_DIALOG);
}
}
private static class NonNLSElement{
ICompilationUnit cu;
int count;
NonNLSElement(ICompilationUnit cu, int count){
this.cu= cu;
this.count= count;
}
}
private String getDialogTitle() {
return ActionMessages.FindStringsToExternalizeAction_dialog_title;
}
}