1 /*******************************************************************************
2 * Copyright (c) 2000, 2011 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.jdt.ui.actions;
13 import java.lang.reflect.InvocationTargetException;
14 import java.util.ArrayList;
15 import java.util.Arrays;
16 import java.util.Collections;
17 import java.util.Iterator;
18 import java.util.List;
20 import org.eclipse.swt.SWT;
21 import org.eclipse.swt.events.SelectionAdapter;
22 import org.eclipse.swt.events.SelectionEvent;
23 import org.eclipse.swt.graphics.Image;
24 import org.eclipse.swt.graphics.Point;
25 import org.eclipse.swt.widgets.Button;
26 import org.eclipse.swt.widgets.Composite;
27 import org.eclipse.swt.widgets.Control;
28 import org.eclipse.swt.widgets.Shell;
30 import org.eclipse.core.runtime.CoreException;
31 import org.eclipse.core.runtime.IAdaptable;
32 import org.eclipse.core.runtime.IProgressMonitor;
33 import org.eclipse.core.runtime.IStatus;
34 import org.eclipse.core.runtime.NullProgressMonitor;
35 import org.eclipse.core.runtime.OperationCanceledException;
36 import org.eclipse.core.runtime.Status;
37 import org.eclipse.core.runtime.SubProgressMonitor;
39 import org.eclipse.jface.dialogs.IDialogConstants;
40 import org.eclipse.jface.dialogs.MessageDialog;
41 import org.eclipse.jface.operation.IRunnableWithProgress;
42 import org.eclipse.jface.viewers.ArrayContentProvider;
43 import org.eclipse.jface.viewers.ISelection;
44 import org.eclipse.jface.viewers.ISelectionChangedListener;
45 import org.eclipse.jface.viewers.IStructuredSelection;
46 import org.eclipse.jface.viewers.LabelProvider;
47 import org.eclipse.jface.viewers.SelectionChangedEvent;
49 import org.eclipse.jface.text.BadLocationException;
50 import org.eclipse.jface.text.ITextSelection;
52 import org.eclipse.ui.IWorkbenchSite;
53 import org.eclipse.ui.IWorkingSet;
54 import org.eclipse.ui.PlatformUI;
55 import org.eclipse.ui.dialogs.ListDialog;
57 import org.eclipse.jdt.core.ICompilationUnit;
58 import org.eclipse.jdt.core.IJavaElement;
59 import org.eclipse.jdt.core.IJavaProject;
60 import org.eclipse.jdt.core.IPackageFragment;
61 import org.eclipse.jdt.core.IPackageFragmentRoot;
62 import org.eclipse.jdt.core.IType;
63 import org.eclipse.jdt.core.JavaModelException;
64 import org.eclipse.jdt.core.compiler.InvalidInputException;
66 import org.eclipse.jdt.internal.corext.refactoring.RefactoringAvailabilityTester;
67 import org.eclipse.jdt.internal.corext.refactoring.nls.NLSElement;
68 import org.eclipse.jdt.internal.corext.refactoring.nls.NLSLine;
69 import org.eclipse.jdt.internal.corext.refactoring.nls.NLSScanner;
70 import org.eclipse.jdt.internal.corext.refactoring.reorg.ReorgUtils;
71 import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
72 import org.eclipse.jdt.internal.corext.util.Messages;
74 import org.eclipse.jdt.ui.JavaElementLabelProvider;
75 import org.eclipse.jdt.ui.JavaElementLabels;
77 import org.eclipse.jdt.internal.ui.IJavaHelpContextIds;
78 import org.eclipse.jdt.internal.ui.JavaPlugin;
79 import org.eclipse.jdt.internal.ui.actions.ActionMessages;
80 import org.eclipse.jdt.internal.ui.actions.ActionUtil;
81 import org.eclipse.jdt.internal.ui.actions.SelectionConverter;
82 import org.eclipse.jdt.internal.ui.javaeditor.CompilationUnitEditor;
83 import org.eclipse.jdt.internal.ui.refactoring.nls.ExternalizeWizard;
84 import org.eclipse.jdt.internal.ui.util.ExceptionHandler;
85 import org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels;
89 * Externalizes the strings of a compilation unit or find all strings
90 * in a package or project that are not externalized yet. Opens a wizard that
91 * gathers additional information to externalize the strings.
93 * The action is applicable to structured selections containing elements
94 * of type <code>ICompilationUnit</code>, <code>IType</code>, <code>IJavaProject</code>,
95 * <code>IPackageFragment</code>, and <code>IPackageFragmentRoot</code>
98 * This class may be instantiated; it is not intended to be subclassed.
103 * @noextend This class is not intended to be subclassed by clients.
105 public class ExternalizeStringsAction extends SelectionDispatchAction {
107 private CompilationUnitEditor fEditor;
109 private NonNLSElement[] fElements;
112 * Creates a new <code>ExternalizeStringsAction</code>. The action requires
113 * that the selection provided by the site's selection provider is of type <code>
114 * org.eclipse.jface.viewers.IStructuredSelection</code>.
116 * @param site the site providing context information for this action
118 public ExternalizeStringsAction(IWorkbenchSite site) {
120 setText(ActionMessages.ExternalizeStringsAction_label);
121 PlatformUI.getWorkbench().getHelpSystem().setHelp(this, IJavaHelpContextIds.EXTERNALIZE_STRINGS_ACTION);
125 * Note: This constructor is for internal use only. Clients should not call this constructor.
126 * @param editor the compilation unit editor
128 * @noreference This constructor is not intended to be referenced by clients.
130 public ExternalizeStringsAction(CompilationUnitEditor editor) {
131 this(editor.getEditorSite());
133 setEnabled(fEditor != null && SelectionConverter.canOperateOn(fEditor));
137 * Method declared on SelectionDispatchAction.
140 public void selectionChanged(ITextSelection selection) {
144 * Method declared on SelectionDispatchAction.
147 public void selectionChanged(IStructuredSelection selection) {
149 setEnabled(RefactoringAvailabilityTester.isExternalizeStringsAvailable(selection));
150 } catch (JavaModelException e) {
151 if (JavaModelUtil.isExceptionToBeLogged(e))
153 setEnabled(false);//no UI - happens on selection changes
158 * Method declared on SelectionDispatchAction.
161 public void run(ITextSelection selection) {
162 IJavaElement element= SelectionConverter.getInput(fEditor);
163 if (!(element instanceof ICompilationUnit))
165 run((ICompilationUnit)element);
169 * Method declared on SelectionDispatchAction.
172 public void run(IStructuredSelection selection) {
173 ICompilationUnit unit= getCompilationUnit(selection);
174 if (unit != null) {//run on cu
179 PlatformUI.getWorkbench().getProgressService().run(true, true, createRunnable(selection));
180 } catch(InvocationTargetException e) {
181 ExceptionHandler.handle(e, getShell(),
182 ActionMessages.ExternalizeStringsAction_dialog_title,
183 ActionMessages.FindStringsToExternalizeAction_error_message);
185 } catch(InterruptedException e) {
194 * Note: this method is for internal use only. Clients should not call this method.
195 * @param unit the compilation unit
197 * @noreference This method is not intended to be referenced by clients.
199 public void run(ICompilationUnit unit) {
200 if (!ActionUtil.isEditable(fEditor, getShell(), unit))
203 ExternalizeWizard.open(unit, getShell());
207 private static ICompilationUnit getCompilationUnit(IStructuredSelection selection) {
208 if (selection.isEmpty() || selection.size() != 1)
210 Object first= selection.getFirstElement();
211 if (first instanceof ICompilationUnit)
212 return (ICompilationUnit) first;
213 if (first instanceof IType)
214 return ((IType) first).getCompilationUnit();
218 private IRunnableWithProgress createRunnable(final IStructuredSelection selection) {
219 return new IRunnableWithProgress() {
220 public void run(IProgressMonitor pm) throws InvocationTargetException {
222 fElements= doRun(selection, pm);
223 } catch (CoreException e) {
224 throw new InvocationTargetException(e);
230 private NonNLSElement[] doRun(IStructuredSelection selection, IProgressMonitor pm) throws CoreException {
231 List<?> elements= getSelectedElementList(selection);
232 if (elements == null || elements.isEmpty())
233 return new NonNLSElement[0];
235 pm.beginTask(ActionMessages.FindStringsToExternalizeAction_find_strings, elements.size());
238 List<NonNLSElement> result= new ArrayList<NonNLSElement>();
239 for (Iterator<?> iter= elements.iterator(); iter.hasNext();) {
240 Object obj= iter.next();
241 result.addAll(analyze(obj, pm));
243 return result.toArray(new NonNLSElement[result.size()]);
249 private List<NonNLSElement> analyze(Object obj, IProgressMonitor pm) throws CoreException, JavaModelException {
250 if (obj instanceof IJavaElement) {
251 IJavaElement element= (IJavaElement) obj;
252 int elementType= element.getElementType();
254 if (elementType == IJavaElement.PACKAGE_FRAGMENT) {
255 return analyze((IPackageFragment) element, new SubProgressMonitor(pm, 1));
256 } else if (elementType == IJavaElement.PACKAGE_FRAGMENT_ROOT) {
257 IPackageFragmentRoot root= (IPackageFragmentRoot)element;
258 if (!root.isExternal() && !ReorgUtils.isClassFolder(root)) {
259 return analyze((IPackageFragmentRoot) element, new SubProgressMonitor(pm, 1));
263 } else if (elementType == IJavaElement.JAVA_PROJECT) {
264 return analyze((IJavaProject) element, new SubProgressMonitor(pm, 1));
265 } else if (elementType == IJavaElement.COMPILATION_UNIT) {
266 ICompilationUnit cu= (ICompilationUnit)element;
268 NonNLSElement nlsElement= analyze(cu);
269 if (nlsElement != null) {
271 ArrayList<NonNLSElement> result= new ArrayList<NonNLSElement>();
272 result.add(nlsElement);
277 } else if (elementType == IJavaElement.TYPE) {
278 IType type= (IType)element;
279 ICompilationUnit cu= type.getCompilationUnit();
280 if (cu != null && cu.exists()) {
281 NonNLSElement nlsElement= analyze(cu);
282 if (nlsElement != null) {
284 ArrayList<NonNLSElement> result= new ArrayList<NonNLSElement>();
285 result.add(nlsElement);
293 } else if (obj instanceof IWorkingSet) {
294 List<NonNLSElement> result= new ArrayList<NonNLSElement>();
296 IWorkingSet workingSet= (IWorkingSet) obj;
297 IAdaptable[] elements= workingSet.getElements();
298 for (int i= 0; i < elements.length; i++) {
299 result.addAll(analyze(elements[i], new NullProgressMonitor()));
307 return Collections.emptyList();
310 private void showResults() {
312 MessageDialog.openInformation(getShell(), ActionMessages.ExternalizeStringsAction_dialog_title, ActionMessages.FindStringsToExternalizeAction_noStrings);
314 new NonNLSListDialog(getShell(), fElements, countStrings()).open();
317 private boolean noStrings() {
318 if (fElements != null) {
319 for (int i= 0; i < fElements.length; i++) {
320 if (fElements[i].count != 0)
328 * returns List of Strings
330 private List<NonNLSElement> analyze(IPackageFragment pack, IProgressMonitor pm) throws CoreException {
333 return new ArrayList<NonNLSElement>(0);
335 ICompilationUnit[] cus= pack.getCompilationUnits();
337 pm.beginTask("", cus.length); //$NON-NLS-1$
338 pm.setTaskName(pack.getElementName());
340 List<NonNLSElement> l= new ArrayList<NonNLSElement>(cus.length);
341 for (int i= 0; i < cus.length; i++){
342 pm.subTask(BasicElementLabels.getFileName(cus[i]));
343 NonNLSElement element= analyze(cus[i]);
348 throw new OperationCanceledException();
357 * returns List of Strings
359 private List<NonNLSElement> analyze(IPackageFragmentRoot sourceFolder, IProgressMonitor pm) throws CoreException {
361 IJavaElement[] children= sourceFolder.getChildren();
362 pm.beginTask("", children.length); //$NON-NLS-1$
363 pm.setTaskName(JavaElementLabels.getElementLabel(sourceFolder, JavaElementLabels.ALL_DEFAULT));
364 List<NonNLSElement> result= new ArrayList<NonNLSElement>();
365 for (int i= 0; i < children.length; i++) {
366 IJavaElement iJavaElement= children[i];
367 if (iJavaElement.getElementType() == IJavaElement.PACKAGE_FRAGMENT){
368 IPackageFragment pack= (IPackageFragment)iJavaElement;
369 if (! pack.isReadOnly())
370 result.addAll(analyze(pack, new SubProgressMonitor(pm, 1)));
383 * returns List of Strings
385 private List<NonNLSElement> analyze(IJavaProject project, IProgressMonitor pm) throws CoreException {
387 IPackageFragment[] packs= project.getPackageFragments();
388 pm.beginTask("", packs.length); //$NON-NLS-1$
389 List<NonNLSElement> result= new ArrayList<NonNLSElement>();
390 for (int i= 0; i < packs.length; i++) {
391 if (! packs[i].isReadOnly())
392 result.addAll(analyze(packs[i], new SubProgressMonitor(pm, 1)));
402 private int countStrings() {
404 if (fElements != null) {
405 for (int i= 0; i < fElements.length; i++)
406 found+= fElements[i].count;
411 private NonNLSElement analyze(ICompilationUnit cu) throws CoreException {
412 int count= countNonExternalizedStrings(cu);
416 return new NonNLSElement(cu, count);
419 private int countNonExternalizedStrings(ICompilationUnit cu) throws CoreException {
421 NLSLine[] lines= NLSScanner.scan(cu);
423 for (int i= 0; i < lines.length; i++) {
424 result += countNonExternalizedStrings(lines[i]);
427 } catch (InvalidInputException e) {
428 throw new CoreException(new Status(IStatus.ERROR, JavaPlugin.getPluginId(), IStatus.ERROR,
429 Messages.format(ActionMessages.FindStringsToExternalizeAction_error_cannotBeParsed, BasicElementLabels.getFileName(cu)), e));
430 } catch (BadLocationException e) {
431 throw new CoreException(new Status(IStatus.ERROR, JavaPlugin.getPluginId(), IStatus.ERROR, Messages.format(ActionMessages.FindStringsToExternalizeAction_error_cannotBeParsed,
432 BasicElementLabels.getFileName(cu)), e));
436 private int countNonExternalizedStrings(NLSLine line){
438 NLSElement[] elements= line.getElements();
439 for (int i= 0; i < elements.length; i++){
440 if (! elements[i].hasTag())
447 * returns <code>List</code> of <code>IPackageFragments</code>, <code>IPackageFragmentRoots</code> or
448 * <code>IJavaProjects</code> (all entries are of the same kind)
449 * @param selection the selection
450 * @return the selected elements
452 private static List<?> getSelectedElementList(IStructuredSelection selection) {
453 if (selection == null)
456 return selection.toList();
459 //-------private classes --------------
461 private static class NonNLSListDialog extends ListDialog {
463 private static final int OPEN_BUTTON_ID= IDialogConstants.CLIENT_ID + 1;
465 private Button fOpenButton;
467 NonNLSListDialog(Shell parent, NonNLSElement[] input, int count) {
469 setAddCancelButton(false);
470 setInput(Arrays.asList(input));
471 setTitle(ActionMessages.ExternalizeStringsAction_dialog_title);
472 String message= count == 1 ? ActionMessages.FindStringsToExternalizeAction_non_externalized_singular : Messages.format(
473 ActionMessages.FindStringsToExternalizeAction_non_externalized_plural, new Object[] { new Integer(count) });
475 setContentProvider(new ArrayContentProvider());
476 setLabelProvider(createLabelProvider());
480 protected Point getInitialSize() {
481 return getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
485 protected Control createDialogArea(Composite parent) {
486 Composite result= (Composite)super.createDialogArea(parent);
487 getTableViewer().addSelectionChangedListener(new ISelectionChangedListener(){
488 public void selectionChanged(SelectionChangedEvent event){
489 if (fOpenButton != null){
490 fOpenButton.setEnabled(! getTableViewer().getSelection().isEmpty());
494 getTableViewer().getTable().addSelectionListener(new SelectionAdapter(){
496 public void widgetDefaultSelected(SelectionEvent e) {
497 NonNLSElement element= (NonNLSElement)e.item.getData();
498 element.generated_8353693410935300812(this);
501 getTableViewer().getTable().setFocus();
502 applyDialogFont(result);
507 protected void createButtonsForButtonBar(Composite parent) {
508 fOpenButton= createButton(parent, OPEN_BUTTON_ID, ActionMessages.FindStringsToExternalizeAction_button_label, true);
509 fOpenButton.setEnabled(false);
511 //looks like a 'close' but it a 'cancel'
512 createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CLOSE_LABEL, false);
516 protected void buttonPressed(int buttonId) {
517 if (buttonId != OPEN_BUTTON_ID){
518 super.buttonPressed(buttonId);
521 ISelection s= getTableViewer().getSelection();
522 if (s instanceof IStructuredSelection){
523 IStructuredSelection ss= (IStructuredSelection)s;
524 if (ss.getFirstElement() instanceof NonNLSElement)
525 ExternalizeWizard.open(((NonNLSElement) ss.getFirstElement()).cu, getShell());
529 private static LabelProvider createLabelProvider() {
530 return new JavaElementLabelProvider(JavaElementLabelProvider.SHOW_DEFAULT){
532 public String getText(Object element) {
533 NonNLSElement nlsel= (NonNLSElement)element;
534 String elementName= BasicElementLabels.getPathLabel(nlsel.cu.getResource().getFullPath(), false);
535 return Messages.format(
536 ActionMessages.FindStringsToExternalizeAction_foundStrings,
537 new Object[] {new Integer(nlsel.count), elementName} );
540 public Image getImage(Object element) {
541 return super.getImage(((NonNLSElement)element).cu);
547 * @see org.eclipse.jface.window.Window#configureShell(Shell)
550 protected void configureShell(Shell newShell) {
551 super.configureShell(newShell);
552 PlatformUI.getWorkbench().getHelpSystem().setHelp(newShell, IJavaHelpContextIds.NONNLS_DIALOG);
558 static class NonNLSElement{
561 NonNLSElement(ICompilationUnit cu, int count){
565 public void generated_8353693410935300812(SelectionAdapter arg) {
566 ExternalizeWizard.open(cu, arg.getShell());