aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.adt/src/com
diff options
context:
space:
mode:
authorTor Norbye <tnorbye@google.com>2011-03-07 14:16:48 -0800
committerTor Norbye <tnorbye@google.com>2011-03-11 16:06:48 -0800
commit9e6db060854d0e890190919a27a1846f50f69d1a (patch)
tree6e5e73e1cbb7549bdaf87d95d535dcf280d382a7 /eclipse/plugins/com.android.ide.eclipse.adt/src/com
parent826ed229db5562dfcb661bda2e9a2a9a844db3ce (diff)
downloadsdk-9e6db060854d0e890190919a27a1846f50f69d1a.tar.gz
Extract as Include support for configuration variations
First, add support for the "Extract as Include" refactoring to update all identical code fragments in configuration variations of the same file. For example, if you have a particular subtree of XML elements in a file that you have then duplicated into say a landscape mode, then applying the Extract as Include refactoring will locate the same code fragment in both files, and replace *both* code fragments with an include (and this is optional with a checkbox in the wizard dialog). This only happens when the extracted code fragment is "identical" in both files. The code fragments can vary in terms of XML formatting and attribute order (and namespace prefix choice), but the element hierarchy order, names, attributes defined and attribute values must be identical. Second, make fixes to the Change Layout and Change Widget Type refactorings such that when the id of the converted element is changed, then references to that id are updated as well. Third, ensure that the refactorings are enabled even when there is no text selection; in that case the refactoring will apply to the element containing the caret. Some test infrastructure improvements. Change-Id: Idb4ba40f4217dba2b13881b3d06e269c80ba4b97
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/DomUtilities.java243
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeLayoutRefactoring.java23
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeLayoutWizard.java14
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeViewRefactoring.java26
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeViewWizard.java16
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractIncludeRefactoring.java199
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractIncludeWizard.java46
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/RelativeLayoutConversionHelper.java30
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/VisualRefactoring.java160
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/VisualRefactoringAction.java10
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/VisualRefactoringWizard.java34
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/WrapInRefactoring.java36
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/WrapInWizard.java86
13 files changed, 629 insertions, 294 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/DomUtilities.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/DomUtilities.java
index 032fe28e4..753010f0a 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/DomUtilities.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/DomUtilities.java
@@ -28,10 +28,18 @@ import org.eclipse.wst.sse.core.StructuredModelManager;
import org.eclipse.wst.sse.core.internal.provisional.IModelManager;
import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.HashSet;
+import java.util.List;
import java.util.Set;
@SuppressWarnings("restriction") // No replacement for restricted XML model yet
@@ -303,4 +311,239 @@ public class DomUtilities {
return generated;
}
+ /**
+ * Returns the element children of the given element
+ *
+ * @param element the parent element
+ * @return a list of child elements, possibly empty but never null
+ */
+ public static List<Element> getChildren(Element element) {
+ // Convenience to avoid lots of ugly DOM access casting
+ NodeList children = element.getChildNodes();
+ // An iterator would have been more natural (to directly drive the child list
+ // iteration) but iterators can't be used in enhanced for loops...
+ List<Element> result = new ArrayList<Element>(children.getLength());
+ for (int i = 0, n = children.getLength(); i < n; i++) {
+ Node node = children.item(i);
+ if (node.getNodeType() == Node.ELEMENT_NODE) {
+ Element child = (Element) node;
+ result.add(child);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns true iff the given elements are contiguous siblings
+ *
+ * @param elements the elements to be tested
+ * @return true if the elements are contiguous siblings with no gaps
+ */
+ public static boolean isContiguous(List<Element> elements) {
+ if (elements.size() > 1) {
+ // All elements must be siblings (e.g. same parent)
+ Node parent = elements.get(0).getParentNode();
+ if (!(parent instanceof Element)) {
+ return false;
+ }
+ for (Element node : elements) {
+ if (parent != node.getParentNode()) {
+ return false;
+ }
+ }
+
+ // Ensure that the siblings are contiguous; no gaps.
+ // If we've selected all the children of the parent then we don't need
+ // to look.
+ List<Element> siblings = DomUtilities.getChildren((Element) parent);
+ if (siblings.size() != elements.size()) {
+ Set<Element> nodeSet = new HashSet<Element>(elements);
+ boolean inRange = false;
+ int remaining = elements.size();
+ for (Element node : siblings) {
+ boolean in = nodeSet.contains(node);
+ if (in) {
+ remaining--;
+ if (remaining == 0) {
+ break;
+ }
+ inRange = true;
+ } else if (inRange) {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Determines whether two element trees are equivalent. Two element trees are
+ * equivalent if they represent the same DOM structure (elements, attributes, and
+ * children in order). This is almost the same as simply checking whether the String
+ * representations of the two nodes are identical, but this allows for minor
+ * variations that are not semantically significant, such as variations in formatting
+ * or ordering of the element attribute declarations, and the text children are
+ * ignored (this is such that in for example layout where content is only used for
+ * indentation the indentation differences are ignored). Null trees are never equal.
+ *
+ * @param element1 the first element to compare
+ * @param element2 the second element to compare
+ * @return true if the two element hierarchies are logically equal
+ */
+ public static boolean isEquivalent(Element element1, Element element2) {
+ if (element1 == null || element2 == null) {
+ return false;
+ }
+
+ if (!element1.getTagName().equals(element2.getTagName())) {
+ return false;
+ }
+
+ // Check attribute map
+ NamedNodeMap attributes1 = element1.getAttributes();
+ NamedNodeMap attributes2 = element2.getAttributes();
+ if (attributes1.getLength() != attributes2.getLength()) {
+ return false;
+ }
+ if (attributes1.getLength() > 0) {
+ List<Attr> attributeNodes1 = new ArrayList<Attr>();
+ for (int i = 0, n = attributes1.getLength(); i < n; i++) {
+ attributeNodes1.add((Attr) attributes1.item(i));
+ }
+ List<Attr> attributeNodes2 = new ArrayList<Attr>();
+ for (int i = 0, n = attributes2.getLength(); i < n; i++) {
+ attributeNodes2.add((Attr) attributes2.item(i));
+ }
+ Collections.sort(attributeNodes1, ATTRIBUTE_COMPARATOR);
+ Collections.sort(attributeNodes2, ATTRIBUTE_COMPARATOR);
+ for (int i = 0; i < attributeNodes1.size(); i++) {
+ Attr attr1 = attributeNodes1.get(i);
+ Attr attr2 = attributeNodes2.get(i);
+ if (attr1.getLocalName() == null || attr2.getLocalName() == null) {
+ if (!attr1.getName().equals(attr2.getName())) {
+ return false;
+ }
+ } else if (!attr1.getLocalName().equals(attr2.getLocalName())) {
+ return false;
+ }
+ if (!attr1.getValue().equals(attr2.getValue())) {
+ return false;
+ }
+ if (attr1.getNamespaceURI() == null) {
+ if (attr2.getNamespaceURI() != null) {
+ return false;
+ }
+ } else if (attr2.getNamespaceURI() == null) {
+ return false;
+ } else if (!attr1.getNamespaceURI().equals(attr2.getNamespaceURI())) {
+ return false;
+ }
+ }
+ }
+
+ NodeList children1 = element1.getChildNodes();
+ NodeList children2 = element2.getChildNodes();
+ int nextIndex1 = 0;
+ int nextIndex2 = 0;
+ while (true) {
+ while (nextIndex1 < children1.getLength() &&
+ children1.item(nextIndex1).getNodeType() != Node.ELEMENT_NODE) {
+ nextIndex1++;
+ }
+
+ while (nextIndex2 < children2.getLength() &&
+ children2.item(nextIndex2).getNodeType() != Node.ELEMENT_NODE) {
+ nextIndex2++;
+ }
+
+ Element nextElement1 = (Element) (nextIndex1 < children1.getLength()
+ ? children1.item(nextIndex1) : null);
+ Element nextElement2 = (Element) (nextIndex2 < children2.getLength()
+ ? children2.item(nextIndex2) : null);
+ if (nextElement1 == null) {
+ if (nextElement2 == null) {
+ return true;
+ } else {
+ return false;
+ }
+ } else if (nextElement2 == null) {
+ return false;
+ } else if (!isEquivalent(nextElement1, nextElement2)) {
+ return false;
+ }
+ nextIndex1++;
+ nextIndex2++;
+ }
+ }
+
+ /**
+ * Finds the corresponding element in a document to a given element in another
+ * document. Note that this does <b>not</b> do any kind of equivalence check
+ * (see {@link #isEquivalent(Element, Element)}), and currently the search
+ * is only by id; there is no structural search.
+ *
+ * @param element the element to find an equivalent for
+ * @param document the document to search for an equivalent element in
+ * @return an equivalent element, or null
+ */
+ public static Element findCorresponding(Element element, Document document) {
+ // Make sure the method is called correctly -- the element is for a different
+ // document than the one we are searching
+ assert element.getOwnerDocument() != document;
+
+ // First search by id. This allows us to find the corresponding
+ String id = element.getAttributeNS(ANDROID_URI, ATTR_ID);
+ if (id != null && id.length() > 0) {
+ if (id.startsWith(ID_PREFIX)) {
+ id = NEW_ID_PREFIX + id.substring(ID_PREFIX.length());
+ }
+
+ return findCorresponding(document.getDocumentElement(), id);
+ }
+
+ // TODO: Search by structure - look in the document and
+ // find a corresponding element in the same location in the structure,
+ // e.g. 4th child of root, 3rd child, 6th child, then pick node with tag "foo".
+
+ return null;
+ }
+
+ /** Helper method for {@link #findCorresponding(Element, Document)} */
+ private static Element findCorresponding(Element element, String targetId) {
+ String id = element.getAttributeNS(ANDROID_URI, ATTR_ID);
+ if (id != null) { // Work around DOM bug
+ if (id.equals(targetId)) {
+ return element;
+ } else if (id.startsWith(ID_PREFIX)) {
+ id = NEW_ID_PREFIX + id.substring(ID_PREFIX.length());
+ if (id.equals(targetId)) {
+ return element;
+ }
+ }
+ }
+
+ NodeList children = element.getChildNodes();
+ for (int i = 0, n = children.getLength(); i < n; i++) {
+ Node node = children.item(i);
+ if (node.getNodeType() == Node.ELEMENT_NODE) {
+ Element child = (Element) node;
+ Element match = findCorresponding(child, targetId);
+ if (match != null) {
+ return match;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /** Can be used to sort attributes by name */
+ private static final Comparator<Attr> ATTRIBUTE_COMPARATOR = new Comparator<Attr>() {
+ public int compare(Attr a1, Attr a2) {
+ return a1.getName().compareTo(a2.getName());
+ }
+ };
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeLayoutRefactoring.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeLayoutRefactoring.java
index b12cb62c4..4626de76f 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeLayoutRefactoring.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeLayoutRefactoring.java
@@ -53,7 +53,10 @@ import org.eclipse.ltk.core.refactoring.RefactoringStatus;
import org.eclipse.ltk.core.refactoring.TextFileChange;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.ReplaceEdit;
+import org.eclipse.text.edits.TextEdit;
+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.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
@@ -219,7 +222,25 @@ public class ChangeLayoutRefactoring extends VisualRefactoring {
}
}
- ensureIdMatchesType(layout, mTypeFqcn, rootEdit);
+ String oldId = getId(layout);
+ String newId = ensureIdMatchesType(layout, mTypeFqcn, rootEdit);
+ // Update any layout references to the old id with the new id
+ if (oldId != null && newId != null) {
+ IStructuredModel model = mEditor.getModelForRead();
+ try {
+ IStructuredDocument doc = model.getStructuredDocument();
+ if (doc != null) {
+ List<TextEdit> replaceIds = replaceIds(getAndroidNamespacePrefix(), doc,
+ mSelectionStart,
+ mSelectionEnd, oldId, newId);
+ for (TextEdit edit : replaceIds) {
+ rootEdit.addChild(edit);
+ }
+ }
+ } finally {
+ model.releaseFromRead();
+ }
+ }
String oldType = getOldType();
String newType = mTypeFqcn;
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeLayoutWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeLayoutWizard.java
index 69275687c..04da01d5a 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeLayoutWizard.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeLayoutWizard.java
@@ -21,9 +21,10 @@ import static com.android.ide.common.layout.LayoutConstants.RELATIVE_LAYOUT;
import static com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors.VIEW_INCLUDE;
import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditor;
+import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.ViewElementDescriptor;
+import com.android.util.Pair;
import org.eclipse.core.resources.IProject;
-import org.eclipse.ltk.ui.refactoring.UserInputWizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
@@ -53,12 +54,12 @@ class ChangeLayoutWizard extends VisualRefactoringWizard {
}
/** Wizard page which inputs parameters for the {@link ChangeLayoutRefactoring} operation */
- private static class InputPage extends UserInputWizardPage {
+ private static class InputPage extends VisualRefactoringInputPage {
private final IProject mProject;
private final String mOldType;
private Combo mTypeCombo;
private Button mFlatten;
- private List<String> mClassNames;
+ private List<Pair<String, ViewElementDescriptor>> mClassNames;
public InputPage(IProject project, String oldType) {
super("ChangeLayoutInputPage"); //$NON-NLS-1$
@@ -91,6 +92,7 @@ class ChangeLayoutWizard extends VisualRefactoringWizard {
}
};
mTypeCombo.addSelectionListener(selectionListener);
+ mTypeCombo.addSelectionListener(mSelectionValidateListener);
mFlatten = new Button(composite, SWT.CHECK);
mFlatten.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER,
@@ -99,6 +101,7 @@ class ChangeLayoutWizard extends VisualRefactoringWizard {
mFlatten.addSelectionListener(selectionListener);
// Should flattening be selected by default?
mFlatten.setSelection(true);
+ mFlatten.addSelectionListener(mSelectionValidateListener);
// We don't exclude RelativeLayout even if the current layout is RelativeLayout,
// in case you are trying to flatten the hierarchy for a hierarchy that has a
@@ -127,11 +130,12 @@ class ChangeLayoutWizard extends VisualRefactoringWizard {
validatePage();
}
- private boolean validatePage() {
+ @Override
+ protected boolean validatePage() {
boolean ok = true;
int selectionIndex = mTypeCombo.getSelectionIndex();
- String type = selectionIndex != -1 ? mClassNames.get(selectionIndex) : null;
+ String type = selectionIndex != -1 ? mClassNames.get(selectionIndex).getFirst() : null;
if (type == null) {
setErrorMessage("Select a layout type");
ok = false; // The user has chosen a separator
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeViewRefactoring.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeViewRefactoring.java
index 181f4139f..045062a04 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeViewRefactoring.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeViewRefactoring.java
@@ -39,7 +39,10 @@ import org.eclipse.ltk.core.refactoring.RefactoringStatus;
import org.eclipse.ltk.core.refactoring.TextFileChange;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.ReplaceEdit;
+import org.eclipse.text.edits.TextEdit;
+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.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
@@ -172,7 +175,28 @@ public class ChangeViewRefactoring extends VisualRefactoring {
}
// Change tag type
- ensureIdMatchesType(element, mTypeFqcn, rootEdit);
+ String oldId = getId(element);
+ String newId = ensureIdMatchesType(element, mTypeFqcn, rootEdit);
+ // Update any layout references to the old id with the new id
+ if (oldId != null && newId != null) {
+ IStructuredModel model = mEditor.getModelForRead();
+ try {
+ IStructuredDocument doc = model.getStructuredDocument();
+ if (doc != null) {
+ IndexedRegion range = getRegion(element);
+ int skipStart = range.getStartOffset();
+ int skipEnd = range.getEndOffset();
+ List<TextEdit> replaceIds = replaceIds(getAndroidNamespacePrefix(), doc,
+ skipStart, skipEnd,
+ oldId, newId);
+ for (TextEdit edit : replaceIds) {
+ rootEdit.addChild(edit);
+ }
+ }
+ } finally {
+ model.releaseFromRead();
+ }
+ }
// Strip out attributes that no longer make sense
removeUndefinedAttrs(rootEdit, element);
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeViewWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeViewWizard.java
index a1e243544..96d8408ba 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeViewWizard.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeViewWizard.java
@@ -26,10 +26,7 @@ import com.android.sdklib.IAndroidTarget;
import com.android.util.Pair;
import org.eclipse.core.resources.IProject;
-import org.eclipse.ltk.ui.refactoring.UserInputWizardPage;
import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Combo;
@@ -66,7 +63,7 @@ class ChangeViewWizard extends VisualRefactoringWizard {
}
/** Wizard page which inputs parameters for the {@link ChangeViewRefactoring} operation */
- private static class InputPage extends UserInputWizardPage {
+ private static class InputPage extends VisualRefactoringInputPage {
private final IProject mProject;
private Combo mTypeCombo;
private final String mOldType;
@@ -88,13 +85,7 @@ class ChangeViewWizard extends VisualRefactoringWizard {
mTypeCombo = new Combo(composite, SWT.READ_ONLY);
mTypeCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
- SelectionAdapter selectionListener = new SelectionAdapter() {
- @Override
- public void widgetSelected(SelectionEvent e) {
- validatePage();
- }
- };
- mTypeCombo.addSelectionListener(selectionListener);
+ mTypeCombo.addSelectionListener(mSelectionValidateListener);
mClassNames = getWidgetTypes(mOldType, mTypeCombo);
mTypeCombo.select(0);
@@ -177,7 +168,8 @@ class ChangeViewWizard extends VisualRefactoringWizard {
return classNames;
}
- private boolean validatePage() {
+ @Override
+ protected boolean validatePage() {
boolean ok = true;
int selectionIndex = mTypeCombo.getSelectionIndex();
String type = selectionIndex != -1 ? mClassNames.get(selectionIndex) : null;
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractIncludeRefactoring.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractIncludeRefactoring.java
index d5921bfbd..1909a189e 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractIncludeRefactoring.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractIncludeRefactoring.java
@@ -15,6 +15,7 @@
*/
package com.android.ide.eclipse.adt.internal.editors.layout.refactoring;
+import static com.android.AndroidConstants.FD_RES_LAYOUT;
import static com.android.ide.common.layout.LayoutConstants.ANDROID_NS_NAME;
import static com.android.ide.common.layout.LayoutConstants.ANDROID_URI;
import static com.android.ide.common.layout.LayoutConstants.ATTR_ID;
@@ -30,6 +31,7 @@ import static com.android.ide.eclipse.adt.AdtConstants.WS_SEP;
import static com.android.ide.eclipse.adt.internal.editors.descriptors.XmlnsAttributeDescriptor.XMLNS;
import static com.android.ide.eclipse.adt.internal.editors.descriptors.XmlnsAttributeDescriptor.XMLNS_COLON;
import static com.android.resources.ResourceType.LAYOUT;
+import static com.android.sdklib.SdkConstants.FD_RES;
import com.android.annotations.VisibleForTesting;
import com.android.ide.eclipse.adt.AdtConstants;
@@ -40,11 +42,11 @@ import com.android.ide.eclipse.adt.internal.editors.layout.gle2.CanvasViewInfo;
import com.android.ide.eclipse.adt.internal.editors.layout.gle2.DomUtilities;
import com.android.ide.eclipse.adt.internal.editors.layout.uimodel.UiViewElementNode;
import com.android.ide.eclipse.adt.internal.resources.ResourceNameValidator;
-import com.android.util.Pair;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
@@ -64,13 +66,20 @@ import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.ReplaceEdit;
import org.eclipse.text.edits.TextEdit;
import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.wst.sse.core.StructuredModelManager;
+import org.eclipse.wst.sse.core.internal.provisional.IModelManager;
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.xml.core.internal.provisional.document.IDOMDocument;
+import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel;
import org.w3c.dom.Attr;
+import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -84,10 +93,8 @@ import java.util.Map;
public class ExtractIncludeRefactoring extends VisualRefactoring {
private static final String KEY_NAME = "name"; //$NON-NLS-1$
private static final String KEY_OCCURRENCES = "all-occurrences"; //$NON-NLS-1$
- private static final String KEY_UPDATE_REFS = "update-refs"; //$NON-NLS-1$
private String mLayoutName;
private boolean mReplaceOccurrences;
- private boolean mUpdateReferences;
/**
* This constructor is solely used by {@link Descriptor},
@@ -97,7 +104,6 @@ public class ExtractIncludeRefactoring extends VisualRefactoring {
ExtractIncludeRefactoring(Map<String, String> arguments) {
super(arguments);
mLayoutName = arguments.get(KEY_NAME);
- mUpdateReferences = Boolean.parseBoolean(arguments.get(KEY_UPDATE_REFS));
mReplaceOccurrences = Boolean.parseBoolean(arguments.get(KEY_OCCURRENCES));
}
@@ -182,7 +188,6 @@ public class ExtractIncludeRefactoring extends VisualRefactoring {
protected Map<String, String> createArgumentMap() {
Map<String, String> args = super.createArgumentMap();
args.put(KEY_NAME, mLayoutName);
- args.put(KEY_UPDATE_REFS, Boolean.toString(mUpdateReferences));
args.put(KEY_OCCURRENCES, Boolean.toString(mReplaceOccurrences));
return args;
@@ -197,10 +202,6 @@ public class ExtractIncludeRefactoring extends VisualRefactoring {
mLayoutName = layoutName;
}
- void setUpdateReferences(boolean selection) {
- mUpdateReferences = selection;
- }
-
void setReplaceOccurrences(boolean selection) {
mReplaceOccurrences = selection;
}
@@ -211,9 +212,7 @@ public class ExtractIncludeRefactoring extends VisualRefactoring {
protected List<Change> computeChanges() {
String extractedText = getExtractedText();
- Pair<String, String> namespace = computeNamespaces();
- String androidNsPrefix = namespace.getFirst();
- String namespaceDeclarations = namespace.getSecond();
+ String namespaceDeclarations = computeNamespaceDeclarations();
// Insert namespace:
extractedText = insertNamespace(extractedText, namespaceDeclarations);
@@ -229,6 +228,94 @@ public class ExtractIncludeRefactoring extends VisualRefactoring {
IProject project = mEditor.getProject();
IFile sourceFile = mEditor.getInputFile();
+ // Replace extracted elements by <include> tag
+ handleIncludingFile(changes, sourceFile, mSelectionStart, mSelectionEnd,
+ getDomDocument(), getPrimaryElement());
+
+ // Also extract in other variations of the same file (landscape/portrait, etc)
+ boolean haveVariations = false;
+ if (mReplaceOccurrences) {
+ //String id = primary.getAttributeNS(ANDROID_URI, ATTR_ID);
+ List<IFile> variations = getConfigurationVariations(sourceFile);
+ for (IFile variation : variations) {
+ IModelManager modelManager = StructuredModelManager.getModelManager();
+ IStructuredModel model = null;
+ try {
+ model = modelManager.getModelForRead(variation);
+ if (model instanceof IDOMModel) {
+ IDOMModel domModel = (IDOMModel) model;
+ IDOMDocument otherDocument = domModel.getDocument();
+ List<Element> otherElements = new ArrayList<Element>();
+ Element otherPrimary = null;
+
+ for (Element element : getElements()) {
+ Element other = DomUtilities.findCorresponding(element,
+ otherDocument);
+ if (other != null) {
+ // See if the structure is similar to what we have in this
+ // document
+ if (DomUtilities.isEquivalent(element, other)) {
+ otherElements.add(other);
+ if (element == getPrimaryElement()) {
+ otherPrimary = other;
+ }
+ }
+ }
+ }
+
+ // Only perform extract in the other file if we find a match for
+ // ALL of elements being extracted, and if they too are contiguous
+ if (otherElements.size() == getElements().size() &&
+ DomUtilities.isContiguous(otherElements)) {
+ // Find the range
+ int begin = Integer.MAX_VALUE;
+ int end = Integer.MIN_VALUE;
+ for (Element element : otherElements) {
+ // Yes!! Extract this one as well!
+ IndexedRegion region = getRegion(element);
+ end = Math.max(end, region.getEndOffset());
+ begin = Math.min(begin, region.getStartOffset());
+ }
+ handleIncludingFile(changes, variation, begin,
+ end, otherDocument, otherPrimary);
+ haveVariations = true;
+ }
+ }
+ } catch (IOException e) {
+ AdtPlugin.log(e, null);
+ } catch (CoreException e) {
+ AdtPlugin.log(e, null);
+ } finally {
+ if (model != null) {
+ model.releaseFromRead();
+ }
+ }
+ }
+ }
+
+ // Add change to create the new file
+ IContainer parent = sourceFile.getParent();
+ if (haveVariations) {
+ // If we're extracting from multiple configuration folders, then we need to
+ // place the extracted include in the base layout folder (if not it goes next to
+ // the including file)
+ parent = mProject.getFolder(FD_RES).getFolder(FD_RES_LAYOUT);
+ }
+ IPath parentPath = parent.getProjectRelativePath();
+ final IFile file = project.getFile(new Path(parentPath + WS_SEP + newFileName));
+ TextFileChange addFile = new TextFileChange("Create new separate layout", file);
+ addFile.setTextType(AdtConstants.EXT_XML);
+ changes.add(addFile);
+ addFile.setEdit(new InsertEdit(0, sb.toString()));
+
+ Change finishHook = createFinishHook(file);
+ changes.add(finishHook);
+
+ return changes;
+ }
+
+ private void handleIncludingFile(List<Change> changes,
+ IFile sourceFile, int begin, int end, Document document, Element primary) {
TextFileChange change = new TextFileChange(sourceFile.getName(), sourceFile);
MultiTextEdit rootEdit = new MultiTextEdit();
change.setEdit(rootEdit);
@@ -237,42 +324,75 @@ public class ExtractIncludeRefactoring extends VisualRefactoring {
String referenceId = getReferenceId();
// Replace existing elements in the source file and insert <include>
- String include = computeIncludeString(mLayoutName, androidNsPrefix, referenceId);
- int length = mSelectionEnd - mSelectionStart;
- ReplaceEdit replace = new ReplaceEdit(mSelectionStart, length, include);
+ String androidNsPrefix = getAndroidNamespacePrefix(document);
+ String include = computeIncludeString(primary, mLayoutName, androidNsPrefix, referenceId);
+ int length = end - begin;
+ ReplaceEdit replace = new ReplaceEdit(begin, length, include);
rootEdit.addChild(replace);
// Update any layout references to the old id with the new id
- if (mUpdateReferences && referenceId != null) {
- String rootId = getRootId();
- IStructuredModel model = mEditor.getModelForRead();
+ if (referenceId != null && primary != null) {
+ String rootId = getId(primary);
+ IStructuredModel model = null;
try {
+ model = StructuredModelManager.getModelManager().getModelForRead(sourceFile);
IStructuredDocument doc = model.getStructuredDocument();
- if (doc != null) {
- List<TextEdit> replaceIds = replaceIds(doc, mSelectionStart,
- mSelectionEnd, rootId, referenceId);
+ if (doc != null && rootId != null) {
+ List<TextEdit> replaceIds = replaceIds(androidNsPrefix, doc, begin,
+ end, rootId, referenceId);
for (TextEdit edit : replaceIds) {
rootEdit.addChild(edit);
}
}
+ } catch (IOException e) {
+ AdtPlugin.log(e, null);
+ } catch (CoreException e) {
+ AdtPlugin.log(e, null);
} finally {
- model.releaseFromRead();
+ if (model != null) {
+ model.releaseFromRead();
+ }
}
}
+ }
- // Add change to create the new file
- IContainer parent = sourceFile.getParent();
- IPath parentPath = parent.getProjectRelativePath();
- final IFile file = project.getFile(new Path(parentPath + WS_SEP + newFileName));
- TextFileChange addFile = new TextFileChange("Create new separate layout", file);
- addFile.setTextType(AdtConstants.EXT_XML);
- changes.add(addFile);
- addFile.setEdit(new InsertEdit(0, sb.toString()));
+ /**
+ * This method returns all the configuration variations of the given layout. For
+ * example, if you have both layout/foo.xml and layout-land/foo.xml and
+ * layout-xlarge/foo.xml, then calling this method on any of the three files will
+ * return the other two.
+ *
+ * @param file the file to find configuration variations of
+ * @return the other layout variations of the file
+ */
+ public static List<IFile> getConfigurationVariations(IFile file) {
+ List<IFile> variations = new ArrayList<IFile>();
- Change finishHook = createFinishHook(file);
- changes.add(finishHook);
+ // This currently just searches the layout folders in the project for an exact
+ // resource name match. This could later use ProjectResources instead, but
+ // currently that's not done since it doesn't work from the tests.
- return changes;
+ String name = file.getName();
+ IContainer resFolder = file.getParent().getParent();
+ try {
+ for (IResource member : resFolder.members()) {
+ if (member.getName().startsWith(FD_RES_LAYOUT)) {
+ if (member instanceof IContainer) {
+ IContainer container = (IContainer) member;
+ IResource alternative = container.findMember(name);
+ IPath relPath = file.getProjectRelativePath();
+ if (alternative instanceof IFile
+ && !alternative.getProjectRelativePath().equals(relPath)) {
+ variations.add((IFile) alternative);
+ }
+ }
+ }
+ }
+ } catch (CoreException e) {
+ AdtPlugin.log(e, null);
+ }
+
+ return variations;
}
String getInitialName() {
@@ -297,6 +417,10 @@ public class ExtractIncludeRefactoring extends VisualRefactoring {
return defaultName;
}
+ IFile getSourceFile() {
+ return mFile;
+ }
+
private Change createFinishHook(final IFile file) {
return new NullChange("Open extracted layout and refresh resources") {
@Override
@@ -322,7 +446,7 @@ public class ExtractIncludeRefactoring extends VisualRefactoring {
};
}
- private Pair<String, String> computeNamespaces() {
+ private String computeNamespaceDeclarations() {
String androidNsPrefix = null;
String namespaceDeclarations = null;
@@ -364,7 +488,7 @@ public class ExtractIncludeRefactoring extends VisualRefactoring {
namespaceDeclarations = sb.toString();
}
- return Pair.of(androidNsPrefix, namespaceDeclarations);
+ return namespaceDeclarations;
}
/** Returns the id to be used for the include tag itself (may be null) */
@@ -381,8 +505,8 @@ public class ExtractIncludeRefactoring extends VisualRefactoring {
* Compute the actual {@code <include>} string to be inserted in place of the old
* selection
*/
- private String computeIncludeString(String newName, String androidNsPrefix,
- String referenceId) {
+ private static String computeIncludeString(Element primaryNode, String newName,
+ String androidNsPrefix, String referenceId) {
StringBuilder sb = new StringBuilder();
sb.append("<include layout=\"@layout/"); //$NON-NLS-1$
sb.append(newName);
@@ -408,7 +532,6 @@ public class ExtractIncludeRefactoring extends VisualRefactoring {
// HACK: see issue 13494: We must duplicate the width/height attributes on the
// <include> statement for designtime rendering only
- Element primaryNode = getPrimaryElement();
String width = null;
String height = null;
if (primaryNode == null) {
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractIncludeWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractIncludeWizard.java
index 403c75311..9b111ab47 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractIncludeWizard.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractIncludeWizard.java
@@ -16,15 +16,13 @@
package com.android.ide.eclipse.adt.internal.editors.layout.refactoring;
-import com.android.ide.eclipse.adt.internal.resources.ResourceNameValidator;
import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditor;
+import com.android.ide.eclipse.adt.internal.resources.ResourceNameValidator;
import com.android.resources.ResourceType;
+import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
-import org.eclipse.ltk.ui.refactoring.UserInputWizardPage;
import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.ModifyEvent;
-import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
@@ -32,6 +30,8 @@ import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
+import java.util.List;
+
class ExtractIncludeWizard extends VisualRefactoringWizard {
public ExtractIncludeWizard(ExtractIncludeRefactoring ref, LayoutEditor editor) {
super(ref, editor);
@@ -42,20 +42,22 @@ class ExtractIncludeWizard extends VisualRefactoringWizard {
protected void addUserInputPages() {
ExtractIncludeRefactoring ref = (ExtractIncludeRefactoring) getRefactoring();
String initialName = ref.getInitialName();
- addPage(new InputPage(mEditor.getProject(), initialName));
+ IFile sourceFile = ref.getSourceFile();
+ addPage(new InputPage(mEditor.getProject(), sourceFile, initialName));
}
/** Wizard page which inputs parameters for the {@link ExtractIncludeRefactoring} operation */
- private static class InputPage extends UserInputWizardPage {
+ private static class InputPage extends VisualRefactoringInputPage {
private final IProject mProject;
+ private final IFile mSourceFile;
private final String mSuggestedName;
private Text mNameText;
- private Button mUpdateReferences;
private Button mReplaceAllOccurrences;
- public InputPage(IProject project, String suggestedName) {
- super("ExtractIncludeInputPage"); //$NON-NLS-1$
+ public InputPage(IProject project, IFile sourceFile, String suggestedName) {
+ super("ExtractIncludeInputPage");
mProject = project;
+ mSourceFile = sourceFile;
mSuggestedName = suggestedName;
}
@@ -69,23 +71,19 @@ class ExtractIncludeWizard extends VisualRefactoringWizard {
mNameText = new Text(composite, SWT.BORDER);
mNameText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
- mNameText.addModifyListener(new ModifyListener() {
- public void modifyText(ModifyEvent e) {
- validatePage();
- }
- });
-
- mUpdateReferences = new Button(composite, SWT.CHECK);
- mUpdateReferences.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER,
- false, false, 2, 1));
- mUpdateReferences.setSelection(true);
- mUpdateReferences.setText("Update layout references");
+ mNameText.addModifyListener(mModifyValidateListener);
mReplaceAllOccurrences = new Button(composite, SWT.CHECK);
mReplaceAllOccurrences.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER,
false, false, 2, 1));
- mReplaceAllOccurrences.setText("Replace all occurrences with include to new layout");
- mReplaceAllOccurrences.setEnabled(false);
+ mReplaceAllOccurrences.setText(
+ "Replace occurrences in all layouts with include to new layout");
+ List<IFile> variations =
+ ExtractIncludeRefactoring.getConfigurationVariations(mSourceFile);
+ boolean enabled = variations.size() > 0;
+ mReplaceAllOccurrences.setEnabled(enabled);
+ mReplaceAllOccurrences.setSelection(enabled);
+ mReplaceAllOccurrences.addSelectionListener(mSelectionValidateListener);
// Initialize UI:
if (mSuggestedName != null) {
@@ -96,7 +94,8 @@ class ExtractIncludeWizard extends VisualRefactoringWizard {
validatePage();
}
- private boolean validatePage() {
+ @Override
+ protected boolean validatePage() {
boolean ok = true;
String text = mNameText.getText().trim();
@@ -122,7 +121,6 @@ class ExtractIncludeWizard extends VisualRefactoringWizard {
(ExtractIncludeRefactoring) getRefactoring();
refactoring.setLayoutName(text);
refactoring.setReplaceOccurrences(mReplaceAllOccurrences.getSelection());
- refactoring.setUpdateReferences(mUpdateReferences.getSelection());
}
setPageComplete(ok);
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/RelativeLayoutConversionHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/RelativeLayoutConversionHelper.java
index 8834210c8..6e8541291 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/RelativeLayoutConversionHelper.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/RelativeLayoutConversionHelper.java
@@ -65,6 +65,7 @@ import static com.android.ide.common.layout.LayoutConstants.VALUE_WRAP_CONTENT;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor;
import com.android.ide.eclipse.adt.internal.editors.layout.gle2.CanvasViewInfo;
+import com.android.ide.eclipse.adt.internal.editors.layout.gle2.DomUtilities;
import com.android.util.Pair;
import org.eclipse.core.runtime.IStatus;
@@ -370,29 +371,6 @@ class RelativeLayoutConversionHelper {
}
/**
- * Returns the element children of the given element
- *
- * @param element the parent element
- * @return a list of child elements, possibly empty but never null
- */
- public static List<Element> getChildren(Element element) {
- // Convenience to avoid lots of ugly DOM access casting
- NodeList children = element.getChildNodes();
- // An iterator would have been more natural (to directly drive the child list
- // iteration) but iterators can't be used in enhanced for loops...
- List<Element> result = new ArrayList<Element>(children.getLength());
- for (int i = 0, n = children.getLength(); i < n; i++) {
- Node node = children.item(i);
- if (node.getNodeType() == Node.ELEMENT_NODE) {
- Element child = (Element) node;
- result.add(child);
- }
- }
-
- return result;
- }
-
- /**
* Returns the layout weight of of the given child of a LinearLayout, or 0.0 if it
* does not define a weight
*/
@@ -417,7 +395,7 @@ class RelativeLayoutConversionHelper {
*/
private float getWeightSum(Element linearLayout) {
float sum = 0;
- for (Element child : getChildren(linearLayout)) {
+ for (Element child : DomUtilities.getChildren(linearLayout)) {
sum += getWeight(child);
}
@@ -439,7 +417,7 @@ class RelativeLayoutConversionHelper {
// Baseline alignment. Find the tallest child and set it as the baseline reference.
int tallestHeight = 0;
View tallest = null;
- for (Element child : getChildren(layout)) {
+ for (Element child : DomUtilities.getChildren(layout)) {
View view = edgeList.getView(child);
if (view != null && view.getHeight() > tallestHeight) {
tallestHeight = view.getHeight();
@@ -454,7 +432,7 @@ class RelativeLayoutConversionHelper {
float weightSum = getWeightSum(layout);
float cumulativeWeight = 0;
- List<Element> children = getChildren(layout);
+ List<Element> children = DomUtilities.getChildren(layout);
String prevId = null;
boolean isFirstChild = true;
boolean linkBackwards = true;
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/VisualRefactoring.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/VisualRefactoring.java
index 3cce3b349..65ec7fd5e 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/VisualRefactoring.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/VisualRefactoring.java
@@ -32,7 +32,6 @@ 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.LayoutEditor;
import com.android.ide.eclipse.adt.internal.editors.layout.configuration.ConfigurationComposite;
-import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors;
import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.ViewElementDescriptor;
import com.android.ide.eclipse.adt.internal.editors.layout.gle2.CanvasViewInfo;
import com.android.ide.eclipse.adt.internal.editors.layout.gle2.DomUtilities;
@@ -210,119 +209,6 @@ public abstract class VisualRefactoring extends Refactoring {
mElements = initElements();
}
- @Override
- public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException,
- OperationCanceledException {
- RefactoringStatus status = new RefactoringStatus();
-
- try {
- pm.beginTask("Checking preconditions...", 6);
-
- if (mSelectionStart == -1 || mSelectionEnd == -1) {
- status.addFatalError("No selection to extract");
- return status;
- }
-
- // Make sure the selection is contiguous
- if (mTreeSelection != null) {
- // TODO - don't do this if we based the selection on text. In this case,
- // make sure we're -balanced-.
-
- List<CanvasViewInfo> infos = new ArrayList<CanvasViewInfo>();
- for (TreePath path : mTreeSelection.getPaths()) {
- Object lastSegment = path.getLastSegment();
- if (lastSegment instanceof CanvasViewInfo) {
- infos.add((CanvasViewInfo) lastSegment);
- }
- }
-
- if (infos.size() == 0) {
- status.addFatalError("No selection to extract");
- return status;
- }
-
- // Can't extract the root -- wouldn't that be pointless? (or maybe not
- // always)
- for (CanvasViewInfo info : infos) {
- if (info.isRoot()) {
- status.addFatalError("Cannot refactor the root");
- return status;
- }
- }
-
- // Disable if you've selected a single include tag
- if (infos.size() == 1) {
- UiViewElementNode uiNode = infos.get(0).getUiViewNode();
- if (uiNode != null) {
- Node xmlNode = uiNode.getXmlNode();
- if (xmlNode.getLocalName().equals(LayoutDescriptors.VIEW_INCLUDE)) {
- status.addWarning("No point in refactoring a single include tag");
- }
- }
- }
-
- // Enforce that the selection is -contiguous-
- if (infos.size() > 1) {
- // All elements must be siblings (e.g. same parent)
- List<UiViewElementNode> nodes = new ArrayList<UiViewElementNode>(infos
- .size());
- for (CanvasViewInfo info : infos) {
- UiViewElementNode node = info.getUiViewNode();
- if (node != null) {
- nodes.add(node);
- }
- }
- if (nodes.size() == 0) {
- status.addFatalError("No selected views");
- return status;
- }
-
- UiElementNode parent = nodes.get(0).getUiParent();
- for (UiViewElementNode node : nodes) {
- if (parent != node.getUiParent()) {
- status.addFatalError("The selected elements must be adjacent");
- return status;
- }
- }
- // Ensure that the siblings are contiguous; no gaps.
- // If we've selected all the children of the parent then we don't need
- // to look.
- List<UiElementNode> siblings = parent.getUiChildren();
- if (siblings.size() != nodes.size()) {
- Set<UiViewElementNode> nodeSet = new HashSet<UiViewElementNode>(nodes);
- boolean inRange = false;
- int remaining = nodes.size();
- for (UiElementNode node : siblings) {
- boolean in = nodeSet.contains(node);
- if (in) {
- remaining--;
- if (remaining == 0) {
- break;
- }
- inRange = true;
- } else if (inRange) {
- status.addFatalError("The selected elements must be adjacent");
- return status;
- }
- }
- }
- }
- }
-
- // Ensures that we have a valid DOM model:
- if (mElements.size() == 0) {
- status.addFatalError("Nothing to extract");
- return status;
- }
-
- pm.worked(1);
- return status;
-
- } finally {
- pm.done();
- }
- }
-
protected abstract List<Change> computeChanges();
@Override
@@ -429,7 +315,8 @@ public abstract class VisualRefactoring extends Refactoring {
/** Produce a list of edits to replace references to the given id with the given new id */
- protected List<TextEdit> replaceIds(IStructuredDocument doc, int skipStart, int skipEnd,
+ protected static List<TextEdit> replaceIds(String androidNamePrefix,
+ IStructuredDocument doc, int skipStart, int skipEnd,
String rootId, String referenceId) {
if (rootId == null) {
return Collections.emptyList();
@@ -448,7 +335,7 @@ public abstract class VisualRefactoring extends Refactoring {
return Collections.emptyList();
}
- String namePrefix = getAndroidNamespacePrefix() + ':' + ATTR_LAYOUT_PREFIX;
+ String namePrefix = androidNamePrefix + ':' + ATTR_LAYOUT_PREFIX;
List<TextEdit> edits = new ArrayList<TextEdit>();
IStructuredDocumentRegion region = doc.getFirstStructuredDocumentRegion();
@@ -528,8 +415,37 @@ public abstract class VisualRefactoring extends Refactoring {
return mAndroidNamespacePrefix;
}
+ protected static String getAndroidNamespacePrefix(Document document) {
+ String nsPrefix = null;
+ List<Attr> attributeNodes = findNamespaceAttributes(document);
+ for (Node attributeNode : attributeNodes) {
+ String prefix = attributeNode.getPrefix();
+ if (XMLNS.equals(prefix)) {
+ String name = attributeNode.getNodeName();
+ String value = attributeNode.getNodeValue();
+ if (value.equals(ANDROID_URI)) {
+ nsPrefix = name;
+ if (nsPrefix.startsWith(XMLNS_COLON)) {
+ nsPrefix =
+ nsPrefix.substring(XMLNS_COLON.length());
+ }
+ }
+ }
+ }
+
+ if (nsPrefix == null) {
+ nsPrefix = ANDROID_NS_NAME;
+ }
+
+ return nsPrefix;
+ }
+
protected List<Attr> findNamespaceAttributes() {
Document document = getDomDocument();
+ return findNamespaceAttributes(document);
+ }
+
+ protected static List<Attr> findNamespaceAttributes(Document document) {
if (document != null) {
Element root = document.getDocumentElement();
return findNamespaceAttributes(root);
@@ -538,7 +454,7 @@ public abstract class VisualRefactoring extends Refactoring {
return Collections.emptyList();
}
- protected List<Attr> findNamespaceAttributes(Node root) {
+ protected static List<Attr> findNamespaceAttributes(Node root) {
List<Attr> result = new ArrayList<Attr>();
NamedNodeMap attributes = root.getAttributes();
for (int i = 0, n = attributes.getLength(); i < n; i++) {
@@ -894,7 +810,11 @@ public abstract class VisualRefactoring extends Refactoring {
return true;
}
- protected void ensureIdMatchesType(Element element, String newType, MultiTextEdit rootEdit) {
+ /**
+ * Updates the given element with a new name if the current id reflects the old
+ * element type. If the name was changed, it will return the new name.
+ */
+ protected String ensureIdMatchesType(Element element, String newType, MultiTextEdit rootEdit) {
String oldType = element.getTagName();
if (oldType.indexOf('.') == -1) {
oldType = ANDROID_WIDGET_PREFIX + oldType;
@@ -903,8 +823,10 @@ public abstract class VisualRefactoring extends Refactoring {
String id = getId(element);
if (id == null || id.toLowerCase().contains(oldTypeBase.toLowerCase())) {
String newTypeBase = newType.substring(newType.lastIndexOf('.') + 1);
- ensureHasId(rootEdit, element, newTypeBase);
+ return ensureHasId(rootEdit, element, newTypeBase);
}
+
+ return null;
}
protected static IndexedRegion getRegion(Node node) {
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/VisualRefactoringAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/VisualRefactoringAction.java
index 627f1b128..48181328f 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/VisualRefactoringAction.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/VisualRefactoringAction.java
@@ -15,8 +15,8 @@
*/
package com.android.ide.eclipse.adt.internal.editors.layout.refactoring;
-import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.AdtConstants;
+import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditor;
import com.android.ide.eclipse.adt.internal.editors.layout.gle2.CanvasViewInfo;
@@ -56,7 +56,7 @@ abstract class VisualRefactoringAction implements IWorkbenchWindowActionDelegate
/**
* Examine the selection to determine if the action should be enabled or not.
* <p/>
- * Keep a link to the relevant selection structure (i.e. a part of the Java AST).
+ * Keep a link to the relevant selection structure
*/
public void selectionChanged(IAction action, ISelection selection) {
// Look for selections in XML and in the layout UI editor
@@ -76,10 +76,8 @@ abstract class VisualRefactoringAction implements IWorkbenchWindowActionDelegate
if (selection instanceof ITextSelection) {
mTextSelection = (ITextSelection) selection;
- if (mTextSelection.getLength() > 0) {
- editor = getActiveEditor();
- mFile = getSelectedFile(editor);
- }
+ editor = getActiveEditor();
+ mFile = getSelectedFile(editor);
} else if (selection instanceof ITreeSelection) {
Object firstElement = ((ITreeSelection)selection).getFirstElement();
if (firstElement instanceof CanvasViewInfo) {
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/VisualRefactoringWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/VisualRefactoringWizard.java
index dceba6e62..2b6f25e91 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/VisualRefactoringWizard.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/VisualRefactoringWizard.java
@@ -19,6 +19,11 @@ import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditor;
import org.eclipse.ltk.core.refactoring.Refactoring;
import org.eclipse.ltk.ui.refactoring.RefactoringWizard;
+import org.eclipse.ltk.ui.refactoring.UserInputWizardPage;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
public abstract class VisualRefactoringWizard extends RefactoringWizard {
protected final LayoutEditor mEditor;
@@ -38,4 +43,33 @@ public abstract class VisualRefactoringWizard extends RefactoringWizard {
mEditor.refreshXmlModel();
}
}
+
+ protected abstract static class VisualRefactoringInputPage extends UserInputWizardPage {
+ public VisualRefactoringInputPage(String name) {
+ super(name);
+ }
+
+ /**
+ * Listener which can be attached on any widget in the wizard page to force
+ * modifications of the associated widget to validate the page again
+ */
+ protected ModifyListener mModifyValidateListener = new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ validatePage();
+ }
+ };
+
+ /**
+ * Listener which can be attached on any widget in the wizard page to force
+ * selection changes of the associated widget to validate the page again
+ */
+ protected SelectionAdapter mSelectionValidateListener = new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ validatePage();
+ }
+ };
+
+ protected abstract boolean validatePage();
+ }
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/WrapInRefactoring.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/WrapInRefactoring.java
index 3c95d94de..708304a89 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/WrapInRefactoring.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/WrapInRefactoring.java
@@ -15,6 +15,7 @@
*/
package com.android.ide.eclipse.adt.internal.editors.layout.refactoring;
+import static com.android.ide.common.layout.LayoutConstants.ANDROID_NS_NAME_PREFIX;
import static com.android.ide.common.layout.LayoutConstants.ANDROID_URI;
import static com.android.ide.common.layout.LayoutConstants.ANDROID_WIDGET_PREFIX;
import static com.android.ide.common.layout.LayoutConstants.ATTR_ID;
@@ -63,11 +64,10 @@ import java.util.Map;
public class WrapInRefactoring extends VisualRefactoring {
private static final String KEY_ID = "name"; //$NON-NLS-1$
private static final String KEY_TYPE = "type"; //$NON-NLS-1$
- private static final String KEY_UPDATE_REFS = "update-refs"; //$NON-NLS-1$
private String mId;
private String mTypeFqcn;
- private boolean mUpdateReferences;
+ private String mInitializedAttributes;
/**
* This constructor is solely used by {@link Descriptor},
@@ -78,7 +78,6 @@ public class WrapInRefactoring extends VisualRefactoring {
super(arguments);
mId = arguments.get(KEY_ID);
mTypeFqcn = arguments.get(KEY_TYPE);
- mUpdateReferences = Boolean.parseBoolean(arguments.get(KEY_UPDATE_REFS));
}
public WrapInRefactoring(IFile file, LayoutEditor editor, ITextSelection selection,
@@ -149,7 +148,6 @@ public class WrapInRefactoring extends VisualRefactoring {
Map<String, String> args = super.createArgumentMap();
args.put(KEY_TYPE, mTypeFqcn);
args.put(KEY_ID, mId);
- args.put(KEY_UPDATE_REFS, Boolean.toString(mUpdateReferences));
return args;
}
@@ -167,8 +165,8 @@ public class WrapInRefactoring extends VisualRefactoring {
mTypeFqcn = typeFqcn;
}
- void setUpdateReferences(boolean selection) {
- mUpdateReferences = selection;
+ void setInitializedAttributes(String initializedAttributes) {
+ mInitializedAttributes = initializedAttributes;
}
@Override
@@ -194,6 +192,8 @@ public class WrapInRefactoring extends VisualRefactoring {
String startIndent = AndroidXmlEditor.getIndentAtOffset(document, mSelectionStart);
String viewClass = getViewClass(mTypeFqcn);
+ String androidNsPrefix = getAndroidNamespacePrefix();
+
IFile file = mEditor.getInputFile();
List<Change> changes = new ArrayList<Change>();
@@ -205,14 +205,14 @@ public class WrapInRefactoring extends VisualRefactoring {
String id = ensureNewId(mId);
// Update any layout references to the old id with the new id
- if (mUpdateReferences && id != null) {
+ if (id != null) {
String rootId = getRootId();
IStructuredModel model = mEditor.getModelForRead();
try {
IStructuredDocument doc = model.getStructuredDocument();
if (doc != null) {
- List<TextEdit> replaceIds = replaceIds(doc, mSelectionStart,
- mSelectionEnd, rootId, id);
+ List<TextEdit> replaceIds = replaceIds(androidNsPrefix,
+ doc, mSelectionStart, mSelectionEnd, rootId, id);
for (TextEdit edit : replaceIds) {
rootEdit.addChild(edit);
}
@@ -262,8 +262,6 @@ public class WrapInRefactoring extends VisualRefactoring {
sb.append(namespace);
}
- String androidNsPrefix = getAndroidNamespacePrefix();
-
// Set the ID if any
if (id != null) {
if (separateAttributes) {
@@ -308,8 +306,22 @@ public class WrapInRefactoring extends VisualRefactoring {
sb.append(androidNsPrefix).append(':');
sb.append(ATTR_LAYOUT_HEIGHT).append('=').append('"').append(height).append('"');
+ if (mInitializedAttributes != null && mInitializedAttributes.length() > 0) {
+ for (String s : mInitializedAttributes.split(",")) { //$NON-NLS-1$
+ sb.append(' ');
+ String[] nameValue = s.split("="); //$NON-NLS-1$
+ String name = nameValue[0];
+ String value = nameValue[1];
+ if (name.startsWith(ANDROID_NS_NAME_PREFIX)) {
+ name = name.substring(ANDROID_NS_NAME_PREFIX.length());
+ sb.append(androidNsPrefix).append(':');
+ }
+ sb.append(name).append('=').append('"').append(value).append('"');
+ }
+ }
+
// Transfer layout_ attributes (other than width and height)
- if (mUpdateReferences) {
+ if (primary != null) {
List<Attr> layoutAttributes = findLayoutAttributes(primary);
for (Attr attribute : layoutAttributes) {
String name = attribute.getLocalName();
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/WrapInWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/WrapInWizard.java
index 033a6572a..d9e746ce3 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/WrapInWizard.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/WrapInWizard.java
@@ -29,6 +29,7 @@ import static com.android.sdklib.SdkConstants.FN_FRAMEWORK_LIBRARY;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditor;
import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.ViewElementDescriptor;
+import com.android.ide.eclipse.adt.internal.editors.layout.gre.PaletteMetadataDescriptor;
import com.android.ide.eclipse.adt.internal.editors.layout.gre.ViewMetadataRepository;
import com.android.ide.eclipse.adt.internal.resources.ResourceNameValidator;
import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
@@ -54,15 +55,9 @@ import org.eclipse.jdt.core.search.SearchPattern;
import org.eclipse.jdt.core.search.SearchRequestor;
import org.eclipse.jdt.internal.core.ResolvedBinaryType;
import org.eclipse.jdt.internal.core.ResolvedSourceType;
-import org.eclipse.ltk.ui.refactoring.UserInputWizardPage;
import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.ModifyEvent;
-import org.eclipse.swt.events.ModifyListener;
-import org.eclipse.swt.events.SelectionAdapter;
-import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
@@ -91,13 +86,12 @@ class WrapInWizard extends VisualRefactoringWizard {
}
/** Wizard page which inputs parameters for the {@link WrapInRefactoring} operation */
- private static class InputPage extends UserInputWizardPage {
+ private static class InputPage extends VisualRefactoringInputPage {
private final IProject mProject;
private final String mOldType;
private Text mIdText;
private Combo mTypeCombo;
- private Button mUpdateReferences;
- private List<String> mClassNames;
+ private List<Pair<String, ViewElementDescriptor>> mClassNames;
public InputPage(IProject project, String oldType) {
super("WrapInInputPage"); //$NON-NLS-1$
@@ -115,13 +109,7 @@ class WrapInWizard extends VisualRefactoringWizard {
mTypeCombo = new Combo(composite, SWT.READ_ONLY);
mTypeCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
- SelectionAdapter selectionListener = new SelectionAdapter() {
- @Override
- public void widgetSelected(SelectionEvent e) {
- validatePage();
- }
- };
- mTypeCombo.addSelectionListener(selectionListener);
+ mTypeCombo.addSelectionListener(mSelectionValidateListener);
Label idLabel = new Label(composite, SWT.NONE);
idLabel.setText("New Layout Id:");
@@ -129,18 +117,7 @@ class WrapInWizard extends VisualRefactoringWizard {
mIdText = new Text(composite, SWT.BORDER);
mIdText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
- mIdText.addModifyListener(new ModifyListener() {
- public void modifyText(ModifyEvent e) {
- validatePage();
- }
- });
-
- mUpdateReferences = new Button(composite, SWT.CHECK);
- mUpdateReferences.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER,
- false, false, 2, 1));
- mUpdateReferences.setSelection(true);
- mUpdateReferences.setText("Update layout references");
- mUpdateReferences.addSelectionListener(selectionListener);
+ mIdText.addModifyListener(mModifyValidateListener);
Set<String> exclude = Collections.singleton(VIEW_INCLUDE);
mClassNames = addLayouts(mProject, mOldType, mTypeCombo, exclude, true);
@@ -152,18 +129,15 @@ class WrapInWizard extends VisualRefactoringWizard {
mTypeCombo.setFocus();
}
- private boolean validatePage() {
+ @Override
+ protected boolean validatePage() {
boolean ok = true;
String id = mIdText.getText().trim();
if (id.length() == 0) {
- // It's okay to not define a title...
- // ...unless you want to update references
- if (mUpdateReferences.getSelection()) {
- setErrorMessage("ID required when updating layout references");
- ok = false;
- }
+ setErrorMessage("ID required");
+ ok = false;
} else {
// ...but if you do, it has to be valid!
ResourceNameValidator validator = ResourceNameValidator.create(false, mProject,
@@ -176,7 +150,7 @@ class WrapInWizard extends VisualRefactoringWizard {
}
int selectionIndex = mTypeCombo.getSelectionIndex();
- String type = selectionIndex != -1 ? mClassNames.get(selectionIndex) : null;
+ String type = selectionIndex != -1 ? mClassNames.get(selectionIndex).getFirst() : null;
if (type == null) {
setErrorMessage("Select a container type");
ok = false; // The user has chosen a separator
@@ -190,7 +164,16 @@ class WrapInWizard extends VisualRefactoringWizard {
(WrapInRefactoring) getRefactoring();
refactoring.setId(id);
refactoring.setType(type);
- refactoring.setUpdateReferences(mUpdateReferences.getSelection());
+
+ ViewElementDescriptor descriptor = mClassNames.get(selectionIndex).getSecond();
+ if (descriptor instanceof PaletteMetadataDescriptor) {
+ PaletteMetadataDescriptor paletteDescriptor =
+ (PaletteMetadataDescriptor) descriptor;
+ String initializedAttributes = paletteDescriptor.getInitializedAttributes();
+ refactoring.setInitializedAttributes(initializedAttributes);
+ } else {
+ refactoring.setInitializedAttributes(null);
+ }
}
setPageComplete(ok);
@@ -198,17 +181,19 @@ class WrapInWizard extends VisualRefactoringWizard {
}
}
- static List<String> addLayouts(IProject project, String oldType, Combo combo,
+ static List<Pair<String, ViewElementDescriptor>> addLayouts(IProject project,
+ String oldType, Combo combo,
Set<String> exclude, boolean addGestureOverlay) {
- List<String> classNames = new ArrayList<String>();
+ List<Pair<String, ViewElementDescriptor>> classNames =
+ new ArrayList<Pair<String, ViewElementDescriptor>>();
- if (oldType.equals(FQCN_RADIO_BUTTON)) {
+ if (oldType != null && oldType.equals(FQCN_RADIO_BUTTON)) {
combo.add(RADIO_GROUP);
// NOT a fully qualified name since android widgets do not include the package
- classNames.add(RADIO_GROUP);
+ classNames.add(Pair.of(RADIO_GROUP, (ViewElementDescriptor) null));
combo.add(SEPARATOR_LABEL);
- classNames.add(null);
+ classNames.add(Pair.<String,ViewElementDescriptor>of(null, null));
}
Pair<List<String>,List<String>> result = findViews(project, true);
@@ -217,10 +202,10 @@ class WrapInWizard extends VisualRefactoringWizard {
if (customViews.size() > 0) {
for (String view : customViews) {
combo.add(view);
- classNames.add(view);
+ classNames.add(Pair.of(view, (ViewElementDescriptor) null));
}
combo.add(SEPARATOR_LABEL);
- classNames.add(null);
+ classNames.add(Pair.<String,ViewElementDescriptor>of(null, null));
}
// Populate type combo
@@ -251,7 +236,7 @@ class WrapInWizard extends VisualRefactoringWizard {
String className = d.getFullClassName();
if (exclude == null || !exclude.contains(className)) {
combo.add(d.getUiName());
- classNames.add(className);
+ classNames.add(Pair.of(className, d));
}
}
@@ -262,7 +247,7 @@ class WrapInWizard extends VisualRefactoringWizard {
if (thirdPartyViews.size() > 0) {
for (String view : thirdPartyViews) {
combo.add(view);
- classNames.add(view);
+ classNames.add(Pair.of(view, (ViewElementDescriptor) null));
}
combo.add(SEPARATOR_LABEL);
classNames.add(null);
@@ -270,10 +255,11 @@ class WrapInWizard extends VisualRefactoringWizard {
if (addGestureOverlay) {
combo.add(GESTURE_OVERLAY_VIEW);
- classNames.add(FQCN_GESTURE_OVERLAY_VIEW);
+ classNames.add(Pair.<String, ViewElementDescriptor> of(
+ FQCN_GESTURE_OVERLAY_VIEW, null));
combo.add(SEPARATOR_LABEL);
- classNames.add(null);
+ classNames.add(Pair.<String,ViewElementDescriptor>of(null, null));
}
}
@@ -286,14 +272,14 @@ class WrapInWizard extends VisualRefactoringWizard {
String className = d.getFullClassName();
if (exclude == null || !exclude.equals(className)) {
combo.add(d.getUiName());
- classNames.add(className);
+ classNames.add(Pair.of(className, d));
}
}
}
}
} else {
combo.add("SDK not initialized");
- classNames.add(null);
+ classNames.add(Pair.<String,ViewElementDescriptor>of(null, null));
}
return classNames;