diff options
3 files changed, 314 insertions, 0 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml b/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml index 9ceccae..dc86dd7 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml +++ b/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml @@ -606,6 +606,17 @@ class="com.android.ide.eclipse.adt.internal.editors.layout.refactoring.JavaQuickAssistant"> </quickAssistProcessor> </extension> + <extension + point="org.eclipse.jdt.ui.quickFixProcessors"> + <quickFixProcessor + name="Android Convert Switch Quickfix Processor" + class="com.android.ide.eclipse.adt.internal.build.ConvertSwitchQuickFixProcessor" + id="com.android.ide.eclipse.adt.internal.build.ConvertSwitchQuickFixProcessor"> + <handledMarkerTypes> + <markerType id="org.eclipse.jdt.core.problem"/> + </handledMarkerTypes> + </quickFixProcessor> + </extension> <extension point="org.eclipse.ui.propertyPages"> <page adaptable="true" diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ConvertSwitchDialog.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ConvertSwitchDialog.java new file mode 100644 index 0000000..cc3f7bf --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ConvertSwitchDialog.java @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.eclipse.org/org/documents/epl-v10.php + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.ide.eclipse.adt.internal.build; + +import com.android.ide.eclipse.adt.internal.editors.IconFactory; + +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.dialogs.TitleAreaDialog; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Link; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.browser.IWebBrowser; + +import java.net.URL; + +/** + * Dialog shown by the {@link ConvertSwitchQuickFixProcessor}. This is a custom + * dialog rather than a plain {@link MessageDialog} such that we can show a link + * and point to a web page for more info. + */ +class ConvertSwitchDialog extends TitleAreaDialog implements SelectionListener { + /** URL containing more info */ + private static final String URL = "http://tools.android.com/tips/non-constant-fields"; //$NON-NLS-1$ + + private final String mField; + + private Link mLink; + + /** + * Create the dialog. + * @param parentShell the parent shell + * @param field the field name we're warning about + */ + public ConvertSwitchDialog(Shell parentShell, String field) { + super(parentShell); + mField = field; + Image image = IconFactory.getInstance().getIcon("android-64"); //$NON-NLS-1$ + setTitleImage(image); + } + + @Override + protected Control createDialogArea(Composite parent) { + String text = String.format( + "As of ADT 14, the resource fields (such as %1$s) are no longer constants " + + "when defined in library projects. This is necessary to make library " + + "projects reusable without recompiling them.\n" + + "\n" + + "One consequence of this is that you can no longer use the fields directly " + + "in switch statements. You must use an if-else chain instead.\n" + + "\n" + + "Eclipse can automatically convert from a switch statement to an if-else " + + "statement. Just place the caret on the switch keyword and invoke " + + "Quick Fix (Ctrl-1 on Windows and Linux, Cmd-1 on Mac), then select " + + "\"Convert 'switch' to 'if-else'\".\n" + + "\n" + + "For more information, see <a href=\"" + URL + "\">" + URL + "</a>", + mField); + + Composite area = (Composite) super.createDialogArea(parent); + Composite container = new Composite(area, SWT.NONE); + container.setLayout(new GridLayout(1, false)); + container.setLayoutData(new GridData(GridData.FILL_BOTH)); + + mLink = new Link(container, SWT.NONE); + mLink.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, true, 1, 1)); + mLink.setText(text); + mLink.addSelectionListener(this); + + setMessage("Non-Constant Expressions: Migration Necessary", IMessageProvider.INFORMATION); + + return area; + } + + @Override + protected void createButtonsForButtonBar(Composite parent) { + createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true); + createButton(parent, IDialogConstants.HELP_ID, IDialogConstants.HELP_LABEL, false); + } + + @Override + protected Point getInitialSize() { + return new Point(500, 400); + } + + private void showWebPage() { + try { + IWorkbench workbench = PlatformUI.getWorkbench(); + IWebBrowser browser = workbench.getBrowserSupport().getExternalBrowser(); + browser.openURL(new URL(URL)); + } catch (Exception e) { + String message = String.format("Could not open browser. Vist\n%1$s\ninstead.", + URL); + MessageDialog.openError(getShell(), "Browser Error", message); + } + + } + + @Override + protected void buttonPressed(int buttonId) { + if (buttonId == IDialogConstants.HELP_ID) { + showWebPage(); + } else { + super.buttonPressed(buttonId); + } + } + + // ---- Implements SelectionListener ---- + + public void widgetSelected(SelectionEvent e) { + if (e.getSource() == mLink) { + showWebPage(); + } + } + + public void widgetDefaultSelected(SelectionEvent e) { + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ConvertSwitchQuickFixProcessor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ConvertSwitchQuickFixProcessor.java new file mode 100644 index 0000000..1a4ccfb --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ConvertSwitchQuickFixProcessor.java @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.eclipse.org/org/documents/epl-v10.php + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.ide.eclipse.adt.internal.build; + +import com.android.ide.eclipse.adt.AdtPlugin; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.core.IBuffer; +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.compiler.IProblem; +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.QualifiedName; +import org.eclipse.jdt.ui.text.java.IInvocationContext; +import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal; +import org.eclipse.jdt.ui.text.java.IProblemLocation; +import org.eclipse.jdt.ui.text.java.IQuickFixProcessor; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.contentassist.IContextInformation; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Shell; + +/** + * A quickfix processor which looks for "case expressions must be constant + * expressions" errors, and if they apply to fields in a class named R, it + * assumes this is code related to library projects that are no longer final and + * will need to be rewritten to use if-else chains instead. + */ +public class ConvertSwitchQuickFixProcessor implements IQuickFixProcessor { + /** Constructs a new {@link ConvertSwitchQuickFixProcessor} */ + public ConvertSwitchQuickFixProcessor() { + } + + public boolean hasCorrections(ICompilationUnit cu, int problemId) { + return problemId == IProblem.NonConstantExpression; + } + + public IJavaCompletionProposal[] getCorrections(IInvocationContext context, + IProblemLocation[] location) throws CoreException { + if (location == null || location.length == 0) { + return null; + } + ASTNode coveringNode = context.getCoveringNode(); + if (coveringNode == null) { + return null; + } + + // Look up the fully qualified name of the non-constant expression, if any, and + // make sure it's R-something. + if (coveringNode.getNodeType() == ASTNode.SIMPLE_NAME) { + coveringNode = coveringNode.getParent(); + if (coveringNode == null) { + return null; + } + } + if (coveringNode.getNodeType() != ASTNode.QUALIFIED_NAME) { + return null; + } + QualifiedName name = (QualifiedName) coveringNode; + if (!name.getFullyQualifiedName().startsWith("R.")) { //$NON-NLS-1$ + return null; + } + + IProblemLocation error = location[0]; + int errorStart = error.getOffset(); + int errorLength = error.getLength(); + int caret = context.getSelectionOffset(); + + IBuffer buffer = context.getCompilationUnit().getBuffer(); + boolean sameLine = false; + // See if the caret is on the same line as the error + if (caret <= errorStart) { + // Search backwards to beginning of line + for (int i = errorStart; i >= 0; i--) { + if (i <= caret) { + sameLine = true; + break; + } + char c = buffer.getChar(i); + if (c == '\n') { + break; + } + } + } else { + // Search forwards to the end of the line + for (int i = errorStart + errorLength, n = buffer.getLength(); i < n; i++) { + if (i >= caret) { + sameLine = true; + break; + } + char c = buffer.getChar(i); + if (c == '\n') { + break; + } + } + } + + if (sameLine) { + String expression = buffer.getText(errorStart, errorLength); + return new IJavaCompletionProposal[] { + new MigrateProposal(expression) + }; + } + + return null; + } + + /** Proposal for the quick fix which displays an explanation message to the user */ + private class MigrateProposal implements IJavaCompletionProposal { + private String mExpression; + + private MigrateProposal(String expression) { + mExpression = expression; + } + + public void apply(IDocument document) { + Shell shell = AdtPlugin.getDisplay().getActiveShell(); + ConvertSwitchDialog dialog = new ConvertSwitchDialog(shell, mExpression); + dialog.open(); + } + + public Point getSelection(IDocument document) { + return null; + } + + public String getAdditionalProposalInfo() { + return "As of ADT 14, resource fields cannot be used as switch cases. Invoke this " + + "fix to get more information."; + } + + public String getDisplayString() { + return "Migrate Android Code"; + } + + public Image getImage() { + return AdtPlugin.getAndroidLogo(); + } + + public IContextInformation getContextInformation() { + return null; + } + + public int getRelevance() { + return 50; + } + } +} |