aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/RefactoringAssistant.java
diff options
context:
space:
mode:
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/RefactoringAssistant.java')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/RefactoringAssistant.java336
1 files changed, 336 insertions, 0 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/RefactoringAssistant.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/RefactoringAssistant.java
new file mode 100644
index 000000000..aa8c11999
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/RefactoringAssistant.java
@@ -0,0 +1,336 @@
+/*
+ * 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.editors.layout.refactoring;
+
+import com.android.ide.common.resources.ResourceUrl;
+import com.android.ide.eclipse.adt.AdtPlugin;
+import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor;
+import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditorDelegate;
+import com.android.ide.eclipse.adt.internal.editors.layout.gle2.DomUtilities;
+import com.android.ide.eclipse.adt.internal.refactorings.core.RenameResourceProcessor;
+import com.android.ide.eclipse.adt.internal.refactorings.core.RenameResourceWizard;
+import com.android.ide.eclipse.adt.internal.refactorings.core.RenameResourceXmlTextAction;
+import com.android.ide.eclipse.adt.internal.refactorings.extractstring.ExtractStringRefactoring;
+import com.android.ide.eclipse.adt.internal.refactorings.extractstring.ExtractStringWizard;
+import com.android.resources.ResourceType;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.ITextSelection;
+import org.eclipse.jface.text.TextSelection;
+import org.eclipse.jface.text.contentassist.ICompletionProposal;
+import org.eclipse.jface.text.contentassist.IContextInformation;
+import org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext;
+import org.eclipse.jface.text.quickassist.IQuickAssistProcessor;
+import org.eclipse.jface.text.source.Annotation;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.ltk.core.refactoring.Refactoring;
+import org.eclipse.ltk.core.refactoring.participants.RenameRefactoring;
+import org.eclipse.ltk.ui.refactoring.RefactoringWizard;
+import org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
+import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion;
+import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument;
+import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion;
+import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion;
+import org.eclipse.wst.sse.ui.StructuredTextEditor;
+import org.eclipse.wst.xml.core.internal.regions.DOMRegionContext;
+import org.w3c.dom.Node;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * QuickAssistProcessor which helps invoke refactoring operations on text elements.
+ */
+@SuppressWarnings("restriction") // XML model
+public class RefactoringAssistant implements IQuickAssistProcessor {
+
+ /**
+ * Creates a new {@link RefactoringAssistant}
+ */
+ public RefactoringAssistant() {
+ }
+
+ @Override
+ public boolean canAssist(IQuickAssistInvocationContext invocationContext) {
+ return true;
+ }
+
+ @Override
+ public boolean canFix(Annotation annotation) {
+ return true;
+ }
+
+ @Override
+ public ICompletionProposal[] computeQuickAssistProposals(
+ IQuickAssistInvocationContext invocationContext) {
+
+ ISourceViewer sourceViewer = invocationContext.getSourceViewer();
+ AndroidXmlEditor xmlEditor = AndroidXmlEditor.fromTextViewer(sourceViewer);
+ if (xmlEditor == null) {
+ return null;
+ }
+
+ IFile file = xmlEditor.getInputFile();
+ if (file == null) {
+ return null;
+ }
+ int offset = invocationContext.getOffset();
+
+ // Ensure that we are over a tag name (for element-based refactoring
+ // operations) or a value (for the extract include refactoring)
+
+ boolean isValue = false;
+ boolean isReferenceValue = false;
+ boolean isTagName = false;
+ boolean isAttributeName = false;
+ boolean isStylableAttribute = false;
+ ResourceUrl resource = null;
+ IStructuredModel model = null;
+ try {
+ model = xmlEditor.getModelForRead();
+ IStructuredDocument doc = model.getStructuredDocument();
+ IStructuredDocumentRegion region = doc.getRegionAtCharacterOffset(offset);
+ ITextRegion subRegion = region.getRegionAtCharacterOffset(offset);
+ if (subRegion != null) {
+ String type = subRegion.getType();
+ if (type.equals(DOMRegionContext.XML_TAG_ATTRIBUTE_VALUE)) {
+ String value = region.getText(subRegion);
+ // Only extract values that aren't already resources
+ // (and value includes leading ' or ")
+ isValue = true;
+ if (value.startsWith("'@") || value.startsWith("\"@")) { //$NON-NLS-1$ //$NON-NLS-2$
+ isReferenceValue = true;
+ resource = RenameResourceXmlTextAction.findResource(doc, offset);
+ }
+ } else if (type.equals(DOMRegionContext.XML_TAG_NAME)
+ || type.equals(DOMRegionContext.XML_TAG_OPEN)
+ || type.equals(DOMRegionContext.XML_TAG_CLOSE)) {
+ isTagName = true;
+ } else if (type.equals(DOMRegionContext.XML_TAG_ATTRIBUTE_NAME) ) {
+ isAttributeName = true;
+ String name = region.getText(subRegion);
+ int index = name.indexOf(':');
+ if (index != -1) {
+ name = name.substring(index + 1);
+ }
+ isStylableAttribute = ExtractStyleRefactoring.isStylableAttribute(name);
+ } else if (type.equals(DOMRegionContext.XML_TAG_ATTRIBUTE_EQUALS)) {
+ // On the edge of an attribute name and an attribute value
+ isAttributeName = true;
+ isStylableAttribute = true;
+ } else if (type.equals(DOMRegionContext.XML_CONTENT)) {
+ resource = RenameResourceXmlTextAction.findResource(doc, offset);
+ }
+ }
+ } finally {
+ if (model != null) {
+ model.releaseFromRead();
+ }
+ }
+
+ List<ICompletionProposal> proposals = new ArrayList<ICompletionProposal>();
+ if (isTagName || isAttributeName || isValue || resource != null) {
+ StructuredTextEditor structuredEditor = xmlEditor.getStructuredTextEditor();
+ ISelectionProvider provider = structuredEditor.getSelectionProvider();
+ ISelection selection = provider.getSelection();
+ if (selection instanceof ITextSelection) {
+ ITextSelection textSelection = (ITextSelection) selection;
+
+ ITextSelection originalSelection = textSelection;
+
+ // Most of the visual refactorings do not work on text ranges
+ // ...except for Extract Style where the actual attributes overlapping
+ // the selection is going to be the set of eligible attributes
+ boolean selectionOkay = false;
+
+ if (textSelection.getLength() == 0 && !isValue) {
+ selectionOkay = true;
+ ISourceViewer textViewer = xmlEditor.getStructuredSourceViewer();
+ int caretOffset = textViewer.getTextWidget().getCaretOffset();
+ if (caretOffset >= 0) {
+ Node node = DomUtilities.getNode(textViewer.getDocument(), caretOffset);
+ if (node instanceof IndexedRegion) {
+ IndexedRegion region = (IndexedRegion) node;
+ int startOffset = region.getStartOffset();
+ int length = region.getEndOffset() - region.getStartOffset();
+ textSelection = new TextSelection(startOffset, length);
+ }
+ }
+ }
+
+ if (isValue && !isReferenceValue) {
+ proposals.add(new RefactoringProposal(xmlEditor,
+ new ExtractStringRefactoring(file, xmlEditor, textSelection)));
+ } else if (resource != null) {
+ RenameResourceProcessor processor = new RenameResourceProcessor(
+ file.getProject(), resource.type, resource.name, null);
+ RenameRefactoring refactoring = new RenameRefactoring(processor);
+ proposals.add(new RefactoringProposal(xmlEditor, refactoring));
+ }
+
+ LayoutEditorDelegate delegate = LayoutEditorDelegate.fromEditor(xmlEditor);
+ if (delegate != null) {
+ boolean showStyleFirst = isValue || (isAttributeName && isStylableAttribute);
+ if (showStyleFirst) {
+ proposals.add(new RefactoringProposal(
+ xmlEditor,
+ new ExtractStyleRefactoring(
+ file,
+ delegate,
+ originalSelection,
+ null)));
+ }
+
+ if (selectionOkay) {
+ proposals.add(new RefactoringProposal(
+ xmlEditor,
+ new WrapInRefactoring(
+ file,
+ delegate,
+ textSelection,
+ null)));
+ proposals.add(new RefactoringProposal(
+ xmlEditor,
+ new UnwrapRefactoring(
+ file,
+ delegate,
+ textSelection,
+ null)));
+ proposals.add(new RefactoringProposal(
+ xmlEditor,
+ new ChangeViewRefactoring(
+ file,
+ delegate,
+ textSelection,
+ null)));
+ proposals.add(new RefactoringProposal(
+ xmlEditor,
+ new ChangeLayoutRefactoring(
+ file,
+ delegate,
+ textSelection,
+ null)));
+ }
+
+ // Extract Include must always have an actual block to be extracted
+ if (textSelection.getLength() > 0) {
+ proposals.add(new RefactoringProposal(
+ xmlEditor,
+ new ExtractIncludeRefactoring(
+ file,
+ delegate,
+ textSelection,
+ null)));
+ }
+
+ // If it's not a value or attribute name, don't place it on top
+ if (!showStyleFirst) {
+ proposals.add(new RefactoringProposal(
+ xmlEditor,
+ new ExtractStyleRefactoring(
+ file,
+ delegate,
+ originalSelection,
+ null)));
+ }
+ }
+ }
+ }
+
+ if (proposals.size() == 0) {
+ return null;
+ } else {
+ return proposals.toArray(new ICompletionProposal[proposals.size()]);
+ }
+ }
+
+ @Override
+ public String getErrorMessage() {
+ return null;
+ }
+
+ private static class RefactoringProposal
+ implements ICompletionProposal {
+ private final AndroidXmlEditor mEditor;
+ private final Refactoring mRefactoring;
+
+ RefactoringProposal(AndroidXmlEditor editor, Refactoring refactoring) {
+ super();
+ mEditor = editor;
+ mRefactoring = refactoring;
+ }
+
+ @Override
+ public void apply(IDocument document) {
+ RefactoringWizard wizard = null;
+ if (mRefactoring instanceof VisualRefactoring) {
+ wizard = ((VisualRefactoring) mRefactoring).createWizard();
+ } else if (mRefactoring instanceof ExtractStringRefactoring) {
+ wizard = new ExtractStringWizard((ExtractStringRefactoring) mRefactoring,
+ mEditor.getProject());
+ } else if (mRefactoring instanceof RenameRefactoring) {
+ RenameRefactoring refactoring = (RenameRefactoring) mRefactoring;
+ RenameResourceProcessor processor =
+ (RenameResourceProcessor) refactoring.getProcessor();
+ ResourceType type = processor.getType();
+ wizard = new RenameResourceWizard((RenameRefactoring) mRefactoring, type, false);
+ } else {
+ throw new IllegalArgumentException();
+ }
+
+ RefactoringWizardOpenOperation op = new RefactoringWizardOpenOperation(wizard);
+ try {
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ op.run(window.getShell(), wizard.getDefaultPageTitle());
+ } catch (InterruptedException e) {
+ }
+ }
+
+ @Override
+ public String getAdditionalProposalInfo() {
+ return String.format("Initiates the \"%1$s\" refactoring", mRefactoring.getName());
+ }
+
+ @Override
+ public IContextInformation getContextInformation() {
+ return null;
+ }
+
+ @Override
+ public String getDisplayString() {
+ return mRefactoring.getName();
+ }
+
+ @Override
+ public Image getImage() {
+ return AdtPlugin.getAndroidLogo();
+ }
+
+ @Override
+ public Point getSelection(IDocument document) {
+ return null;
+ }
+ }
+}