aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring
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')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeLayoutAction.java47
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeLayoutContribution.java40
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeLayoutRefactoring.java657
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeLayoutWizard.java195
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeViewAction.java47
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeViewContribution.java40
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeViewRefactoring.java298
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeViewWizard.java199
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractIncludeAction.java47
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractIncludeContribution.java40
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractIncludeRefactoring.java670
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractIncludeWizard.java126
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractStyleAction.java47
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractStyleContribution.java40
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractStyleRefactoring.java579
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractStyleWizard.java440
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/GridLayoutConverter.java988
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/JavaQuickAssistant.java73
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/RefactoringAssistant.java336
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/RelativeLayoutConversionHelper.java1633
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UnwrapAction.java47
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UnwrapContribution.java40
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UnwrapRefactoring.java246
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UnwrapWizard.java31
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UseCompoundDrawableAction.java48
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UseCompoundDrawableRefactoring.java452
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UseCompoundDrawableWizard.java31
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/VisualRefactoring.java1403
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/VisualRefactoringAction.java170
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/VisualRefactoringWizard.java76
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/WrapInAction.java47
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/WrapInContribution.java40
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/WrapInRefactoring.java439
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/WrapInWizard.java268
34 files changed, 0 insertions, 9880 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeLayoutAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeLayoutAction.java
deleted file mode 100644
index 306dd68c8..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeLayoutAction.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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.eclipse.adt.internal.editors.layout.LayoutEditorDelegate;
-
-import org.eclipse.jface.action.IAction;
-import org.eclipse.ltk.ui.refactoring.RefactoringWizard;
-import org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation;
-
-/**
- * Action executed when the "Convert Layout" menu item is invoked.
- */
-public class ChangeLayoutAction extends VisualRefactoringAction {
- @Override
- public void run(IAction action) {
- if ((mTextSelection != null || mTreeSelection != null) && mFile != null) {
- ChangeLayoutRefactoring ref = new ChangeLayoutRefactoring(mFile, mDelegate,
- mTextSelection, mTreeSelection);
- RefactoringWizard wizard = new ChangeLayoutWizard(ref, mDelegate);
- RefactoringWizardOpenOperation op = new RefactoringWizardOpenOperation(wizard);
- try {
- op.run(mWindow.getShell(), wizard.getDefaultPageTitle());
- } catch (InterruptedException e) {
- // Interrupted. Pass.
- }
- }
- }
-
- public static IAction create(LayoutEditorDelegate editorDelegate) {
- return create("Change Layout...", editorDelegate, ChangeLayoutAction.class);
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeLayoutContribution.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeLayoutContribution.java
deleted file mode 100644
index c508b7e92..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeLayoutContribution.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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 org.eclipse.ltk.core.refactoring.RefactoringContribution;
-import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
-
-import java.util.Map;
-
-public class ChangeLayoutContribution extends RefactoringContribution {
-
- @SuppressWarnings("unchecked")
- @Override
- public RefactoringDescriptor createDescriptor(String id, String project, String description,
- String comment, Map arguments, int flags) throws IllegalArgumentException {
- return new ChangeLayoutRefactoring.Descriptor(project, description, comment, arguments);
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public Map retrieveArgumentMap(RefactoringDescriptor descriptor) {
- if (descriptor instanceof ChangeLayoutRefactoring.Descriptor) {
- return ((ChangeLayoutRefactoring.Descriptor) descriptor).getArguments();
- }
- return super.retrieveArgumentMap(descriptor);
- }
-}
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
deleted file mode 100644
index d8c85aab5..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeLayoutRefactoring.java
+++ /dev/null
@@ -1,657 +0,0 @@
-/*
- * 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 static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.ANDROID_WIDGET_PREFIX;
-import static com.android.SdkConstants.ATTR_BASELINE_ALIGNED;
-import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_BASELINE;
-import static com.android.SdkConstants.ATTR_LAYOUT_BELOW;
-import static com.android.SdkConstants.ATTR_LAYOUT_HEIGHT;
-import static com.android.SdkConstants.ATTR_LAYOUT_RESOURCE_PREFIX;
-import static com.android.SdkConstants.ATTR_LAYOUT_TO_RIGHT_OF;
-import static com.android.SdkConstants.ATTR_LAYOUT_WIDTH;
-import static com.android.SdkConstants.ATTR_ORIENTATION;
-import static com.android.SdkConstants.EXT_XML;
-import static com.android.SdkConstants.FQCN_GESTURE_OVERLAY_VIEW;
-import static com.android.SdkConstants.FQCN_GRID_LAYOUT;
-import static com.android.SdkConstants.FQCN_LINEAR_LAYOUT;
-import static com.android.SdkConstants.FQCN_RELATIVE_LAYOUT;
-import static com.android.SdkConstants.FQCN_TABLE_LAYOUT;
-import static com.android.SdkConstants.GESTURE_OVERLAY_VIEW;
-import static com.android.SdkConstants.LINEAR_LAYOUT;
-import static com.android.SdkConstants.TABLE_ROW;
-import static com.android.SdkConstants.VALUE_FALSE;
-import static com.android.SdkConstants.VALUE_VERTICAL;
-import static com.android.SdkConstants.VALUE_WRAP_CONTENT;
-
-import com.android.SdkConstants;
-import com.android.annotations.NonNull;
-import com.android.annotations.VisibleForTesting;
-import com.android.ide.common.xml.XmlFormatStyle;
-import com.android.ide.eclipse.adt.AdtPlugin;
-import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor;
-import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditorDelegate;
-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;
-import com.android.ide.eclipse.adt.internal.editors.layout.gle2.LayoutCanvas;
-import com.android.ide.eclipse.adt.internal.editors.layout.gle2.ViewHierarchy;
-import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs;
-
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.IStatus;
-import org.eclipse.core.runtime.OperationCanceledException;
-import org.eclipse.jface.text.ITextSelection;
-import org.eclipse.jface.viewers.ITreeSelection;
-import org.eclipse.ltk.core.refactoring.Change;
-import org.eclipse.ltk.core.refactoring.Refactoring;
-import org.eclipse.ltk.core.refactoring.RefactoringStatus;
-import org.eclipse.ltk.core.refactoring.TextFileChange;
-import org.eclipse.text.edits.MalformedTreeException;
-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;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Converts the selected layout into a layout of a different type.
- */
-@SuppressWarnings("restriction") // XML model
-public class ChangeLayoutRefactoring extends VisualRefactoring {
- private static final String KEY_TYPE = "type"; //$NON-NLS-1$
- private static final String KEY_FLATTEN = "flatten"; //$NON-NLS-1$
-
- private String mTypeFqcn;
- private String mInitializedAttributes;
- private boolean mFlatten;
-
- /**
- * This constructor is solely used by {@link Descriptor},
- * to replay a previous refactoring.
- * @param arguments argument map created by #createArgumentMap.
- */
- ChangeLayoutRefactoring(Map<String, String> arguments) {
- super(arguments);
- mTypeFqcn = arguments.get(KEY_TYPE);
- mFlatten = Boolean.parseBoolean(arguments.get(KEY_FLATTEN));
- }
-
- @VisibleForTesting
- ChangeLayoutRefactoring(List<Element> selectedElements, LayoutEditorDelegate delegate) {
- super(selectedElements, delegate);
- }
-
- public ChangeLayoutRefactoring(
- IFile file,
- LayoutEditorDelegate delegate,
- ITextSelection selection,
- ITreeSelection treeSelection) {
- super(file, delegate, selection, treeSelection);
- }
-
- @Override
- public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException,
- OperationCanceledException {
- RefactoringStatus status = new RefactoringStatus();
-
- try {
- pm.beginTask("Checking preconditions...", 2);
-
- if (mSelectionStart == -1 || mSelectionEnd == -1) {
- status.addFatalError("No selection to convert");
- return status;
- }
-
- if (mElements.size() != 1) {
- status.addFatalError("Select precisely one layout to convert");
- return status;
- }
-
- pm.worked(1);
- return status;
-
- } finally {
- pm.done();
- }
- }
-
- @Override
- protected VisualRefactoringDescriptor createDescriptor() {
- String comment = getName();
- return new Descriptor(
- mProject.getName(), //project
- comment, //description
- comment, //comment
- createArgumentMap());
- }
-
- @Override
- protected Map<String, String> createArgumentMap() {
- Map<String, String> args = super.createArgumentMap();
- args.put(KEY_TYPE, mTypeFqcn);
- args.put(KEY_FLATTEN, Boolean.toString(mFlatten));
-
- return args;
- }
-
- @Override
- public String getName() {
- return "Change Layout";
- }
-
- void setType(String typeFqcn) {
- mTypeFqcn = typeFqcn;
- }
-
- void setInitializedAttributes(String initializedAttributes) {
- mInitializedAttributes = initializedAttributes;
- }
-
- void setFlatten(boolean flatten) {
- mFlatten = flatten;
- }
-
- @Override
- protected List<Element> initElements() {
- List<Element> elements = super.initElements();
-
- // Don't convert a root GestureOverlayView; convert its child. This looks for
- // gesture overlays, and if found, it generates a new child list where the gesture
- // overlay children are replaced by their first element children
- for (Element element : elements) {
- String tagName = element.getTagName();
- if (tagName.equals(GESTURE_OVERLAY_VIEW)
- || tagName.equals(FQCN_GESTURE_OVERLAY_VIEW)) {
- List<Element> replacement = new ArrayList<Element>(elements.size());
- for (Element e : elements) {
- tagName = e.getTagName();
- if (tagName.equals(GESTURE_OVERLAY_VIEW)
- || tagName.equals(FQCN_GESTURE_OVERLAY_VIEW)) {
- NodeList children = e.getChildNodes();
- Element first = null;
- for (int i = 0, n = children.getLength(); i < n; i++) {
- Node node = children.item(i);
- if (node.getNodeType() == Node.ELEMENT_NODE) {
- first = (Element) node;
- break;
- }
- }
- if (first != null) {
- e = first;
- }
- }
- replacement.add(e);
- }
- return replacement;
- }
- }
-
- return elements;
- }
-
- @Override
- protected @NonNull List<Change> computeChanges(IProgressMonitor monitor) {
- String name = getViewClass(mTypeFqcn);
-
- IFile file = mDelegate.getEditor().getInputFile();
- List<Change> changes = new ArrayList<Change>();
- if (file == null) {
- return changes;
- }
- TextFileChange change = new TextFileChange(file.getName(), file);
- MultiTextEdit rootEdit = new MultiTextEdit();
- change.setTextType(EXT_XML);
- changes.add(change);
-
- String text = getText(mSelectionStart, mSelectionEnd);
- Element layout = getPrimaryElement();
- String oldName = layout.getNodeName();
- int open = text.indexOf(oldName);
- int close = text.lastIndexOf(oldName);
-
- if (open != -1 && close != -1) {
- int oldLength = oldName.length();
- rootEdit.addChild(new ReplaceEdit(mSelectionStart + open, oldLength, name));
- if (close != open) { // Gracefully handle <FooLayout/>
- rootEdit.addChild(new ReplaceEdit(mSelectionStart + close, oldLength, name));
- }
- }
-
- 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 = mDelegate.getEditor().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;
-
- if (newType.equals(FQCN_RELATIVE_LAYOUT)) {
- if (oldType.equals(FQCN_LINEAR_LAYOUT) && !mFlatten) {
- // Hand-coded conversion specifically tailored for linear to relative, provided
- // there is no hierarchy flattening
- // TODO: use the RelativeLayoutConversionHelper for this; it does a better job
- // analyzing gravities etc.
- convertLinearToRelative(rootEdit);
- removeUndefinedAttrs(rootEdit, layout);
- addMissingWrapContentAttributes(rootEdit, layout, oldType, newType, null);
- } else {
- // Generic conversion to relative - can also flatten the hierarchy
- convertAnyToRelative(rootEdit, oldType, newType);
- // This already handles removing undefined layout attributes -- right?
- //removeUndefinedLayoutAttrs(rootEdit, layout);
- }
- } else if (newType.equals(FQCN_GRID_LAYOUT)) {
- convertAnyToGridLayout(rootEdit);
- // Layout attributes on children have already been removed as part of conversion
- // during the flattening
- removeUndefinedAttrs(rootEdit, layout, false /*removeLayoutAttrs*/);
- } else if (oldType.equals(FQCN_RELATIVE_LAYOUT) && newType.equals(FQCN_LINEAR_LAYOUT)) {
- convertRelativeToLinear(rootEdit);
- removeUndefinedAttrs(rootEdit, layout);
- addMissingWrapContentAttributes(rootEdit, layout, oldType, newType, null);
- } else if (oldType.equals(FQCN_LINEAR_LAYOUT) && newType.equals(FQCN_TABLE_LAYOUT)) {
- convertLinearToTable(rootEdit);
- removeUndefinedAttrs(rootEdit, layout);
- addMissingWrapContentAttributes(rootEdit, layout, oldType, newType, null);
- } else {
- convertGeneric(rootEdit, oldType, newType, layout);
- }
-
- if (mInitializedAttributes != null && mInitializedAttributes.length() > 0) {
- String namespace = getAndroidNamespacePrefix();
- for (String s : mInitializedAttributes.split(",")) { //$NON-NLS-1$
- String[] nameValue = s.split("="); //$NON-NLS-1$
- String attribute = nameValue[0];
- String value = nameValue[1];
- String prefix = null;
- String namespaceUri = null;
- if (attribute.startsWith(SdkConstants.ANDROID_NS_NAME_PREFIX)) {
- prefix = namespace;
- namespaceUri = ANDROID_URI;
- attribute = attribute.substring(SdkConstants.ANDROID_NS_NAME_PREFIX.length());
- }
- setAttribute(rootEdit, layout, namespaceUri,
- prefix, attribute, value);
- }
- }
-
- if (AdtPrefs.getPrefs().getFormatGuiXml()) {
- MultiTextEdit formatted = reformat(rootEdit, XmlFormatStyle.LAYOUT);
- if (formatted != null) {
- rootEdit = formatted;
- }
- }
- change.setEdit(rootEdit);
-
- return changes;
- }
-
- /** Checks whether we need to add any missing attributes on the elements */
- private void addMissingWrapContentAttributes(MultiTextEdit rootEdit, Element layout,
- String oldType, String newType, Set<Element> skip) {
- if (oldType.equals(FQCN_GRID_LAYOUT) && !newType.equals(FQCN_GRID_LAYOUT)) {
- String namespace = getAndroidNamespacePrefix();
-
- for (Element child : DomUtilities.getChildren(layout)) {
- if (skip != null && skip.contains(child)) {
- continue;
- }
-
- if (!child.hasAttributeNS(ANDROID_URI, ATTR_LAYOUT_WIDTH)) {
- setAttribute(rootEdit, child, ANDROID_URI,
- namespace, ATTR_LAYOUT_WIDTH, VALUE_WRAP_CONTENT);
- }
- if (!child.hasAttributeNS(ANDROID_URI, ATTR_LAYOUT_HEIGHT)) {
- setAttribute(rootEdit, child, ANDROID_URI,
- namespace, ATTR_LAYOUT_HEIGHT, VALUE_WRAP_CONTENT);
- }
- }
- }
- }
-
- /** Hand coded conversion from a LinearLayout to a TableLayout */
- private void convertLinearToTable(MultiTextEdit rootEdit) {
- // This is pretty easy; just switch the root tag (already done by the initial generic
- // conversion) and then convert all the children into <TableRow> elements.
- // Finally, get rid of the orientation attribute, if any.
- Element layout = getPrimaryElement();
- removeOrientationAttribute(rootEdit, layout);
-
- NodeList children = layout.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;
- if (node instanceof IndexedRegion) {
- IndexedRegion region = (IndexedRegion) node;
- int start = region.getStartOffset();
- int end = region.getEndOffset();
- String text = getText(start, end);
- String oldName = child.getNodeName();
- if (oldName.equals(LINEAR_LAYOUT)) {
- removeOrientationAttribute(rootEdit, child);
- int open = text.indexOf(oldName);
- int close = text.lastIndexOf(oldName);
-
- if (open != -1 && close != -1) {
- int oldLength = oldName.length();
- rootEdit.addChild(new ReplaceEdit(mSelectionStart + open, oldLength,
- TABLE_ROW));
- if (close != open) { // Gracefully handle <FooLayout/>
- rootEdit.addChild(new ReplaceEdit(mSelectionStart + close,
- oldLength, TABLE_ROW));
- }
- }
- } // else: WRAP in TableLayout!
- }
- }
- }
- }
-
- /** Hand coded conversion from a LinearLayout to a RelativeLayout */
- private void convertLinearToRelative(MultiTextEdit rootEdit) {
- // This can be done accurately.
- Element layout = getPrimaryElement();
- // Horizontal is the default, so if no value is specified it is horizontal.
- boolean isVertical = VALUE_VERTICAL.equals(layout.getAttributeNS(ANDROID_URI,
- ATTR_ORIENTATION));
-
- String attributePrefix = getAndroidNamespacePrefix();
-
- // TODO: Consider gravity of each element
- // TODO: Consider weight of each element
- // Right now it simply makes a single attachment to keep the order.
-
- if (isVertical) {
- // Align each child to the bottom and left of its parent
- NodeList children = layout.getChildNodes();
- String prevId = null;
- 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;
- String id = ensureHasId(rootEdit, child, null);
- if (prevId != null) {
- setAttribute(rootEdit, child, ANDROID_URI, attributePrefix,
- ATTR_LAYOUT_BELOW, prevId);
- }
- prevId = id;
- }
- }
- } else {
- // Align each child to the left
- NodeList children = layout.getChildNodes();
- boolean isBaselineAligned =
- !VALUE_FALSE.equals(layout.getAttributeNS(ANDROID_URI, ATTR_BASELINE_ALIGNED));
-
- String prevId = null;
- 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;
- String id = ensureHasId(rootEdit, child, null);
- if (prevId != null) {
- setAttribute(rootEdit, child, ANDROID_URI, attributePrefix,
- ATTR_LAYOUT_TO_RIGHT_OF, prevId);
- if (isBaselineAligned) {
- setAttribute(rootEdit, child, ANDROID_URI, attributePrefix,
- ATTR_LAYOUT_ALIGN_BASELINE, prevId);
- }
- }
- prevId = id;
- }
- }
- }
- }
-
- /** Strips out the android:orientation attribute from the given linear layout element */
- private void removeOrientationAttribute(MultiTextEdit rootEdit, Element layout) {
- assert layout.getTagName().equals(LINEAR_LAYOUT);
- removeAttribute(rootEdit, layout, ANDROID_URI, ATTR_ORIENTATION);
- }
-
- /**
- * Hand coded conversion from a RelativeLayout to a LinearLayout
- *
- * @param rootEdit the root multi text edit to add edits to
- */
- private void convertRelativeToLinear(MultiTextEdit rootEdit) {
- // This is going to be lossy...
- // TODO: Attempt to "order" the items based on their visual positions
- // and insert them in that order in the LinearLayout.
- // TODO: Possibly use nesting if necessary, by spatial subdivision,
- // to accomplish roughly the same layout as the relative layout specifies.
- }
-
- /**
- * Hand coded -generic- conversion from one layout to another. This is not going to be
- * an accurate layout transformation; instead it simply migrates the layout attributes
- * that are supported, and adds defaults for any new required layout attributes. In
- * addition, it attempts to order the children visually based on where they fit in a
- * rendering. (Unsupported layout attributes will be removed by the caller at the
- * end.)
- * <ul>
- * <li>Try to handle nesting. Converting a *hierarchy* of layouts into a flatter
- * layout for powerful layouts that support it, like RelativeLayout.
- * <li>Try to do automatic "inference" about the layout. I can render it and look at
- * the ViewInfo positions and sizes. I can render it multiple times, at different
- * sizes, to infer "stretchiness" and "weight" properties of the children.
- * <li>Try to do indirect transformations. E.g. if I can go from A to B, and B to C,
- * then an attempt to go from A to C should perform conversions A to B and then B to
- * C.
- * </ul>
- *
- * @param rootEdit the root multi text edit to add edits to
- * @param oldType the fully qualified class name of the layout type we are converting
- * from
- * @param newType the fully qualified class name of the layout type we are converting
- * to
- * @param layout the layout to be converted
- */
- private void convertGeneric(MultiTextEdit rootEdit, String oldType, String newType,
- Element layout) {
- // TODO: Add hooks for 3rd party conversions getting registered through the
- // IViewRule interface.
-
- // For now we simply go with the default behavior, which is to just strip the
- // layout attributes that aren't supported.
- removeUndefinedAttrs(rootEdit, layout);
- addMissingWrapContentAttributes(rootEdit, layout, oldType, newType, null);
- }
-
- /**
- * Removes all the unavailable attributes after a conversion, both on the
- * layout element itself as well as the layout attributes of any of the
- * children
- */
- private void removeUndefinedAttrs(MultiTextEdit rootEdit, Element layout) {
- removeUndefinedAttrs(rootEdit, layout, true /*removeLayoutAttrs*/);
- }
-
- private void removeUndefinedAttrs(MultiTextEdit rootEdit, Element layout,
- boolean removeLayoutAttrs) {
- ViewElementDescriptor descriptor = getElementDescriptor(mTypeFqcn);
- if (descriptor == null) {
- return;
- }
-
- if (removeLayoutAttrs) {
- Set<String> defined = new HashSet<String>();
- AttributeDescriptor[] layoutAttributes = descriptor.getLayoutAttributes();
- for (AttributeDescriptor attribute : layoutAttributes) {
- defined.add(attribute.getXmlLocalName());
- }
-
- NodeList children = layout.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;
-
- List<Attr> attributes = findLayoutAttributes(child);
- for (Attr attribute : attributes) {
- String name = attribute.getLocalName();
- if (!defined.contains(name)) {
- // Remove it
- try {
- removeAttribute(rootEdit, child, attribute.getNamespaceURI(), name);
- } catch (MalformedTreeException mte) {
- // Sometimes refactoring has modified attribute; not removing
- // it is non-fatal so just warn instead of letting refactoring
- // operation abort
- AdtPlugin.log(IStatus.WARNING,
- "Could not remove unsupported attribute %1$s; " + //$NON-NLS-1$
- "already modified during refactoring?", //$NON-NLS-1$
- attribute.getLocalName());
- }
- }
- }
- }
- }
- }
-
- // Also remove the unavailable attributes (not layout attributes) on the
- // converted element
- Set<String> defined = new HashSet<String>();
- AttributeDescriptor[] attributes = descriptor.getAttributes();
- for (AttributeDescriptor attribute : attributes) {
- defined.add(attribute.getXmlLocalName());
- }
-
- // Remove undefined attributes on the layout element itself
- NamedNodeMap attributeMap = layout.getAttributes();
- for (int i = 0, n = attributeMap.getLength(); i < n; i++) {
- Node attributeNode = attributeMap.item(i);
-
- String name = attributeNode.getLocalName();
- if (!name.startsWith(ATTR_LAYOUT_RESOURCE_PREFIX)
- && ANDROID_URI.equals(attributeNode.getNamespaceURI())) {
- if (!defined.contains(name)) {
- // Remove it
- removeAttribute(rootEdit, layout, ANDROID_URI, name);
- }
- }
- }
- }
-
- /** Hand coded conversion from any layout to a RelativeLayout */
- private void convertAnyToRelative(MultiTextEdit rootEdit, String oldType, String newType) {
- // To perform a conversion from any other layout type, including nested conversion,
- Element layout = getPrimaryElement();
- CanvasViewInfo rootView = mRootView;
- if (rootView == null) {
- LayoutCanvas canvas = mDelegate.getGraphicalEditor().getCanvasControl();
- ViewHierarchy viewHierarchy = canvas.getViewHierarchy();
- rootView = viewHierarchy.getRoot();
- }
-
- RelativeLayoutConversionHelper helper =
- new RelativeLayoutConversionHelper(this, layout, mFlatten, rootEdit, rootView);
- helper.convertToRelative();
- List<Element> deletedElements = helper.getDeletedElements();
- Set<Element> deleted = null;
- if (deletedElements != null && deletedElements.size() > 0) {
- deleted = new HashSet<Element>(deletedElements);
- }
- addMissingWrapContentAttributes(rootEdit, layout, oldType, newType, deleted);
- }
-
- /** Hand coded conversion from any layout to a GridLayout */
- private void convertAnyToGridLayout(MultiTextEdit rootEdit) {
- // To perform a conversion from any other layout type, including nested conversion,
- Element layout = getPrimaryElement();
- CanvasViewInfo rootView = mRootView;
- if (rootView == null) {
- LayoutCanvas canvas = mDelegate.getGraphicalEditor().getCanvasControl();
- ViewHierarchy viewHierarchy = canvas.getViewHierarchy();
- rootView = viewHierarchy.getRoot();
- }
-
- GridLayoutConverter converter = new GridLayoutConverter(this, layout, mFlatten,
- rootEdit, rootView);
- converter.convertToGridLayout();
- }
-
- public static class Descriptor extends VisualRefactoringDescriptor {
- public Descriptor(String project, String description, String comment,
- Map<String, String> arguments) {
- super("com.android.ide.eclipse.adt.refactoring.convert", //$NON-NLS-1$
- project, description, comment, arguments);
- }
-
- @Override
- protected Refactoring createRefactoring(Map<String, String> args) {
- return new ChangeLayoutRefactoring(args);
- }
- }
-
- String getOldType() {
- Element primary = getPrimaryElement();
- if (primary != null) {
- String oldType = primary.getTagName();
- if (oldType.indexOf('.') == -1) {
- oldType = ANDROID_WIDGET_PREFIX + oldType;
- }
- return oldType;
- }
-
- return null;
- }
-
- @VisibleForTesting
- protected CanvasViewInfo mRootView;
-
- @VisibleForTesting
- public void setRootView(CanvasViewInfo rootView) {
- mRootView = rootView;
- }
-
- @Override
- VisualRefactoringWizard createWizard() {
- return new ChangeLayoutWizard(this, mDelegate);
- }
-}
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
deleted file mode 100644
index f5582712f..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeLayoutWizard.java
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * 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 static com.android.SdkConstants.FQCN_GRID_LAYOUT;
-import static com.android.SdkConstants.FQCN_RELATIVE_LAYOUT;
-import static com.android.SdkConstants.GRID_LAYOUT;
-import static com.android.SdkConstants.RELATIVE_LAYOUT;
-import static com.android.SdkConstants.VIEW_FRAGMENT;
-import static com.android.SdkConstants.VIEW_INCLUDE;
-import static com.android.SdkConstants.VIEW_MERGE;
-
-import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditorDelegate;
-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.utils.Pair;
-
-import org.eclipse.core.resources.IProject;
-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.Button;
-import org.eclipse.swt.widgets.Combo;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Label;
-
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-class ChangeLayoutWizard extends VisualRefactoringWizard {
-
- public ChangeLayoutWizard(ChangeLayoutRefactoring ref, LayoutEditorDelegate editor) {
- super(ref, editor);
- setDefaultPageTitle("Change Layout");
- }
-
- @Override
- protected void addUserInputPages() {
- ChangeLayoutRefactoring ref = (ChangeLayoutRefactoring) getRefactoring();
- String oldType = ref.getOldType();
- addPage(new InputPage(mDelegate.getEditor().getProject(), oldType));
- }
-
- /** Wizard page which inputs parameters for the {@link ChangeLayoutRefactoring} operation */
- private static class InputPage extends VisualRefactoringInputPage {
- private final IProject mProject;
- private final String mOldType;
- private Combo mTypeCombo;
- private Button mFlatten;
- private List<Pair<String, ViewElementDescriptor>> mClassNames;
-
- public InputPage(IProject project, String oldType) {
- super("ChangeLayoutInputPage"); //$NON-NLS-1$
- mProject = project;
- mOldType = oldType;
- }
-
- @Override
- public void createControl(Composite parent) {
- Composite composite = new Composite(parent, SWT.NONE);
- composite.setLayout(new GridLayout(2, false));
-
- Label fromLabel = new Label(composite, SWT.NONE);
- fromLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1));
- String oldTypeBase = mOldType.substring(mOldType.lastIndexOf('.') + 1);
- fromLabel.setText(String.format("Change from %1$s", oldTypeBase));
-
- Label typeLabel = new Label(composite, SWT.NONE);
- typeLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
- typeLabel.setText("New Layout Type:");
-
- 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();
- // Hierarchy flattening only works for relative layout (and any future
- // layouts that can also support arbitrary layouts).
- String text = mTypeCombo.getText();
- mFlatten.setVisible(text.equals(RELATIVE_LAYOUT) || text.equals(GRID_LAYOUT));
- }
- };
- mTypeCombo.addSelectionListener(selectionListener);
- mTypeCombo.addSelectionListener(mSelectionValidateListener);
-
- mFlatten = new Button(composite, SWT.CHECK);
- mFlatten.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER,
- false, false, 2, 1));
- mFlatten.setText("Flatten hierarchy");
- 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
- // RelativeLayout at the root.
- Set<String> exclude = new HashSet<String>();
- exclude.add(VIEW_INCLUDE);
- exclude.add(VIEW_MERGE);
- exclude.add(VIEW_FRAGMENT);
- boolean oldIsRelativeLayout = mOldType.equals(FQCN_RELATIVE_LAYOUT);
- boolean oldIsGridLayout = mOldType.equals(FQCN_GRID_LAYOUT);
- if (oldIsRelativeLayout || oldIsGridLayout) {
- exclude.add(mOldType);
- }
- mClassNames = WrapInWizard.addLayouts(mProject, mOldType, mTypeCombo, exclude, false);
-
- boolean gridLayoutAvailable = false;
- for (int i = 0; i < mTypeCombo.getItemCount(); i++) {
- if (mTypeCombo.getItem(i).equals(GRID_LAYOUT)) {
- gridLayoutAvailable = true;
- break;
- }
- }
-
- mTypeCombo.select(0);
- // The default should be GridLayout (if available) and if not RelativeLayout,
- // if available (and not the old Type)
- if (gridLayoutAvailable && !oldIsGridLayout) {
- for (int i = 0; i < mTypeCombo.getItemCount(); i++) {
- if (mTypeCombo.getItem(i).equals(GRID_LAYOUT)) {
- mTypeCombo.select(i);
- break;
- }
- }
- } else if (!oldIsRelativeLayout) {
- for (int i = 0; i < mTypeCombo.getItemCount(); i++) {
- if (mTypeCombo.getItem(i).equals(RELATIVE_LAYOUT)) {
- mTypeCombo.select(i);
- break;
- }
- }
- }
- mFlatten.setVisible(mTypeCombo.getText().equals(RELATIVE_LAYOUT)
- || mTypeCombo.getText().equals(GRID_LAYOUT));
-
- setControl(composite);
- validatePage();
- }
-
- @Override
- protected boolean validatePage() {
- boolean ok = true;
-
- int selectionIndex = mTypeCombo.getSelectionIndex();
- 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
- } else {
- setErrorMessage(null);
-
- // Record state
- ChangeLayoutRefactoring refactoring =
- (ChangeLayoutRefactoring) getRefactoring();
- refactoring.setType(type);
- refactoring.setFlatten(mFlatten.getSelection());
-
- ViewElementDescriptor descriptor = mClassNames.get(selectionIndex).getSecond();
- if (descriptor instanceof PaletteMetadataDescriptor) {
- PaletteMetadataDescriptor paletteDescriptor =
- (PaletteMetadataDescriptor) descriptor;
- String initializedAttributes = paletteDescriptor.getInitializedAttributes();
- if (initializedAttributes != null && initializedAttributes.length() > 0) {
- refactoring.setInitializedAttributes(initializedAttributes);
- }
- } else {
- refactoring.setInitializedAttributes(null);
- }
- }
-
- setPageComplete(ok);
- return ok;
- }
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeViewAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeViewAction.java
deleted file mode 100644
index fa14e5222..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeViewAction.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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.eclipse.adt.internal.editors.layout.LayoutEditorDelegate;
-
-import org.eclipse.jface.action.IAction;
-import org.eclipse.ltk.ui.refactoring.RefactoringWizard;
-import org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation;
-
-/**
- * Action executed when the "Change View Type" menu item is invoked.
- */
-public class ChangeViewAction extends VisualRefactoringAction {
- @Override
- public void run(IAction action) {
- if ((mTextSelection != null || mTreeSelection != null) && mFile != null) {
- ChangeViewRefactoring ref = new ChangeViewRefactoring(mFile, mDelegate,
- mTextSelection, mTreeSelection);
- RefactoringWizard wizard = new ChangeViewWizard(ref, mDelegate);
- RefactoringWizardOpenOperation op = new RefactoringWizardOpenOperation(wizard);
- try {
- op.run(mWindow.getShell(), wizard.getDefaultPageTitle());
- } catch (InterruptedException e) {
- // Interrupted. Pass.
- }
- }
- }
-
- public static IAction create(LayoutEditorDelegate editorDelegate) {
- return create("Change Widget Type...", editorDelegate, ChangeViewAction.class);
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeViewContribution.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeViewContribution.java
deleted file mode 100644
index 7705ed808..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeViewContribution.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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 org.eclipse.ltk.core.refactoring.RefactoringContribution;
-import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
-
-import java.util.Map;
-
-public class ChangeViewContribution extends RefactoringContribution {
-
- @SuppressWarnings("unchecked")
- @Override
- public RefactoringDescriptor createDescriptor(String id, String project, String description,
- String comment, Map arguments, int flags) throws IllegalArgumentException {
- return new ChangeViewRefactoring.Descriptor(project, description, comment, arguments);
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public Map retrieveArgumentMap(RefactoringDescriptor descriptor) {
- if (descriptor instanceof ChangeViewRefactoring.Descriptor) {
- return ((ChangeViewRefactoring.Descriptor) descriptor).getArguments();
- }
- return super.retrieveArgumentMap(descriptor);
- }
-}
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
deleted file mode 100644
index 73f5eb149..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeViewRefactoring.java
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * 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 static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.ANDROID_WIDGET_PREFIX;
-import static com.android.SdkConstants.ATTR_LAYOUT_RESOURCE_PREFIX;
-import static com.android.SdkConstants.ATTR_TEXT;
-import static com.android.SdkConstants.EXT_XML;
-import static com.android.SdkConstants.VIEW_FRAGMENT;
-import static com.android.SdkConstants.VIEW_INCLUDE;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.VisibleForTesting;
-import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor;
-import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditorDelegate;
-import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.ViewElementDescriptor;
-import com.android.ide.eclipse.adt.internal.editors.layout.gle2.CanvasViewInfo;
-
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.OperationCanceledException;
-import org.eclipse.jface.text.ITextSelection;
-import org.eclipse.jface.viewers.ITreeSelection;
-import org.eclipse.ltk.core.refactoring.Change;
-import org.eclipse.ltk.core.refactoring.Refactoring;
-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.eclipse.wst.xml.core.internal.document.ElementImpl;
-import org.w3c.dom.Attr;
-import org.w3c.dom.Element;
-import org.w3c.dom.NamedNodeMap;
-import org.w3c.dom.Node;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Changes the type of the given widgets to the given target type
- * and updates the attributes if necessary
- */
-@SuppressWarnings("restriction") // XML model
-public class ChangeViewRefactoring extends VisualRefactoring {
- private static final String KEY_TYPE = "type"; //$NON-NLS-1$
- private String mTypeFqcn;
-
- /**
- * This constructor is solely used by {@link Descriptor},
- * to replay a previous refactoring.
- * @param arguments argument map created by #createArgumentMap.
- */
- ChangeViewRefactoring(Map<String, String> arguments) {
- super(arguments);
- mTypeFqcn = arguments.get(KEY_TYPE);
- }
-
- public ChangeViewRefactoring(
- IFile file,
- LayoutEditorDelegate delegate,
- ITextSelection selection,
- ITreeSelection treeSelection) {
- super(file, delegate, selection, treeSelection);
- }
-
- @VisibleForTesting
- ChangeViewRefactoring(List<Element> selectedElements, LayoutEditorDelegate editor) {
- super(selectedElements, editor);
- }
-
- @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 convert");
- return status;
- }
-
- // Make sure the selection is contiguous
- if (mTreeSelection != null) {
- List<CanvasViewInfo> infos = getSelectedViewInfos();
- if (!validateNotEmpty(infos, status)) {
- return status;
- }
- }
-
- // Ensures that we have a valid DOM model:
- if (mElements.size() == 0) {
- status.addFatalError("Nothing to convert");
- return status;
- }
-
- pm.worked(1);
- return status;
-
- } finally {
- pm.done();
- }
- }
-
- @Override
- protected VisualRefactoringDescriptor createDescriptor() {
- String comment = getName();
- return new Descriptor(
- mProject.getName(), //project
- comment, //description
- comment, //comment
- createArgumentMap());
- }
-
- @Override
- protected Map<String, String> createArgumentMap() {
- Map<String, String> args = super.createArgumentMap();
- args.put(KEY_TYPE, mTypeFqcn);
-
- return args;
- }
-
- @Override
- public String getName() {
- return "Change Widget Type";
- }
-
- void setType(String typeFqcn) {
- mTypeFqcn = typeFqcn;
- }
-
- @Override
- protected @NonNull List<Change> computeChanges(IProgressMonitor monitor) {
- String name = getViewClass(mTypeFqcn);
-
- IFile file = mDelegate.getEditor().getInputFile();
- List<Change> changes = new ArrayList<Change>();
- if (file == null) {
- return changes;
- }
- TextFileChange change = new TextFileChange(file.getName(), file);
- MultiTextEdit rootEdit = new MultiTextEdit();
- change.setEdit(rootEdit);
- change.setTextType(EXT_XML);
- changes.add(change);
-
- for (Element element : getElements()) {
- IndexedRegion region = getRegion(element);
- String text = getText(region.getStartOffset(), region.getEndOffset());
- String oldName = element.getNodeName();
- int open = text.indexOf(oldName);
- int close = text.lastIndexOf(oldName);
- if (element instanceof ElementImpl && ((ElementImpl) element).isEmptyTag()) {
- close = -1;
- }
-
- if (open != -1) {
- int oldLength = oldName.length();
- rootEdit.addChild(new ReplaceEdit(region.getStartOffset() + open,
- oldLength, name));
- }
- if (close != -1 && close != open) {
- int oldLength = oldName.length();
- rootEdit.addChild(new ReplaceEdit(region.getStartOffset() + close, oldLength,
- name));
- }
-
- // Change tag type
- 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 = mDelegate.getEditor().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);
- }
-
- return changes;
- }
-
- /** Removes all the unused attributes after a conversion */
- private void removeUndefinedAttrs(MultiTextEdit rootEdit, Element element) {
- ViewElementDescriptor descriptor = getElementDescriptor(mTypeFqcn);
- if (descriptor == null) {
- return;
- }
-
- Set<String> defined = new HashSet<String>();
- AttributeDescriptor[] layoutAttributes = descriptor.getAttributes();
- for (AttributeDescriptor attribute : layoutAttributes) {
- defined.add(attribute.getXmlLocalName());
- }
-
- List<Attr> attributes = findAttributes(element);
- for (Attr attribute : attributes) {
- String name = attribute.getLocalName();
- if (!defined.contains(name)) {
- // Remove it
- removeAttribute(rootEdit, element, attribute.getNamespaceURI(), name);
- }
- }
-
- // Set text attribute if it's defined
- if (defined.contains(ATTR_TEXT) && !element.hasAttributeNS(ANDROID_URI, ATTR_TEXT)) {
- setAttribute(rootEdit, element, ANDROID_URI, getAndroidNamespacePrefix(),
- ATTR_TEXT, descriptor.getUiName());
- }
- }
-
- protected List<Attr> findAttributes(Node root) {
- List<Attr> result = new ArrayList<Attr>();
- NamedNodeMap attributes = root.getAttributes();
- for (int i = 0, n = attributes.getLength(); i < n; i++) {
- Node attributeNode = attributes.item(i);
-
- String name = attributeNode.getLocalName();
- if (!name.startsWith(ATTR_LAYOUT_RESOURCE_PREFIX)
- && ANDROID_URI.equals(attributeNode.getNamespaceURI())) {
- result.add((Attr) attributeNode);
- }
- }
-
- return result;
- }
-
- List<String> getOldTypes() {
- List<String> types = new ArrayList<String>();
- for (Element primary : getElements()) {
- String oldType = primary.getTagName();
- if (oldType.indexOf('.') == -1
- && !oldType.equals(VIEW_INCLUDE) && !oldType.equals(VIEW_FRAGMENT)) {
- oldType = ANDROID_WIDGET_PREFIX + oldType;
- }
- types.add(oldType);
- }
-
- return types;
- }
-
- @Override
- VisualRefactoringWizard createWizard() {
- return new ChangeViewWizard(this, mDelegate);
- }
-
- public static class Descriptor extends VisualRefactoringDescriptor {
- public Descriptor(String project, String description, String comment,
- Map<String, String> arguments) {
- super("com.android.ide.eclipse.adt.refactoring.changeview", //$NON-NLS-1$
- project, description, comment, arguments);
- }
-
- @Override
- protected Refactoring createRefactoring(Map<String, String> args) {
- return new ChangeViewRefactoring(args);
- }
- }
-}
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
deleted file mode 100644
index 0ac7106b3..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeViewWizard.java
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * 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 static com.android.SdkConstants.REQUEST_FOCUS;
-import static com.android.SdkConstants.VIEW_FRAGMENT;
-import static com.android.SdkConstants.VIEW_INCLUDE;
-
-import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditorDelegate;
-import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.ViewElementDescriptor;
-import com.android.ide.eclipse.adt.internal.editors.layout.gle2.CustomViewFinder;
-import com.android.ide.eclipse.adt.internal.editors.layout.gre.ViewMetadataRepository;
-import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
-import com.android.ide.eclipse.adt.internal.sdk.Sdk;
-import com.android.sdklib.IAndroidTarget;
-import com.android.utils.Pair;
-
-import org.eclipse.core.resources.IProject;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Combo;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Label;
-
-import java.util.ArrayList;
-import java.util.List;
-
-class ChangeViewWizard extends VisualRefactoringWizard {
- private static final String SEPARATOR_LABEL =
- "----------------------------------------"; //$NON-NLS-1$
-
- public ChangeViewWizard(ChangeViewRefactoring ref, LayoutEditorDelegate editor) {
- super(ref, editor);
- setDefaultPageTitle("Change Widget Type");
- }
-
- @Override
- protected void addUserInputPages() {
- ChangeViewRefactoring ref = (ChangeViewRefactoring) getRefactoring();
- List<String> oldTypes = ref.getOldTypes();
- String oldType = null;
- for (String type : oldTypes) {
- if (oldType == null) {
- oldType = type;
- } else if (!oldType.equals(type)) {
- // If the types differ, don't offer related categories
- oldType = null;
- break;
- }
- }
- addPage(new InputPage(mDelegate.getEditor().getProject(), oldType));
- }
-
- /** Wizard page which inputs parameters for the {@link ChangeViewRefactoring} operation */
- private static class InputPage extends VisualRefactoringInputPage {
- private final IProject mProject;
- private Combo mTypeCombo;
- private final String mOldType;
- private List<String> mClassNames;
-
- public InputPage(IProject project, String oldType) {
- super("ChangeViewInputPage"); //$NON-NLS-1$
- mProject = project;
- mOldType = oldType;
- }
-
- @Override
- public void createControl(Composite parent) {
- Composite composite = new Composite(parent, SWT.NONE);
- composite.setLayout(new GridLayout(2, false));
-
- Label typeLabel = new Label(composite, SWT.NONE);
- typeLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
- typeLabel.setText("New Widget Type:");
-
- mTypeCombo = new Combo(composite, SWT.READ_ONLY);
- mTypeCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
- mTypeCombo.addSelectionListener(mSelectionValidateListener);
-
- mClassNames = getWidgetTypes(mOldType, mTypeCombo);
- mTypeCombo.select(0);
-
- setControl(composite);
- validatePage();
-
- mTypeCombo.setFocus();
- }
-
- private List<String> getWidgetTypes(String oldType, Combo combo) {
- List<String> classNames = new ArrayList<String>();
-
- // Populate type combo
- Sdk currentSdk = Sdk.getCurrent();
- if (currentSdk != null) {
- IAndroidTarget target = currentSdk.getTarget(mProject);
- if (target != null) {
- // Try to pick "related" widgets to the one you have selected.
- // For example, for an AnalogClock, display DigitalClock first.
- // For a Text, offer EditText, AutoComplete, etc.
- if (oldType != null) {
- ViewMetadataRepository repository = ViewMetadataRepository.get();
- List<String> relatedTo = repository.getRelatedTo(oldType);
- if (relatedTo.size() > 0) {
- for (String className : relatedTo) {
- String base = className.substring(className.lastIndexOf('.') + 1);
- combo.add(base);
- classNames.add(className);
- }
- combo.add(SEPARATOR_LABEL);
- classNames.add(null);
- }
- }
-
- Pair<List<String>,List<String>> result =
- CustomViewFinder.findViews(mProject, false);
- List<String> customViews = result.getFirst();
- List<String> thirdPartyViews = result.getSecond();
- if (customViews.size() > 0) {
- for (String view : customViews) {
- combo.add(view);
- classNames.add(view);
- }
- combo.add(SEPARATOR_LABEL);
- classNames.add(null);
- }
-
- if (thirdPartyViews.size() > 0) {
- for (String view : thirdPartyViews) {
- combo.add(view);
- classNames.add(view);
- }
- combo.add(SEPARATOR_LABEL);
- classNames.add(null);
- }
-
- AndroidTargetData targetData = currentSdk.getTargetData(target);
- if (targetData != null) {
- // Now add ALL known layout descriptors in case the user has
- // a special case
- List<ViewElementDescriptor> descriptors =
- targetData.getLayoutDescriptors().getViewDescriptors();
- for (ViewElementDescriptor d : descriptors) {
- String className = d.getFullClassName();
- if (className.equals(VIEW_INCLUDE)
- || className.equals(VIEW_FRAGMENT)
- || className.equals(REQUEST_FOCUS)) {
- continue;
- }
- combo.add(d.getUiName());
- classNames.add(className);
-
- }
- }
- }
- } else {
- combo.add("SDK not initialized");
- classNames.add(null);
- }
-
- return classNames;
- }
-
- @Override
- protected boolean validatePage() {
- boolean ok = true;
- int selectionIndex = mTypeCombo.getSelectionIndex();
- String type = selectionIndex != -1 ? mClassNames.get(selectionIndex) : null;
- if (type == null) {
- setErrorMessage("Select a widget type to convert to");
- ok = false; // The user has chosen a separator
- } else {
- setErrorMessage(null);
- }
-
- // Record state
- ChangeViewRefactoring refactoring =
- (ChangeViewRefactoring) getRefactoring();
- refactoring.setType(type);
-
- setPageComplete(ok);
- return ok;
- }
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractIncludeAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractIncludeAction.java
deleted file mode 100644
index 6f96fe489..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractIncludeAction.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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.eclipse.adt.internal.editors.layout.LayoutEditorDelegate;
-
-import org.eclipse.jface.action.IAction;
-import org.eclipse.ltk.ui.refactoring.RefactoringWizard;
-import org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation;
-
-/**
- * Action executed when the "Extract as Include" menu item is invoked.
- */
-public class ExtractIncludeAction extends VisualRefactoringAction {
- @Override
- public void run(IAction action) {
- if ((mTextSelection != null || mTreeSelection != null) && mFile != null) {
- ExtractIncludeRefactoring ref = new ExtractIncludeRefactoring(mFile, mDelegate,
- mTextSelection, mTreeSelection);
- RefactoringWizard wizard = new ExtractIncludeWizard(ref, mDelegate);
- RefactoringWizardOpenOperation op = new RefactoringWizardOpenOperation(wizard);
- try {
- op.run(mWindow.getShell(), wizard.getDefaultPageTitle());
- } catch (InterruptedException e) {
- // Interrupted. Pass.
- }
- }
- }
-
- public static IAction create(LayoutEditorDelegate editorDelegate) {
- return create("Extract Include...", editorDelegate, ExtractIncludeAction.class);
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractIncludeContribution.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractIncludeContribution.java
deleted file mode 100644
index 5903812ea..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractIncludeContribution.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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 org.eclipse.ltk.core.refactoring.RefactoringContribution;
-import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
-
-import java.util.Map;
-
-public class ExtractIncludeContribution extends RefactoringContribution {
-
- @SuppressWarnings("unchecked")
- @Override
- public RefactoringDescriptor createDescriptor(String id, String project, String description,
- String comment, Map arguments, int flags) throws IllegalArgumentException {
- return new ExtractIncludeRefactoring.Descriptor(project, description, comment, arguments);
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public Map retrieveArgumentMap(RefactoringDescriptor descriptor) {
- if (descriptor instanceof ExtractIncludeRefactoring.Descriptor) {
- return ((ExtractIncludeRefactoring.Descriptor) descriptor).getArguments();
- }
- return super.retrieveArgumentMap(descriptor);
- }
-}
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
deleted file mode 100644
index f58ac5501..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractIncludeRefactoring.java
+++ /dev/null
@@ -1,670 +0,0 @@
-/*
- * 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 static com.android.SdkConstants.ANDROID_NS_NAME;
-import static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.ATTR_ID;
-import static com.android.SdkConstants.ATTR_LAYOUT_HEIGHT;
-import static com.android.SdkConstants.ATTR_LAYOUT_RESOURCE_PREFIX;
-import static com.android.SdkConstants.ATTR_LAYOUT_WIDTH;
-import static com.android.SdkConstants.DOT_XML;
-import static com.android.SdkConstants.EXT_XML;
-import static com.android.SdkConstants.FD_RES;
-import static com.android.SdkConstants.FD_RESOURCES;
-import static com.android.SdkConstants.FD_RES_LAYOUT;
-import static com.android.SdkConstants.ID_PREFIX;
-import static com.android.SdkConstants.NEW_ID_PREFIX;
-import static com.android.SdkConstants.VALUE_WRAP_CONTENT;
-import static com.android.SdkConstants.VIEW_INCLUDE;
-import static com.android.SdkConstants.XMLNS;
-import static com.android.SdkConstants.XMLNS_PREFIX;
-import static com.android.ide.eclipse.adt.AdtConstants.WS_SEP;
-import static com.android.resources.ResourceType.LAYOUT;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.VisibleForTesting;
-import com.android.ide.common.xml.XmlFormatStyle;
-import com.android.ide.eclipse.adt.AdtPlugin;
-import com.android.ide.eclipse.adt.internal.editors.formatting.EclipseXmlFormatPreferences;
-import com.android.ide.eclipse.adt.internal.editors.formatting.EclipseXmlPrettyPrinter;
-import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditorDelegate;
-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.preferences.AdtPrefs;
-import com.android.ide.eclipse.adt.internal.resources.ResourceNameValidator;
-import com.android.utils.XmlUtils;
-
-import org.eclipse.core.resources.IContainer;
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IFolder;
-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;
-import org.eclipse.core.runtime.OperationCanceledException;
-import org.eclipse.core.runtime.Path;
-import org.eclipse.jface.dialogs.IInputValidator;
-import org.eclipse.jface.text.ITextSelection;
-import org.eclipse.jface.viewers.ITreeSelection;
-import org.eclipse.ltk.core.refactoring.Change;
-import org.eclipse.ltk.core.refactoring.NullChange;
-import org.eclipse.ltk.core.refactoring.Refactoring;
-import org.eclipse.ltk.core.refactoring.RefactoringStatus;
-import org.eclipse.ltk.core.refactoring.TextFileChange;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.text.edits.InsertEdit;
-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.Locale;
-import java.util.Map;
-
-/**
- * Extracts the selection and writes it out as a separate layout file, then adds an
- * include to that new layout file. Interactively asks the user for a new name for the
- * layout.
- */
-@SuppressWarnings("restriction") // XML model
-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 String mLayoutName;
- private boolean mReplaceOccurrences;
-
- /**
- * This constructor is solely used by {@link Descriptor},
- * to replay a previous refactoring.
- * @param arguments argument map created by #createArgumentMap.
- */
- ExtractIncludeRefactoring(Map<String, String> arguments) {
- super(arguments);
- mLayoutName = arguments.get(KEY_NAME);
- mReplaceOccurrences = Boolean.parseBoolean(arguments.get(KEY_OCCURRENCES));
- }
-
- public ExtractIncludeRefactoring(
- IFile file,
- LayoutEditorDelegate delegate,
- ITextSelection selection,
- ITreeSelection treeSelection) {
- super(file, delegate, selection, treeSelection);
- }
-
- @VisibleForTesting
- ExtractIncludeRefactoring(List<Element> selectedElements, LayoutEditorDelegate editor) {
- super(selectedElements, editor);
- }
-
- @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 = getSelectedViewInfos();
- if (!validateNotEmpty(infos, status)) {
- return status;
- }
-
- if (!validateNotRoot(infos, status)) {
- 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(VIEW_INCLUDE)) {
- status.addWarning("No point in refactoring a single include tag");
- }
- }
- }
-
- // Enforce that the selection is -contiguous-
- if (!validateContiguous(infos, status)) {
- return status;
- }
- }
-
- // This also 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();
- }
- }
-
- @Override
- protected VisualRefactoringDescriptor createDescriptor() {
- String comment = getName();
- return new Descriptor(
- mProject.getName(), //project
- comment, //description
- comment, //comment
- createArgumentMap());
- }
-
- @Override
- protected Map<String, String> createArgumentMap() {
- Map<String, String> args = super.createArgumentMap();
- args.put(KEY_NAME, mLayoutName);
- args.put(KEY_OCCURRENCES, Boolean.toString(mReplaceOccurrences));
-
- return args;
- }
-
- @Override
- public String getName() {
- return "Extract as Include";
- }
-
- void setLayoutName(String layoutName) {
- mLayoutName = layoutName;
- }
-
- void setReplaceOccurrences(boolean selection) {
- mReplaceOccurrences = selection;
- }
-
- // ---- Actual implementation of Extract as Include modification computation ----
-
- @Override
- protected @NonNull List<Change> computeChanges(IProgressMonitor monitor) {
- String extractedText = getExtractedText();
-
- String namespaceDeclarations = computeNamespaceDeclarations();
-
- // Insert namespace:
- extractedText = insertNamespace(extractedText, namespaceDeclarations);
-
- StringBuilder sb = new StringBuilder();
- sb.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"); //$NON-NLS-1$
- sb.append(extractedText);
- sb.append('\n');
-
- List<Change> changes = new ArrayList<Change>();
-
- String newFileName = mLayoutName + DOT_XML;
- IProject project = mDelegate.getEditor().getProject();
- IFile sourceFile = mDelegate.getEditor().getInputFile();
- if (sourceFile == null) {
- return changes;
- }
-
- // 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) {
- List<IFile> layouts = getOtherLayouts(sourceFile);
- for (IFile file : layouts) {
- IModelManager modelManager = StructuredModelManager.getModelManager();
- IStructuredModel model = null;
- // We could enhance this with a SubMonitor to make the progress bar move as
- // well.
- monitor.subTask(String.format("Looking for duplicates in %1$s",
- file.getProjectRelativePath()));
- if (monitor.isCanceled()) {
- throw new OperationCanceledException();
- }
-
- try {
- model = modelManager.getModelForRead(file);
- 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, file, 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(EXT_XML);
- changes.add(addFile);
-
- String newFile = sb.toString();
- if (AdtPrefs.getPrefs().getFormatGuiXml()) {
- newFile = EclipseXmlPrettyPrinter.prettyPrint(newFile,
- EclipseXmlFormatPreferences.create(), XmlFormatStyle.LAYOUT,
- null /*lineSeparator*/);
- }
- addFile.setEdit(new InsertEdit(0, newFile));
-
- 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.setTextType(EXT_XML);
- changes.add(change);
-
- String referenceId = getReferenceId();
- // Replace existing elements in the source file and insert <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 (referenceId != null && primary != null) {
- String rootId = getId(primary);
- IStructuredModel model = null;
- try {
- model = StructuredModelManager.getModelManager().getModelForRead(sourceFile);
- IStructuredDocument doc = model.getStructuredDocument();
- if (doc != null && rootId != null) {
- List<TextEdit> replaceIds = replaceIds(androidNsPrefix, doc, begin,
- end, rootId, referenceId);
- for (TextEdit edit : replaceIds) {
- rootEdit.addChild(edit);
- }
-
- if (AdtPrefs.getPrefs().getFormatGuiXml()) {
- MultiTextEdit formatted = reformat(doc.get(), rootEdit,
- XmlFormatStyle.LAYOUT);
- if (formatted != null) {
- rootEdit = formatted;
- }
- }
- }
- } catch (IOException e) {
- AdtPlugin.log(e, null);
- } catch (CoreException e) {
- AdtPlugin.log(e, null);
- } finally {
- if (model != null) {
- model.releaseFromRead();
- }
- }
- }
-
- change.setEdit(rootEdit);
- }
-
- /**
- * Returns a list of all the other layouts (in all configurations) in the project other
- * than the given source layout where the refactoring was initiated. Never null.
- */
- private List<IFile> getOtherLayouts(IFile sourceFile) {
- List<IFile> layouts = new ArrayList<IFile>(100);
- IPath sourcePath = sourceFile.getProjectRelativePath();
- IFolder resources = mProject.getFolder(FD_RESOURCES);
- try {
- for (IResource folder : resources.members()) {
- if (folder.getName().startsWith(FD_RES_LAYOUT) &&
- folder instanceof IFolder) {
- IFolder layoutFolder = (IFolder) folder;
- for (IResource file : layoutFolder.members()) {
- if (file.getName().endsWith(EXT_XML)
- && file instanceof IFile) {
- if (!file.getProjectRelativePath().equals(sourcePath)) {
- layouts.add((IFile) file);
- }
- }
- }
- }
- }
- } catch (CoreException e) {
- AdtPlugin.log(e, null);
- }
-
- return layouts;
- }
-
- String getInitialName() {
- String defaultName = ""; //$NON-NLS-1$
- Element primary = getPrimaryElement();
- if (primary != null) {
- String id = primary.getAttributeNS(ANDROID_URI, ATTR_ID);
- // id null check for https://bugs.eclipse.org/bugs/show_bug.cgi?id=272378
- if (id != null && (id.startsWith(ID_PREFIX) || id.startsWith(NEW_ID_PREFIX))) {
- // Use everything following the id/, and make it lowercase since that is
- // the convention for layouts (and use Locale.US to ensure that "Image" becomes
- // "image" etc)
- defaultName = id.substring(id.indexOf('/') + 1).toLowerCase(Locale.US);
-
- IInputValidator validator = ResourceNameValidator.create(true, mProject, LAYOUT);
-
- if (validator.isValid(defaultName) != null) { // Already exists?
- defaultName = ""; //$NON-NLS-1$
- }
- }
- }
-
- return defaultName;
- }
-
- IFile getSourceFile() {
- return mFile;
- }
-
- private Change createFinishHook(final IFile file) {
- return new NullChange("Open extracted layout and refresh resources") {
- @Override
- public Change perform(IProgressMonitor pm) throws CoreException {
- Display display = AdtPlugin.getDisplay();
- display.asyncExec(new Runnable() {
- @Override
- public void run() {
- openFile(file);
- mDelegate.getGraphicalEditor().refreshProjectResources();
- // Save file to trigger include finder scanning (as well as making
- // the
- // actual show-include feature work since it relies on reading
- // files from
- // disk, not a live buffer)
- IWorkbenchPage page = mDelegate.getEditor().getEditorSite().getPage();
- page.saveEditor(mDelegate.getEditor(), false);
- }
- });
-
- // Not undoable: just return null instead of an undo-change.
- return null;
- }
- };
- }
-
- private String computeNamespaceDeclarations() {
- String androidNsPrefix = null;
- String namespaceDeclarations = null;
-
- StringBuilder sb = new StringBuilder();
- List<Attr> attributeNodes = findNamespaceAttributes();
- for (Node attributeNode : attributeNodes) {
- String prefix = attributeNode.getPrefix();
- if (XMLNS.equals(prefix)) {
- sb.append(' ');
- String name = attributeNode.getNodeName();
- sb.append(name);
- sb.append('=').append('"');
-
- String value = attributeNode.getNodeValue();
- if (value.equals(ANDROID_URI)) {
- androidNsPrefix = name;
- if (androidNsPrefix.startsWith(XMLNS_PREFIX)) {
- androidNsPrefix = androidNsPrefix.substring(XMLNS_PREFIX.length());
- }
- }
- sb.append(XmlUtils.toXmlAttributeValue(value));
- sb.append('"');
- }
- }
- namespaceDeclarations = sb.toString();
-
- if (androidNsPrefix == null) {
- androidNsPrefix = ANDROID_NS_NAME;
- }
-
- if (namespaceDeclarations.length() == 0) {
- sb.setLength(0);
- sb.append(' ');
- sb.append(XMLNS_PREFIX);
- sb.append(androidNsPrefix);
- sb.append('=').append('"');
- sb.append(ANDROID_URI);
- sb.append('"');
- namespaceDeclarations = sb.toString();
- }
-
- return namespaceDeclarations;
- }
-
- /** Returns the id to be used for the include tag itself (may be null) */
- private String getReferenceId() {
- String rootId = getRootId();
- if (rootId != null) {
- return rootId + "_ref";
- }
-
- return null;
- }
-
- /**
- * Compute the actual {@code <include>} string to be inserted in place of the old
- * selection
- */
- 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);
- sb.append('"');
- sb.append(' ');
-
- // Create new id for the include itself
- if (referenceId != null) {
- sb.append(androidNsPrefix);
- sb.append(':');
- sb.append(ATTR_ID);
- sb.append('=').append('"');
- sb.append(referenceId);
- sb.append('"').append(' ');
- }
-
- // Add id string, unless it's a <merge>, since we may need to adjust any layout
- // references to apply to the <include> tag instead
-
- // I should move all the layout_ attributes as well
- // I also need to duplicate and modify the id and then replace
- // everything else in the file with this new id...
-
- // HACK: see issue 13494: We must duplicate the width/height attributes on the
- // <include> statement for designtime rendering only
- String width = null;
- String height = null;
- if (primaryNode == null) {
- // Multiple selection - in that case we will be creating an outer <merge>
- // so we need to set our own width/height on it
- width = height = VALUE_WRAP_CONTENT;
- } else {
- if (!primaryNode.hasAttributeNS(ANDROID_URI, ATTR_LAYOUT_WIDTH)) {
- width = VALUE_WRAP_CONTENT;
- } else {
- width = primaryNode.getAttributeNS(ANDROID_URI, ATTR_LAYOUT_WIDTH);
- }
- if (!primaryNode.hasAttributeNS(ANDROID_URI, ATTR_LAYOUT_HEIGHT)) {
- height = VALUE_WRAP_CONTENT;
- } else {
- height = primaryNode.getAttributeNS(ANDROID_URI, ATTR_LAYOUT_HEIGHT);
- }
- }
- if (width != null) {
- sb.append(' ');
- sb.append(androidNsPrefix);
- sb.append(':');
- sb.append(ATTR_LAYOUT_WIDTH);
- sb.append('=').append('"');
- sb.append(XmlUtils.toXmlAttributeValue(width));
- sb.append('"');
- }
- if (height != null) {
- sb.append(' ');
- sb.append(androidNsPrefix);
- sb.append(':');
- sb.append(ATTR_LAYOUT_HEIGHT);
- sb.append('=').append('"');
- sb.append(XmlUtils.toXmlAttributeValue(height));
- sb.append('"');
- }
-
- // Duplicate all the other layout attributes as well
- if (primaryNode != null) {
- NamedNodeMap attributes = primaryNode.getAttributes();
- for (int i = 0, n = attributes.getLength(); i < n; i++) {
- Node attr = attributes.item(i);
- String name = attr.getLocalName();
- if (name.startsWith(ATTR_LAYOUT_RESOURCE_PREFIX)
- && ANDROID_URI.equals(attr.getNamespaceURI())) {
- if (name.equals(ATTR_LAYOUT_WIDTH) || name.equals(ATTR_LAYOUT_HEIGHT)) {
- // Already handled
- continue;
- }
-
- sb.append(' ');
- sb.append(androidNsPrefix);
- sb.append(':');
- sb.append(name);
- sb.append('=').append('"');
- sb.append(XmlUtils.toXmlAttributeValue(attr.getNodeValue()));
- sb.append('"');
- }
- }
- }
-
- sb.append("/>");
- return sb.toString();
- }
-
- /** Return the text in the document in the range start to end */
- private String getExtractedText() {
- String xml = getText(mSelectionStart, mSelectionEnd);
- Element primaryNode = getPrimaryElement();
- xml = stripTopLayoutAttributes(primaryNode, mSelectionStart, xml);
- xml = dedent(xml);
-
- // Wrap siblings in <merge>?
- if (primaryNode == null) {
- StringBuilder sb = new StringBuilder();
- sb.append("<merge>\n"); //$NON-NLS-1$
- // indent an extra level
- for (String line : xml.split("\n")) { //$NON-NLS-1$
- sb.append(" "); //$NON-NLS-1$
- sb.append(line).append('\n');
- }
- sb.append("</merge>\n"); //$NON-NLS-1$
- xml = sb.toString();
- }
-
- return xml;
- }
-
- @Override
- VisualRefactoringWizard createWizard() {
- return new ExtractIncludeWizard(this, mDelegate);
- }
-
- public static class Descriptor extends VisualRefactoringDescriptor {
- public Descriptor(String project, String description, String comment,
- Map<String, String> arguments) {
- super("com.android.ide.eclipse.adt.refactoring.extract.include", //$NON-NLS-1$
- project, description, comment, arguments);
- }
-
- @Override
- protected Refactoring createRefactoring(Map<String, String> args) {
- return new ExtractIncludeRefactoring(args);
- }
- }
-}
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
deleted file mode 100644
index f3ac3f1b3..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractIncludeWizard.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * 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.eclipse.adt.internal.editors.layout.LayoutEditorDelegate;
-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.swt.SWT;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Text;
-
-class ExtractIncludeWizard extends VisualRefactoringWizard {
- public ExtractIncludeWizard(ExtractIncludeRefactoring ref, LayoutEditorDelegate editor) {
- super(ref, editor);
- setDefaultPageTitle(ref.getName());
- }
-
- @Override
- protected void addUserInputPages() {
- ExtractIncludeRefactoring ref = (ExtractIncludeRefactoring) getRefactoring();
- String initialName = ref.getInitialName();
- IFile sourceFile = ref.getSourceFile();
- addPage(new InputPage(mDelegate.getEditor().getProject(), sourceFile, initialName));
- }
-
- /** Wizard page which inputs parameters for the {@link ExtractIncludeRefactoring} operation */
- private static class InputPage extends VisualRefactoringInputPage {
- private final IProject mProject;
- private final IFile mSourceFile;
- private final String mSuggestedName;
- private Text mNameText;
- private Button mReplaceAllOccurrences;
-
- public InputPage(IProject project, IFile sourceFile, String suggestedName) {
- super("ExtractIncludeInputPage");
- mProject = project;
- mSourceFile = sourceFile;
- mSuggestedName = suggestedName;
- }
-
- @Override
- public void createControl(Composite parent) {
- Composite composite = new Composite(parent, SWT.NONE);
- composite.setLayout(new GridLayout(2, false));
-
- Label nameLabel = new Label(composite, SWT.NONE);
- nameLabel.setText("New Layout Name:");
- nameLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
-
- mNameText = new Text(composite, SWT.BORDER);
- mNameText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
- mNameText.addModifyListener(mModifyValidateListener);
-
- mReplaceAllOccurrences = new Button(composite, SWT.CHECK);
- mReplaceAllOccurrences.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER,
- false, false, 2, 1));
- mReplaceAllOccurrences.setText(
- "Replace occurrences in all layouts with include to new layout");
- mReplaceAllOccurrences.setEnabled(true);
- mReplaceAllOccurrences.setSelection(true);
- mReplaceAllOccurrences.addSelectionListener(mSelectionValidateListener);
-
- // Initialize UI:
- if (mSuggestedName != null) {
- mNameText.setText(mSuggestedName);
- }
-
- setControl(composite);
- validatePage();
- }
-
- @Override
- protected boolean validatePage() {
- boolean ok = true;
-
- String text = mNameText.getText().trim();
-
- if (text.length() == 0) {
- setErrorMessage("Provide a name for the new layout");
- ok = false;
- } else {
- ResourceNameValidator validator = ResourceNameValidator.create(false, mProject,
- ResourceType.LAYOUT);
- String message = validator.isValid(text);
- if (message != null) {
- setErrorMessage(message);
- ok = false;
- }
- }
-
- if (ok) {
- setErrorMessage(null);
-
- // Record state
- ExtractIncludeRefactoring refactoring =
- (ExtractIncludeRefactoring) getRefactoring();
- refactoring.setLayoutName(text);
- refactoring.setReplaceOccurrences(mReplaceAllOccurrences.getSelection());
- }
-
- setPageComplete(ok);
- return ok;
- }
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractStyleAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractStyleAction.java
deleted file mode 100644
index 4a498637d..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractStyleAction.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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.eclipse.adt.internal.editors.layout.LayoutEditorDelegate;
-
-import org.eclipse.jface.action.IAction;
-import org.eclipse.ltk.ui.refactoring.RefactoringWizard;
-import org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation;
-
-/**
- * Action executed when the "Extract Style" menu item is invoked.
- */
-public class ExtractStyleAction extends VisualRefactoringAction {
- @Override
- public void run(IAction action) {
- if ((mTextSelection != null || mTreeSelection != null) && mFile != null) {
- ExtractStyleRefactoring ref = new ExtractStyleRefactoring(mFile, mDelegate,
- mTextSelection, mTreeSelection);
- RefactoringWizard wizard = new ExtractStyleWizard(ref, mDelegate);
- RefactoringWizardOpenOperation op = new RefactoringWizardOpenOperation(wizard);
- try {
- op.run(mWindow.getShell(), wizard.getDefaultPageTitle());
- } catch (InterruptedException e) {
- // Interrupted. Pass.
- }
- }
- }
-
- public static IAction create(LayoutEditorDelegate editorDelegate) {
- return create("Extract Style...", editorDelegate, ExtractStyleAction.class);
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractStyleContribution.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractStyleContribution.java
deleted file mode 100644
index 95fbdbc43..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractStyleContribution.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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 org.eclipse.ltk.core.refactoring.RefactoringContribution;
-import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
-
-import java.util.Map;
-
-public class ExtractStyleContribution extends RefactoringContribution {
-
- @SuppressWarnings("unchecked")
- @Override
- public RefactoringDescriptor createDescriptor(String id, String project, String description,
- String comment, Map arguments, int flags) throws IllegalArgumentException {
- return new ExtractStyleRefactoring.Descriptor(project, description, comment, arguments);
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public Map retrieveArgumentMap(RefactoringDescriptor descriptor) {
- if (descriptor instanceof ExtractStyleRefactoring.Descriptor) {
- return ((ExtractStyleRefactoring.Descriptor) descriptor).getArguments();
- }
- return super.retrieveArgumentMap(descriptor);
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractStyleRefactoring.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractStyleRefactoring.java
deleted file mode 100644
index 9b1770d82..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractStyleRefactoring.java
+++ /dev/null
@@ -1,579 +0,0 @@
-/*
- * 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 static com.android.SdkConstants.ANDROID_NS_NAME;
-import static com.android.SdkConstants.ANDROID_NS_NAME_PREFIX;
-import static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.ATTR_HINT;
-import static com.android.SdkConstants.ATTR_ID;
-import static com.android.SdkConstants.ATTR_LAYOUT_MARGIN;
-import static com.android.SdkConstants.ATTR_LAYOUT_RESOURCE_PREFIX;
-import static com.android.SdkConstants.ATTR_NAME;
-import static com.android.SdkConstants.ATTR_ON_CLICK;
-import static com.android.SdkConstants.ATTR_PARENT;
-import static com.android.SdkConstants.ATTR_SRC;
-import static com.android.SdkConstants.ATTR_STYLE;
-import static com.android.SdkConstants.ATTR_TEXT;
-import static com.android.SdkConstants.EXT_XML;
-import static com.android.SdkConstants.FD_RESOURCES;
-import static com.android.SdkConstants.FD_RES_VALUES;
-import static com.android.SdkConstants.PREFIX_ANDROID;
-import static com.android.SdkConstants.PREFIX_RESOURCE_REF;
-import static com.android.SdkConstants.REFERENCE_STYLE;
-import static com.android.SdkConstants.TAG_ITEM;
-import static com.android.SdkConstants.TAG_RESOURCES;
-import static com.android.SdkConstants.XMLNS_PREFIX;
-import static com.android.ide.eclipse.adt.AdtConstants.WS_SEP;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.VisibleForTesting;
-import com.android.ide.common.rendering.api.ResourceValue;
-import com.android.ide.common.resources.ResourceResolver;
-import com.android.ide.common.xml.XmlFormatStyle;
-import com.android.ide.eclipse.adt.AdtPlugin;
-import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor;
-import com.android.ide.eclipse.adt.internal.editors.descriptors.DescriptorsUtils;
-import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditorDelegate;
-import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs;
-import com.android.ide.eclipse.adt.internal.wizards.newxmlfile.NewXmlFileWizard;
-import com.android.utils.Pair;
-
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.OperationCanceledException;
-import org.eclipse.core.runtime.Path;
-import org.eclipse.jface.text.ITextSelection;
-import org.eclipse.jface.viewers.ITreeSelection;
-import org.eclipse.ltk.core.refactoring.Change;
-import org.eclipse.ltk.core.refactoring.Refactoring;
-import org.eclipse.ltk.core.refactoring.RefactoringStatus;
-import org.eclipse.ltk.core.refactoring.TextFileChange;
-import org.eclipse.text.edits.InsertEdit;
-import org.eclipse.text.edits.MultiTextEdit;
-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.Element;
-import org.w3c.dom.NamedNodeMap;
-import org.w3c.dom.Node;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-
-/**
- * Extracts the selection and writes it out as a separate layout file, then adds an
- * include to that new layout file. Interactively asks the user for a new name for the
- * layout.
- * <p>
- * Remaining work to do / Possible enhancements:
- * <ul>
- * <li>Optionally look in other files in the project and attempt to set style attributes
- * in other cases where the style attributes match?
- * <li>If the elements we are extracting from already contain a style attribute, set that
- * style as the parent style of the current style?
- * <li>Add a parent-style picker to the wizard (initialized with the above if applicable)
- * <li>Pick up indentation settings from the XML module
- * <li>Integrate with themes somehow -- make an option to have the extracted style go into
- * the theme instead
- * </ul>
- */
-@SuppressWarnings("restriction") // XML model
-public class ExtractStyleRefactoring extends VisualRefactoring {
- private static final String KEY_NAME = "name"; //$NON-NLS-1$
- private static final String KEY_REMOVE_EXTRACTED = "removeextracted"; //$NON-NLS-1$
- private static final String KEY_REMOVE_ALL = "removeall"; //$NON-NLS-1$
- private static final String KEY_APPLY_STYLE = "applystyle"; //$NON-NLS-1$
- private static final String KEY_PARENT = "parent"; //$NON-NLS-1$
- private String mStyleName;
- /** The name of the file in res/values/ that the style will be added to. Normally
- * res/values/styles.xml - but unit tests pick other names */
- private String mStyleFileName = "styles.xml";
- /** Set a style reference on the extracted elements? */
- private boolean mApplyStyle;
- /** Remove the attributes that were extracted? */
- private boolean mRemoveExtracted;
- /** List of attributes chosen by the user to be extracted */
- private List<Attr> mChosenAttributes = new ArrayList<Attr>();
- /** Remove all attributes that match the extracted attributes names, regardless of value */
- private boolean mRemoveAll;
- /** The parent style to extend */
- private String mParent;
- /** The full list of available attributes in the refactoring */
- private Map<String, List<Attr>> mAvailableAttributes;
-
- /**
- * This constructor is solely used by {@link Descriptor},
- * to replay a previous refactoring.
- * @param arguments argument map created by #createArgumentMap.
- */
- ExtractStyleRefactoring(Map<String, String> arguments) {
- super(arguments);
- mStyleName = arguments.get(KEY_NAME);
- mRemoveExtracted = Boolean.parseBoolean(arguments.get(KEY_REMOVE_EXTRACTED));
- mRemoveAll = Boolean.parseBoolean(arguments.get(KEY_REMOVE_ALL));
- mApplyStyle = Boolean.parseBoolean(arguments.get(KEY_APPLY_STYLE));
- mParent = arguments.get(KEY_PARENT);
- if (mParent != null && mParent.length() == 0) {
- mParent = null;
- }
- }
-
- public ExtractStyleRefactoring(
- IFile file,
- LayoutEditorDelegate delegate,
- ITextSelection selection,
- ITreeSelection treeSelection) {
- super(file, delegate, selection, treeSelection);
- }
-
- @VisibleForTesting
- ExtractStyleRefactoring(List<Element> selectedElements, LayoutEditorDelegate editor) {
- super(selectedElements, editor);
- }
-
- @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;
- }
-
- // This also 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();
- }
- }
-
- @Override
- protected VisualRefactoringDescriptor createDescriptor() {
- String comment = getName();
- return new Descriptor(
- mProject.getName(), //project
- comment, //description
- comment, //comment
- createArgumentMap());
- }
-
- @Override
- protected Map<String, String> createArgumentMap() {
- Map<String, String> args = super.createArgumentMap();
- args.put(KEY_NAME, mStyleName);
- args.put(KEY_REMOVE_EXTRACTED, Boolean.toString(mRemoveExtracted));
- args.put(KEY_REMOVE_ALL, Boolean.toString(mRemoveAll));
- args.put(KEY_APPLY_STYLE, Boolean.toString(mApplyStyle));
- args.put(KEY_PARENT, mParent != null ? mParent : "");
-
- return args;
- }
-
- @Override
- public String getName() {
- return "Extract Style";
- }
-
- void setStyleName(String styleName) {
- mStyleName = styleName;
- }
-
- void setStyleFileName(String styleFileName) {
- mStyleFileName = styleFileName;
- }
-
- void setChosenAttributes(List<Attr> attributes) {
- mChosenAttributes = attributes;
- }
-
- void setRemoveExtracted(boolean removeExtracted) {
- mRemoveExtracted = removeExtracted;
- }
-
- void setApplyStyle(boolean applyStyle) {
- mApplyStyle = applyStyle;
- }
-
- void setRemoveAll(boolean removeAll) {
- mRemoveAll = removeAll;
- }
-
- void setParent(String parent) {
- mParent = parent;
- }
-
- // ---- Actual implementation of Extract Style modification computation ----
-
- /**
- * Returns two items: a map from attribute name to a list of attribute nodes of that
- * name, and a subset of these attributes that fall within the text selection
- * (used to drive initial selection in the wizard)
- */
- Pair<Map<String, List<Attr>>, Set<Attr>> getAvailableAttributes() {
- mAvailableAttributes = new TreeMap<String, List<Attr>>();
- Set<Attr> withinSelection = new HashSet<Attr>();
- for (Element element : getElements()) {
- IndexedRegion elementRegion = getRegion(element);
- boolean allIncluded =
- (mOriginalSelectionStart <= elementRegion.getStartOffset() &&
- mOriginalSelectionEnd >= elementRegion.getEndOffset());
-
- NamedNodeMap attributeMap = element.getAttributes();
- for (int i = 0, n = attributeMap.getLength(); i < n; i++) {
- Attr attribute = (Attr) attributeMap.item(i);
-
- String name = attribute.getLocalName();
- if (!isStylableAttribute(name)) {
- // Don't offer to extract attributes that don't make sense in
- // styles (like "id" or "style"), or attributes that the user
- // probably does not want to define in styles (like layout
- // attributes such as layout_width, or the label of a button etc).
- // This makes the options offered listed in the wizard simpler.
- // In special cases where the user *does* want to set one of these
- // attributes, they can always do it manually so optimize for
- // the common case here.
- continue;
- }
-
- // Skip attributes that are in a namespace other than the Android one
- String namespace = attribute.getNamespaceURI();
- if (namespace != null && !ANDROID_URI.equals(namespace)) {
- continue;
- }
-
- if (!allIncluded) {
- IndexedRegion region = getRegion(attribute);
- boolean attributeIncluded = mOriginalSelectionStart < region.getEndOffset() &&
- mOriginalSelectionEnd >= region.getStartOffset();
- if (attributeIncluded) {
- withinSelection.add(attribute);
- }
- } else {
- withinSelection.add(attribute);
- }
-
- List<Attr> list = mAvailableAttributes.get(name);
- if (list == null) {
- list = new ArrayList<Attr>();
- mAvailableAttributes.put(name, list);
- }
- list.add(attribute);
- }
- }
-
- return Pair.of(mAvailableAttributes, withinSelection);
- }
-
- /**
- * Returns whether the given local attribute name is one the style wizard
- * should present as a selectable attribute to be extracted.
- *
- * @param name the attribute name, not including a namespace prefix
- * @return true if the name is one that the user can extract
- */
- public static boolean isStylableAttribute(String name) {
- return !(name == null
- || name.equals(ATTR_ID)
- || name.startsWith(ATTR_STYLE)
- || (name.startsWith(ATTR_LAYOUT_RESOURCE_PREFIX) &&
- !name.startsWith(ATTR_LAYOUT_MARGIN))
- || name.equals(ATTR_TEXT)
- || name.equals(ATTR_HINT)
- || name.equals(ATTR_SRC)
- || name.equals(ATTR_ON_CLICK));
- }
-
- IFile getStyleFile(IProject project) {
- return project.getFile(new Path(FD_RESOURCES + WS_SEP + FD_RES_VALUES + WS_SEP
- + mStyleFileName));
- }
-
- @Override
- protected @NonNull List<Change> computeChanges(IProgressMonitor monitor) {
- List<Change> changes = new ArrayList<Change>();
- if (mChosenAttributes.size() == 0) {
- return changes;
- }
-
- IFile file = getStyleFile(mDelegate.getEditor().getProject());
- boolean createFile = !file.exists();
- int insertAtIndex;
- String initialIndent = null;
- if (!createFile) {
- Pair<Integer, String> context = computeInsertContext(file);
- insertAtIndex = context.getFirst();
- initialIndent = context.getSecond();
- } else {
- insertAtIndex = 0;
- }
-
- TextFileChange addFile = new TextFileChange("Create new separate style declaration", file);
- addFile.setTextType(EXT_XML);
- changes.add(addFile);
- String styleString = computeStyleDeclaration(createFile, initialIndent);
- addFile.setEdit(new InsertEdit(insertAtIndex, styleString));
-
- // Remove extracted attributes?
- MultiTextEdit rootEdit = new MultiTextEdit();
- if (mRemoveExtracted || mRemoveAll) {
- for (Attr attribute : mChosenAttributes) {
- List<Attr> list = mAvailableAttributes.get(attribute.getLocalName());
- for (Attr attr : list) {
- if (mRemoveAll || attr.getValue().equals(attribute.getValue())) {
- removeAttribute(rootEdit, attr);
- }
- }
- }
- }
-
- // Set the style attribute?
- if (mApplyStyle) {
- for (Element element : getElements()) {
- String value = PREFIX_RESOURCE_REF + REFERENCE_STYLE + mStyleName;
- setAttribute(rootEdit, element, null, null, ATTR_STYLE, value);
- }
- }
-
- if (rootEdit.hasChildren()) {
- IFile sourceFile = mDelegate.getEditor().getInputFile();
- if (sourceFile == null) {
- return changes;
- }
- TextFileChange change = new TextFileChange(sourceFile.getName(), sourceFile);
- change.setTextType(EXT_XML);
- changes.add(change);
-
- if (AdtPrefs.getPrefs().getFormatGuiXml()) {
- MultiTextEdit formatted = reformat(rootEdit, XmlFormatStyle.LAYOUT);
- if (formatted != null) {
- rootEdit = formatted;
- }
- }
-
- change.setEdit(rootEdit);
- }
-
- return changes;
- }
-
- private String computeStyleDeclaration(boolean createFile, String initialIndent) {
- StringBuilder sb = new StringBuilder();
- if (createFile) {
- sb.append(NewXmlFileWizard.XML_HEADER_LINE);
- sb.append('<').append(TAG_RESOURCES).append(' ');
- sb.append(XMLNS_PREFIX).append(ANDROID_NS_NAME).append('=').append('"');
- sb.append(ANDROID_URI);
- sb.append('"').append('>').append('\n');
- }
-
- // Indent. Use the existing indent found for previous <style> elements in
- // the resource file - but if that indent was 0 (e.g. <style> elements are
- // at the left margin) only use it to indent the style elements and use a real
- // nonzero indent for its children.
- String indent = " "; //$NON-NLS-1$
- if (initialIndent == null) {
- initialIndent = indent;
- } else if (initialIndent.length() > 0) {
- indent = initialIndent;
- }
- sb.append(initialIndent);
- String styleTag = "style"; //$NON-NLS-1$ // TODO - use constant in parallel changeset
- sb.append('<').append(styleTag).append(' ').append(ATTR_NAME).append('=').append('"');
- sb.append(mStyleName);
- sb.append('"');
- if (mParent != null) {
- sb.append(' ').append(ATTR_PARENT).append('=').append('"');
- sb.append(mParent);
- sb.append('"');
- }
- sb.append('>').append('\n');
-
- for (Attr attribute : mChosenAttributes) {
- sb.append(initialIndent).append(indent);
- sb.append('<').append(TAG_ITEM).append(' ').append(ATTR_NAME).append('=').append('"');
- // We've already enforced that regardless of prefix, only attributes with
- // an Android namespace can be in the set of chosen attributes. Rewrite the
- // prefix to android here.
- if (attribute.getPrefix() != null) {
- sb.append(ANDROID_NS_NAME_PREFIX);
- }
- sb.append(attribute.getLocalName());
- sb.append('"').append('>');
- sb.append(attribute.getValue());
- sb.append('<').append('/').append(TAG_ITEM).append('>').append('\n');
- }
- sb.append(initialIndent).append('<').append('/').append(styleTag).append('>').append('\n');
-
- if (createFile) {
- sb.append('<').append('/').append(TAG_RESOURCES).append('>').append('\n');
- }
- String styleString = sb.toString();
- return styleString;
- }
-
- /** Computes the location in the file to insert the new style element at, as well as
- * the exact indent string to use to indent the {@code <style>} element.
- * @param file the styles.xml file to insert into
- * @return a pair of an insert offset and an indent string
- */
- private Pair<Integer, String> computeInsertContext(final IFile file) {
- int insertAtIndex = -1;
- // Find the insert of the final </resources> item where we will insert
- // the new style elements.
- String indent = null;
- IModelManager modelManager = StructuredModelManager.getModelManager();
- IStructuredModel model = null;
- try {
- model = modelManager.getModelForRead(file);
- if (model instanceof IDOMModel) {
- IDOMModel domModel = (IDOMModel) model;
- IDOMDocument otherDocument = domModel.getDocument();
- Element root = otherDocument.getDocumentElement();
- Node lastChild = root.getLastChild();
- if (lastChild != null) {
- if (lastChild instanceof IndexedRegion) {
- IndexedRegion region = (IndexedRegion) lastChild;
- insertAtIndex = region.getStartOffset() + region.getLength();
- }
-
- // Compute indent
- while (lastChild != null) {
- if (lastChild.getNodeType() == Node.ELEMENT_NODE) {
- IStructuredDocument document = model.getStructuredDocument();
- indent = AndroidXmlEditor.getIndent(document, lastChild);
- break;
- }
- lastChild = lastChild.getPreviousSibling();
- }
- }
- }
- } catch (IOException e) {
- AdtPlugin.log(e, null);
- } catch (CoreException e) {
- AdtPlugin.log(e, null);
- } finally {
- if (model != null) {
- model.releaseFromRead();
- }
- }
-
- if (insertAtIndex == -1) {
- String contents = AdtPlugin.readFile(file);
- insertAtIndex = contents.indexOf("</" + TAG_RESOURCES + ">"); //$NON-NLS-1$
- if (insertAtIndex == -1) {
- insertAtIndex = contents.length();
- }
- }
-
- return Pair.of(insertAtIndex, indent);
- }
-
- @Override
- VisualRefactoringWizard createWizard() {
- return new ExtractStyleWizard(this, mDelegate);
- }
-
- public static class Descriptor extends VisualRefactoringDescriptor {
- public Descriptor(String project, String description, String comment,
- Map<String, String> arguments) {
- super("com.android.ide.eclipse.adt.refactoring.extract.style", //$NON-NLS-1$
- project, description, comment, arguments);
- }
-
- @Override
- protected Refactoring createRefactoring(Map<String, String> args) {
- return new ExtractStyleRefactoring(args);
- }
- }
-
- /**
- * Determines the parent style to be used for this refactoring
- *
- * @return the parent style to be used for this refactoring
- */
- public String getParentStyle() {
- Set<String> styles = new HashSet<String>();
- for (Element element : getElements()) {
- // Includes "" for elements not setting the style
- styles.add(element.getAttribute(ATTR_STYLE));
- }
-
- if (styles.size() > 1) {
- // The elements differ in what style attributes they are set to
- return null;
- }
-
- String style = styles.iterator().next();
- if (style != null && style.length() > 0) {
- return style;
- }
-
- // None of the elements set the style -- see if they have the same widget types
- // and if so offer to extend the theme style for that widget type
-
- Set<String> types = new HashSet<String>();
- for (Element element : getElements()) {
- types.add(element.getTagName());
- }
-
- if (types.size() == 1) {
- String view = DescriptorsUtils.getBasename(types.iterator().next());
-
- ResourceResolver resolver = mDelegate.getGraphicalEditor().getResourceResolver();
- // Look up the theme item name, which for a Button would be "buttonStyle", and so on.
- String n = Character.toLowerCase(view.charAt(0)) + view.substring(1)
- + "Style"; //$NON-NLS-1$
- ResourceValue value = resolver.findItemInTheme(n);
- if (value != null) {
- ResourceValue resolvedValue = resolver.resolveResValue(value);
- String name = resolvedValue.getName();
- if (name != null) {
- if (resolvedValue.isFramework()) {
- return PREFIX_ANDROID + name;
- } else {
- return name;
- }
- }
- }
- }
-
- return null;
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractStyleWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractStyleWizard.java
deleted file mode 100644
index 187452d21..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractStyleWizard.java
+++ /dev/null
@@ -1,440 +0,0 @@
-/*
- * 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 static org.eclipse.jface.viewers.StyledString.DECORATIONS_STYLER;
-import static org.eclipse.jface.viewers.StyledString.QUALIFIER_STYLER;
-
-import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditorDelegate;
-import com.android.ide.eclipse.adt.internal.resources.ResourceNameValidator;
-import com.android.resources.ResourceType;
-import com.android.utils.Pair;
-
-import org.eclipse.core.resources.IProject;
-import org.eclipse.jface.viewers.CheckStateChangedEvent;
-import org.eclipse.jface.viewers.CheckboxTableViewer;
-import org.eclipse.jface.viewers.ICheckStateListener;
-import org.eclipse.jface.viewers.IStructuredContentProvider;
-import org.eclipse.jface.viewers.StyledCellLabelProvider;
-import org.eclipse.jface.viewers.StyledString;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.jface.viewers.ViewerCell;
-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.layout.RowLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Table;
-import org.eclipse.swt.widgets.Text;
-import org.w3c.dom.Attr;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-class ExtractStyleWizard extends VisualRefactoringWizard {
- public ExtractStyleWizard(ExtractStyleRefactoring ref, LayoutEditorDelegate editor) {
- super(ref, editor);
- setDefaultPageTitle(ref.getName());
- }
-
- @Override
- protected void addUserInputPages() {
- String initialName = "styleName";
- addPage(new InputPage(mDelegate.getEditor().getProject(), initialName));
- }
-
- /**
- * Wizard page which inputs parameters for the {@link ExtractStyleRefactoring}
- * operation
- */
- private static class InputPage extends VisualRefactoringInputPage {
- private final IProject mProject;
- private final String mSuggestedName;
- private Text mNameText;
- private Table mTable;
- private Button mRemoveExtracted;
- private Button mSetStyle;
- private Button mRemoveAll;
- private Button mExtend;
- private CheckboxTableViewer mCheckedView;
-
- private String mParentStyle;
- private Set<Attr> mInSelection;
- private List<Attr> mAllAttributes;
- private int mElementCount;
- private Map<Attr, Integer> mFrequencyCount;
- private Set<Attr> mShown;
- private List<Attr> mInitialChecked;
- private List<Attr> mAllChecked;
- private List<Map.Entry<String, List<Attr>>> mRoot;
- private Map<String, List<Attr>> mAvailableAttributes;
-
- public InputPage(IProject project, String suggestedName) {
- super("ExtractStyleInputPage");
- mProject = project;
- mSuggestedName = suggestedName;
- }
-
- @Override
- public void createControl(Composite parent) {
- initialize();
-
- Composite composite = new Composite(parent, SWT.NONE);
- composite.setLayout(new GridLayout(2, false));
-
- Label nameLabel = new Label(composite, SWT.NONE);
- nameLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
- nameLabel.setText("Style Name:");
-
- mNameText = new Text(composite, SWT.BORDER);
- mNameText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
- mNameText.addModifyListener(mModifyValidateListener);
-
- mRemoveExtracted = new Button(composite, SWT.CHECK);
- mRemoveExtracted.setSelection(true);
- mRemoveExtracted.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false, 2, 1));
- mRemoveExtracted.setText("Remove extracted attributes");
- mRemoveExtracted.addSelectionListener(mSelectionValidateListener);
-
- mRemoveAll = new Button(composite, SWT.CHECK);
- mRemoveAll.setSelection(false);
- mRemoveAll.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false, 2, 1));
- mRemoveAll.setText("Remove all extracted attributes regardless of value");
- mRemoveAll.addSelectionListener(mSelectionValidateListener);
-
- boolean defaultSetStyle = false;
- if (mParentStyle != null) {
- mExtend = new Button(composite, SWT.CHECK);
- mExtend.setSelection(true);
- mExtend.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false, 2, 1));
- mExtend.setText(String.format("Extend %1$s", mParentStyle));
- mExtend.addSelectionListener(mSelectionValidateListener);
- defaultSetStyle = true;
- }
-
- mSetStyle = new Button(composite, SWT.CHECK);
- mSetStyle.setSelection(defaultSetStyle);
- mSetStyle.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, false, false, 2, 1));
- mSetStyle.setText("Set style attribute on extracted elements");
- mSetStyle.addSelectionListener(mSelectionValidateListener);
-
- new Label(composite, SWT.NONE);
- new Label(composite, SWT.NONE);
-
- Label tableLabel = new Label(composite, SWT.NONE);
- tableLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1));
- tableLabel.setText("Choose style attributes to extract:");
-
- mCheckedView = CheckboxTableViewer.newCheckList(composite, SWT.BORDER
- | SWT.FULL_SELECTION | SWT.HIDE_SELECTION);
- mTable = mCheckedView.getTable();
- mTable.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 2));
- ((GridData) mTable.getLayoutData()).heightHint = 200;
-
- mCheckedView.setContentProvider(new ArgumentContentProvider());
- mCheckedView.setLabelProvider(new ArgumentLabelProvider());
- mCheckedView.setInput(mRoot);
- final Object[] initialSelection = mInitialChecked.toArray();
- mCheckedView.setCheckedElements(initialSelection);
-
- mCheckedView.addCheckStateListener(new ICheckStateListener() {
- @Override
- public void checkStateChanged(CheckStateChangedEvent event) {
- // Try to disable other elements that conflict with this
- boolean isChecked = event.getChecked();
- if (isChecked) {
- Attr attribute = (Attr) event.getElement();
- List<Attr> list = mAvailableAttributes.get(attribute.getLocalName());
- for (Attr other : list) {
- if (other != attribute && mShown.contains(other)) {
- mCheckedView.setChecked(other, false);
- }
- }
- }
-
- validatePage();
- }
- });
-
- // Select All / Deselect All
- Composite buttonForm = new Composite(composite, SWT.NONE);
- buttonForm.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1));
- RowLayout rowLayout = new RowLayout(SWT.HORIZONTAL);
- rowLayout.marginTop = 0;
- rowLayout.marginLeft = 0;
- buttonForm.setLayout(rowLayout);
- Button checkAllButton = new Button(buttonForm, SWT.FLAT);
- checkAllButton.setText("Select All");
- checkAllButton.addSelectionListener(new SelectionAdapter() {
- @Override
- public void widgetSelected(SelectionEvent e) {
- // Select "all" (but not conflicting settings)
- mCheckedView.setCheckedElements(mAllChecked.toArray());
- validatePage();
- }
- });
- Button uncheckAllButton = new Button(buttonForm, SWT.FLAT);
- uncheckAllButton.setText("Deselect All");
- uncheckAllButton.addSelectionListener(new SelectionAdapter() {
- @Override
- public void widgetSelected(SelectionEvent e) {
- mCheckedView.setAllChecked(false);
- validatePage();
- }
- });
-
- // Initialize UI:
- if (mSuggestedName != null) {
- mNameText.setText(mSuggestedName);
- }
-
- setControl(composite);
- validatePage();
- }
-
- private void initialize() {
- ExtractStyleRefactoring ref = (ExtractStyleRefactoring) getRefactoring();
-
- mElementCount = ref.getElements().size();
-
- mParentStyle = ref.getParentStyle();
-
- // Set up data structures needed by the wizard -- to compute the actual
- // attributes to list in the wizard (there could be multiple attributes
- // of the same name (on different elements) and we only want to show one, etc.)
-
- Pair<Map<String, List<Attr>>, Set<Attr>> result = ref.getAvailableAttributes();
- // List of all available attributes on the selected elements
- mAvailableAttributes = result.getFirst();
- // Set of attributes that overlap the text selection, or all attributes if
- // wizard is invoked from GUI context
- mInSelection = result.getSecond();
-
- // The root data structure, which we set as the table root. The content provider
- // will produce children from it. This is the entry set of a map from
- // attribute name to list of attribute nodes for that attribute name.
- mRoot = new ArrayList<Map.Entry<String, List<Attr>>>(
- mAvailableAttributes.entrySet());
-
- // Sort the items by attribute name -- the attribute name is the key
- // in the entry set above.
- Collections.sort(mRoot, new Comparator<Map.Entry<String, List<Attr>>>() {
- @Override
- public int compare(Map.Entry<String, List<Attr>> e1,
- Map.Entry<String, List<Attr>> e2) {
- return e1.getKey().compareTo(e2.getKey());
- }
- });
-
- // Set of attributes actually included in the list shown to the user.
- // (There could be many additional "aliasing" nodes on other elements
- // with the same name.) Note however that we DO show multiple attribute
- // occurrences of the same attribute name: precisely one for each unique -value-
- // of that attribute.
- mShown = new HashSet<Attr>();
-
- // The list of initially checked attributes.
- mInitialChecked = new ArrayList<Attr>();
-
- // The list of attributes to be checked if "Select All" is chosen (this is not
- // the same as *all* attributes, since we need to exclude any conflicts)
- mAllChecked = new ArrayList<Attr>();
-
- // All attributes.
- mAllAttributes = new ArrayList<Attr>();
-
- // Frequency count, from attribute to integer. Attributes that do not
- // appear in the list have frequency 1, not 0.
- mFrequencyCount = new HashMap<Attr, Integer>();
-
- for (Map.Entry<String, List<Attr>> entry : mRoot) {
- // Iterate over all attributes of the same name, and sort them
- // by value. This will make it easy to list each -unique- value in the
- // wizard.
- List<Attr> attrList = entry.getValue();
- Collections.sort(attrList, new Comparator<Attr>() {
- @Override
- public int compare(Attr a1, Attr a2) {
- return a1.getValue().compareTo(a2.getValue());
- }
- });
-
- // We need to compute a couple of things: the frequency for all identical
- // values (and stash them in the frequency map), and record the first
- // attribute with a particular value into the list of attributes to
- // be shown.
- Attr prevAttr = null;
- String prev = null;
- List<Attr> uniqueValueAttrs = new ArrayList<Attr>();
- for (Attr attr : attrList) {
- String value = attr.getValue();
- if (value.equals(prev)) {
- Integer count = mFrequencyCount.get(prevAttr);
- if (count == null) {
- count = Integer.valueOf(2);
- } else {
- count = Integer.valueOf(count.intValue() + 1);
- }
- mFrequencyCount.put(prevAttr, count);
- } else {
- uniqueValueAttrs.add(attr);
- prev = value;
- prevAttr = attr;
- }
- }
-
- // Sort the values by frequency (and for equal frequencies, alphabetically
- // by value)
- Collections.sort(uniqueValueAttrs, new Comparator<Attr>() {
- @Override
- public int compare(Attr a1, Attr a2) {
- Integer f1 = mFrequencyCount.get(a1);
- Integer f2 = mFrequencyCount.get(a2);
- if (f1 == null) {
- f1 = Integer.valueOf(1);
- }
- if (f2 == null) {
- f2 = Integer.valueOf(1);
- }
- int delta = f2.intValue() - f1.intValue();
- if (delta != 0) {
- return delta;
- } else {
- return a1.getValue().compareTo(a2.getValue());
- }
- }
- });
-
- // Add the items in order, and select those attributes that overlap
- // the selection
- mAllAttributes.addAll(uniqueValueAttrs);
- mShown.addAll(uniqueValueAttrs);
- Attr first = uniqueValueAttrs.get(0);
- mAllChecked.add(first);
- if (mInSelection.contains(first)) {
- mInitialChecked.add(first);
- }
- }
- }
-
- @Override
- protected boolean validatePage() {
- boolean ok = true;
-
- String text = mNameText.getText().trim();
-
- if (text.length() == 0) {
- setErrorMessage("Provide a name for the new style");
- ok = false;
- } else {
- ResourceNameValidator validator = ResourceNameValidator.create(false, mProject,
- ResourceType.STYLE);
- String message = validator.isValid(text);
- if (message != null) {
- setErrorMessage(message);
- ok = false;
- }
- }
-
- Object[] checkedElements = mCheckedView.getCheckedElements();
- if (checkedElements.length == 0) {
- setErrorMessage("Choose at least one attribute to extract");
- ok = false;
- }
-
- if (ok) {
- setErrorMessage(null);
-
- // Record state
- ExtractStyleRefactoring refactoring = (ExtractStyleRefactoring) getRefactoring();
- refactoring.setStyleName(text);
- refactoring.setRemoveExtracted(mRemoveExtracted.getSelection());
- refactoring.setRemoveAll(mRemoveAll.getSelection());
- refactoring.setApplyStyle(mSetStyle.getSelection());
- if (mExtend != null && mExtend.getSelection()) {
- refactoring.setParent(mParentStyle);
- }
- List<Attr> attributes = new ArrayList<Attr>();
- for (Object o : checkedElements) {
- attributes.add((Attr) o);
- }
- refactoring.setChosenAttributes(attributes);
- }
-
- setPageComplete(ok);
- return ok;
- }
-
- private class ArgumentLabelProvider extends StyledCellLabelProvider {
- public ArgumentLabelProvider() {
- }
-
- @Override
- public void update(ViewerCell cell) {
- Object element = cell.getElement();
- Attr attribute = (Attr) element;
-
- StyledString styledString = new StyledString();
- styledString.append(attribute.getLocalName());
- styledString.append(" = ", QUALIFIER_STYLER);
- styledString.append(attribute.getValue());
-
- if (mElementCount > 1) {
- Integer f = mFrequencyCount.get(attribute);
- String s = String.format(" (in %d/%d elements)",
- f != null ? f.intValue(): 1, mElementCount);
- styledString.append(s, DECORATIONS_STYLER);
- }
- cell.setText(styledString.toString());
- cell.setStyleRanges(styledString.getStyleRanges());
- super.update(cell);
- }
- }
-
- private class ArgumentContentProvider implements IStructuredContentProvider {
- public ArgumentContentProvider() {
- }
-
- @Override
- public Object[] getElements(Object inputElement) {
- if (inputElement == mRoot) {
- return mAllAttributes.toArray();
- }
-
- return new Object[0];
- }
-
- @Override
- public void dispose() {
- }
-
- @Override
- public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
- }
- }
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/GridLayoutConverter.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/GridLayoutConverter.java
deleted file mode 100644
index fe673a5b7..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/GridLayoutConverter.java
+++ /dev/null
@@ -1,988 +0,0 @@
-/*
- * 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 static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.ATTR_BACKGROUND;
-import static com.android.SdkConstants.ATTR_COLUMN_COUNT;
-import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_BASELINE;
-import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_BOTTOM;
-import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_LEFT;
-import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_RIGHT;
-import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_TOP;
-import static com.android.SdkConstants.ATTR_LAYOUT_COLUMN;
-import static com.android.SdkConstants.ATTR_LAYOUT_COLUMN_SPAN;
-import static com.android.SdkConstants.ATTR_LAYOUT_GRAVITY;
-import static com.android.SdkConstants.ATTR_LAYOUT_HEIGHT;
-import static com.android.SdkConstants.ATTR_LAYOUT_RESOURCE_PREFIX;
-import static com.android.SdkConstants.ATTR_LAYOUT_ROW;
-import static com.android.SdkConstants.ATTR_LAYOUT_ROW_SPAN;
-import static com.android.SdkConstants.ATTR_LAYOUT_WIDTH;
-import static com.android.SdkConstants.ATTR_ORIENTATION;
-import static com.android.SdkConstants.FQCN_GRID_LAYOUT;
-import static com.android.SdkConstants.FQCN_SPACE;
-import static com.android.SdkConstants.GRAVITY_VALUE_FILL;
-import static com.android.SdkConstants.GRAVITY_VALUE_FILL_HORIZONTAL;
-import static com.android.SdkConstants.GRAVITY_VALUE_FILL_VERTICAL;
-import static com.android.SdkConstants.ID_PREFIX;
-import static com.android.SdkConstants.LINEAR_LAYOUT;
-import static com.android.SdkConstants.NEW_ID_PREFIX;
-import static com.android.SdkConstants.RADIO_GROUP;
-import static com.android.SdkConstants.RELATIVE_LAYOUT;
-import static com.android.SdkConstants.SPACE;
-import static com.android.SdkConstants.TABLE_LAYOUT;
-import static com.android.SdkConstants.TABLE_ROW;
-import static com.android.SdkConstants.VALUE_FILL_PARENT;
-import static com.android.SdkConstants.VALUE_HORIZONTAL;
-import static com.android.SdkConstants.VALUE_MATCH_PARENT;
-import static com.android.SdkConstants.VALUE_VERTICAL;
-import static com.android.SdkConstants.VALUE_WRAP_CONTENT;
-import static com.android.ide.common.layout.GravityHelper.GRAVITY_HORIZ_MASK;
-import static com.android.ide.common.layout.GravityHelper.GRAVITY_VERT_MASK;
-
-import com.android.ide.common.api.IViewMetadata.FillPreference;
-import com.android.ide.common.layout.BaseLayoutRule;
-import com.android.ide.common.layout.GravityHelper;
-import com.android.ide.common.layout.GridLayoutRule;
-import com.android.ide.eclipse.adt.AdtPlugin;
-import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor;
-import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor;
-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;
-import com.android.ide.eclipse.adt.internal.editors.layout.gre.ViewMetadataRepository;
-import com.android.ide.eclipse.adt.internal.project.SupportLibraryHelper;
-
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.runtime.IStatus;
-import org.eclipse.swt.graphics.Rectangle;
-import org.eclipse.text.edits.InsertEdit;
-import org.eclipse.text.edits.MalformedTreeException;
-import org.eclipse.text.edits.MultiTextEdit;
-import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion;
-import org.w3c.dom.Attr;
-import org.w3c.dom.Element;
-import org.w3c.dom.NamedNodeMap;
-import org.w3c.dom.Node;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Helper class which performs the bulk of the layout conversion to grid layout
- * <p>
- * Future enhancements:
- * <ul>
- * <li>Render the layout at multiple screen sizes and analyze how the widget bounds
- * change and use this to infer gravity
- * <li> Use the layout_width and layout_height attributes on views to infer column and
- * row flexibility (and as mentioned above, possibly layout_weight).
- * move and stretch and use that to add in additional constraints
- * <li> Take into account existing margins and add/subtract those from the
- * bounds computations and either clear or update them.
- * <li>Try to reorder elements into their natural order
- * <li> Try to preserve spacing? Right now everything gets converted into a compact
- * grid with no spacing between the views; consider inserting {@code <Space>} views
- * with dimensions based on existing distances.
- * </ul>
- */
-@SuppressWarnings("restriction") // DOM model access
-class GridLayoutConverter {
- private final MultiTextEdit mRootEdit;
- private final boolean mFlatten;
- private final Element mLayout;
- private final ChangeLayoutRefactoring mRefactoring;
- private final CanvasViewInfo mRootView;
-
- private List<View> mViews;
- private String mNamespace;
- private int mColumnCount;
-
- /** Creates a new {@link GridLayoutConverter} */
- GridLayoutConverter(ChangeLayoutRefactoring refactoring,
- Element layout, boolean flatten, MultiTextEdit rootEdit, CanvasViewInfo rootView) {
- mRefactoring = refactoring;
- mLayout = layout;
- mFlatten = flatten;
- mRootEdit = rootEdit;
- mRootView = rootView;
- }
-
- /** Performs conversion from any layout to a RelativeLayout */
- public void convertToGridLayout() {
- if (mRootView == null) {
- return;
- }
-
- // Locate the view for the layout
- CanvasViewInfo layoutView = findViewForElement(mRootView, mLayout);
- if (layoutView == null || layoutView.getChildren().size() == 0) {
- // No children. THAT was an easy conversion!
- return;
- }
-
- // Study the layout and get information about how to place individual elements
- GridModel gridModel = new GridModel(layoutView, mLayout, mFlatten);
- mViews = gridModel.getViews();
- mColumnCount = gridModel.computeColumnCount();
-
- deleteRemovedElements(gridModel.getDeletedElements());
- mNamespace = mRefactoring.getAndroidNamespacePrefix();
-
- processGravities();
-
- // Insert space views if necessary
- insertStretchableSpans();
-
- // Create/update relative layout constraints
- assignGridAttributes();
-
- removeUndefinedAttrs();
-
- if (mColumnCount > 0) {
- mRefactoring.setAttribute(mRootEdit, mLayout, ANDROID_URI,
- mNamespace, ATTR_COLUMN_COUNT, Integer.toString(mColumnCount));
- }
- }
-
- private void insertStretchableSpans() {
- // Look at the rows and columns and determine if we need to have a stretchable
- // row and/or a stretchable column in the layout.
- // In a GridLayout, a row or column is stretchable if it defines a gravity (regardless
- // of what the gravity is -- in other words, a column is not just stretchable if it
- // has gravity=fill but also if it has gravity=left). Furthermore, ALL the elements
- // in the row/column have to be stretchable for the overall row/column to be
- // considered stretchable.
-
- // Map from row index to boolean for "is the row fixed/inflexible?"
- Map<Integer, Boolean> rowFixed = new HashMap<Integer, Boolean>();
- Map<Integer, Boolean> columnFixed = new HashMap<Integer, Boolean>();
- for (View view : mViews) {
- if (view.mElement == mLayout) {
- continue;
- }
-
- int gravity = GravityHelper.getGravity(view.mGravity, 0);
- if ((gravity & GRAVITY_HORIZ_MASK) == 0) {
- columnFixed.put(view.mCol, true);
- } else if (!columnFixed.containsKey(view.mCol)) {
- columnFixed.put(view.mCol, false);
- }
- if ((gravity & GRAVITY_VERT_MASK) == 0) {
- rowFixed.put(view.mRow, true);
- } else if (!rowFixed.containsKey(view.mRow)) {
- rowFixed.put(view.mRow, false);
- }
- }
-
- boolean hasStretchableRow = false;
- boolean hasStretchableColumn = false;
- for (boolean fixed : rowFixed.values()) {
- if (!fixed) {
- hasStretchableRow = true;
- }
- }
- for (boolean fixed : columnFixed.values()) {
- if (!fixed) {
- hasStretchableColumn = true;
- }
- }
-
- if (!hasStretchableRow || !hasStretchableColumn) {
- // Insert <Space> to hold stretchable space
- // TODO: May also have to increment column count!
- int offset = 0; // WHERE?
-
- String gridLayout = mLayout.getTagName();
- if (mLayout instanceof IndexedRegion) {
- IndexedRegion region = (IndexedRegion) mLayout;
- int end = region.getEndOffset();
- // TODO: Look backwards for the "</"
- // (and can it ever be <foo/>) ?
- end -= (gridLayout.length() + 3); // 3: <, /, >
- offset = end;
- }
-
- int row = rowFixed.size();
- int column = columnFixed.size();
- StringBuilder sb = new StringBuilder(64);
- String spaceTag = SPACE;
- IFile file = mRefactoring.getFile();
- if (file != null) {
- spaceTag = SupportLibraryHelper.getTagFor(file.getProject(), FQCN_SPACE);
- if (spaceTag.equals(FQCN_SPACE)) {
- spaceTag = SPACE;
- }
- }
-
- sb.append('<').append(spaceTag).append(' ');
- String gravity;
- if (!hasStretchableRow && !hasStretchableColumn) {
- gravity = GRAVITY_VALUE_FILL;
- } else if (!hasStretchableRow) {
- gravity = GRAVITY_VALUE_FILL_VERTICAL;
- } else {
- assert !hasStretchableColumn;
- gravity = GRAVITY_VALUE_FILL_HORIZONTAL;
- }
-
- sb.append(mNamespace).append(':');
- sb.append(ATTR_LAYOUT_GRAVITY).append('=').append('"').append(gravity);
- sb.append('"').append(' ');
-
- sb.append(mNamespace).append(':');
- sb.append(ATTR_LAYOUT_ROW).append('=').append('"').append(Integer.toString(row));
- sb.append('"').append(' ');
-
- sb.append(mNamespace).append(':');
- sb.append(ATTR_LAYOUT_COLUMN).append('=').append('"').append(Integer.toString(column));
- sb.append('"').append('/').append('>');
-
- String space = sb.toString();
- InsertEdit replace = new InsertEdit(offset, space);
- mRootEdit.addChild(replace);
-
- mColumnCount++;
- }
- }
-
- private void removeUndefinedAttrs() {
- ViewElementDescriptor descriptor = mRefactoring.getElementDescriptor(FQCN_GRID_LAYOUT);
- if (descriptor == null) {
- return;
- }
-
- Set<String> defined = new HashSet<String>();
- AttributeDescriptor[] layoutAttributes = descriptor.getLayoutAttributes();
- for (AttributeDescriptor attribute : layoutAttributes) {
- defined.add(attribute.getXmlLocalName());
- }
-
- for (View view : mViews) {
- Element child = view.mElement;
-
- List<Attr> attributes = mRefactoring.findLayoutAttributes(child);
- for (Attr attribute : attributes) {
- String name = attribute.getLocalName();
- if (!defined.contains(name)) {
- // Remove it
- try {
- mRefactoring.removeAttribute(mRootEdit, child, attribute.getNamespaceURI(),
- name);
- } catch (MalformedTreeException mte) {
- // Sometimes refactoring has modified attribute; not
- // removing
- // it is non-fatal so just warn instead of letting
- // refactoring
- // operation abort
- AdtPlugin.log(IStatus.WARNING,
- "Could not remove unsupported attribute %1$s; " + //$NON-NLS-1$
- "already modified during refactoring?", //$NON-NLS-1$
- attribute.getLocalName());
- }
- }
- }
- }
- }
-
- /** Removes any elements targeted for deletion */
- private void deleteRemovedElements(List<Element> delete) {
- if (mFlatten && delete.size() > 0) {
- for (Element element : delete) {
- mRefactoring.removeElementTags(mRootEdit, element, delete,
- false /*changeIndentation*/);
- }
- }
- }
-
- /**
- * Creates refactoring edits which adds or updates the grid attributes
- */
- private void assignGridAttributes() {
- // We always convert to horizontal grid layouts for now
- mRefactoring.setAttribute(mRootEdit, mLayout, ANDROID_URI,
- mNamespace, ATTR_ORIENTATION, VALUE_HORIZONTAL);
-
- assignCellAttributes();
- }
-
- /**
- * Assign cell attributes to the table, skipping those that will be implied
- * by the grid model
- */
- private void assignCellAttributes() {
- int implicitRow = 0;
- int implicitColumn = 0;
- int nextRow = 0;
- for (View view : mViews) {
- Element element = view.getElement();
- if (element == mLayout) {
- continue;
- }
-
- int row = view.getRow();
- int column = view.getColumn();
-
- if (column != implicitColumn && (implicitColumn > 0 || implicitRow > 0)) {
- mRefactoring.setAttribute(mRootEdit, element, ANDROID_URI,
- mNamespace, ATTR_LAYOUT_COLUMN, Integer.toString(column));
- if (column < implicitColumn) {
- implicitRow++;
- }
- implicitColumn = column;
- }
- if (row != implicitRow) {
- mRefactoring.setAttribute(mRootEdit, element, ANDROID_URI,
- mNamespace, ATTR_LAYOUT_ROW, Integer.toString(row));
- implicitRow = row;
- }
-
- int rowSpan = view.getRowSpan();
- int columnSpan = view.getColumnSpan();
- assert columnSpan >= 1;
-
- if (rowSpan > 1) {
- mRefactoring.setAttribute(mRootEdit, element, ANDROID_URI,
- mNamespace, ATTR_LAYOUT_ROW_SPAN, Integer.toString(rowSpan));
- }
- if (columnSpan > 1) {
- mRefactoring.setAttribute(mRootEdit, element, ANDROID_URI,
- mNamespace, ATTR_LAYOUT_COLUMN_SPAN,
- Integer.toString(columnSpan));
- }
- nextRow = Math.max(nextRow, row + rowSpan);
-
- // wrap_content is redundant in GridLayouts
- Attr width = element.getAttributeNodeNS(ANDROID_URI, ATTR_LAYOUT_WIDTH);
- if (width != null && VALUE_WRAP_CONTENT.equals(width.getValue())) {
- mRefactoring.removeAttribute(mRootEdit, width);
- }
- Attr height = element.getAttributeNodeNS(ANDROID_URI, ATTR_LAYOUT_HEIGHT);
- if (height != null && VALUE_WRAP_CONTENT.equals(height.getValue())) {
- mRefactoring.removeAttribute(mRootEdit, height);
- }
-
- // Fix up children moved from LinearLayouts that have "invalid" sizes that
- // was intended for layout weight handling in their old parent
- if (LINEAR_LAYOUT.equals(element.getParentNode().getNodeName())) {
- convert0dipToWrapContent(element);
- }
-
- implicitColumn += columnSpan;
- if (implicitColumn >= mColumnCount) {
- implicitColumn = 0;
- assert nextRow > implicitRow;
- implicitRow = nextRow;
- }
- }
- }
-
- private void processGravities() {
- for (View view : mViews) {
- Element element = view.getElement();
- if (element == mLayout) {
- continue;
- }
-
- Attr width = element.getAttributeNodeNS(ANDROID_URI, ATTR_LAYOUT_WIDTH);
- Attr height = element.getAttributeNodeNS(ANDROID_URI, ATTR_LAYOUT_HEIGHT);
- String gravity = element.getAttributeNS(ANDROID_URI, ATTR_LAYOUT_GRAVITY);
- String newGravity = null;
- if (width != null && (VALUE_MATCH_PARENT.equals(width.getValue()) ||
- VALUE_FILL_PARENT.equals(width.getValue()))) {
- mRefactoring.removeAttribute(mRootEdit, width);
- newGravity = gravity = GRAVITY_VALUE_FILL_HORIZONTAL;
- }
- if (height != null && (VALUE_MATCH_PARENT.equals(height.getValue()) ||
- VALUE_FILL_PARENT.equals(height.getValue()))) {
- mRefactoring.removeAttribute(mRootEdit, height);
- if (newGravity == GRAVITY_VALUE_FILL_HORIZONTAL) {
- newGravity = GRAVITY_VALUE_FILL;
- } else {
- newGravity = GRAVITY_VALUE_FILL_VERTICAL;
- }
- gravity = newGravity;
- }
-
- if (gravity == null || gravity.length() == 0) {
- ElementDescriptor descriptor = view.mInfo.getUiViewNode().getDescriptor();
- if (descriptor instanceof ViewElementDescriptor) {
- ViewElementDescriptor viewDescriptor = (ViewElementDescriptor) descriptor;
- String fqcn = viewDescriptor.getFullClassName();
- FillPreference fill = ViewMetadataRepository.get().getFillPreference(fqcn);
- gravity = GridLayoutRule.computeDefaultGravity(fill);
- if (gravity != null) {
- newGravity = gravity;
- }
- }
- }
-
- if (newGravity != null) {
- mRefactoring.setAttribute(mRootEdit, element, ANDROID_URI,
- mNamespace, ATTR_LAYOUT_GRAVITY, newGravity);
- }
-
- view.mGravity = newGravity != null ? newGravity : gravity;
- }
- }
-
-
- /** Converts 0dip values in layout_width and layout_height to wrap_content instead */
- private void convert0dipToWrapContent(Element child) {
- // Must convert layout_height="0dip" to layout_height="wrap_content".
- // (And since wrap_content is the default, what we really do is remove
- // the attribute completely.)
- // 0dip is a special trick used in linear layouts in the presence of
- // weights where 0dip ensures that the height of the view is not taken
- // into account when distributing the weights. However, when converted
- // to RelativeLayout this will instead cause the view to actually be assigned
- // 0 height.
- Attr height = child.getAttributeNodeNS(ANDROID_URI, ATTR_LAYOUT_HEIGHT);
- // 0dip, 0dp, 0px, etc
- if (height != null && height.getValue().startsWith("0")) { //$NON-NLS-1$
- mRefactoring.removeAttribute(mRootEdit, height);
- }
- Attr width = child.getAttributeNodeNS(ANDROID_URI, ATTR_LAYOUT_WIDTH);
- if (width != null && width.getValue().startsWith("0")) { //$NON-NLS-1$
- mRefactoring.removeAttribute(mRootEdit, width);
- }
- }
-
- /**
- * Searches a view hierarchy and locates the {@link CanvasViewInfo} for the given
- * {@link Element}
- *
- * @param info the root {@link CanvasViewInfo} to search below
- * @param element the target element
- * @return the {@link CanvasViewInfo} which corresponds to the given element
- */
- private CanvasViewInfo findViewForElement(CanvasViewInfo info, Element element) {
- if (getElement(info) == element) {
- return info;
- }
-
- for (CanvasViewInfo child : info.getChildren()) {
- CanvasViewInfo result = findViewForElement(child, element);
- if (result != null) {
- return result;
- }
- }
-
- return null;
- }
-
- /** Returns the {@link Element} for the given {@link CanvasViewInfo} */
- private static Element getElement(CanvasViewInfo info) {
- Node node = info.getUiViewNode().getXmlNode();
- if (node instanceof Element) {
- return (Element) node;
- }
-
- return null;
- }
-
-
- /** Holds layout information about an individual view */
- private static class View {
- private final Element mElement;
- private int mRow = -1;
- private int mCol = -1;
- private int mRowSpan = -1;
- private int mColSpan = -1;
- private int mX1;
- private int mY1;
- private int mX2;
- private int mY2;
- private CanvasViewInfo mInfo;
- private String mGravity;
-
- public View(CanvasViewInfo view, Element element) {
- mInfo = view;
- mElement = element;
-
- Rectangle b = mInfo.getAbsRect();
- mX1 = b.x;
- mX2 = b.x + b.width;
- mY1 = b.y;
- mY2 = b.y + b.height;
- }
-
- /**
- * Returns the element for this view
- *
- * @return the element for the view
- */
- public Element getElement() {
- return mElement;
- }
-
- /**
- * The assigned row for this view
- *
- * @return the assigned row
- */
- public int getRow() {
- return mRow;
- }
-
- /**
- * The assigned column for this view
- *
- * @return the assigned column
- */
- public int getColumn() {
- return mCol;
- }
-
- /**
- * The assigned row span for this view
- *
- * @return the assigned row span
- */
- public int getRowSpan() {
- return mRowSpan;
- }
-
- /**
- * The assigned column span for this view
- *
- * @return the assigned column span
- */
- public int getColumnSpan() {
- return mColSpan;
- }
-
- /**
- * The left edge of the view to be used for placement
- *
- * @return the left edge x coordinate
- */
- public int getLeftEdge() {
- return mX1;
- }
-
- /**
- * The top edge of the view to be used for placement
- *
- * @return the top edge y coordinate
- */
- public int getTopEdge() {
- return mY1;
- }
-
- /**
- * The right edge of the view to be used for placement
- *
- * @return the right edge x coordinate
- */
- public int getRightEdge() {
- return mX2;
- }
-
- /**
- * The bottom edge of the view to be used for placement
- *
- * @return the bottom edge y coordinate
- */
- public int getBottomEdge() {
- return mY2;
- }
-
- @Override
- public String toString() {
- return "View(" + VisualRefactoring.getId(mElement) + ": " + mX1 + "," + mY1 + ")";
- }
- }
-
- /** Grid model for the views found in the view hierarchy, partitioned into rows and columns */
- private static class GridModel {
- private final List<View> mViews = new ArrayList<View>();
- private final List<Element> mDelete = new ArrayList<Element>();
- private final Map<Element, View> mElementToView = new HashMap<Element, View>();
- private Element mLayout;
- private boolean mFlatten;
-
- GridModel(CanvasViewInfo view, Element layout, boolean flatten) {
- mLayout = layout;
- mFlatten = flatten;
-
- scan(view, true);
- analyzeKnownLayouts();
- initializeColumns();
- initializeRows();
- mDelete.remove(getElement(view));
- }
-
- /**
- * Returns the {@link View} objects to be placed in the grid
- *
- * @return list of {@link View} objects, never null but possibly empty
- */
- public List<View> getViews() {
- return mViews;
- }
-
- /**
- * Returns the list of elements that are scheduled for deletion in the
- * flattening operation
- *
- * @return elements to be deleted, never null but possibly empty
- */
- public List<Element> getDeletedElements() {
- return mDelete;
- }
-
- /**
- * Compute and return column count
- *
- * @return the column count
- */
- public int computeColumnCount() {
- int columnCount = 0;
- for (View view : mViews) {
- if (view.getElement() == mLayout) {
- continue;
- }
-
- int column = view.getColumn();
- int columnSpan = view.getColumnSpan();
- if (column + columnSpan > columnCount) {
- columnCount = column + columnSpan;
- }
- }
- return columnCount;
- }
-
- /**
- * Initializes the column and columnSpan attributes of the views
- */
- private void initializeColumns() {
- // Now initialize table view row, column and spans
- Map<Integer, List<View>> mColumnViews = new HashMap<Integer, List<View>>();
- for (View view : mViews) {
- if (view.mElement == mLayout) {
- continue;
- }
- int x = view.getLeftEdge();
- List<View> list = mColumnViews.get(x);
- if (list == null) {
- list = new ArrayList<View>();
- mColumnViews.put(x, list);
- }
- list.add(view);
- }
-
- List<Integer> columnOffsets = new ArrayList<Integer>(mColumnViews.keySet());
- Collections.sort(columnOffsets);
-
- int columnIndex = 0;
- for (Integer column : columnOffsets) {
- List<View> views = mColumnViews.get(column);
- if (views != null) {
- for (View view : views) {
- view.mCol = columnIndex;
- }
- }
- columnIndex++;
- }
- // Initialize column spans
- for (View view : mViews) {
- if (view.mElement == mLayout) {
- continue;
- }
- int index = Collections.binarySearch(columnOffsets, view.getRightEdge());
- int column;
- if (index == -1) {
- // Smaller than the first element; just use the first column
- column = 0;
- } else if (index < 0) {
- column = -(index + 2);
- } else {
- column = index;
- }
-
- if (column < view.mCol) {
- column = view.mCol;
- }
-
- view.mColSpan = column - view.mCol + 1;
- }
- }
-
- /**
- * Initializes the row and rowSpan attributes of the views
- */
- private void initializeRows() {
- Map<Integer, List<View>> mRowViews = new HashMap<Integer, List<View>>();
- for (View view : mViews) {
- if (view.mElement == mLayout) {
- continue;
- }
- int y = view.getTopEdge();
- List<View> list = mRowViews.get(y);
- if (list == null) {
- list = new ArrayList<View>();
- mRowViews.put(y, list);
- }
- list.add(view);
- }
-
- List<Integer> rowOffsets = new ArrayList<Integer>(mRowViews.keySet());
- Collections.sort(rowOffsets);
-
- int rowIndex = 0;
- for (Integer row : rowOffsets) {
- List<View> views = mRowViews.get(row);
- if (views != null) {
- for (View view : views) {
- view.mRow = rowIndex;
- }
- }
- rowIndex++;
- }
-
- // Initialize row spans
- for (View view : mViews) {
- if (view.mElement == mLayout) {
- continue;
- }
- int index = Collections.binarySearch(rowOffsets, view.getBottomEdge());
- int row;
- if (index == -1) {
- // Smaller than the first element; just use the first row
- row = 0;
- } else if (index < 0) {
- row = -(index + 2);
- } else {
- row = index;
- }
-
- if (row < view.mRow) {
- row = view.mRow;
- }
-
- view.mRowSpan = row - view.mRow + 1;
- }
- }
-
- /**
- * Walks over a given view hierarchy and locates views to be placed in
- * the grid layout (or deleted if we are flattening the hierarchy)
- *
- * @param view the view to analyze
- * @param isRoot whether this view is the root (which cannot be removed)
- * @return the {@link View} object for the {@link CanvasViewInfo}
- * hierarchy we just analyzed, or null
- */
- private View scan(CanvasViewInfo view, boolean isRoot) {
- View added = null;
- if (!mFlatten || !isRemovableLayout(view)) {
- added = add(view);
- if (!isRoot) {
- return added;
- }
- } else {
- mDelete.add(getElement(view));
- }
-
- // Build up a table model of the view
- for (CanvasViewInfo child : view.getChildren()) {
- Element childElement = getElement(child);
-
- // See if this view shares the edge with the removed
- // parent layout, and if so, record that such that we can
- // later handle attachments to the removed parent edges
-
- if (mFlatten && isRemovableLayout(child)) {
- // When flattening, we want to disregard all layouts and instead
- // add their children!
- for (CanvasViewInfo childView : child.getChildren()) {
- scan(childView, false);
- }
- mDelete.add(childElement);
- } else {
- scan(child, false);
- }
- }
-
- return added;
- }
-
- /** Adds the given {@link CanvasViewInfo} into our internal view list */
- private View add(CanvasViewInfo info) {
- Element element = getElement(info);
- View view = new View(info, element);
- mViews.add(view);
- mElementToView.put(element, view);
- return view;
- }
-
- private void analyzeKnownLayouts() {
- Set<Element> parents = new HashSet<Element>();
- for (View view : mViews) {
- Node parent = view.getElement().getParentNode();
- if (parent instanceof Element) {
- parents.add((Element) parent);
- }
- }
-
- List<Collection<View>> rowGroups = new ArrayList<Collection<View>>();
- List<Collection<View>> columnGroups = new ArrayList<Collection<View>>();
- for (Element parent : parents) {
- String tagName = parent.getTagName();
- if (tagName.equals(LINEAR_LAYOUT) || tagName.equals(TABLE_LAYOUT) ||
- tagName.equals(TABLE_ROW) || tagName.equals(RADIO_GROUP)) {
- Set<View> group = new HashSet<View>();
- for (Element child : DomUtilities.getChildren(parent)) {
- View view = mElementToView.get(child);
- if (view != null) {
- group.add(view);
- }
- }
- if (group.size() > 1) {
- boolean isVertical = VALUE_VERTICAL.equals(parent.getAttributeNS(
- ANDROID_URI, ATTR_ORIENTATION));
- if (tagName.equals(TABLE_LAYOUT)) {
- isVertical = true;
- } else if (tagName.equals(TABLE_ROW)) {
- isVertical = false;
- }
- if (isVertical) {
- columnGroups.add(group);
- } else {
- rowGroups.add(group);
- }
- }
- } else if (tagName.equals(RELATIVE_LAYOUT)) {
- List<Element> children = DomUtilities.getChildren(parent);
- for (Element child : children) {
- View view = mElementToView.get(child);
- if (view == null) {
- continue;
- }
- NamedNodeMap attributes = child.getAttributes();
- for (int i = 0, n = attributes.getLength(); i < n; i++) {
- Attr attr = (Attr) attributes.item(i);
- String name = attr.getLocalName();
- if (name.startsWith(ATTR_LAYOUT_RESOURCE_PREFIX)) {
- boolean alignVertical =
- name.equals(ATTR_LAYOUT_ALIGN_TOP) ||
- name.equals(ATTR_LAYOUT_ALIGN_BOTTOM) ||
- name.equals(ATTR_LAYOUT_ALIGN_BASELINE);
- boolean alignHorizontal =
- name.equals(ATTR_LAYOUT_ALIGN_LEFT) ||
- name.equals(ATTR_LAYOUT_ALIGN_RIGHT);
- if (!alignVertical && !alignHorizontal) {
- continue;
- }
- String value = attr.getValue();
- if (value.startsWith(ID_PREFIX)
- || value.startsWith(NEW_ID_PREFIX)) {
- String targetName = BaseLayoutRule.stripIdPrefix(value);
- Element target = null;
- for (Element c : children) {
- String id = VisualRefactoring.getId(c);
- if (targetName.equals(BaseLayoutRule.stripIdPrefix(id))) {
- target = c;
- break;
- }
- }
- View targetView = mElementToView.get(target);
- if (targetView != null) {
- List<View> group = new ArrayList<View>(2);
- group.add(view);
- group.add(targetView);
- if (alignHorizontal) {
- columnGroups.add(group);
- } else {
- assert alignVertical;
- rowGroups.add(group);
- }
- }
- }
- }
- }
- }
- } else {
- // TODO: Consider looking for interesting metadata from other layouts
- }
- }
-
- // Assign the same top or left coordinates to the groups to ensure that they
- // all get positioned in the same row or column
- for (Collection<View> rowGroup : rowGroups) {
- // Find the smallest one
- Iterator<View> iterator = rowGroup.iterator();
- int smallest = iterator.next().mY1;
- while (iterator.hasNext()) {
- smallest = Math.min(smallest, iterator.next().mY1);
- }
- for (View view : rowGroup) {
- view.mY2 -= (view.mY1 - smallest);
- view.mY1 = smallest;
- }
- }
- for (Collection<View> columnGroup : columnGroups) {
- Iterator<View> iterator = columnGroup.iterator();
- int smallest = iterator.next().mX1;
- while (iterator.hasNext()) {
- smallest = Math.min(smallest, iterator.next().mX1);
- }
- for (View view : columnGroup) {
- view.mX2 -= (view.mX1 - smallest);
- view.mX1 = smallest;
- }
- }
- }
-
- /**
- * Returns true if the given {@link CanvasViewInfo} represents an element we
- * should remove in a flattening conversion. We don't want to remove non-layout
- * views, or layout views that for example contain drawables on their own.
- */
- private boolean isRemovableLayout(CanvasViewInfo child) {
- // The element being converted is NOT removable!
- Element element = getElement(child);
- if (element == mLayout) {
- return false;
- }
-
- ElementDescriptor descriptor = child.getUiViewNode().getDescriptor();
- String name = descriptor.getXmlLocalName();
- if (name.equals(LINEAR_LAYOUT) || name.equals(RELATIVE_LAYOUT)
- || name.equals(TABLE_LAYOUT) || name.equals(TABLE_ROW)) {
- // Don't delete layouts that provide a background image or gradient
- if (element.hasAttributeNS(ANDROID_URI, ATTR_BACKGROUND)) {
- AdtPlugin.log(IStatus.WARNING,
- "Did not flatten layout %1$s because it defines a '%2$s' attribute",
- VisualRefactoring.getId(element), ATTR_BACKGROUND);
- return false;
- }
-
- return true;
- }
-
- return false;
- }
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/JavaQuickAssistant.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/JavaQuickAssistant.java
deleted file mode 100644
index df5d9eaf3..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/JavaQuickAssistant.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * 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.eclipse.adt.internal.project.BaseProjectHelper;
-import com.android.ide.eclipse.adt.internal.refactorings.extractstring.ExtractStringProposal;
-
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.jdt.core.dom.ASTNode;
-import org.eclipse.jdt.ui.text.java.IInvocationContext;
-import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal;
-import org.eclipse.jdt.ui.text.java.IProblemLocation;
-
-/**
- * Quick Assistant for Java files in Android projects
- */
-public class JavaQuickAssistant implements org.eclipse.jdt.ui.text.java.IQuickAssistProcessor {
- public JavaQuickAssistant() {
- }
-
- @Override
- public boolean hasAssists(IInvocationContext context) throws CoreException {
- return true;
- }
-
- @Override
- public IJavaCompletionProposal[] getAssists(IInvocationContext context,
- IProblemLocation[] locations) throws CoreException {
- // We should only offer Android quick assists within Android projects.
- // This can be done by adding this logic to the extension registration:
- //
- // <enablement>
- // <with variable="projectNatures">
- // <iterate operator="or">
- // <equals value="com.android.ide.eclipse.adt.AndroidNature"/>
- // </iterate>
- // </with>
- // </enablement>
- //
- // However, this causes some errors to be dumped to the log, so instead we filter
- // out non Android projects programmatically:
-
- IProject project = context.getCompilationUnit().getJavaProject().getProject();
- if (project == null || !BaseProjectHelper.isAndroidProject(project)) {
- return null;
- }
-
- ASTNode coveringNode = context.getCoveringNode();
- if (coveringNode != null && coveringNode.getNodeType() == ASTNode.STRING_LITERAL
- && coveringNode.getLength() > 2) { // don't extract empty strings (includes quotes)
- return new IJavaCompletionProposal[] {
- new ExtractStringProposal(context)
- };
- }
-
- return null;
- }
-}
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
deleted file mode 100644
index aa8c11999..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/RefactoringAssistant.java
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- * 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;
- }
- }
-}
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
deleted file mode 100644
index e0d6313bf..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/RelativeLayoutConversionHelper.java
+++ /dev/null
@@ -1,1633 +0,0 @@
-/*
- * 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 static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.ATTR_BACKGROUND;
-import static com.android.SdkConstants.ATTR_BASELINE_ALIGNED;
-import static com.android.SdkConstants.ATTR_LAYOUT_ABOVE;
-import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_BASELINE;
-import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_BOTTOM;
-import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_LEFT;
-import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_PARENT_BOTTOM;
-import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_PARENT_LEFT;
-import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_PARENT_RIGHT;
-import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_PARENT_TOP;
-import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_RIGHT;
-import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_TOP;
-import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_WITH_PARENT_MISSING;
-import static com.android.SdkConstants.ATTR_LAYOUT_BELOW;
-import static com.android.SdkConstants.ATTR_LAYOUT_CENTER_HORIZONTAL;
-import static com.android.SdkConstants.ATTR_LAYOUT_CENTER_VERTICAL;
-import static com.android.SdkConstants.ATTR_LAYOUT_HEIGHT;
-import static com.android.SdkConstants.ATTR_LAYOUT_MARGIN_LEFT;
-import static com.android.SdkConstants.ATTR_LAYOUT_MARGIN_TOP;
-import static com.android.SdkConstants.ATTR_LAYOUT_RESOURCE_PREFIX;
-import static com.android.SdkConstants.ATTR_LAYOUT_TO_LEFT_OF;
-import static com.android.SdkConstants.ATTR_LAYOUT_TO_RIGHT_OF;
-import static com.android.SdkConstants.ATTR_LAYOUT_WEIGHT;
-import static com.android.SdkConstants.ATTR_LAYOUT_WIDTH;
-import static com.android.SdkConstants.ATTR_ORIENTATION;
-import static com.android.SdkConstants.ID_PREFIX;
-import static com.android.SdkConstants.LINEAR_LAYOUT;
-import static com.android.SdkConstants.NEW_ID_PREFIX;
-import static com.android.SdkConstants.RELATIVE_LAYOUT;
-import static com.android.SdkConstants.VALUE_FALSE;
-import static com.android.SdkConstants.VALUE_N_DP;
-import static com.android.SdkConstants.VALUE_TRUE;
-import static com.android.SdkConstants.VALUE_VERTICAL;
-import static com.android.SdkConstants.VALUE_WRAP_CONTENT;
-import static com.android.ide.common.layout.GravityHelper.GRAVITY_BOTTOM;
-import static com.android.ide.common.layout.GravityHelper.GRAVITY_CENTER_HORIZ;
-import static com.android.ide.common.layout.GravityHelper.GRAVITY_CENTER_VERT;
-import static com.android.ide.common.layout.GravityHelper.GRAVITY_FILL_HORIZ;
-import static com.android.ide.common.layout.GravityHelper.GRAVITY_FILL_VERT;
-import static com.android.ide.common.layout.GravityHelper.GRAVITY_LEFT;
-import static com.android.ide.common.layout.GravityHelper.GRAVITY_RIGHT;
-import static com.android.ide.common.layout.GravityHelper.GRAVITY_TOP;
-import static com.android.ide.common.layout.GravityHelper.GRAVITY_VERT_MASK;
-
-import com.android.ide.common.layout.GravityHelper;
-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.ide.eclipse.adt.internal.preferences.AdtPrefs;
-import com.android.utils.Pair;
-
-import org.eclipse.core.runtime.IStatus;
-import org.eclipse.swt.graphics.Rectangle;
-import org.eclipse.text.edits.MultiTextEdit;
-import org.w3c.dom.Attr;
-import org.w3c.dom.Element;
-import org.w3c.dom.NamedNodeMap;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Helper class which performs the bulk of the layout conversion to relative layout
- * <p>
- * Future enhancements:
- * <ul>
- * <li>Render the layout at multiple screen sizes and analyze how the widgets move and
- * stretch and use that to add in additional constraints
- * <li> Adapt the LinearLayout analysis code to work with TableLayouts and TableRows as well
- * (just need to tweak the "isVertical" interpretation to account for the different defaults,
- * and perhaps do something about column size properties.
- * <li> We need to take into account existing margins and clear/update them
- * </ul>
- */
-class RelativeLayoutConversionHelper {
- private final MultiTextEdit mRootEdit;
- private final boolean mFlatten;
- private final Element mLayout;
- private final ChangeLayoutRefactoring mRefactoring;
- private final CanvasViewInfo mRootView;
- private List<Element> mDeletedElements;
-
- RelativeLayoutConversionHelper(ChangeLayoutRefactoring refactoring,
- Element layout, boolean flatten, MultiTextEdit rootEdit, CanvasViewInfo rootView) {
- mRefactoring = refactoring;
- mLayout = layout;
- mFlatten = flatten;
- mRootEdit = rootEdit;
- mRootView = rootView;
- }
-
- /** Performs conversion from any layout to a RelativeLayout */
- public void convertToRelative() {
- if (mRootView == null) {
- return;
- }
-
- // Locate the view for the layout
- CanvasViewInfo layoutView = findViewForElement(mRootView, mLayout);
- if (layoutView == null || layoutView.getChildren().size() == 0) {
- // No children. THAT was an easy conversion!
- return;
- }
-
- // Study the layout and get information about how to place individual elements
- List<View> views = analyzeLayout(layoutView);
-
- // Create/update relative layout constraints
- createAttachments(views);
- }
-
- /** Returns the elements that were deleted, or null */
- List<Element> getDeletedElements() {
- return mDeletedElements;
- }
-
- /**
- * Analyzes the given view hierarchy and produces a list of {@link View} objects which
- * contain placement information for each element
- */
- private List<View> analyzeLayout(CanvasViewInfo layoutView) {
- EdgeList edgeList = new EdgeList(layoutView);
- mDeletedElements = edgeList.getDeletedElements();
- deleteRemovedElements(mDeletedElements);
-
- List<Integer> columnOffsets = edgeList.getColumnOffsets();
- List<Integer> rowOffsets = edgeList.getRowOffsets();
-
- // Compute x/y offsets for each row/column index
- int[] left = new int[columnOffsets.size()];
- int[] top = new int[rowOffsets.size()];
-
- Map<Integer, Integer> xToCol = new HashMap<Integer, Integer>();
- int columnIndex = 0;
- for (Integer offset : columnOffsets) {
- left[columnIndex] = offset;
- xToCol.put(offset, columnIndex++);
- }
- Map<Integer, Integer> yToRow = new HashMap<Integer, Integer>();
- int rowIndex = 0;
- for (Integer offset : rowOffsets) {
- top[rowIndex] = offset;
- yToRow.put(offset, rowIndex++);
- }
-
- // Create a complete list of view objects
- List<View> views = createViews(edgeList, columnOffsets);
- initializeSpans(edgeList, columnOffsets, rowOffsets, xToCol, yToRow);
-
- // Sanity check
- for (View view : views) {
- assert view.getLeftEdge() == left[view.mCol];
- assert view.getTopEdge() == top[view.mRow];
- assert view.getRightEdge() == left[view.mCol+view.mColSpan];
- assert view.getBottomEdge() == top[view.mRow+view.mRowSpan];
- }
-
- // Ensure that every view has a proper id such that it can be referred to
- // with a constraint
- initializeIds(edgeList, views);
-
- // Attempt to lay the views out in a grid with constraints (though not that widgets
- // can overlap as well)
- Grid grid = new Grid(views, left, top);
- computeKnownConstraints(views, edgeList);
- computeHorizontalConstraints(grid);
- computeVerticalConstraints(grid);
-
- return views;
- }
-
- /** Produces a list of {@link View} objects from an {@link EdgeList} */
- private List<View> createViews(EdgeList edgeList, List<Integer> columnOffsets) {
- List<View> views = new ArrayList<View>();
- for (Integer offset : columnOffsets) {
- List<View> leftEdgeViews = edgeList.getLeftEdgeViews(offset);
- if (leftEdgeViews == null) {
- // must have been a right edge
- continue;
- }
- for (View view : leftEdgeViews) {
- views.add(view);
- }
- }
- return views;
- }
-
- /** Removes any elements targeted for deletion */
- private void deleteRemovedElements(List<Element> delete) {
- if (mFlatten && delete.size() > 0) {
- for (Element element : delete) {
- mRefactoring.removeElementTags(mRootEdit, element, delete,
- !AdtPrefs.getPrefs().getFormatGuiXml() /*changeIndentation*/);
- }
- }
- }
-
- /** Ensures that every element has an id such that it can be referenced from a constraint */
- private void initializeIds(EdgeList edgeList, List<View> views) {
- // Ensure that all views have a valid id
- for (View view : views) {
- String id = mRefactoring.ensureHasId(mRootEdit, view.mElement, null);
- edgeList.setIdAttributeValue(view, id);
- }
- }
-
- /**
- * Initializes the column and row indices, as well as any column span and row span
- * values
- */
- private void initializeSpans(EdgeList edgeList, List<Integer> columnOffsets,
- List<Integer> rowOffsets, Map<Integer, Integer> xToCol, Map<Integer, Integer> yToRow) {
- // Now initialize table view row, column and spans
- for (Integer offset : columnOffsets) {
- List<View> leftEdgeViews = edgeList.getLeftEdgeViews(offset);
- if (leftEdgeViews == null) {
- // must have been a right edge
- continue;
- }
- for (View view : leftEdgeViews) {
- Integer col = xToCol.get(view.getLeftEdge());
- assert col != null;
- Integer end = xToCol.get(view.getRightEdge());
- assert end != null;
-
- view.mCol = col;
- view.mColSpan = end - col;
- }
- }
-
- for (Integer offset : rowOffsets) {
- List<View> topEdgeViews = edgeList.getTopEdgeViews(offset);
- if (topEdgeViews == null) {
- // must have been a bottom edge
- continue;
- }
- for (View view : topEdgeViews) {
- Integer row = yToRow.get(view.getTopEdge());
- assert row != null;
- Integer end = yToRow.get(view.getBottomEdge());
- assert end != null;
-
- view.mRow = row;
- view.mRowSpan = end - row;
- }
- }
- }
-
- /**
- * Creates refactoring edits which adds or updates constraints for the given list of
- * views
- */
- private void createAttachments(List<View> views) {
- // Make the attachments
- String namespace = mRefactoring.getAndroidNamespacePrefix();
- for (View view : views) {
- for (Pair<String, String> constraint : view.getHorizConstraints()) {
- mRefactoring.setAttribute(mRootEdit, view.mElement, ANDROID_URI,
- namespace, constraint.getFirst(), constraint.getSecond());
- }
- for (Pair<String, String> constraint : view.getVerticalConstraints()) {
- mRefactoring.setAttribute(mRootEdit, view.mElement, ANDROID_URI,
- namespace, constraint.getFirst(), constraint.getSecond());
- }
- }
- }
-
- /**
- * Analyzes the existing layouts and layout parameter objects in the document to infer
- * constraints for layout types that we know about - such as LinearLayout baseline
- * alignment, weights, gravity, etc.
- */
- private void computeKnownConstraints(List<View> views, EdgeList edgeList) {
- // List of parent layout elements we've already processed. We iterate through all
- // the -children-, and we ask each for its element parent (which won't have a view)
- // and we look at the parent's layout attributes and its children layout constraints,
- // and then we stash away constraints that we can infer. This means that we will
- // encounter the same parent for every sibling, so that's why there's a map to
- // prevent duplicate work.
- Set<Node> seen = new HashSet<Node>();
-
- for (View view : views) {
- Element element = view.getElement();
- Node parent = element.getParentNode();
- if (seen.contains(parent)) {
- continue;
- }
- seen.add(parent);
-
- if (parent.getNodeType() != Node.ELEMENT_NODE) {
- continue;
- }
- Element layout = (Element) parent;
- String layoutName = layout.getTagName();
-
- if (LINEAR_LAYOUT.equals(layoutName)) {
- analyzeLinearLayout(edgeList, layout);
- } else if (RELATIVE_LAYOUT.equals(layoutName)) {
- analyzeRelativeLayout(edgeList, layout);
- } else {
- // Some other layout -- add more conditional handling here
- // for framelayout, tables, etc.
- }
- }
- }
-
- /**
- * Returns the layout weight of of the given child of a LinearLayout, or 0.0 if it
- * does not define a weight
- */
- private float getWeight(Element linearLayoutChild) {
- String weight = linearLayoutChild.getAttributeNS(ANDROID_URI, ATTR_LAYOUT_WEIGHT);
- if (weight != null && weight.length() > 0) {
- try {
- return Float.parseFloat(weight);
- } catch (NumberFormatException nfe) {
- AdtPlugin.log(nfe, "Invalid weight %1$s", weight);
- }
- }
-
- return 0.0f;
- }
-
- /**
- * Returns the sum of all the layout weights of the children in the given LinearLayout
- *
- * @param linearLayout the layout to compute the total sum for
- * @return the total sum of all the layout weights in the given layout
- */
- private float getWeightSum(Element linearLayout) {
- float sum = 0;
- for (Element child : DomUtilities.getChildren(linearLayout)) {
- sum += getWeight(child);
- }
-
- return sum;
- }
-
- /**
- * Analyzes the given LinearLayout and updates the constraints to reflect
- * relationships it can infer - based on baseline alignment, gravity, order and
- * weights. This method also removes "0dip" as a special width/height used in
- * LinearLayouts with weight distribution.
- */
- private void analyzeLinearLayout(EdgeList edgeList, Element layout) {
- boolean isVertical = VALUE_VERTICAL.equals(layout.getAttributeNS(ANDROID_URI,
- ATTR_ORIENTATION));
- View baselineRef = null;
- if (!isVertical &&
- !VALUE_FALSE.equals(layout.getAttributeNS(ANDROID_URI, ATTR_BASELINE_ALIGNED))) {
- // Baseline alignment. Find the tallest child and set it as the baseline reference.
- int tallestHeight = 0;
- View tallest = null;
- for (Element child : DomUtilities.getChildren(layout)) {
- View view = edgeList.getView(child);
- if (view != null && view.getHeight() > tallestHeight) {
- tallestHeight = view.getHeight();
- tallest = view;
- }
- }
- if (tallest != null) {
- baselineRef = tallest;
- }
- }
-
- float weightSum = getWeightSum(layout);
- float cumulativeWeight = 0;
-
- List<Element> children = DomUtilities.getChildren(layout);
- String prevId = null;
- boolean isFirstChild = true;
- boolean linkBackwards = true;
- boolean linkForwards = false;
-
- for (int index = 0, childCount = children.size(); index < childCount; index++) {
- Element child = children.get(index);
-
- View childView = edgeList.getView(child);
- if (childView == null) {
- // Could be a nested layout that is being removed etc
- prevId = null;
- isFirstChild = false;
- continue;
- }
-
- // Look at the layout_weight attributes and determine whether we should be
- // attached on the bottom/right or on the top/left
- if (weightSum > 0.0f) {
- float weight = getWeight(child);
-
- // We can't emulate a LinearLayout where multiple children have positive
- // weights. However, we CAN support the common scenario where a single
- // child has a non-zero weight, and all children after it are pushed
- // to the end and the weighted child fills the remaining space.
- if (cumulativeWeight == 0 && weight > 0) {
- // See if we have a bottom/right edge to attach the forwards link to
- // (at the end of the forwards chains). Only if so can we link forwards.
- View referenced;
- if (isVertical) {
- referenced = edgeList.getSharedBottomEdge(layout);
- } else {
- referenced = edgeList.getSharedRightEdge(layout);
- }
- if (referenced != null) {
- linkForwards = true;
- }
- } else if (cumulativeWeight > 0) {
- linkBackwards = false;
- }
-
- cumulativeWeight += weight;
- }
-
- analyzeGravity(edgeList, layout, isVertical, child, childView);
- convert0dipToWrapContent(child);
-
- // Chain elements together in the flow direction of the linear layout
- if (prevId != null) { // No constraint for first child
- if (linkBackwards) {
- if (isVertical) {
- childView.addVerticalConstraint(ATTR_LAYOUT_BELOW, prevId);
- } else {
- childView.addHorizConstraint(ATTR_LAYOUT_TO_RIGHT_OF, prevId);
- }
- }
- } else if (isFirstChild) {
- assert linkBackwards;
-
- // First element; attach it to the parent if we can
- if (isVertical) {
- View referenced = edgeList.getSharedTopEdge(layout);
- if (referenced != null) {
- if (isAncestor(referenced.getElement(), child)) {
- childView.addVerticalConstraint(ATTR_LAYOUT_ALIGN_PARENT_TOP,
- VALUE_TRUE);
- } else {
- childView.addVerticalConstraint(ATTR_LAYOUT_ALIGN_TOP,
- referenced.getId());
- }
- }
- } else {
- View referenced = edgeList.getSharedLeftEdge(layout);
- if (referenced != null) {
- if (isAncestor(referenced.getElement(), child)) {
- childView.addHorizConstraint(ATTR_LAYOUT_ALIGN_PARENT_LEFT,
- VALUE_TRUE);
- } else {
- childView.addHorizConstraint(
- ATTR_LAYOUT_ALIGN_LEFT, referenced.getId());
- }
- }
- }
- }
-
- if (linkForwards) {
- if (index < (childCount - 1)) {
- Element nextChild = children.get(index + 1);
- String nextId = mRefactoring.ensureHasId(mRootEdit, nextChild, null);
- if (nextId != null) {
- if (isVertical) {
- childView.addVerticalConstraint(ATTR_LAYOUT_ABOVE, nextId);
- } else {
- childView.addHorizConstraint(ATTR_LAYOUT_TO_LEFT_OF, nextId);
- }
- }
- } else {
- // Attach to right/bottom edge of the layout
- if (isVertical) {
- View referenced = edgeList.getSharedBottomEdge(layout);
- if (referenced != null) {
- if (isAncestor(referenced.getElement(), child)) {
- childView.addVerticalConstraint(ATTR_LAYOUT_ALIGN_PARENT_BOTTOM,
- VALUE_TRUE);
- } else {
- childView.addVerticalConstraint(ATTR_LAYOUT_ALIGN_BOTTOM,
- referenced.getId());
- }
- }
- } else {
- View referenced = edgeList.getSharedRightEdge(layout);
- if (referenced != null) {
- if (isAncestor(referenced.getElement(), child)) {
- childView.addHorizConstraint(ATTR_LAYOUT_ALIGN_PARENT_RIGHT,
- VALUE_TRUE);
- } else {
- childView.addHorizConstraint(
- ATTR_LAYOUT_ALIGN_RIGHT, referenced.getId());
- }
- }
- }
- }
- }
-
- if (baselineRef != null && baselineRef.getId() != null
- && !baselineRef.getId().equals(childView.getId())) {
- assert !isVertical;
- // Only align if they share the same gravity
- if ((childView.getGravity() & GRAVITY_VERT_MASK) ==
- (baselineRef.getGravity() & GRAVITY_VERT_MASK)) {
- childView.addHorizConstraint(ATTR_LAYOUT_ALIGN_BASELINE, baselineRef.getId());
- }
- }
-
- prevId = mRefactoring.ensureHasId(mRootEdit, child, null);
- isFirstChild = false;
- }
- }
-
- /**
- * Checks the layout "gravity" value for the given child and updates the constraints
- * to account for the gravity
- */
- private int analyzeGravity(EdgeList edgeList, Element layout, boolean isVertical,
- Element child, View childView) {
- // Use gravity to constrain elements in the axis orthogonal to the
- // direction of the layout
- int gravity = childView.getGravity();
- if (isVertical) {
- if ((gravity & GRAVITY_RIGHT) != 0) {
- View referenced = edgeList.getSharedRightEdge(layout);
- if (referenced != null) {
- if (isAncestor(referenced.getElement(), child)) {
- childView.addHorizConstraint(ATTR_LAYOUT_ALIGN_PARENT_RIGHT,
- VALUE_TRUE);
- } else {
- childView.addHorizConstraint(ATTR_LAYOUT_ALIGN_RIGHT,
- referenced.getId());
- }
- }
- } else if ((gravity & GRAVITY_CENTER_HORIZ) != 0) {
- View referenced1 = edgeList.getSharedLeftEdge(layout);
- View referenced2 = edgeList.getSharedRightEdge(layout);
- if (referenced1 != null && referenced2 == referenced1) {
- if (isAncestor(referenced1.getElement(), child)) {
- childView.addHorizConstraint(ATTR_LAYOUT_CENTER_HORIZONTAL,
- VALUE_TRUE);
- }
- }
- } else if ((gravity & GRAVITY_FILL_HORIZ) != 0) {
- View referenced1 = edgeList.getSharedLeftEdge(layout);
- View referenced2 = edgeList.getSharedRightEdge(layout);
- if (referenced1 != null && referenced2 == referenced1) {
- if (isAncestor(referenced1.getElement(), child)) {
- childView.addHorizConstraint(ATTR_LAYOUT_ALIGN_PARENT_LEFT,
- VALUE_TRUE);
- childView.addHorizConstraint(ATTR_LAYOUT_ALIGN_PARENT_RIGHT,
- VALUE_TRUE);
- } else {
- childView.addHorizConstraint(ATTR_LAYOUT_ALIGN_LEFT,
- referenced1.getId());
- childView.addHorizConstraint(ATTR_LAYOUT_ALIGN_RIGHT,
- referenced2.getId());
- }
- }
- } else if ((gravity & GRAVITY_LEFT) != 0) {
- View referenced = edgeList.getSharedLeftEdge(layout);
- if (referenced != null) {
- if (isAncestor(referenced.getElement(), child)) {
- childView.addHorizConstraint(ATTR_LAYOUT_ALIGN_PARENT_LEFT,
- VALUE_TRUE);
- } else {
- childView.addHorizConstraint(ATTR_LAYOUT_ALIGN_LEFT,
- referenced.getId());
- }
- }
- }
- } else {
- // Handle horizontal layout: perform vertical gravity attachments
- if ((gravity & GRAVITY_BOTTOM) != 0) {
- View referenced = edgeList.getSharedBottomEdge(layout);
- if (referenced != null) {
- if (isAncestor(referenced.getElement(), child)) {
- childView.addVerticalConstraint(ATTR_LAYOUT_ALIGN_PARENT_BOTTOM,
- VALUE_TRUE);
- } else {
- childView.addVerticalConstraint(ATTR_LAYOUT_ALIGN_BOTTOM,
- referenced.getId());
- }
- }
- } else if ((gravity & GRAVITY_CENTER_VERT) != 0) {
- View referenced1 = edgeList.getSharedTopEdge(layout);
- View referenced2 = edgeList.getSharedBottomEdge(layout);
- if (referenced1 != null && referenced2 == referenced1) {
- if (isAncestor(referenced1.getElement(), child)) {
- childView.addVerticalConstraint(ATTR_LAYOUT_CENTER_VERTICAL,
- VALUE_TRUE);
- }
- }
- } else if ((gravity & GRAVITY_FILL_VERT) != 0) {
- View referenced1 = edgeList.getSharedTopEdge(layout);
- View referenced2 = edgeList.getSharedBottomEdge(layout);
- if (referenced1 != null && referenced2 == referenced1) {
- if (isAncestor(referenced1.getElement(), child)) {
- childView.addVerticalConstraint(ATTR_LAYOUT_ALIGN_PARENT_TOP,
- VALUE_TRUE);
- childView.addVerticalConstraint(ATTR_LAYOUT_ALIGN_PARENT_BOTTOM,
- VALUE_TRUE);
- } else {
- childView.addVerticalConstraint(ATTR_LAYOUT_ALIGN_TOP,
- referenced1.getId());
- childView.addVerticalConstraint(ATTR_LAYOUT_ALIGN_BOTTOM,
- referenced2.getId());
- }
- }
- } else if ((gravity & GRAVITY_TOP) != 0) {
- View referenced = edgeList.getSharedTopEdge(layout);
- if (referenced != null) {
- if (isAncestor(referenced.getElement(), child)) {
- childView.addVerticalConstraint(ATTR_LAYOUT_ALIGN_PARENT_TOP,
- VALUE_TRUE);
- } else {
- childView.addVerticalConstraint(ATTR_LAYOUT_ALIGN_TOP,
- referenced.getId());
- }
- }
- }
- }
- return gravity;
- }
-
- /** Converts 0dip values in layout_width and layout_height to wrap_content instead */
- private void convert0dipToWrapContent(Element child) {
- // Must convert layout_height="0dip" to layout_height="wrap_content".
- // 0dip is a special trick used in linear layouts in the presence of
- // weights where 0dip ensures that the height of the view is not taken
- // into account when distributing the weights. However, when converted
- // to RelativeLayout this will instead cause the view to actually be assigned
- // 0 height.
- String height = child.getAttributeNS(ANDROID_URI, ATTR_LAYOUT_HEIGHT);
- // 0dip, 0dp, 0px, etc
- if (height != null && height.startsWith("0")) { //$NON-NLS-1$
- mRefactoring.setAttribute(mRootEdit, child, ANDROID_URI,
- mRefactoring.getAndroidNamespacePrefix(), ATTR_LAYOUT_HEIGHT,
- VALUE_WRAP_CONTENT);
- }
- String width = child.getAttributeNS(ANDROID_URI, ATTR_LAYOUT_WIDTH);
- if (width != null && width.startsWith("0")) { //$NON-NLS-1$
- mRefactoring.setAttribute(mRootEdit, child, ANDROID_URI,
- mRefactoring.getAndroidNamespacePrefix(), ATTR_LAYOUT_WIDTH,
- VALUE_WRAP_CONTENT);
- }
- }
-
- /**
- * Analyzes an embedded RelativeLayout within a layout hierarchy and updates the
- * constraints in the EdgeList with those relationships which can continue in the
- * outer single RelativeLayout.
- */
- private void analyzeRelativeLayout(EdgeList edgeList, Element layout) {
- NodeList children = layout.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;
- View childView = edgeList.getView(child);
- if (childView == null) {
- // Could be a nested layout that is being removed etc
- continue;
- }
-
- NamedNodeMap attributes = child.getAttributes();
- for (int j = 0, m = attributes.getLength(); j < m; j++) {
- Attr attribute = (Attr) attributes.item(j);
- String name = attribute.getLocalName();
- String value = attribute.getValue();
- if (name.equals(ATTR_LAYOUT_WIDTH)
- || name.equals(ATTR_LAYOUT_HEIGHT)) {
- // Ignore these for now
- } else if (name.startsWith(ATTR_LAYOUT_RESOURCE_PREFIX)
- && ANDROID_URI.equals(attribute.getNamespaceURI())) {
- // Determine if the reference is to a known edge
- String id = getIdBasename(value);
- if (id != null) {
- View referenced = edgeList.getView(id);
- if (referenced != null) {
- // This is a valid reference, so preserve
- // the attribute
- if (name.equals(ATTR_LAYOUT_BELOW) ||
- name.equals(ATTR_LAYOUT_ABOVE) ||
- name.equals(ATTR_LAYOUT_ALIGN_TOP) ||
- name.equals(ATTR_LAYOUT_ALIGN_BOTTOM) ||
- name.equals(ATTR_LAYOUT_ALIGN_BASELINE)) {
- // Vertical constraint
- childView.addVerticalConstraint(name, value);
- } else if (name.equals(ATTR_LAYOUT_ALIGN_LEFT) ||
- name.equals(ATTR_LAYOUT_TO_LEFT_OF) ||
- name.equals(ATTR_LAYOUT_TO_RIGHT_OF) ||
- name.equals(ATTR_LAYOUT_ALIGN_RIGHT)) {
- // Horizontal constraint
- childView.addHorizConstraint(name, value);
- } else {
- // We don't expect this
- assert false : name;
- }
- } else {
- // Reference to some layout that is not included here.
- // TODO: See if the given layout has an edge
- // that corresponds to one of our known views
- // so we can adjust the constraints and keep it after all.
- }
- } else {
- // It's a parent-relative constraint (such
- // as aligning with a parent edge, or centering
- // in the parent view)
- boolean remove = true;
- if (name.equals(ATTR_LAYOUT_ALIGN_PARENT_LEFT)) {
- View referenced = edgeList.getSharedLeftEdge(layout);
- if (referenced != null) {
- if (isAncestor(referenced.getElement(), child)) {
- childView.addHorizConstraint(name, VALUE_TRUE);
- } else {
- childView.addHorizConstraint(
- ATTR_LAYOUT_ALIGN_LEFT, referenced.getId());
- }
- remove = false;
- }
- } else if (name.equals(ATTR_LAYOUT_ALIGN_PARENT_RIGHT)) {
- View referenced = edgeList.getSharedRightEdge(layout);
- if (referenced != null) {
- if (isAncestor(referenced.getElement(), child)) {
- childView.addHorizConstraint(name, VALUE_TRUE);
- } else {
- childView.addHorizConstraint(
- ATTR_LAYOUT_ALIGN_RIGHT, referenced.getId());
- }
- remove = false;
- }
- } else if (name.equals(ATTR_LAYOUT_ALIGN_PARENT_TOP)) {
- View referenced = edgeList.getSharedTopEdge(layout);
- if (referenced != null) {
- if (isAncestor(referenced.getElement(), child)) {
- childView.addVerticalConstraint(name, VALUE_TRUE);
- } else {
- childView.addVerticalConstraint(ATTR_LAYOUT_ALIGN_TOP,
- referenced.getId());
- }
- remove = false;
- }
- } else if (name.equals(ATTR_LAYOUT_ALIGN_PARENT_BOTTOM)) {
- View referenced = edgeList.getSharedBottomEdge(layout);
- if (referenced != null) {
- if (isAncestor(referenced.getElement(), child)) {
- childView.addVerticalConstraint(name, VALUE_TRUE);
- } else {
- childView.addVerticalConstraint(ATTR_LAYOUT_ALIGN_BOTTOM,
- referenced.getId());
- }
- remove = false;
- }
- }
-
- boolean alignWithParent =
- name.equals(ATTR_LAYOUT_ALIGN_WITH_PARENT_MISSING);
- if (remove && alignWithParent) {
- // TODO - look for this one AFTER we have processed
- // everything else, and then set constraints as necessary
- // IF there are no other conflicting constraints!
- }
-
- // Otherwise it's some kind of centering which we don't support
- // yet.
-
- // TODO: Find a way to determine whether we have
- // a corresponding edge for the parent (e.g. if
- // the ViewInfo bounds match our outer parent or
- // some other edge) and if so, substitute for that
- // id.
- // For example, if this element was centered
- // horizontally in a RelativeLayout that actually
- // occupies the entire width of our outer layout,
- // then it can be preserved after all!
-
- if (remove) {
- if (name.startsWith("layout_margin")) { //$NON-NLS-1$
- continue;
- }
-
- // Remove unknown attributes?
- // It's too early to do this, because we may later want
- // to *set* this value and it would result in an overlapping edits
- // exception. Therefore, we need to RECORD which attributes should
- // be removed, which lines should have its indentation adjusted
- // etc and finally process it all at the end!
- //mRefactoring.removeAttribute(mRootEdit, child,
- // attribute.getNamespaceURI(), name);
- }
- }
- }
- }
- }
- }
- }
-
- /**
- * Given {@code @id/foo} or {@code @+id/foo}, returns foo. Note that given foo it will
- * return null.
- */
- private static String getIdBasename(String id) {
- if (id.startsWith(NEW_ID_PREFIX)) {
- return id.substring(NEW_ID_PREFIX.length());
- } else if (id.startsWith(ID_PREFIX)) {
- return id.substring(ID_PREFIX.length());
- }
-
- return null;
- }
-
- /** Returns true if the given second argument is a descendant of the first argument */
- private static boolean isAncestor(Node ancestor, Node node) {
- while (node != null) {
- if (node == ancestor) {
- return true;
- }
- node = node.getParentNode();
- }
- return false;
- }
-
- /**
- * Computes horizontal constraints for the views in the grid for any remaining views
- * that do not have constraints (as the result of the analysis of known layouts). This
- * will look at the rendered layout coordinates and attempt to connect elements based
- * on a spatial layout in the grid.
- */
- private void computeHorizontalConstraints(Grid grid) {
- int columns = grid.getColumns();
-
- String attachLeftProperty = ATTR_LAYOUT_ALIGN_PARENT_LEFT;
- String attachLeftValue = VALUE_TRUE;
- int marginLeft = 0;
- for (int col = 0; col < columns; col++) {
- if (!grid.colContainsTopLeftCorner(col)) {
- // Just accumulate margins for the next column
- marginLeft += grid.getColumnWidth(col);
- } else {
- // Add horizontal attachments
- String firstId = null;
- for (View view : grid.viewsStartingInCol(col, true)) {
- assert view.getId() != null;
- if (firstId == null) {
- firstId = view.getId();
- if (view.isConstrainedHorizontally()) {
- // Nothing to do -- we already have an accurate position for
- // this view
- } else if (attachLeftProperty != null) {
- view.addHorizConstraint(attachLeftProperty, attachLeftValue);
- if (marginLeft > 0) {
- view.addHorizConstraint(ATTR_LAYOUT_MARGIN_LEFT,
- String.format(VALUE_N_DP, marginLeft));
- marginLeft = 0;
- }
- } else {
- assert false;
- }
- } else if (!view.isConstrainedHorizontally()) {
- view.addHorizConstraint(ATTR_LAYOUT_ALIGN_LEFT, firstId);
- }
- }
- }
-
- // Figure out edge for the next column
- View view = grid.findRightEdgeView(col);
- if (view != null) {
- assert view.getId() != null;
- attachLeftProperty = ATTR_LAYOUT_TO_RIGHT_OF;
- attachLeftValue = view.getId();
-
- marginLeft = 0;
- } else if (marginLeft == 0) {
- marginLeft = grid.getColumnWidth(col);
- }
- }
- }
-
- /**
- * Performs vertical layout just like the {@link #computeHorizontalConstraints} method
- * did horizontally
- */
- private void computeVerticalConstraints(Grid grid) {
- int rows = grid.getRows();
-
- String attachTopProperty = ATTR_LAYOUT_ALIGN_PARENT_TOP;
- String attachTopValue = VALUE_TRUE;
- int marginTop = 0;
- for (int row = 0; row < rows; row++) {
- if (!grid.rowContainsTopLeftCorner(row)) {
- // Just accumulate margins for the next column
- marginTop += grid.getRowHeight(row);
- } else {
- // Add horizontal attachments
- String firstId = null;
- for (View view : grid.viewsStartingInRow(row, true)) {
- assert view.getId() != null;
- if (firstId == null) {
- firstId = view.getId();
- if (view.isConstrainedVertically()) {
- // Nothing to do -- we already have an accurate position for
- // this view
- } else if (attachTopProperty != null) {
- view.addVerticalConstraint(attachTopProperty, attachTopValue);
- if (marginTop > 0) {
- view.addVerticalConstraint(ATTR_LAYOUT_MARGIN_TOP,
- String.format(VALUE_N_DP, marginTop));
- marginTop = 0;
- }
- } else {
- assert false;
- }
- } else if (!view.isConstrainedVertically()) {
- view.addVerticalConstraint(ATTR_LAYOUT_ALIGN_TOP, firstId);
- }
- }
- }
-
- // Figure out edge for the next row
- View view = grid.findBottomEdgeView(row);
- if (view != null) {
- assert view.getId() != null;
- attachTopProperty = ATTR_LAYOUT_BELOW;
- attachTopValue = view.getId();
- marginTop = 0;
- } else if (marginTop == 0) {
- marginTop = grid.getRowHeight(row);
- }
- }
- }
-
- /**
- * Searches a view hierarchy and locates the {@link CanvasViewInfo} for the given
- * {@link Element}
- *
- * @param info the root {@link CanvasViewInfo} to search below
- * @param element the target element
- * @return the {@link CanvasViewInfo} which corresponds to the given element
- */
- private CanvasViewInfo findViewForElement(CanvasViewInfo info, Element element) {
- if (getElement(info) == element) {
- return info;
- }
-
- for (CanvasViewInfo child : info.getChildren()) {
- CanvasViewInfo result = findViewForElement(child, element);
- if (result != null) {
- return result;
- }
- }
-
- return null;
- }
-
- /** Returns the {@link Element} for the given {@link CanvasViewInfo} */
- private static Element getElement(CanvasViewInfo info) {
- Node node = info.getUiViewNode().getXmlNode();
- if (node instanceof Element) {
- return (Element) node;
- }
-
- return null;
- }
-
- /**
- * A grid of cells which can contain views, used to infer spatial relationships when
- * computing constraints. Note that a view can appear in than one cell; they will
- * appear in all cells that their bounds overlap with!
- */
- private class Grid {
- private final int[] mLeft;
- private final int[] mTop;
- // A list from row to column to cell, where a cell is a list of views
- private final List<List<List<View>>> mRowList;
- private int mRowCount;
- private int mColCount;
-
- Grid(List<View> views, int[] left, int[] top) {
- mLeft = left;
- mTop = top;
-
- // The left/top arrays should include the ending point too
- mColCount = left.length - 1;
- mRowCount = top.length - 1;
-
- // Using nested lists rather than arrays to avoid lack of typed arrays
- // (can't create List<View>[row][column] arrays)
- mRowList = new ArrayList<List<List<View>>>(top.length);
- for (int row = 0; row < top.length; row++) {
- List<List<View>> columnList = new ArrayList<List<View>>(left.length);
- for (int col = 0; col < left.length; col++) {
- columnList.add(new ArrayList<View>(4));
- }
- mRowList.add(columnList);
- }
-
- for (View view : views) {
- // Get rid of the root view; we don't want that in the attachments logic;
- // it was there originally such that it would contribute the outermost
- // edges.
- if (view.mElement == mLayout) {
- continue;
- }
-
- for (int i = 0; i < view.mRowSpan; i++) {
- for (int j = 0; j < view.mColSpan; j++) {
- mRowList.get(view.mRow + i).get(view.mCol + j).add(view);
- }
- }
- }
- }
-
- /**
- * Returns the number of rows in the grid
- *
- * @return the row count
- */
- public int getRows() {
- return mRowCount;
- }
-
- /**
- * Returns the number of columns in the grid
- *
- * @return the column count
- */
- public int getColumns() {
- return mColCount;
- }
-
- /**
- * Returns the list of views overlapping the given cell
- *
- * @param row the row of the target cell
- * @param col the column of the target cell
- * @return a list of views overlapping the given column
- */
- public List<View> get(int row, int col) {
- return mRowList.get(row).get(col);
- }
-
- /**
- * Returns true if the given column contains a top left corner of a view
- *
- * @param column the column to check
- * @return true if one or more views have their top left corner in this column
- */
- public boolean colContainsTopLeftCorner(int column) {
- for (int row = 0; row < mRowCount; row++) {
- View view = getTopLeftCorner(row, column);
- if (view != null) {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * Returns true if the given row contains a top left corner of a view
- *
- * @param row the row to check
- * @return true if one or more views have their top left corner in this row
- */
- public boolean rowContainsTopLeftCorner(int row) {
- for (int col = 0; col < mColCount; col++) {
- View view = getTopLeftCorner(row, col);
- if (view != null) {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * Returns a list of views (optionally sorted by increasing row index) that have
- * their left edge starting in the given column
- *
- * @param col the column to look up views for
- * @param sort whether to sort the result in increasing row order
- * @return a list of views starting in the given column
- */
- public List<View> viewsStartingInCol(int col, boolean sort) {
- List<View> views = new ArrayList<View>();
- for (int row = 0; row < mRowCount; row++) {
- View view = getTopLeftCorner(row, col);
- if (view != null) {
- views.add(view);
- }
- }
-
- if (sort) {
- View.sortByRow(views);
- }
-
- return views;
- }
-
- /**
- * Returns a list of views (optionally sorted by increasing column index) that have
- * their top edge starting in the given row
- *
- * @param row the row to look up views for
- * @param sort whether to sort the result in increasing column order
- * @return a list of views starting in the given row
- */
- public List<View> viewsStartingInRow(int row, boolean sort) {
- List<View> views = new ArrayList<View>();
- for (int col = 0; col < mColCount; col++) {
- View view = getTopLeftCorner(row, col);
- if (view != null) {
- views.add(view);
- }
- }
-
- if (sort) {
- View.sortByColumn(views);
- }
-
- return views;
- }
-
- /**
- * Returns the pixel width of the given column
- *
- * @param col the column to look up the width of
- * @return the width of the column
- */
- public int getColumnWidth(int col) {
- return mLeft[col + 1] - mLeft[col];
- }
-
- /**
- * Returns the pixel height of the given row
- *
- * @param row the row to look up the height of
- * @return the height of the row
- */
- public int getRowHeight(int row) {
- return mTop[row + 1] - mTop[row];
- }
-
- /**
- * Returns the first view found that has its top left corner in the cell given by
- * the row and column indexes, or null if not found.
- *
- * @param row the row of the target cell
- * @param col the column of the target cell
- * @return a view with its top left corner in the given cell, or null if not found
- */
- View getTopLeftCorner(int row, int col) {
- List<View> views = get(row, col);
- if (views.size() > 0) {
- for (View view : views) {
- if (view.mRow == row && view.mCol == col) {
- return view;
- }
- }
- }
-
- return null;
- }
-
- public View findRightEdgeView(int col) {
- for (int row = 0; row < mRowCount; row++) {
- List<View> views = get(row, col);
- if (views.size() > 0) {
- List<View> result = new ArrayList<View>();
- for (View view : views) {
- // Ends on the right edge of this column?
- if (view.mCol + view.mColSpan == col + 1) {
- result.add(view);
- }
- }
- if (result.size() > 1) {
- View.sortByColumn(result);
- }
- if (result.size() > 0) {
- return result.get(0);
- }
- }
- }
-
- return null;
- }
-
- public View findBottomEdgeView(int row) {
- for (int col = 0; col < mColCount; col++) {
- List<View> views = get(row, col);
- if (views.size() > 0) {
- List<View> result = new ArrayList<View>();
- for (View view : views) {
- // Ends on the bottom edge of this column?
- if (view.mRow + view.mRowSpan == row + 1) {
- result.add(view);
- }
- }
- if (result.size() > 1) {
- View.sortByRow(result);
- }
- if (result.size() > 0) {
- return result.get(0);
- }
-
- }
- }
-
- return null;
- }
-
- /**
- * Produces a display of view contents along with the pixel positions of each row/column,
- * like the following (used for diagnostics only)
- * <pre>
- * |0 |49 |143 |192 |240
- * 36| | |button2 |
- * 72| |radioButton1 |button2 |
- * 74|button1 |radioButton1 |button2 |
- * 108|button1 | |button2 |
- * 110| | |button2 |
- * 149| | | |
- * 320
- * </pre>
- */
- @Override
- public String toString() {
- // Dump out the view table
- int cellWidth = 20;
-
- StringWriter stringWriter = new StringWriter();
- PrintWriter out = new PrintWriter(stringWriter);
- out.printf("%" + cellWidth + "s", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- for (int col = 0; col < mColCount + 1; col++) {
- out.printf("|%-" + (cellWidth - 1) + "d", mLeft[col]); //$NON-NLS-1$ //$NON-NLS-2$
- }
- out.printf("\n"); //$NON-NLS-1$
- for (int row = 0; row < mRowCount + 1; row++) {
- out.printf("%" + cellWidth + "d", mTop[row]); //$NON-NLS-1$ //$NON-NLS-2$
- if (row == mRowCount) {
- break;
- }
- for (int col = 0; col < mColCount; col++) {
- List<View> views = get(row, col);
- StringBuilder sb = new StringBuilder();
- for (View view : views) {
- String id = view != null ? view.getId() : ""; //$NON-NLS-1$
- if (id.startsWith(NEW_ID_PREFIX)) {
- id = id.substring(NEW_ID_PREFIX.length());
- }
- if (id.length() > cellWidth - 2) {
- id = id.substring(0, cellWidth - 2);
- }
- if (sb.length() > 0) {
- sb.append(',');
- }
- sb.append(id);
- }
- String cellString = sb.toString();
- if (cellString.contains(",") && cellString.length() > cellWidth - 2) { //$NON-NLS-1$
- cellString = cellString.substring(0, cellWidth - 6) + "...,"; //$NON-NLS-1$
- }
- out.printf("|%-" + (cellWidth - 2) + "s ", cellString); //$NON-NLS-1$ //$NON-NLS-2$
- }
- out.printf("\n"); //$NON-NLS-1$
- }
-
- out.flush();
- return stringWriter.toString();
- }
- }
-
- /** Holds layout information about an individual view. */
- private static class View {
- private final Element mElement;
- private int mRow = -1;
- private int mCol = -1;
- private int mRowSpan = -1;
- private int mColSpan = -1;
- private CanvasViewInfo mInfo;
- private String mId;
- private List<Pair<String, String>> mHorizConstraints =
- new ArrayList<Pair<String, String>>(4);
- private List<Pair<String, String>> mVerticalConstraints =
- new ArrayList<Pair<String, String>>(4);
- private int mGravity;
-
- public View(CanvasViewInfo view, Element element) {
- mInfo = view;
- mElement = element;
- mGravity = GravityHelper.getGravity(element);
- }
-
- public int getHeight() {
- return mInfo.getAbsRect().height;
- }
-
- public int getGravity() {
- return mGravity;
- }
-
- public String getId() {
- return mId;
- }
-
- public Element getElement() {
- return mElement;
- }
-
- public List<Pair<String, String>> getHorizConstraints() {
- return mHorizConstraints;
- }
-
- public List<Pair<String, String>> getVerticalConstraints() {
- return mVerticalConstraints;
- }
-
- public boolean isConstrainedHorizontally() {
- return mHorizConstraints.size() > 0;
- }
-
- public boolean isConstrainedVertically() {
- return mVerticalConstraints.size() > 0;
- }
-
- public void addHorizConstraint(String property, String value) {
- assert property != null && value != null;
- // TODO - look for duplicates?
- mHorizConstraints.add(Pair.of(property, value));
- }
-
- public void addVerticalConstraint(String property, String value) {
- assert property != null && value != null;
- mVerticalConstraints.add(Pair.of(property, value));
- }
-
- public int getLeftEdge() {
- return mInfo.getAbsRect().x;
- }
-
- public int getTopEdge() {
- return mInfo.getAbsRect().y;
- }
-
- public int getRightEdge() {
- Rectangle bounds = mInfo.getAbsRect();
- // +1: make the bounds overlap, so the right edge is the same as the
- // left edge of the neighbor etc. Otherwise we end up with lots of 1-pixel wide
- // columns between adjacent items.
- return bounds.x + bounds.width + 1;
- }
-
- public int getBottomEdge() {
- Rectangle bounds = mInfo.getAbsRect();
- return bounds.y + bounds.height + 1;
- }
-
- @Override
- public String toString() {
- return "View [mId=" + mId + "]"; //$NON-NLS-1$ //$NON-NLS-2$
- }
-
- public static void sortByRow(List<View> views) {
- Collections.sort(views, new ViewComparator(true/*rowSort*/));
- }
-
- public static void sortByColumn(List<View> views) {
- Collections.sort(views, new ViewComparator(false/*rowSort*/));
- }
-
- /** Comparator to help sort views by row or column index */
- private static class ViewComparator implements Comparator<View> {
- boolean mRowSort;
-
- public ViewComparator(boolean rowSort) {
- mRowSort = rowSort;
- }
-
- @Override
- public int compare(View view1, View view2) {
- if (mRowSort) {
- return view1.mRow - view2.mRow;
- } else {
- return view1.mCol - view2.mCol;
- }
- }
- }
- }
-
- /**
- * An edge list takes a hierarchy of elements and records the bounds of each element
- * into various lists such that it can answer queries about shared edges, about which
- * particular pixels occur as a boundary edge, etc.
- */
- private class EdgeList {
- private final Map<Element, View> mElementToViewMap = new HashMap<Element, View>(100);
- private final Map<String, View> mIdToViewMap = new HashMap<String, View>(100);
- private final Map<Integer, List<View>> mLeft = new HashMap<Integer, List<View>>();
- private final Map<Integer, List<View>> mTop = new HashMap<Integer, List<View>>();
- private final Map<Integer, List<View>> mRight = new HashMap<Integer, List<View>>();
- private final Map<Integer, List<View>> mBottom = new HashMap<Integer, List<View>>();
- private final Map<Element, Element> mSharedLeftEdge = new HashMap<Element, Element>();
- private final Map<Element, Element> mSharedTopEdge = new HashMap<Element, Element>();
- private final Map<Element, Element> mSharedRightEdge = new HashMap<Element, Element>();
- private final Map<Element, Element> mSharedBottomEdge = new HashMap<Element, Element>();
- private final List<Element> mDelete = new ArrayList<Element>();
-
- EdgeList(CanvasViewInfo view) {
- analyze(view, true);
- mDelete.remove(getElement(view));
- }
-
- public void setIdAttributeValue(View view, String id) {
- assert id.startsWith(NEW_ID_PREFIX) || id.startsWith(ID_PREFIX);
- view.mId = id;
- mIdToViewMap.put(getIdBasename(id), view);
- }
-
- public View getView(Element element) {
- return mElementToViewMap.get(element);
- }
-
- public View getView(String id) {
- return mIdToViewMap.get(id);
- }
-
- public List<View> getTopEdgeViews(Integer topOffset) {
- return mTop.get(topOffset);
- }
-
- public List<View> getLeftEdgeViews(Integer leftOffset) {
- return mLeft.get(leftOffset);
- }
-
- void record(Map<Integer, List<View>> map, Integer edge, View info) {
- List<View> list = map.get(edge);
- if (list == null) {
- list = new ArrayList<View>();
- map.put(edge, list);
- }
- list.add(info);
- }
-
- private List<Integer> getOffsets(Set<Integer> first, Set<Integer> second) {
- Set<Integer> joined = new HashSet<Integer>(first.size() + second.size());
- joined.addAll(first);
- joined.addAll(second);
- List<Integer> unique = new ArrayList<Integer>(joined);
- Collections.sort(unique);
-
- return unique;
- }
-
- public List<Element> getDeletedElements() {
- return mDelete;
- }
-
- public List<Integer> getColumnOffsets() {
- return getOffsets(mLeft.keySet(), mRight.keySet());
- }
- public List<Integer> getRowOffsets() {
- return getOffsets(mTop.keySet(), mBottom.keySet());
- }
-
- private View analyze(CanvasViewInfo view, boolean isRoot) {
- View added = null;
- if (!mFlatten || !isRemovableLayout(view)) {
- added = add(view);
- if (!isRoot) {
- return added;
- }
- } else {
- mDelete.add(getElement(view));
- }
-
- Element parentElement = getElement(view);
- Rectangle parentBounds = view.getAbsRect();
-
- // Build up a table model of the view
- for (CanvasViewInfo child : view.getChildren()) {
- Rectangle childBounds = child.getAbsRect();
- Element childElement = getElement(child);
-
- // See if this view shares the edge with the removed
- // parent layout, and if so, record that such that we can
- // later handle attachments to the removed parent edges
- if (parentBounds.x == childBounds.x) {
- mSharedLeftEdge.put(childElement, parentElement);
- }
- if (parentBounds.y == childBounds.y) {
- mSharedTopEdge.put(childElement, parentElement);
- }
- if (parentBounds.x + parentBounds.width == childBounds.x + childBounds.width) {
- mSharedRightEdge.put(childElement, parentElement);
- }
- if (parentBounds.y + parentBounds.height == childBounds.y + childBounds.height) {
- mSharedBottomEdge.put(childElement, parentElement);
- }
-
- if (mFlatten && isRemovableLayout(child)) {
- // When flattening, we want to disregard all layouts and instead
- // add their children!
- for (CanvasViewInfo childView : child.getChildren()) {
- analyze(childView, false);
-
- Element childViewElement = getElement(childView);
- Rectangle childViewBounds = childView.getAbsRect();
-
- // See if this view shares the edge with the removed
- // parent layout, and if so, record that such that we can
- // later handle attachments to the removed parent edges
- if (parentBounds.x == childViewBounds.x) {
- mSharedLeftEdge.put(childViewElement, parentElement);
- }
- if (parentBounds.y == childViewBounds.y) {
- mSharedTopEdge.put(childViewElement, parentElement);
- }
- if (parentBounds.x + parentBounds.width == childViewBounds.x
- + childViewBounds.width) {
- mSharedRightEdge.put(childViewElement, parentElement);
- }
- if (parentBounds.y + parentBounds.height == childViewBounds.y
- + childViewBounds.height) {
- mSharedBottomEdge.put(childViewElement, parentElement);
- }
- }
- mDelete.add(childElement);
- } else {
- analyze(child, false);
- }
- }
-
- return added;
- }
-
- public View getSharedLeftEdge(Element element) {
- return getSharedEdge(element, mSharedLeftEdge);
- }
-
- public View getSharedRightEdge(Element element) {
- return getSharedEdge(element, mSharedRightEdge);
- }
-
- public View getSharedTopEdge(Element element) {
- return getSharedEdge(element, mSharedTopEdge);
- }
-
- public View getSharedBottomEdge(Element element) {
- return getSharedEdge(element, mSharedBottomEdge);
- }
-
- private View getSharedEdge(Element element, Map<Element, Element> sharedEdgeMap) {
- Element original = element;
-
- while (element != null) {
- View view = getView(element);
- if (view != null) {
- assert isAncestor(element, original);
- return view;
- }
- element = sharedEdgeMap.get(element);
- }
-
- return null;
- }
-
- private View add(CanvasViewInfo info) {
- Rectangle bounds = info.getAbsRect();
- Element element = getElement(info);
- View view = new View(info, element);
- mElementToViewMap.put(element, view);
- record(mLeft, Integer.valueOf(bounds.x), view);
- record(mTop, Integer.valueOf(bounds.y), view);
- record(mRight, Integer.valueOf(view.getRightEdge()), view);
- record(mBottom, Integer.valueOf(view.getBottomEdge()), view);
- return view;
- }
-
- /**
- * Returns true if the given {@link CanvasViewInfo} represents an element we
- * should remove in a flattening conversion. We don't want to remove non-layout
- * views, or layout views that for example contain drawables on their own.
- */
- private boolean isRemovableLayout(CanvasViewInfo child) {
- // The element being converted is NOT removable!
- Element element = getElement(child);
- if (element == mLayout) {
- return false;
- }
-
- ElementDescriptor descriptor = child.getUiViewNode().getDescriptor();
- String name = descriptor.getXmlLocalName();
- if (name.equals(LINEAR_LAYOUT) || name.equals(RELATIVE_LAYOUT)) {
- // Don't delete layouts that provide a background image or gradient
- if (element.hasAttributeNS(ANDROID_URI, ATTR_BACKGROUND)) {
- AdtPlugin.log(IStatus.WARNING,
- "Did not flatten layout %1$s because it defines a '%2$s' attribute",
- VisualRefactoring.getId(element), ATTR_BACKGROUND);
- return false;
- }
-
- return true;
- }
-
- return false;
- }
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UnwrapAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UnwrapAction.java
deleted file mode 100644
index 02c2a276c..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UnwrapAction.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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.eclipse.adt.internal.editors.layout.LayoutEditorDelegate;
-
-import org.eclipse.jface.action.IAction;
-import org.eclipse.ltk.ui.refactoring.RefactoringWizard;
-import org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation;
-
-/**
- * Action executed when the "Remove Container" menu item is invoked.
- */
-public class UnwrapAction extends VisualRefactoringAction {
- @Override
- public void run(IAction action) {
- if ((mTextSelection != null || mTreeSelection != null) && mFile != null) {
- UnwrapRefactoring ref = new UnwrapRefactoring(mFile, mDelegate,
- mTextSelection, mTreeSelection);
- RefactoringWizard wizard = new UnwrapWizard(ref, mDelegate);
- RefactoringWizardOpenOperation op = new RefactoringWizardOpenOperation(wizard);
- try {
- op.run(mWindow.getShell(), wizard.getDefaultPageTitle());
- } catch (InterruptedException e) {
- // Interrupted. Pass.
- }
- }
- }
-
- public static IAction create(LayoutEditorDelegate editorDelegate) {
- return create("Remove Container...", editorDelegate, UnwrapAction.class);
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UnwrapContribution.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UnwrapContribution.java
deleted file mode 100644
index 0869fd637..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UnwrapContribution.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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 org.eclipse.ltk.core.refactoring.RefactoringContribution;
-import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
-
-import java.util.Map;
-
-public class UnwrapContribution extends RefactoringContribution {
-
- @SuppressWarnings("unchecked")
- @Override
- public RefactoringDescriptor createDescriptor(String id, String project, String description,
- String comment, Map arguments, int flags) throws IllegalArgumentException {
- return new UnwrapRefactoring.Descriptor(project, description, comment, arguments);
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public Map retrieveArgumentMap(RefactoringDescriptor descriptor) {
- if (descriptor instanceof UnwrapRefactoring.Descriptor) {
- return ((UnwrapRefactoring.Descriptor) descriptor).getArguments();
- }
- return super.retrieveArgumentMap(descriptor);
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UnwrapRefactoring.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UnwrapRefactoring.java
deleted file mode 100644
index 4eff2cde5..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UnwrapRefactoring.java
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * 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 static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.ATTR_LAYOUT_HEIGHT;
-import static com.android.SdkConstants.ATTR_LAYOUT_WIDTH;
-import static com.android.SdkConstants.EXT_XML;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.VisibleForTesting;
-import com.android.ide.common.xml.XmlFormatStyle;
-import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditorDelegate;
-import com.android.ide.eclipse.adt.internal.editors.layout.gle2.DomUtilities;
-
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.OperationCanceledException;
-import org.eclipse.jface.text.ITextSelection;
-import org.eclipse.jface.viewers.ITreeSelection;
-import org.eclipse.ltk.core.refactoring.Change;
-import org.eclipse.ltk.core.refactoring.Refactoring;
-import org.eclipse.ltk.core.refactoring.RefactoringStatus;
-import org.eclipse.ltk.core.refactoring.TextFileChange;
-import org.eclipse.text.edits.MultiTextEdit;
-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.Node;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Removes the layout surrounding the current selection (or if the current selection has
- * children, removes the current layout), and migrates namespace and layout attributes.
- */
-@SuppressWarnings("restriction") // XML model
-public class UnwrapRefactoring extends VisualRefactoring {
- private Element mContainer;
-
- /**
- * This constructor is solely used by {@link Descriptor},
- * to replay a previous refactoring.
- * @param arguments argument map created by #createArgumentMap.
- */
- UnwrapRefactoring(Map<String, String> arguments) {
- super(arguments);
- }
-
- public UnwrapRefactoring(
- IFile file,
- LayoutEditorDelegate delegate,
- ITextSelection selection,
- ITreeSelection treeSelection) {
- super(file, delegate, selection, treeSelection);
- }
-
- @VisibleForTesting
- UnwrapRefactoring(List<Element> selectedElements, LayoutEditorDelegate editor) {
- super(selectedElements, editor);
- }
-
- @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 wrap");
- return status;
- }
-
- // Make sure that the selection all has the same parent?
- if (mElements.size() == 0) {
- status.addFatalError("Nothing to unwrap");
- return status;
- }
-
- Element first = mElements.get(0);
-
- // Determine the element of the container to be removed.
- // If you've selected a non-container, or you've selected multiple
- // elements, then it's the parent which should be removed. Otherwise,
- // it's the selection itself which represents the container.
- boolean useParent = mElements.size() > 1;
- if (!useParent) {
- if (DomUtilities.getChildren(first).size() == 0) {
- useParent = true;
- }
- }
- Node parent = first.getParentNode();
- if (parent instanceof Document) {
- mContainer = first;
- List<Element> elements = DomUtilities.getChildren(mContainer);
- if (elements.size() == 0) {
- status.addFatalError(
- "Cannot remove container when it has no children");
- return status;
- }
- } else if (useParent && (parent instanceof Element)) {
- mContainer = (Element) parent;
- } else {
- mContainer = first;
- }
-
- for (Element element : mElements) {
- if (element.getParentNode() != parent) {
- status.addFatalError(
- "All unwrapped elements must share the same parent element");
- return status;
- }
- }
-
- // Ensure that if we are removing the root, that it has only one child
- // such that there is a new single root
- if (mContainer.getParentNode() instanceof Document) {
- if (DomUtilities.getChildren(mContainer).size() > 1) {
- status.addFatalError(
- "Cannot remove root: it has more than one child "
- + "which would result in multiple new roots");
- return status;
- }
- }
-
- pm.worked(1);
- return status;
-
- } finally {
- pm.done();
- }
- }
-
- @Override
- protected VisualRefactoringDescriptor createDescriptor() {
- String comment = getName();
- return new Descriptor(
- mProject.getName(), //project
- comment, //description
- comment, //comment
- createArgumentMap());
- }
-
- @Override
- public String getName() {
- return "Remove Container";
- }
-
- @Override
- protected @NonNull List<Change> computeChanges(IProgressMonitor monitor) {
- // (1) If the removed parent is the root container, transfer its
- // namespace declarations
- // (2) Remove the root element completely
- // (3) Transfer layout attributes?
- // (4) Check for Java R.file usages?
-
- IFile file = mDelegate.getEditor().getInputFile();
- List<Change> changes = new ArrayList<Change>();
- if (file == null) {
- return changes;
- }
- MultiTextEdit rootEdit = new MultiTextEdit();
-
- // Transfer namespace elements?
- if (mContainer.getParentNode() instanceof Document) {
- List<Element> elements = DomUtilities.getChildren(mContainer);
- assert elements.size() == 1;
- Element newRoot = elements.get(0);
-
- List<Attr> declarations = findNamespaceAttributes(mContainer);
- for (Attr attribute : declarations) {
- if (attribute instanceof IndexedRegion) {
- setAttribute(rootEdit, newRoot, attribute.getNamespaceURI(),
- attribute.getPrefix(), attribute.getLocalName(), attribute.getValue());
- }
- }
- }
-
- // Transfer layout_ attributes (other than width and height)
- List<Element> children = DomUtilities.getChildren(mContainer);
- if (children.size() == 1) {
- List<Attr> layoutAttributes = findLayoutAttributes(mContainer);
- for (Attr attribute : layoutAttributes) {
- String name = attribute.getLocalName();
- if ((name.equals(ATTR_LAYOUT_WIDTH) || name.equals(ATTR_LAYOUT_HEIGHT))
- && ANDROID_URI.equals(attribute.getNamespaceURI())) {
- // Already handled specially
- continue;
- }
- }
- }
-
- // Remove the root
- removeElementTags(rootEdit, mContainer, Collections.<Element>emptyList() /* skip */,
- false /*changeIndentation*/);
-
- MultiTextEdit formatted = reformat(rootEdit, XmlFormatStyle.LAYOUT);
- if (formatted != null) {
- rootEdit = formatted;
- }
-
- TextFileChange change = new TextFileChange(file.getName(), file);
- change.setEdit(rootEdit);
- change.setTextType(EXT_XML);
- changes.add(change);
- return changes;
- }
-
- @Override
- public VisualRefactoringWizard createWizard() {
- return new UnwrapWizard(this, mDelegate);
- }
-
- public static class Descriptor extends VisualRefactoringDescriptor {
- public Descriptor(String project, String description, String comment,
- Map<String, String> arguments) {
- super("com.android.ide.eclipse.adt.refactoring.unwrap", //$NON-NLS-1$
- project, description, comment, arguments);
- }
-
- @Override
- protected Refactoring createRefactoring(Map<String, String> args) {
- return new UnwrapRefactoring(args);
- }
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UnwrapWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UnwrapWizard.java
deleted file mode 100644
index 6e3bcf1e7..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UnwrapWizard.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * 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.eclipse.adt.internal.editors.layout.LayoutEditorDelegate;
-
-public class UnwrapWizard extends VisualRefactoringWizard {
- public UnwrapWizard(UnwrapRefactoring ref, LayoutEditorDelegate editor) {
- super(ref, editor);
- setDefaultPageTitle("Remove Container");
- }
-
- @Override
- protected void addUserInputPages() {
- // This refactoring takes no parameters
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UseCompoundDrawableAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UseCompoundDrawableAction.java
deleted file mode 100644
index 84d3e7ee8..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UseCompoundDrawableAction.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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.eclipse.adt.internal.editors.layout.LayoutEditorDelegate;
-
-import org.eclipse.jface.action.IAction;
-import org.eclipse.ltk.ui.refactoring.RefactoringWizard;
-import org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation;
-
-/**
- * Action executed when the "Convert Layout" menu item is invoked.
- */
-public class UseCompoundDrawableAction extends VisualRefactoringAction {
- @Override
- public void run(IAction action) {
- if ((mTextSelection != null || mTreeSelection != null) && mFile != null) {
- UseCompoundDrawableRefactoring ref = new UseCompoundDrawableRefactoring(
- mFile, mDelegate, mTextSelection, mTreeSelection);
- RefactoringWizard wizard = new UseCompoundDrawableWizard(ref, mDelegate);
- RefactoringWizardOpenOperation op = new RefactoringWizardOpenOperation(wizard);
- try {
- op.run(mWindow.getShell(), wizard.getDefaultPageTitle());
- } catch (InterruptedException e) {
- // Interrupted. Pass.
- }
- }
- }
-
- public static IAction create(LayoutEditorDelegate editorDelegate) {
- return create("Convert to a Compound Drawable...", editorDelegate,
- UseCompoundDrawableAction.class);
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UseCompoundDrawableRefactoring.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UseCompoundDrawableRefactoring.java
deleted file mode 100644
index 0e56bdf4d..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UseCompoundDrawableRefactoring.java
+++ /dev/null
@@ -1,452 +0,0 @@
-/*
- * Copyright (C) 2012 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 static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.ATTR_DRAWABLE_BOTTOM;
-import static com.android.SdkConstants.ATTR_DRAWABLE_LEFT;
-import static com.android.SdkConstants.ATTR_DRAWABLE_PADDING;
-import static com.android.SdkConstants.ATTR_DRAWABLE_RIGHT;
-import static com.android.SdkConstants.ATTR_DRAWABLE_TOP;
-import static com.android.SdkConstants.ATTR_GRAVITY;
-import static com.android.SdkConstants.ATTR_ID;
-import static com.android.SdkConstants.ATTR_LAYOUT_HEIGHT;
-import static com.android.SdkConstants.ATTR_LAYOUT_MARGIN_BOTTOM;
-import static com.android.SdkConstants.ATTR_LAYOUT_MARGIN_LEFT;
-import static com.android.SdkConstants.ATTR_LAYOUT_MARGIN_RIGHT;
-import static com.android.SdkConstants.ATTR_LAYOUT_MARGIN_TOP;
-import static com.android.SdkConstants.ATTR_LAYOUT_RESOURCE_PREFIX;
-import static com.android.SdkConstants.ATTR_LAYOUT_WIDTH;
-import static com.android.SdkConstants.ATTR_ORIENTATION;
-import static com.android.SdkConstants.ATTR_SRC;
-import static com.android.SdkConstants.EXT_XML;
-import static com.android.SdkConstants.IMAGE_VIEW;
-import static com.android.SdkConstants.LINEAR_LAYOUT;
-import static com.android.SdkConstants.PREFIX_RESOURCE_REF;
-import static com.android.SdkConstants.TEXT_VIEW;
-import static com.android.SdkConstants.VALUE_VERTICAL;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.annotations.VisibleForTesting;
-import com.android.ide.common.xml.XmlFormatStyle;
-import com.android.ide.eclipse.adt.AdtUtils;
-import com.android.ide.eclipse.adt.internal.editors.formatting.EclipseXmlFormatPreferences;
-import com.android.ide.eclipse.adt.internal.editors.formatting.EclipseXmlPrettyPrinter;
-import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditorDelegate;
-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.preferences.AdtPrefs;
-
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.OperationCanceledException;
-import org.eclipse.jface.text.ITextSelection;
-import org.eclipse.jface.viewers.ITreeSelection;
-import org.eclipse.ltk.core.refactoring.Change;
-import org.eclipse.ltk.core.refactoring.Refactoring;
-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.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.NamedNodeMap;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Converts a LinearLayout with exactly a TextView child and an ImageView child into
- * a single TextView with a compound drawable.
- */
-@SuppressWarnings("restriction") // XML model
-public class UseCompoundDrawableRefactoring extends VisualRefactoring {
- /**
- * Constructs a new {@link UseCompoundDrawableRefactoring}
- *
- * @param file the file to refactor in
- * @param editor the corresponding editor
- * @param selection the editor selection, or null
- * @param treeSelection the canvas selection, or null
- */
- public UseCompoundDrawableRefactoring(IFile file, LayoutEditorDelegate editor,
- ITextSelection selection, ITreeSelection treeSelection) {
- super(file, editor, selection, treeSelection);
- }
-
- /**
- * This constructor is solely used by {@link Descriptor}, to replay a
- * previous refactoring.
- *
- * @param arguments argument map created by #createArgumentMap.
- */
- private UseCompoundDrawableRefactoring(Map<String, String> arguments) {
- super(arguments);
- }
-
- @VisibleForTesting
- UseCompoundDrawableRefactoring(List<Element> selectedElements, LayoutEditorDelegate editor) {
- super(selectedElements, editor);
- }
-
- @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("Nothing to convert");
- return status;
- }
-
- // Make sure the selection is contiguous
- if (mTreeSelection != null) {
- List<CanvasViewInfo> infos = getSelectedViewInfos();
- if (!validateNotEmpty(infos, status)) {
- return status;
- }
-
- // Enforce that the selection is -contiguous-
- if (!validateContiguous(infos, status)) {
- return status;
- }
- }
-
- // Ensures that we have a valid DOM model:
- if (mElements.size() == 0) {
- status.addFatalError("Nothing to convert");
- return status;
- }
-
- // Ensure that we have selected precisely one LinearLayout
- if (mElements.size() != 1 ||
- !(mElements.get(0).getTagName().equals(LINEAR_LAYOUT))) {
- status.addFatalError("Must select exactly one LinearLayout");
- return status;
- }
-
- Element layout = mElements.get(0);
- List<Element> children = DomUtilities.getChildren(layout);
- if (children.size() != 2) {
- status.addFatalError("The LinearLayout must have exactly two children");
- return status;
- }
- Element first = children.get(0);
- Element second = children.get(1);
- boolean haveTextView =
- first.getTagName().equals(TEXT_VIEW)
- || second.getTagName().equals(TEXT_VIEW);
- boolean haveImageView =
- first.getTagName().equals(IMAGE_VIEW)
- || second.getTagName().equals(IMAGE_VIEW);
- if (!(haveTextView && haveImageView)) {
- status.addFatalError("The LinearLayout must have exactly one TextView child " +
- "and one ImageView child");
- return status;
- }
-
- pm.worked(1);
- return status;
-
- } finally {
- pm.done();
- }
- }
-
- @Override
- protected VisualRefactoringDescriptor createDescriptor() {
- String comment = getName();
- return new Descriptor(
- mProject.getName(), //project
- comment, //description
- comment, //comment
- createArgumentMap());
- }
-
- @Override
- protected Map<String, String> createArgumentMap() {
- return super.createArgumentMap();
- }
-
- @Override
- public String getName() {
- return "Convert to Compound Drawable";
- }
-
- @Override
- protected @NonNull List<Change> computeChanges(IProgressMonitor monitor) {
- String androidNsPrefix = getAndroidNamespacePrefix();
- IFile file = mDelegate.getEditor().getInputFile();
- List<Change> changes = new ArrayList<Change>();
- if (file == null) {
- return changes;
- }
- TextFileChange change = new TextFileChange(file.getName(), file);
- MultiTextEdit rootEdit = new MultiTextEdit();
- change.setTextType(EXT_XML);
-
- // (1) Build up the contents of the new TextView. This is identical
- // to the old contents, but with the addition of a drawableTop/Left/Right/Bottom
- // attribute (depending on the orientation and order), as well as any layout
- // params from the LinearLayout.
- // (2) Delete the linear layout and replace with the text view.
- // (3) Reformat.
-
- // checkInitialConditions has already validated that we have exactly a LinearLayout
- // with an ImageView and a TextView child (in either order)
- Element layout = mElements.get(0);
- List<Element> children = DomUtilities.getChildren(layout);
- Element first = children.get(0);
- Element second = children.get(1);
- final Element text;
- final Element image;
- if (first.getTagName().equals(TEXT_VIEW)) {
- text = first;
- image = second;
- } else {
- text = second;
- image = first;
- }
-
- // Horizontal is the default, so if no value is specified it is horizontal.
- boolean isVertical = VALUE_VERTICAL.equals(layout.getAttributeNS(ANDROID_URI,
- ATTR_ORIENTATION));
-
- // The WST DOM implementation doesn't correctly implement cloneNode: this returns
- // an empty document instead:
- // text.getOwnerDocument().cloneNode(false/*deep*/);
- // Luckily we just need to clone a single element, not a nested structure, so it's
- // easy enough to do this manually:
- Document tempDocument = DomUtilities.createEmptyDocument();
- if (tempDocument == null) {
- return changes;
- }
- Element newTextElement = tempDocument.createElement(text.getTagName());
- tempDocument.appendChild(newTextElement);
-
- NamedNodeMap attributes = text.getAttributes();
- for (int i = 0, n = attributes.getLength(); i < n; i++) {
- Attr attribute = (Attr) attributes.item(i);
- String name = attribute.getLocalName();
- if (name.startsWith(ATTR_LAYOUT_RESOURCE_PREFIX)
- && ANDROID_URI.equals(attribute.getNamespaceURI())
- && !(name.equals(ATTR_LAYOUT_WIDTH) || name.equals(ATTR_LAYOUT_HEIGHT))) {
- // Ignore layout params: the parent layout is going away
- } else {
- newTextElement.setAttribute(attribute.getName(), attribute.getValue());
- }
- }
-
- // Apply all layout params from the parent (except width and height),
- // as well as android:gravity
- List<Attr> layoutAttributes = findLayoutAttributes(layout);
- for (Attr attribute : layoutAttributes) {
- String name = attribute.getLocalName();
- if ((name.equals(ATTR_LAYOUT_WIDTH) || name.equals(ATTR_LAYOUT_HEIGHT))
- && ANDROID_URI.equals(attribute.getNamespaceURI())) {
- // Already handled specially
- continue;
- }
- newTextElement.setAttribute(attribute.getName(), attribute.getValue());
- }
- String gravity = layout.getAttributeNS(ANDROID_URI, ATTR_GRAVITY);
- if (gravity.length() > 0) {
- setAndroidAttribute(newTextElement, androidNsPrefix, ATTR_GRAVITY, gravity);
- }
-
- String src = image.getAttributeNS(ANDROID_URI, ATTR_SRC);
-
- // Set the drawable
- String drawableAttribute;
- // The space between the image and the text can have margins/padding, both
- // from the text's perspective and from the image's perspective. We need to
- // combine these.
- String padding1 = null;
- String padding2 = null;
- if (isVertical) {
- if (first == image) {
- drawableAttribute = ATTR_DRAWABLE_TOP;
- padding1 = getPadding(image, ATTR_LAYOUT_MARGIN_BOTTOM);
- padding2 = getPadding(text, ATTR_LAYOUT_MARGIN_TOP);
- } else {
- drawableAttribute = ATTR_DRAWABLE_BOTTOM;
- padding1 = getPadding(text, ATTR_LAYOUT_MARGIN_BOTTOM);
- padding2 = getPadding(image, ATTR_LAYOUT_MARGIN_TOP);
- }
- } else {
- if (first == image) {
- drawableAttribute = ATTR_DRAWABLE_LEFT;
- padding1 = getPadding(image, ATTR_LAYOUT_MARGIN_RIGHT);
- padding2 = getPadding(text, ATTR_LAYOUT_MARGIN_LEFT);
- } else {
- drawableAttribute = ATTR_DRAWABLE_RIGHT;
- padding1 = getPadding(text, ATTR_LAYOUT_MARGIN_RIGHT);
- padding2 = getPadding(image, ATTR_LAYOUT_MARGIN_LEFT);
- }
- }
-
- setAndroidAttribute(newTextElement, androidNsPrefix, drawableAttribute, src);
-
- String padding = combine(padding1, padding2);
- if (padding != null) {
- setAndroidAttribute(newTextElement, androidNsPrefix, ATTR_DRAWABLE_PADDING, padding);
- }
-
- // If the removed LinearLayout is the root container, transfer its namespace
- // declaration to the TextView
- if (layout.getParentNode() instanceof Document) {
- List<Attr> declarations = findNamespaceAttributes(layout);
- for (Attr attribute : declarations) {
- if (attribute instanceof IndexedRegion) {
- newTextElement.setAttribute(attribute.getName(), attribute.getValue());
- }
- }
- }
-
- // Update any layout references to the layout to point to the text view
- String layoutId = getId(layout);
- if (layoutId.length() > 0) {
- String id = getId(text);
- if (id.length() == 0) {
- id = ensureHasId(rootEdit, text, null, false);
- setAndroidAttribute(newTextElement, androidNsPrefix, ATTR_ID, id);
- }
-
- IStructuredModel model = mDelegate.getEditor().getModelForRead();
- try {
- IStructuredDocument doc = model.getStructuredDocument();
- if (doc != null) {
- List<TextEdit> replaceIds = replaceIds(androidNsPrefix,
- doc, mSelectionStart, mSelectionEnd, layoutId, id);
- for (TextEdit edit : replaceIds) {
- rootEdit.addChild(edit);
- }
- }
- } finally {
- model.releaseFromRead();
- }
- }
-
- String xml = EclipseXmlPrettyPrinter.prettyPrint(
- tempDocument.getDocumentElement(),
- EclipseXmlFormatPreferences.create(),
- XmlFormatStyle.LAYOUT, null, false);
-
- TextEdit replace = new ReplaceEdit(mSelectionStart, mSelectionEnd - mSelectionStart, xml);
- rootEdit.addChild(replace);
-
- if (AdtPrefs.getPrefs().getFormatGuiXml()) {
- MultiTextEdit formatted = reformat(rootEdit, XmlFormatStyle.LAYOUT);
- if (formatted != null) {
- rootEdit = formatted;
- }
- }
-
- change.setEdit(rootEdit);
- changes.add(change);
- return changes;
- }
-
- @Nullable
- private static String getPadding(@NonNull Element element, @NonNull String attribute) {
- String padding = element.getAttributeNS(ANDROID_URI, attribute);
- if (padding != null && padding.isEmpty()) {
- padding = null;
- }
- return padding;
- }
-
- @VisibleForTesting
- @Nullable
- static String combine(@Nullable String dimension1, @Nullable String dimension2) {
- if (dimension1 == null || dimension1.isEmpty()) {
- if (dimension2 != null && dimension2.isEmpty()) {
- return null;
- }
- return dimension2;
- } else if (dimension2 == null || dimension2.isEmpty()) {
- if (dimension1 != null && dimension1.isEmpty()) {
- return null;
- }
- return dimension1;
- } else {
- // Two dimensions are specified (e.g. marginRight for the left one and marginLeft
- // for the right one); we have to add these together. We can only do that if
- // they use the same units, and do not use resources.
- if (dimension1.startsWith(PREFIX_RESOURCE_REF)
- || dimension2.startsWith(PREFIX_RESOURCE_REF)) {
- return null;
- }
-
- Pattern p = Pattern.compile("([\\d\\.]+)(.+)"); //$NON-NLS-1$
- Matcher matcher1 = p.matcher(dimension1);
- Matcher matcher2 = p.matcher(dimension2);
- if (matcher1.matches() && matcher2.matches()) {
- String unit = matcher1.group(2);
- if (unit.equals(matcher2.group(2))) {
- float value1 = Float.parseFloat(matcher1.group(1));
- float value2 = Float.parseFloat(matcher2.group(1));
- return AdtUtils.formatFloatAttribute(value1 + value2) + unit;
- }
- }
- }
-
- return null;
- }
-
- /**
- * Sets an Android attribute (in the Android namespace) on an element
- * without a given namespace prefix. This is done when building a new Element
- * in a temporary document such that the namespace prefix matches when the element is
- * formatted and replaced in the target document.
- */
- private static void setAndroidAttribute(Element element, String prefix, String name,
- String value) {
- element.setAttribute(prefix + ':' + name, value);
- }
-
- @Override
- public VisualRefactoringWizard createWizard() {
- return new UseCompoundDrawableWizard(this, mDelegate);
- }
-
- @SuppressWarnings("javadoc")
- public static class Descriptor extends VisualRefactoringDescriptor {
- public Descriptor(String project, String description, String comment,
- Map<String, String> arguments) {
- super("com.android.ide.eclipse.adt.refactoring.usecompound", //$NON-NLS-1$
- project, description, comment, arguments);
- }
-
- @Override
- protected Refactoring createRefactoring(Map<String, String> args) {
- return new UseCompoundDrawableRefactoring(args);
- }
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UseCompoundDrawableWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UseCompoundDrawableWizard.java
deleted file mode 100644
index 3ffd6b5ea..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UseCompoundDrawableWizard.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2012 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.eclipse.adt.internal.editors.layout.LayoutEditorDelegate;
-
-class UseCompoundDrawableWizard extends VisualRefactoringWizard {
- UseCompoundDrawableWizard(UseCompoundDrawableRefactoring ref, LayoutEditorDelegate editor) {
- super(ref, editor);
- setDefaultPageTitle("Use Compound Drawable");
- }
-
- @Override
- protected void addUserInputPages() {
- // This refactoring takes no parameters
- }
-}
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
deleted file mode 100644
index 904a3a084..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/VisualRefactoring.java
+++ /dev/null
@@ -1,1403 +0,0 @@
-/*
- * 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 static com.android.SdkConstants.ANDROID_NS_NAME;
-import static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.ANDROID_WIDGET_PREFIX;
-import static com.android.SdkConstants.ATTR_ID;
-import static com.android.SdkConstants.ATTR_LAYOUT_HEIGHT;
-import static com.android.SdkConstants.ATTR_LAYOUT_RESOURCE_PREFIX;
-import static com.android.SdkConstants.ATTR_LAYOUT_WIDTH;
-import static com.android.SdkConstants.ID_PREFIX;
-import static com.android.SdkConstants.NEW_ID_PREFIX;
-import static com.android.SdkConstants.XMLNS;
-import static com.android.SdkConstants.XMLNS_PREFIX;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.VisibleForTesting;
-import com.android.ide.common.xml.XmlFormatStyle;
-import com.android.ide.eclipse.adt.AdtPlugin;
-import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor;
-import com.android.ide.eclipse.adt.internal.editors.formatting.EclipseXmlFormatPreferences;
-import com.android.ide.eclipse.adt.internal.editors.formatting.EclipseXmlPrettyPrinter;
-import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditorDelegate;
-import com.android.ide.eclipse.adt.internal.editors.layout.configuration.ConfigurationDescription;
-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;
-import com.android.ide.eclipse.adt.internal.editors.layout.gle2.GraphicalEditorPart;
-import com.android.ide.eclipse.adt.internal.editors.layout.uimodel.UiViewElementNode;
-import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode;
-import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs;
-import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
-import com.android.utils.Pair;
-
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.resources.ResourcesPlugin;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IPath;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.OperationCanceledException;
-import org.eclipse.core.runtime.Path;
-import org.eclipse.jface.text.BadLocationException;
-import org.eclipse.jface.text.IDocument;
-import org.eclipse.jface.text.IRegion;
-import org.eclipse.jface.text.ITextSelection;
-import org.eclipse.jface.viewers.ITreeSelection;
-import org.eclipse.jface.viewers.TreePath;
-import org.eclipse.ltk.core.refactoring.Change;
-import org.eclipse.ltk.core.refactoring.ChangeDescriptor;
-import org.eclipse.ltk.core.refactoring.CompositeChange;
-import org.eclipse.ltk.core.refactoring.Refactoring;
-import org.eclipse.ltk.core.refactoring.RefactoringChangeDescriptor;
-import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
-import org.eclipse.ltk.core.refactoring.RefactoringStatus;
-import org.eclipse.text.edits.DeleteEdit;
-import org.eclipse.text.edits.InsertEdit;
-import org.eclipse.text.edits.MalformedTreeException;
-import org.eclipse.text.edits.MultiTextEdit;
-import org.eclipse.text.edits.ReplaceEdit;
-import org.eclipse.text.edits.TextEdit;
-import org.eclipse.ui.IEditorPart;
-import org.eclipse.ui.PartInitException;
-import org.eclipse.ui.ide.IDE;
-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.core.internal.provisional.text.ITextRegionList;
-import org.eclipse.wst.xml.core.internal.regions.DOMRegionContext;
-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.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Parent class for the various visual refactoring operations; contains shared
- * implementations needed by most of them
- */
-@SuppressWarnings("restriction") // XML model
-public abstract class VisualRefactoring extends Refactoring {
- private static final String KEY_FILE = "file"; //$NON-NLS-1$
- private static final String KEY_PROJECT = "proj"; //$NON-NLS-1$
- private static final String KEY_SEL_START = "sel-start"; //$NON-NLS-1$
- private static final String KEY_SEL_END = "sel-end"; //$NON-NLS-1$
-
- protected final IFile mFile;
- protected final LayoutEditorDelegate mDelegate;
- protected final IProject mProject;
- protected int mSelectionStart = -1;
- protected int mSelectionEnd = -1;
- protected final List<Element> mElements;
- protected final ITreeSelection mTreeSelection;
- protected final ITextSelection mSelection;
- /** Same as {@link #mSelectionStart} but not adjusted to element edges */
- protected int mOriginalSelectionStart = -1;
- /** Same as {@link #mSelectionEnd} but not adjusted to element edges */
- protected int mOriginalSelectionEnd = -1;
-
- protected final Map<Element, String> mGeneratedIdMap = new HashMap<Element, String>();
- protected final Set<String> mGeneratedIds = new HashSet<String>();
-
- protected List<Change> mChanges;
- private String mAndroidNamespacePrefix;
-
- /**
- * This constructor is solely used by {@link VisualRefactoringDescriptor},
- * to replay a previous refactoring.
- * @param arguments argument map created by #createArgumentMap.
- */
- VisualRefactoring(Map<String, String> arguments) {
- IPath path = Path.fromPortableString(arguments.get(KEY_PROJECT));
- mProject = (IProject) ResourcesPlugin.getWorkspace().getRoot().findMember(path);
- path = Path.fromPortableString(arguments.get(KEY_FILE));
- mFile = (IFile) ResourcesPlugin.getWorkspace().getRoot().findMember(path);
- mSelectionStart = Integer.parseInt(arguments.get(KEY_SEL_START));
- mSelectionEnd = Integer.parseInt(arguments.get(KEY_SEL_END));
- mOriginalSelectionStart = mSelectionStart;
- mOriginalSelectionEnd = mSelectionEnd;
- mDelegate = null;
- mElements = null;
- mSelection = null;
- mTreeSelection = null;
- }
-
- @VisibleForTesting
- VisualRefactoring(List<Element> elements, LayoutEditorDelegate delegate) {
- mElements = elements;
- mDelegate = delegate;
-
- mFile = delegate != null ? delegate.getEditor().getInputFile() : null;
- mProject = delegate != null ? delegate.getEditor().getProject() : null;
- mSelectionStart = 0;
- mSelectionEnd = 0;
- mOriginalSelectionStart = 0;
- mOriginalSelectionEnd = 0;
- mSelection = null;
- mTreeSelection = null;
-
- int end = Integer.MIN_VALUE;
- int start = Integer.MAX_VALUE;
- for (Element element : elements) {
- if (element instanceof IndexedRegion) {
- IndexedRegion region = (IndexedRegion) element;
- start = Math.min(start, region.getStartOffset());
- end = Math.max(end, region.getEndOffset());
- }
- }
- if (start >= 0) {
- mSelectionStart = start;
- mSelectionEnd = end;
- mOriginalSelectionStart = start;
- mOriginalSelectionEnd = end;
- }
- }
-
- public VisualRefactoring(IFile file, LayoutEditorDelegate editor, ITextSelection selection,
- ITreeSelection treeSelection) {
- mFile = file;
- mDelegate = editor;
- mProject = file.getProject();
- mSelection = selection;
- mTreeSelection = treeSelection;
-
- // Initialize mSelectionStart and mSelectionEnd based on the selection context, which
- // is either a treeSelection (when invoked from the layout editor or the outline), or
- // a selection (when invoked from an XML editor)
- if (treeSelection != null) {
- int end = Integer.MIN_VALUE;
- int start = Integer.MAX_VALUE;
- for (TreePath path : treeSelection.getPaths()) {
- Object lastSegment = path.getLastSegment();
- if (lastSegment instanceof CanvasViewInfo) {
- CanvasViewInfo viewInfo = (CanvasViewInfo) lastSegment;
- UiViewElementNode uiNode = viewInfo.getUiViewNode();
- if (uiNode == null) {
- continue;
- }
- Node xmlNode = uiNode.getXmlNode();
- if (xmlNode instanceof IndexedRegion) {
- IndexedRegion region = (IndexedRegion) xmlNode;
-
- start = Math.min(start, region.getStartOffset());
- end = Math.max(end, region.getEndOffset());
- }
- }
- }
- if (start >= 0) {
- mSelectionStart = start;
- mSelectionEnd = end;
- mOriginalSelectionStart = mSelectionStart;
- mOriginalSelectionEnd = mSelectionEnd;
- }
- if (selection != null) {
- mOriginalSelectionStart = selection.getOffset();
- mOriginalSelectionEnd = mOriginalSelectionStart + selection.getLength();
- }
- } else if (selection != null) {
- // TODO: update selection to boundaries!
- mSelectionStart = selection.getOffset();
- mSelectionEnd = mSelectionStart + selection.getLength();
- mOriginalSelectionStart = mSelectionStart;
- mOriginalSelectionEnd = mSelectionEnd;
- }
-
- mElements = initElements();
- }
-
- @NonNull
- protected abstract List<Change> computeChanges(IProgressMonitor monitor);
-
- @Override
- public RefactoringStatus checkFinalConditions(IProgressMonitor monitor) throws CoreException,
- OperationCanceledException {
- RefactoringStatus status = new RefactoringStatus();
- mChanges = new ArrayList<Change>();
- try {
- monitor.beginTask("Checking post-conditions...", 5);
-
- // Reset state for each computeChanges call, in case the user goes back
- // and forth in the refactoring wizard
- mGeneratedIdMap.clear();
- mGeneratedIds.clear();
- List<Change> changes = computeChanges(monitor);
- mChanges.addAll(changes);
-
- monitor.worked(1);
- } finally {
- monitor.done();
- }
-
- return status;
- }
-
- @Override
- public Change createChange(IProgressMonitor monitor) throws CoreException,
- OperationCanceledException {
- try {
- monitor.beginTask("Applying changes...", 1);
-
- CompositeChange change = new CompositeChange(
- getName(),
- mChanges.toArray(new Change[mChanges.size()])) {
- @Override
- public ChangeDescriptor getDescriptor() {
- VisualRefactoringDescriptor desc = createDescriptor();
- return new RefactoringChangeDescriptor(desc);
- }
- };
-
- monitor.worked(1);
- return change;
-
- } finally {
- monitor.done();
- }
- }
-
- protected abstract VisualRefactoringDescriptor createDescriptor();
-
- protected Map<String, String> createArgumentMap() {
- HashMap<String, String> args = new HashMap<String, String>();
- args.put(KEY_PROJECT, mProject.getFullPath().toPortableString());
- args.put(KEY_FILE, mFile.getFullPath().toPortableString());
- args.put(KEY_SEL_START, Integer.toString(mSelectionStart));
- args.put(KEY_SEL_END, Integer.toString(mSelectionEnd));
-
- return args;
- }
-
- IFile getFile() {
- return mFile;
- }
-
- // ---- Shared functionality ----
-
-
- protected void openFile(IFile file) {
- GraphicalEditorPart graphicalEditor = mDelegate.getGraphicalEditor();
- IFile leavingFile = graphicalEditor.getEditedFile();
-
- try {
- // Duplicate the current state into the newly created file
- String state = ConfigurationDescription.getDescription(leavingFile);
-
- // TODO: Look for a ".NoTitleBar.Fullscreen" theme version of the current
- // theme to show.
-
- file.setSessionProperty(GraphicalEditorPart.NAME_INITIAL_STATE, state);
- } catch (CoreException e) {
- // pass
- }
-
- /* TBD: "Show Included In" if supported.
- * Not sure if this is a good idea.
- if (graphicalEditor.renderingSupports(Capability.EMBEDDED_LAYOUT)) {
- try {
- Reference include = Reference.create(graphicalEditor.getEditedFile());
- file.setSessionProperty(GraphicalEditorPart.NAME_INCLUDE, include);
- } catch (CoreException e) {
- // pass - worst that can happen is that we don't start with inclusion
- }
- }
- */
-
- try {
- IEditorPart part =
- IDE.openEditor(mDelegate.getEditor().getEditorSite().getPage(), file);
- if (part instanceof AndroidXmlEditor && AdtPrefs.getPrefs().getFormatGuiXml()) {
- AndroidXmlEditor newEditor = (AndroidXmlEditor) part;
- newEditor.reformatDocument();
- }
- } catch (PartInitException e) {
- AdtPlugin.log(e, "Can't open new included layout");
- }
- }
-
-
- /** Produce a list of edits to replace references to the given id with the given new id */
- protected static List<TextEdit> replaceIds(String androidNamePrefix,
- IStructuredDocument doc, int skipStart, int skipEnd,
- String rootId, String referenceId) {
- if (rootId == null) {
- return Collections.emptyList();
- }
-
- // We need to search for either @+id/ or @id/
- String match1 = rootId;
- String match2;
- if (match1.startsWith(ID_PREFIX)) {
- match2 = '"' + NEW_ID_PREFIX + match1.substring(ID_PREFIX.length()) + '"';
- match1 = '"' + match1 + '"';
- } else if (match1.startsWith(NEW_ID_PREFIX)) {
- match2 = '"' + ID_PREFIX + match1.substring(NEW_ID_PREFIX.length()) + '"';
- match1 = '"' + match1 + '"';
- } else {
- return Collections.emptyList();
- }
-
- String namePrefix = androidNamePrefix + ':' + ATTR_LAYOUT_RESOURCE_PREFIX;
- List<TextEdit> edits = new ArrayList<TextEdit>();
-
- IStructuredDocumentRegion region = doc.getFirstStructuredDocumentRegion();
- for (; region != null; region = region.getNext()) {
- ITextRegionList list = region.getRegions();
- int regionStart = region.getStart();
-
- // Look at all attribute values and look for an id reference match
- String attributeName = ""; //$NON-NLS-1$
- for (int j = 0; j < region.getNumberOfRegions(); j++) {
- ITextRegion subRegion = list.get(j);
- String type = subRegion.getType();
- if (DOMRegionContext.XML_TAG_ATTRIBUTE_NAME.equals(type)) {
- attributeName = region.getText(subRegion);
- } else if (DOMRegionContext.XML_TAG_ATTRIBUTE_VALUE.equals(type)) {
- // Only replace references in layout attributes
- if (!attributeName.startsWith(namePrefix)) {
- continue;
- }
- // Skip occurrences in the given skip range
- int subRegionStart = regionStart + subRegion.getStart();
- if (subRegionStart >= skipStart && subRegionStart <= skipEnd) {
- continue;
- }
-
- String attributeValue = region.getText(subRegion);
- if (attributeValue.equals(match1) || attributeValue.equals(match2)) {
- int start = subRegionStart + 1; // skip quote
- int end = start + rootId.length();
-
- edits.add(new ReplaceEdit(start, end - start, referenceId));
- }
- }
- }
- }
-
- return edits;
- }
-
- /** Get the id of the root selected element, if any */
- protected String getRootId() {
- Element primary = getPrimaryElement();
- if (primary != null) {
- String oldId = primary.getAttributeNS(ANDROID_URI, ATTR_ID);
- // id null check for https://bugs.eclipse.org/bugs/show_bug.cgi?id=272378
- if (oldId != null && oldId.length() > 0) {
- return oldId;
- }
- }
-
- return null;
- }
-
- protected String getAndroidNamespacePrefix() {
- if (mAndroidNamespacePrefix == null) {
- List<Attr> attributeNodes = findNamespaceAttributes();
- 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)) {
- mAndroidNamespacePrefix = name;
- if (mAndroidNamespacePrefix.startsWith(XMLNS_PREFIX)) {
- mAndroidNamespacePrefix =
- mAndroidNamespacePrefix.substring(XMLNS_PREFIX.length());
- }
- }
- }
- }
-
- if (mAndroidNamespacePrefix == null) {
- mAndroidNamespacePrefix = ANDROID_NS_NAME;
- }
- }
-
- 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_PREFIX)) {
- nsPrefix =
- nsPrefix.substring(XMLNS_PREFIX.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);
- }
-
- return Collections.emptyList();
- }
-
- 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++) {
- Node attributeNode = attributes.item(i);
-
- String prefix = attributeNode.getPrefix();
- if (XMLNS.equals(prefix)) {
- result.add((Attr) attributeNode);
- }
- }
-
- return result;
- }
-
- protected List<Attr> findLayoutAttributes(Node root) {
- List<Attr> result = new ArrayList<Attr>();
- NamedNodeMap attributes = root.getAttributes();
- for (int i = 0, n = attributes.getLength(); i < n; i++) {
- Node attributeNode = attributes.item(i);
-
- String name = attributeNode.getLocalName();
- if (name.startsWith(ATTR_LAYOUT_RESOURCE_PREFIX)
- && ANDROID_URI.equals(attributeNode.getNamespaceURI())) {
- result.add((Attr) attributeNode);
- }
- }
-
- return result;
- }
-
- protected String insertNamespace(String xmlText, String namespaceDeclarations) {
- // Insert namespace declarations into the extracted XML fragment
- int firstSpace = xmlText.indexOf(' ');
- int elementEnd = xmlText.indexOf('>');
- int insertAt;
- if (firstSpace != -1 && firstSpace < elementEnd) {
- insertAt = firstSpace;
- } else {
- insertAt = elementEnd;
- }
- xmlText = xmlText.substring(0, insertAt) + namespaceDeclarations
- + xmlText.substring(insertAt);
-
- return xmlText;
- }
-
- /** Remove sections of the document that correspond to top level layout attributes;
- * these are placed on the include element instead */
- protected String stripTopLayoutAttributes(Element primary, int start, String xml) {
- if (primary != null) {
- // List of attributes to remove
- List<IndexedRegion> skip = new ArrayList<IndexedRegion>();
- NamedNodeMap attributes = primary.getAttributes();
- for (int i = 0, n = attributes.getLength(); i < n; i++) {
- Node attr = attributes.item(i);
- String name = attr.getLocalName();
- if (name.startsWith(ATTR_LAYOUT_RESOURCE_PREFIX)
- && ANDROID_URI.equals(attr.getNamespaceURI())) {
- if (name.equals(ATTR_LAYOUT_WIDTH) || name.equals(ATTR_LAYOUT_HEIGHT)) {
- // These are special and are left in
- continue;
- }
-
- if (attr instanceof IndexedRegion) {
- skip.add((IndexedRegion) attr);
- }
- }
- }
- if (skip.size() > 0) {
- Collections.sort(skip, new Comparator<IndexedRegion>() {
- // Sort in start order
- @Override
- public int compare(IndexedRegion r1, IndexedRegion r2) {
- return r1.getStartOffset() - r2.getStartOffset();
- }
- });
-
- // Successively cut out the various layout attributes
- // TODO remove adjacent whitespace too (but not newlines, unless they
- // are newly adjacent)
- StringBuilder sb = new StringBuilder(xml.length());
- int nextStart = 0;
-
- // Copy out all the sections except the skip sections
- for (IndexedRegion r : skip) {
- int regionStart = r.getStartOffset();
- // Adjust to string offsets since we've copied the string out of
- // the document
- regionStart -= start;
-
- sb.append(xml.substring(nextStart, regionStart));
-
- nextStart = regionStart + r.getLength();
- }
- if (nextStart < xml.length()) {
- sb.append(xml.substring(nextStart));
- }
-
- return sb.toString();
- }
- }
-
- return xml;
- }
-
- protected static String getIndent(String line, int max) {
- int i = 0;
- int n = Math.min(max, line.length());
- for (; i < n; i++) {
- char c = line.charAt(i);
- if (!Character.isWhitespace(c)) {
- return line.substring(0, i);
- }
- }
-
- if (n < line.length()) {
- return line.substring(0, n);
- } else {
- return line;
- }
- }
-
- protected static String dedent(String xml) {
- String[] lines = xml.split("\n"); //$NON-NLS-1$
- if (lines.length < 2) {
- // The first line never has any indentation since we copy it out from the
- // element start index
- return xml;
- }
-
- String indentPrefix = getIndent(lines[1], lines[1].length());
- for (int i = 2, n = lines.length; i < n; i++) {
- String line = lines[i];
-
- // Ignore blank lines
- if (line.trim().length() == 0) {
- continue;
- }
-
- indentPrefix = getIndent(line, indentPrefix.length());
-
- if (indentPrefix.length() == 0) {
- return xml;
- }
- }
-
- StringBuilder sb = new StringBuilder();
- for (String line : lines) {
- if (line.startsWith(indentPrefix)) {
- sb.append(line.substring(indentPrefix.length()));
- } else {
- sb.append(line);
- }
- sb.append('\n');
- }
- return sb.toString();
- }
-
- protected String getText(int start, int end) {
- try {
- IStructuredDocument document = mDelegate.getEditor().getStructuredDocument();
- return document.get(start, end - start);
- } catch (BadLocationException e) {
- // the region offset was invalid. ignore.
- return null;
- }
- }
-
- protected List<Element> getElements() {
- return mElements;
- }
-
- protected List<Element> initElements() {
- List<Element> nodes = new ArrayList<Element>();
-
- assert mTreeSelection == null || mSelection == null :
- "treeSel= " + mTreeSelection + ", sel=" + mSelection;
-
- // Initialize mSelectionStart and mSelectionEnd based on the selection context, which
- // is either a treeSelection (when invoked from the layout editor or the outline), or
- // a selection (when invoked from an XML editor)
- if (mTreeSelection != null) {
- int end = Integer.MIN_VALUE;
- int start = Integer.MAX_VALUE;
- for (TreePath path : mTreeSelection.getPaths()) {
- Object lastSegment = path.getLastSegment();
- if (lastSegment instanceof CanvasViewInfo) {
- CanvasViewInfo viewInfo = (CanvasViewInfo) lastSegment;
- UiViewElementNode uiNode = viewInfo.getUiViewNode();
- if (uiNode == null) {
- continue;
- }
- Node xmlNode = uiNode.getXmlNode();
- if (xmlNode instanceof Element) {
- Element element = (Element) xmlNode;
- nodes.add(element);
- IndexedRegion region = getRegion(element);
- start = Math.min(start, region.getStartOffset());
- end = Math.max(end, region.getEndOffset());
- }
- }
- }
- if (start >= 0) {
- mSelectionStart = start;
- mSelectionEnd = end;
- }
- } else if (mSelection != null) {
- mSelectionStart = mSelection.getOffset();
- mSelectionEnd = mSelectionStart + mSelection.getLength();
- mOriginalSelectionStart = mSelectionStart;
- mOriginalSelectionEnd = mSelectionEnd;
-
- // Figure out the range of selected nodes from the document offsets
- IStructuredDocument doc = mDelegate.getEditor().getStructuredDocument();
- Pair<Element, Element> range = DomUtilities.getElementRange(doc,
- mSelectionStart, mSelectionEnd);
- if (range != null) {
- Element first = range.getFirst();
- Element last = range.getSecond();
-
- // Adjust offsets to get rid of surrounding text nodes (if you happened
- // to select a text range and included whitespace on either end etc)
- mSelectionStart = getRegion(first).getStartOffset();
- mSelectionEnd = getRegion(last).getEndOffset();
-
- if (mSelectionStart > mSelectionEnd) {
- int tmp = mSelectionStart;
- mSelectionStart = mSelectionEnd;
- mSelectionEnd = tmp;
- }
-
- if (first == last) {
- nodes.add(first);
- } else if (first.getParentNode() == last.getParentNode()) {
- // Add the range
- Node node = first;
- while (node != null) {
- if (node instanceof Element) {
- nodes.add((Element) node);
- }
- if (node == last) {
- break;
- }
- node = node.getNextSibling();
- }
- } else {
- // Different parents: this means we have an uneven selection, selecting
- // elements from different levels. We can't extract ranges like that.
- }
- }
- } else {
- assert false;
- }
-
- // Make sure that the list of elements is unique
- //Set<Element> seen = new HashSet<Element>();
- //for (Element element : nodes) {
- // assert !seen.contains(element) : element;
- // seen.add(element);
- //}
-
- return nodes;
- }
-
- protected Element getPrimaryElement() {
- List<Element> elements = getElements();
- if (elements != null && elements.size() == 1) {
- return elements.get(0);
- }
-
- return null;
- }
-
- protected Document getDomDocument() {
- if (mDelegate.getUiRootNode() != null) {
- return mDelegate.getUiRootNode().getXmlDocument();
- } else {
- return getElements().get(0).getOwnerDocument();
- }
- }
-
- protected List<CanvasViewInfo> getSelectedViewInfos() {
- List<CanvasViewInfo> infos = new ArrayList<CanvasViewInfo>();
- if (mTreeSelection != null) {
- for (TreePath path : mTreeSelection.getPaths()) {
- Object lastSegment = path.getLastSegment();
- if (lastSegment instanceof CanvasViewInfo) {
- infos.add((CanvasViewInfo) lastSegment);
- }
- }
- }
- return infos;
- }
-
- protected boolean validateNotEmpty(List<CanvasViewInfo> infos, RefactoringStatus status) {
- if (infos.size() == 0) {
- status.addFatalError("No selection to extract");
- return false;
- }
-
- return true;
- }
-
- protected boolean validateNotRoot(List<CanvasViewInfo> infos, RefactoringStatus status) {
- for (CanvasViewInfo info : infos) {
- if (info.isRoot()) {
- status.addFatalError("Cannot refactor the root");
- return false;
- }
- }
-
- return true;
- }
-
- protected boolean validateContiguous(List<CanvasViewInfo> infos, RefactoringStatus status) {
- 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 false;
- }
-
- UiElementNode parent = nodes.get(0).getUiParent();
- for (UiViewElementNode node : nodes) {
- if (parent != node.getUiParent()) {
- status.addFatalError("The selected elements must be adjacent");
- 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<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 false;
- }
- }
- }
- }
-
- return true;
- }
-
- /**
- * 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;
- }
- String oldTypeBase = oldType.substring(oldType.lastIndexOf('.') + 1);
- String id = getId(element);
- if (id == null || id.length() == 0
- || id.toLowerCase(Locale.US).contains(oldTypeBase.toLowerCase(Locale.US))) {
- String newTypeBase = newType.substring(newType.lastIndexOf('.') + 1);
- return ensureHasId(rootEdit, element, newTypeBase);
- }
-
- return null;
- }
-
- /**
- * Returns the {@link IndexedRegion} for the given node
- *
- * @param node the node to look up the region for
- * @return the corresponding region, or null
- */
- public static IndexedRegion getRegion(Node node) {
- if (node instanceof IndexedRegion) {
- return (IndexedRegion) node;
- }
-
- return null;
- }
-
- protected String ensureHasId(MultiTextEdit rootEdit, Element element, String prefix) {
- return ensureHasId(rootEdit, element, prefix, true);
- }
-
- protected String ensureHasId(MultiTextEdit rootEdit, Element element, String prefix,
- boolean apply) {
- String id = mGeneratedIdMap.get(element);
- if (id != null) {
- return NEW_ID_PREFIX + id;
- }
-
- if (!element.hasAttributeNS(ANDROID_URI, ATTR_ID)
- || (prefix != null && !getId(element).startsWith(prefix))) {
- id = DomUtilities.getFreeWidgetId(element, mGeneratedIds, prefix);
- // Make sure we don't use this one again
- mGeneratedIds.add(id);
- mGeneratedIdMap.put(element, id);
- id = NEW_ID_PREFIX + id;
- if (apply) {
- setAttribute(rootEdit, element,
- ANDROID_URI, getAndroidNamespacePrefix(), ATTR_ID, id);
- }
- return id;
- }
-
- return getId(element);
- }
-
- protected int getFirstAttributeOffset(Element element) {
- IndexedRegion region = getRegion(element);
- if (region != null) {
- int startOffset = region.getStartOffset();
- int endOffset = region.getEndOffset();
- String text = getText(startOffset, endOffset);
- String name = element.getLocalName();
- int nameOffset = text.indexOf(name);
- if (nameOffset != -1) {
- return startOffset + nameOffset + name.length();
- }
- }
-
- return -1;
- }
-
- /**
- * Returns the id of the given element
- *
- * @param element the element to look up the id for
- * @return the corresponding id, or an empty string (should not be null
- * according to the DOM API, but has been observed to be null on
- * some versions of Eclipse)
- */
- public static String getId(Element element) {
- return element.getAttributeNS(ANDROID_URI, ATTR_ID);
- }
-
- protected String ensureNewId(String id) {
- if (id != null && id.length() > 0) {
- if (id.startsWith(ID_PREFIX)) {
- id = NEW_ID_PREFIX + id.substring(ID_PREFIX.length());
- } else if (!id.startsWith(NEW_ID_PREFIX)) {
- id = NEW_ID_PREFIX + id;
- }
- } else {
- id = null;
- }
-
- return id;
- }
-
- protected String getViewClass(String fqcn) {
- // Don't include android.widget. as a package prefix in layout files
- if (fqcn.startsWith(ANDROID_WIDGET_PREFIX)) {
- fqcn = fqcn.substring(ANDROID_WIDGET_PREFIX.length());
- }
-
- return fqcn;
- }
-
- protected void setAttribute(MultiTextEdit rootEdit, Element element,
- String attributeUri,
- String attributePrefix, String attributeName, String attributeValue) {
- int offset = getFirstAttributeOffset(element);
- if (offset != -1) {
- if (element.hasAttributeNS(attributeUri, attributeName)) {
- replaceAttributeDeclaration(rootEdit, offset, element, attributePrefix,
- attributeUri, attributeName, attributeValue);
- } else {
- addAttributeDeclaration(rootEdit, offset, attributePrefix, attributeName,
- attributeValue);
- }
- }
- }
-
- private void addAttributeDeclaration(MultiTextEdit rootEdit, int offset,
- String attributePrefix, String attributeName, String attributeValue) {
- StringBuilder sb = new StringBuilder();
- sb.append(' ');
-
- if (attributePrefix != null) {
- sb.append(attributePrefix).append(':');
- }
- sb.append(attributeName).append('=').append('"');
- sb.append(attributeValue).append('"');
-
- InsertEdit setAttribute = new InsertEdit(offset, sb.toString());
- rootEdit.addChild(setAttribute);
- }
-
- /** Replaces the value declaration of the given attribute */
- private void replaceAttributeDeclaration(MultiTextEdit rootEdit, int offset,
- Element element, String attributePrefix, String attributeUri,
- String attributeName, String attributeValue) {
- // Find attribute value and replace it
- IStructuredModel model = mDelegate.getEditor().getModelForRead();
- try {
- IStructuredDocument doc = model.getStructuredDocument();
-
- IStructuredDocumentRegion region = doc.getRegionAtCharacterOffset(offset);
- ITextRegionList list = region.getRegions();
- int regionStart = region.getStart();
-
- int valueStart = -1;
- boolean useNextValue = false;
- String targetName = attributePrefix != null
- ? attributePrefix + ':' + attributeName : attributeName;
-
- // Look at all attribute values and look for an id reference match
- for (int j = 0; j < region.getNumberOfRegions(); j++) {
- ITextRegion subRegion = list.get(j);
- String type = subRegion.getType();
- if (DOMRegionContext.XML_TAG_ATTRIBUTE_NAME.equals(type)) {
- // What about prefix?
- if (targetName.equals(region.getText(subRegion))) {
- useNextValue = true;
- }
- } else if (DOMRegionContext.XML_TAG_ATTRIBUTE_VALUE.equals(type)) {
- if (useNextValue) {
- valueStart = regionStart + subRegion.getStart();
- break;
- }
- }
- }
-
- if (valueStart != -1) {
- String oldValue = element.getAttributeNS(attributeUri, attributeName);
- int start = valueStart + 1; // Skip opening "
- ReplaceEdit setAttribute = new ReplaceEdit(start, oldValue.length(),
- attributeValue);
- try {
- rootEdit.addChild(setAttribute);
- } catch (MalformedTreeException mte) {
- AdtPlugin.log(mte, "Could not replace attribute %1$s with %2$s",
- attributeName, attributeValue);
- throw mte;
- }
- }
- } finally {
- model.releaseFromRead();
- }
- }
-
- /** Strips out the given attribute, if defined */
- protected void removeAttribute(MultiTextEdit rootEdit, Element element, String uri,
- String attributeName) {
- if (element.hasAttributeNS(uri, attributeName)) {
- Attr attribute = element.getAttributeNodeNS(uri, attributeName);
- removeAttribute(rootEdit, attribute);
- }
- }
-
- /** Strips out the given attribute, if defined */
- protected void removeAttribute(MultiTextEdit rootEdit, Attr attribute) {
- IndexedRegion region = getRegion(attribute);
- if (region != null) {
- int startOffset = region.getStartOffset();
- int endOffset = region.getEndOffset();
- DeleteEdit deletion = new DeleteEdit(startOffset, endOffset - startOffset);
- rootEdit.addChild(deletion);
- }
- }
-
-
- /**
- * Removes the given element's opening and closing tags (including all of its
- * attributes) but leaves any children alone
- *
- * @param rootEdit the multi edit to add the removal operation to
- * @param element the element to delete the open and closing tags for
- * @param skip a list of elements that should not be modified (for example because they
- * are targeted for deletion)
- *
- * TODO: Rename this to "unwrap" ? And allow for handling nested deletions.
- */
- protected void removeElementTags(MultiTextEdit rootEdit, Element element, List<Element> skip,
- boolean changeIndentation) {
- IndexedRegion elementRegion = getRegion(element);
- if (elementRegion == null) {
- return;
- }
-
- // Look for the opening tag
- IStructuredModel model = mDelegate.getEditor().getModelForRead();
- try {
- int startLineInclusive = -1;
- int endLineInclusive = -1;
- IStructuredDocument doc = model.getStructuredDocument();
- if (doc != null) {
- int start = elementRegion.getStartOffset();
- IStructuredDocumentRegion region = doc.getRegionAtCharacterOffset(start);
- ITextRegionList list = region.getRegions();
- int regionStart = region.getStart();
- int startOffset = regionStart;
- for (int j = 0; j < region.getNumberOfRegions(); j++) {
- ITextRegion subRegion = list.get(j);
- String type = subRegion.getType();
- if (DOMRegionContext.XML_TAG_OPEN.equals(type)) {
- startOffset = regionStart + subRegion.getStart();
- } else if (DOMRegionContext.XML_TAG_CLOSE.equals(type)) {
- int endOffset = regionStart + subRegion.getStart() + subRegion.getLength();
-
- DeleteEdit deletion = createDeletion(doc, startOffset, endOffset);
- rootEdit.addChild(deletion);
- startLineInclusive = doc.getLineOfOffset(endOffset) + 1;
- break;
- }
- }
-
- // Find the close tag
- // Look at all attribute values and look for an id reference match
- region = doc.getRegionAtCharacterOffset(elementRegion.getEndOffset()
- - element.getTagName().length() - 1);
- list = region.getRegions();
- regionStart = region.getStartOffset();
- startOffset = -1;
- for (int j = 0; j < region.getNumberOfRegions(); j++) {
- ITextRegion subRegion = list.get(j);
- String type = subRegion.getType();
- if (DOMRegionContext.XML_END_TAG_OPEN.equals(type)) {
- startOffset = regionStart + subRegion.getStart();
- } else if (DOMRegionContext.XML_TAG_CLOSE.equals(type)) {
- int endOffset = regionStart + subRegion.getStart() + subRegion.getLength();
- if (startOffset != -1) {
- DeleteEdit deletion = createDeletion(doc, startOffset, endOffset);
- rootEdit.addChild(deletion);
- endLineInclusive = doc.getLineOfOffset(startOffset) - 1;
- }
- break;
- }
- }
- }
-
- // Dedent the contents
- if (changeIndentation && startLineInclusive != -1 && endLineInclusive != -1) {
- String indent = AndroidXmlEditor.getIndentAtOffset(doc, getRegion(element)
- .getStartOffset());
- setIndentation(rootEdit, indent, doc, startLineInclusive, endLineInclusive,
- element, skip);
- }
- } finally {
- model.releaseFromRead();
- }
- }
-
- protected void removeIndentation(MultiTextEdit rootEdit, String removeIndent,
- IStructuredDocument doc, int startLineInclusive, int endLineInclusive,
- Element element, List<Element> skip) {
- if (startLineInclusive > endLineInclusive) {
- return;
- }
- int indentLength = removeIndent.length();
- if (indentLength == 0) {
- return;
- }
-
- try {
- for (int line = startLineInclusive; line <= endLineInclusive; line++) {
- IRegion info = doc.getLineInformation(line);
- int lineStart = info.getOffset();
- int lineLength = info.getLength();
- int lineEnd = lineStart + lineLength;
- if (overlaps(lineStart, lineEnd, element, skip)) {
- continue;
- }
- String lineText = getText(lineStart,
- lineStart + Math.min(lineLength, indentLength));
- if (lineText.startsWith(removeIndent)) {
- rootEdit.addChild(new DeleteEdit(lineStart, indentLength));
- }
- }
- } catch (BadLocationException e) {
- AdtPlugin.log(e, null);
- }
- }
-
- protected void setIndentation(MultiTextEdit rootEdit, String indent,
- IStructuredDocument doc, int startLineInclusive, int endLineInclusive,
- Element element, List<Element> skip) {
- if (startLineInclusive > endLineInclusive) {
- return;
- }
- int indentLength = indent.length();
- if (indentLength == 0) {
- return;
- }
-
- try {
- for (int line = startLineInclusive; line <= endLineInclusive; line++) {
- IRegion info = doc.getLineInformation(line);
- int lineStart = info.getOffset();
- int lineLength = info.getLength();
- int lineEnd = lineStart + lineLength;
- if (overlaps(lineStart, lineEnd, element, skip)) {
- continue;
- }
- String lineText = getText(lineStart, lineStart + lineLength);
- int indentEnd = getFirstNonSpace(lineText);
- rootEdit.addChild(new ReplaceEdit(lineStart, indentEnd, indent));
- }
- } catch (BadLocationException e) {
- AdtPlugin.log(e, null);
- }
- }
-
- private int getFirstNonSpace(String s) {
- for (int i = 0; i < s.length(); i++) {
- if (!Character.isWhitespace(s.charAt(i))) {
- return i;
- }
- }
-
- return s.length();
- }
-
- /** Returns true if the given line overlaps any of the given elements */
- private static boolean overlaps(int startOffset, int endOffset,
- Element element, List<Element> overlaps) {
- for (Element e : overlaps) {
- if (e == element) {
- continue;
- }
-
- IndexedRegion region = getRegion(e);
- if (region.getEndOffset() >= startOffset && region.getStartOffset() <= endOffset) {
- return true;
- }
- }
- return false;
- }
-
- protected DeleteEdit createDeletion(IStructuredDocument doc, int startOffset, int endOffset) {
- // Expand to delete the whole line?
- try {
- IRegion info = doc.getLineInformationOfOffset(startOffset);
- int lineBegin = info.getOffset();
- // Is the text on the line leading up to the deletion region,
- // and the text following it, all whitespace?
- boolean deleteLine = true;
- if (lineBegin < startOffset) {
- String prefix = getText(lineBegin, startOffset);
- if (prefix.trim().length() > 0) {
- deleteLine = false;
- }
- }
- info = doc.getLineInformationOfOffset(endOffset);
- int lineEnd = info.getOffset() + info.getLength();
- if (lineEnd > endOffset) {
- String suffix = getText(endOffset, lineEnd);
- if (suffix.trim().length() > 0) {
- deleteLine = false;
- }
- }
- if (deleteLine) {
- startOffset = lineBegin;
- endOffset = Math.min(doc.getLength(), lineEnd + 1);
- }
- } catch (BadLocationException e) {
- AdtPlugin.log(e, null);
- }
-
-
- return new DeleteEdit(startOffset, endOffset - startOffset);
- }
-
- /**
- * Rewrite the edits in the given {@link MultiTextEdit} such that same edits are
- * applied, but the resulting range is also formatted
- */
- protected MultiTextEdit reformat(MultiTextEdit edit, XmlFormatStyle style) {
- String xml = mDelegate.getEditor().getStructuredDocument().get();
- return reformat(xml, edit, style);
- }
-
- /**
- * Rewrite the edits in the given {@link MultiTextEdit} such that same edits are
- * applied, but the resulting range is also formatted
- *
- * @param oldContents the original contents that should be edited by a
- * {@link MultiTextEdit}
- * @param edit the {@link MultiTextEdit} to be applied to some string
- * @param style the formatting style to use
- * @return a new {@link MultiTextEdit} which performs the same edits as the input edit
- * but also reformats the text
- */
- public static MultiTextEdit reformat(String oldContents, MultiTextEdit edit,
- XmlFormatStyle style) {
- IDocument document = new org.eclipse.jface.text.Document();
- document.set(oldContents);
-
- try {
- edit.apply(document);
- } catch (MalformedTreeException e) {
- AdtPlugin.log(e, null);
- return null; // Abort formatting
- } catch (BadLocationException e) {
- AdtPlugin.log(e, null);
- return null; // Abort formatting
- }
-
- String actual = document.get();
-
- // TODO: Try to format only the affected portion of the document.
- // To do that we need to find out what the affected offsets are; we know
- // the MultiTextEdit's affected range, but that is referring to offsets
- // in the old document. Use that to compute offsets in the new document.
- //int distanceFromEnd = actual.length() - edit.getExclusiveEnd();
- //IStructuredModel model = DomUtilities.createStructuredModel(actual);
- //int start = edit.getOffset();
- //int end = actual.length() - distanceFromEnd;
- //int length = end - start;
- //TextEdit format = AndroidXmlFormattingStrategy.format(model, start, length);
- EclipseXmlFormatPreferences formatPrefs = EclipseXmlFormatPreferences.create();
- String formatted = EclipseXmlPrettyPrinter.prettyPrint(actual, formatPrefs, style,
- null /*lineSeparator*/);
-
-
- // Figure out how much of the before and after strings are identical and narrow
- // the replacement scope
- boolean foundDifference = false;
- int firstDifference = 0;
- int lastDifference = formatted.length();
- int start = 0;
- int end = oldContents.length();
-
- for (int i = 0, j = start; i < formatted.length() && j < end; i++, j++) {
- if (formatted.charAt(i) != oldContents.charAt(j)) {
- firstDifference = i;
- foundDifference = true;
- break;
- }
- }
-
- if (!foundDifference) {
- // No differences - the document is already formatted, nothing to do
- return null;
- }
-
- lastDifference = firstDifference + 1;
- for (int i = formatted.length() - 1, j = end - 1;
- i > firstDifference && j > start;
- i--, j--) {
- if (formatted.charAt(i) != oldContents.charAt(j)) {
- lastDifference = i + 1;
- break;
- }
- }
-
- start += firstDifference;
- end -= (formatted.length() - lastDifference);
- end = Math.max(start, end);
- formatted = formatted.substring(firstDifference, lastDifference);
-
- ReplaceEdit format = new ReplaceEdit(start, end - start,
- formatted);
-
- MultiTextEdit newEdit = new MultiTextEdit();
- newEdit.addChild(format);
-
- return newEdit;
- }
-
- protected ViewElementDescriptor getElementDescriptor(String fqcn) {
- AndroidTargetData data = mDelegate.getEditor().getTargetData();
- if (data != null) {
- return data.getLayoutDescriptors().findDescriptorByClass(fqcn);
- }
-
- return null;
- }
-
- /** Create a wizard for this refactoring */
- abstract VisualRefactoringWizard createWizard();
-
- public abstract static class VisualRefactoringDescriptor extends RefactoringDescriptor {
- private final Map<String, String> mArguments;
-
- public VisualRefactoringDescriptor(
- String id, String project, String description, String comment,
- Map<String, String> arguments) {
- super(id, project, description, comment, STRUCTURAL_CHANGE | MULTI_CHANGE);
- mArguments = arguments;
- }
-
- public Map<String, String> getArguments() {
- return mArguments;
- }
-
- protected abstract Refactoring createRefactoring(Map<String, String> args);
-
- @Override
- public Refactoring createRefactoring(RefactoringStatus status) throws CoreException {
- try {
- return createRefactoring(mArguments);
- } catch (NullPointerException e) {
- status.addFatalError("Failed to recreate refactoring from descriptor");
- return null;
- }
- }
- }
-}
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
deleted file mode 100644
index f1cc988d7..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/VisualRefactoringAction.java
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * 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.eclipse.adt.AdtConstants;
-import com.android.ide.eclipse.adt.AdtPlugin;
-import com.android.ide.eclipse.adt.AdtUtils;
-import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditorDelegate;
-import com.android.ide.eclipse.adt.internal.editors.layout.gle2.CanvasViewInfo;
-
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.jface.action.Action;
-import org.eclipse.jface.action.IAction;
-import org.eclipse.jface.text.ITextSelection;
-import org.eclipse.jface.viewers.ISelection;
-import org.eclipse.jface.viewers.ITreeSelection;
-import org.eclipse.ui.IEditorInput;
-import org.eclipse.ui.IEditorPart;
-import org.eclipse.ui.IEditorSite;
-import org.eclipse.ui.IWorkbenchWindow;
-import org.eclipse.ui.IWorkbenchWindowActionDelegate;
-import org.eclipse.ui.part.FileEditorInput;
-
-abstract class VisualRefactoringAction implements IWorkbenchWindowActionDelegate {
- protected IWorkbenchWindow mWindow;
- protected ITextSelection mTextSelection;
- protected ITreeSelection mTreeSelection;
- protected LayoutEditorDelegate mDelegate;
- protected IFile mFile;
-
- /**
- * Keep track of the current workbench window.
- */
- @Override
- public void init(IWorkbenchWindow window) {
- mWindow = window;
- }
-
- @Override
- public void dispose() {
- }
-
- /**
- * Examine the selection to determine if the action should be enabled or not.
- * <p/>
- * Keep a link to the relevant selection structure
- */
- @Override
- public void selectionChanged(IAction action, ISelection selection) {
- // Look for selections in XML and in the layout UI editor
-
- // Note, two kinds of selections are returned here:
- // ITextSelection on a Java source window
- // IStructuredSelection in the outline or navigator
- // This simply deals with the refactoring based on a non-empty selection.
- // At that point, just enable the action and later decide if it's valid when it actually
- // runs since we don't have access to the AST yet.
-
- mTextSelection = null;
- mTreeSelection = null;
- mFile = null;
-
- IEditorPart editor = null;
-
- if (selection instanceof ITextSelection) {
- mTextSelection = (ITextSelection) selection;
- editor = AdtUtils.getActiveEditor();
- mFile = getSelectedFile(editor);
- } else if (selection instanceof ITreeSelection) {
- Object firstElement = ((ITreeSelection)selection).getFirstElement();
- if (firstElement instanceof CanvasViewInfo) {
- mTreeSelection = (ITreeSelection) selection;
- editor = AdtUtils.getActiveEditor();
- mFile = getSelectedFile(editor);
- }
- }
-
- mDelegate = LayoutEditorDelegate.fromEditor(editor);
-
- action.setEnabled((mTextSelection != null || mTreeSelection != null)
- && mFile != null && mDelegate != null);
- }
-
- /**
- * Create a new instance of our refactoring and a wizard to configure it.
- */
- @Override
- public abstract void run(IAction action);
-
- /**
- * Returns the active {@link IFile} (hopefully matching our selection) or null.
- * The file is only returned if it's a file from a project with an Android nature.
- * <p/>
- * At that point we do not try to analyze if the selection nor the file is suitable
- * for the refactoring. This check is performed when the refactoring is invoked since
- * it can then produce meaningful error messages as needed.
- */
- private IFile getSelectedFile(IEditorPart editor) {
- if (editor != null) {
- IEditorInput input = editor.getEditorInput();
-
- if (input instanceof FileEditorInput) {
- FileEditorInput fi = (FileEditorInput) input;
- IFile file = fi.getFile();
- if (file.exists()) {
- IProject proj = file.getProject();
- try {
- if (proj != null && proj.hasNature(AdtConstants.NATURE_DEFAULT)) {
- return file;
- }
- } catch (CoreException e) {
- // ignore
- }
- }
- }
- }
-
- return null;
- }
-
- public static IAction create(String title, LayoutEditorDelegate editorDelegate,
- Class<? extends VisualRefactoringAction> clz) {
- return new ActionWrapper(title, editorDelegate, clz);
- }
-
- private static class ActionWrapper extends Action {
- private Class<? extends VisualRefactoringAction> mClass;
- private LayoutEditorDelegate mEditorDelegate;
-
- ActionWrapper(String title, LayoutEditorDelegate editorDelegate,
- Class<? extends VisualRefactoringAction> clz) {
- super(title);
- mEditorDelegate = editorDelegate;
- mClass = clz;
- }
-
- @Override
- public void run() {
- VisualRefactoringAction action;
- try {
- action = mClass.newInstance();
- } catch (Exception e) {
- AdtPlugin.log(e, null);
- return;
- }
- IEditorSite site = mEditorDelegate.getEditor().getEditorSite();
- action.init(site.getWorkbenchWindow());
- ISelection selection = site.getSelectionProvider().getSelection();
- action.selectionChanged(ActionWrapper.this, selection);
- if (isEnabled()) {
- action.run(ActionWrapper.this);
- }
- }
- }
-}
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
deleted file mode 100644
index c103e47dc..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/VisualRefactoringWizard.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * 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.eclipse.adt.internal.editors.layout.LayoutEditorDelegate;
-
-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 LayoutEditorDelegate mDelegate;
-
- public VisualRefactoringWizard(Refactoring refactoring, LayoutEditorDelegate editor) {
- super(refactoring, DIALOG_BASED_USER_INTERFACE | PREVIEW_EXPAND_FIRST_NODE);
- mDelegate = editor;
- }
-
- @Override
- public boolean performFinish() {
- mDelegate.getEditor().setIgnoreXmlUpdate(true);
- try {
- return super.performFinish();
- } finally {
- mDelegate.getEditor().setIgnoreXmlUpdate(false);
- mDelegate.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() {
- @Override
- 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/WrapInAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/WrapInAction.java
deleted file mode 100644
index 1cd66596b..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/WrapInAction.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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.eclipse.adt.internal.editors.layout.LayoutEditorDelegate;
-
-import org.eclipse.jface.action.IAction;
-import org.eclipse.ltk.ui.refactoring.RefactoringWizard;
-import org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation;
-
-/**
- * Action executed when the "Wrap In" menu item is invoked.
- */
-public class WrapInAction extends VisualRefactoringAction {
- @Override
- public void run(IAction action) {
- if ((mTextSelection != null || mTreeSelection != null) && mFile != null) {
- WrapInRefactoring ref = new WrapInRefactoring(mFile, mDelegate,
- mTextSelection, mTreeSelection);
- RefactoringWizard wizard = new WrapInWizard(ref, mDelegate);
- RefactoringWizardOpenOperation op = new RefactoringWizardOpenOperation(wizard);
- try {
- op.run(mWindow.getShell(), wizard.getDefaultPageTitle());
- } catch (InterruptedException e) {
- // Interrupted. Pass.
- }
- }
- }
-
- public static IAction create(LayoutEditorDelegate editorDelegate) {
- return create("Wrap in Container...", editorDelegate, WrapInAction.class);
- }
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/WrapInContribution.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/WrapInContribution.java
deleted file mode 100644
index 61d7987d7..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/WrapInContribution.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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 org.eclipse.ltk.core.refactoring.RefactoringContribution;
-import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
-
-import java.util.Map;
-
-public class WrapInContribution extends RefactoringContribution {
-
- @SuppressWarnings("unchecked")
- @Override
- public RefactoringDescriptor createDescriptor(String id, String project, String description,
- String comment, Map arguments, int flags) throws IllegalArgumentException {
- return new WrapInRefactoring.Descriptor(project, description, comment, arguments);
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public Map retrieveArgumentMap(RefactoringDescriptor descriptor) {
- if (descriptor instanceof WrapInRefactoring.Descriptor) {
- return ((WrapInRefactoring.Descriptor) descriptor).getArguments();
- }
- return super.retrieveArgumentMap(descriptor);
- }
-}
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
deleted file mode 100644
index 07b00b8da..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/WrapInRefactoring.java
+++ /dev/null
@@ -1,439 +0,0 @@
-/*
- * 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 static com.android.SdkConstants.ANDROID_NS_NAME_PREFIX;
-import static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.ANDROID_WIDGET_PREFIX;
-import static com.android.SdkConstants.ATTR_ID;
-import static com.android.SdkConstants.ATTR_LAYOUT_HEIGHT;
-import static com.android.SdkConstants.ATTR_LAYOUT_WIDTH;
-import static com.android.SdkConstants.EXT_XML;
-import static com.android.SdkConstants.VALUE_FILL_PARENT;
-import static com.android.SdkConstants.VALUE_MATCH_PARENT;
-import static com.android.SdkConstants.VALUE_WRAP_CONTENT;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.VisibleForTesting;
-import com.android.ide.common.xml.XmlFormatStyle;
-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.CanvasViewInfo;
-import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs;
-
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.OperationCanceledException;
-import org.eclipse.jface.text.ITextSelection;
-import org.eclipse.jface.viewers.ITreeSelection;
-import org.eclipse.ltk.core.refactoring.Change;
-import org.eclipse.ltk.core.refactoring.Refactoring;
-import org.eclipse.ltk.core.refactoring.RefactoringStatus;
-import org.eclipse.ltk.core.refactoring.TextFileChange;
-import org.eclipse.text.edits.DeleteEdit;
-import org.eclipse.text.edits.InsertEdit;
-import org.eclipse.text.edits.MultiTextEdit;
-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 java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Inserts a new layout surrounding the current selection, migrates namespace
- * attributes (if wrapping the root node), and optionally migrates layout
- * attributes and updates references elsewhere.
- */
-@SuppressWarnings("restriction") // XML model
-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 String mId;
- private String mTypeFqcn;
- private String mInitializedAttributes;
-
- /**
- * This constructor is solely used by {@link Descriptor},
- * to replay a previous refactoring.
- * @param arguments argument map created by #createArgumentMap.
- */
- WrapInRefactoring(Map<String, String> arguments) {
- super(arguments);
- mId = arguments.get(KEY_ID);
- mTypeFqcn = arguments.get(KEY_TYPE);
- }
-
- public WrapInRefactoring(
- IFile file,
- LayoutEditorDelegate delegate,
- ITextSelection selection,
- ITreeSelection treeSelection) {
- super(file, delegate, selection, treeSelection);
- }
-
- @VisibleForTesting
- WrapInRefactoring(List<Element> selectedElements, LayoutEditorDelegate editor) {
- super(selectedElements, editor);
- }
-
- @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 wrap");
- 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 = getSelectedViewInfos();
- if (!validateNotEmpty(infos, status)) {
- return status;
- }
-
- // Enforce that the selection is -contiguous-
- if (!validateContiguous(infos, status)) {
- return status;
- }
- }
-
- // Ensures that we have a valid DOM model:
- if (mElements.size() == 0) {
- status.addFatalError("Nothing to wrap");
- return status;
- }
-
- pm.worked(1);
- return status;
-
- } finally {
- pm.done();
- }
- }
-
- @Override
- protected VisualRefactoringDescriptor createDescriptor() {
- String comment = getName();
- return new Descriptor(
- mProject.getName(), //project
- comment, //description
- comment, //comment
- createArgumentMap());
- }
-
- @Override
- protected Map<String, String> createArgumentMap() {
- Map<String, String> args = super.createArgumentMap();
- args.put(KEY_TYPE, mTypeFqcn);
- args.put(KEY_ID, mId);
-
- return args;
- }
-
- @Override
- public String getName() {
- return "Wrap in Container";
- }
-
- void setId(String id) {
- mId = id;
- }
-
- void setType(String typeFqcn) {
- mTypeFqcn = typeFqcn;
- }
-
- void setInitializedAttributes(String initializedAttributes) {
- mInitializedAttributes = initializedAttributes;
- }
-
- @Override
- protected @NonNull List<Change> computeChanges(IProgressMonitor monitor) {
- // (1) Insert the new container in front of the beginning of the
- // first wrapped view
- // (2) If the container is the new root, transfer namespace declarations
- // to it
- // (3) Insert the closing tag of the new container at the end of the
- // last wrapped view
- // (4) Reindent the wrapped views
- // (5) If the user requested it, update all layout references to the
- // wrapped views with the new container?
- // For that matter, does RelativeLayout even require it? Probably not,
- // it can point inside the current layout...
-
- // Add indent to all lines between mSelectionStart and mEnd
- // TODO: Figure out the indentation amount?
- // For now, use 4 spaces
- String indentUnit = " "; //$NON-NLS-1$
- boolean separateAttributes = true;
- IStructuredDocument document = mDelegate.getEditor().getStructuredDocument();
- String startIndent = AndroidXmlEditor.getIndentAtOffset(document, mSelectionStart);
-
- String viewClass = getViewClass(mTypeFqcn);
- String androidNsPrefix = getAndroidNamespacePrefix();
-
-
- IFile file = mDelegate.getEditor().getInputFile();
- List<Change> changes = new ArrayList<Change>();
- if (file == null) {
- return changes;
- }
- TextFileChange change = new TextFileChange(file.getName(), file);
- MultiTextEdit rootEdit = new MultiTextEdit();
- change.setTextType(EXT_XML);
-
- String id = ensureNewId(mId);
-
- // Update any layout references to the old id with the new id
- if (id != null) {
- String rootId = getRootId();
- IStructuredModel model = mDelegate.getEditor().getModelForRead();
- try {
- IStructuredDocument doc = model.getStructuredDocument();
- if (doc != null) {
- List<TextEdit> replaceIds = replaceIds(androidNsPrefix,
- doc, mSelectionStart, mSelectionEnd, rootId, id);
- for (TextEdit edit : replaceIds) {
- rootEdit.addChild(edit);
- }
- }
- } finally {
- model.releaseFromRead();
- }
- }
-
- // Insert namespace elements?
- StringBuilder namespace = null;
- List<DeleteEdit> deletions = new ArrayList<DeleteEdit>();
- Element primary = getPrimaryElement();
- if (primary != null && getDomDocument().getDocumentElement() == primary) {
- namespace = new StringBuilder();
-
- List<Attr> declarations = findNamespaceAttributes(primary);
- for (Attr attribute : declarations) {
- if (attribute instanceof IndexedRegion) {
- // Delete the namespace declaration in the node which is no longer the root
- IndexedRegion region = (IndexedRegion) attribute;
- int startOffset = region.getStartOffset();
- int endOffset = region.getEndOffset();
- String text = getText(startOffset, endOffset);
- DeleteEdit deletion = new DeleteEdit(startOffset, endOffset - startOffset);
- deletions.add(deletion);
- rootEdit.addChild(deletion);
- text = text.trim();
-
- // Insert the namespace declaration in the new root
- if (separateAttributes) {
- namespace.append('\n').append(startIndent).append(indentUnit);
- } else {
- namespace.append(' ');
- }
- namespace.append(text);
- }
- }
- }
-
- // Insert begin tag: <type ...>
- StringBuilder sb = new StringBuilder();
- sb.append('<');
- sb.append(viewClass);
-
- if (namespace != null) {
- sb.append(namespace);
- }
-
- // Set the ID if any
- if (id != null) {
- if (separateAttributes) {
- sb.append('\n').append(startIndent).append(indentUnit);
- } else {
- sb.append(' ');
- }
- sb.append(androidNsPrefix).append(':');
- sb.append(ATTR_ID).append('=').append('"').append(id).append('"');
- }
-
- // If any of the elements are fill/match parent, use that instead
- String width = VALUE_WRAP_CONTENT;
- String height = VALUE_WRAP_CONTENT;
-
- for (Element element : getElements()) {
- String oldWidth = element.getAttributeNS(ANDROID_URI, ATTR_LAYOUT_WIDTH);
- String oldHeight = element.getAttributeNS(ANDROID_URI, ATTR_LAYOUT_HEIGHT);
-
- if (VALUE_MATCH_PARENT.equals(oldWidth) || VALUE_FILL_PARENT.equals(oldWidth)) {
- width = oldWidth;
- }
- if (VALUE_MATCH_PARENT.equals(oldHeight) || VALUE_FILL_PARENT.equals(oldHeight)) {
- height = oldHeight;
- }
- }
-
- // Add in width/height.
- if (separateAttributes) {
- sb.append('\n').append(startIndent).append(indentUnit);
- } else {
- sb.append(' ');
- }
- sb.append(androidNsPrefix).append(':');
- sb.append(ATTR_LAYOUT_WIDTH).append('=').append('"').append(width).append('"');
-
- if (separateAttributes) {
- sb.append('\n').append(startIndent).append(indentUnit);
- } else {
- sb.append(' ');
- }
- 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 (primary != null) {
- List<Attr> layoutAttributes = findLayoutAttributes(primary);
- for (Attr attribute : layoutAttributes) {
- String name = attribute.getLocalName();
- if ((name.equals(ATTR_LAYOUT_WIDTH) || name.equals(ATTR_LAYOUT_HEIGHT))
- && ANDROID_URI.equals(attribute.getNamespaceURI())) {
- // Already handled specially
- continue;
- }
-
- if (attribute instanceof IndexedRegion) {
- IndexedRegion region = (IndexedRegion) attribute;
- int startOffset = region.getStartOffset();
- int endOffset = region.getEndOffset();
- String text = getText(startOffset, endOffset);
- DeleteEdit deletion = new DeleteEdit(startOffset, endOffset - startOffset);
- rootEdit.addChild(deletion);
- deletions.add(deletion);
-
- if (separateAttributes) {
- sb.append('\n').append(startIndent).append(indentUnit);
- } else {
- sb.append(' ');
- }
- sb.append(text.trim());
- }
- }
- }
-
- // Finish open tag:
- sb.append('>');
- sb.append('\n').append(startIndent).append(indentUnit);
-
- InsertEdit beginEdit = new InsertEdit(mSelectionStart, sb.toString());
- rootEdit.addChild(beginEdit);
-
- String nested = getText(mSelectionStart, mSelectionEnd);
- int index = 0;
- while (index != -1) {
- index = nested.indexOf('\n', index);
- if (index != -1) {
- index++;
- InsertEdit newline = new InsertEdit(mSelectionStart + index, indentUnit);
- // Some of the deleted namespaces may have had newlines - be careful
- // not to overlap edits
- boolean covered = false;
- for (DeleteEdit deletion : deletions) {
- if (deletion.covers(newline)) {
- covered = true;
- break;
- }
- }
- if (!covered) {
- rootEdit.addChild(newline);
- }
- }
- }
-
- // Insert end tag: </type>
- sb.setLength(0);
- sb.append('\n').append(startIndent);
- sb.append('<').append('/').append(viewClass).append('>');
- InsertEdit endEdit = new InsertEdit(mSelectionEnd, sb.toString());
- rootEdit.addChild(endEdit);
-
- if (AdtPrefs.getPrefs().getFormatGuiXml()) {
- MultiTextEdit formatted = reformat(rootEdit, XmlFormatStyle.LAYOUT);
- if (formatted != null) {
- rootEdit = formatted;
- }
- }
-
- change.setEdit(rootEdit);
- changes.add(change);
- return changes;
- }
-
- String getOldType() {
- Element primary = getPrimaryElement();
- if (primary != null) {
- String oldType = primary.getTagName();
- if (oldType.indexOf('.') == -1) {
- oldType = ANDROID_WIDGET_PREFIX + oldType;
- }
- return oldType;
- }
-
- return null;
- }
-
- @Override
- VisualRefactoringWizard createWizard() {
- return new WrapInWizard(this, mDelegate);
- }
-
- public static class Descriptor extends VisualRefactoringDescriptor {
- public Descriptor(String project, String description, String comment,
- Map<String, String> arguments) {
- super("com.android.ide.eclipse.adt.refactoring.wrapin", //$NON-NLS-1$
- project, description, comment, arguments);
- }
-
- @Override
- protected Refactoring createRefactoring(Map<String, String> args) {
- return new WrapInRefactoring(args);
- }
- }
-}
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
deleted file mode 100644
index 2e06a3bbd..000000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/WrapInWizard.java
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * 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 static com.android.SdkConstants.FQCN_GESTURE_OVERLAY_VIEW;
-import static com.android.SdkConstants.FQCN_LINEAR_LAYOUT;
-import static com.android.SdkConstants.FQCN_RADIO_BUTTON;
-import static com.android.SdkConstants.GESTURE_OVERLAY_VIEW;
-import static com.android.SdkConstants.RADIO_GROUP;
-import static com.android.SdkConstants.VIEW_INCLUDE;
-
-import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditorDelegate;
-import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.ViewElementDescriptor;
-import com.android.ide.eclipse.adt.internal.editors.layout.gle2.CustomViewFinder;
-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;
-import com.android.ide.eclipse.adt.internal.sdk.Sdk;
-import com.android.resources.ResourceType;
-import com.android.sdklib.IAndroidTarget;
-import com.android.utils.Pair;
-
-import org.eclipse.core.resources.IProject;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Combo;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Label;
-import org.eclipse.swt.widgets.Text;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-
-public class WrapInWizard extends VisualRefactoringWizard {
- private static final String SEPARATOR_LABEL =
- "----------------------------------------"; //$NON-NLS-1$
-
- public WrapInWizard(WrapInRefactoring ref, LayoutEditorDelegate editor) {
- super(ref, editor);
- setDefaultPageTitle("Wrap in Container");
- }
-
- @Override
- protected void addUserInputPages() {
- WrapInRefactoring ref = (WrapInRefactoring) getRefactoring();
- String oldType = ref.getOldType();
- addPage(new InputPage(mDelegate.getEditor().getProject(), oldType));
- }
-
- /** Wizard page which inputs parameters for the {@link WrapInRefactoring} operation */
- private static class InputPage extends VisualRefactoringInputPage {
- private final IProject mProject;
- private final String mOldType;
- private Text mIdText;
- private Combo mTypeCombo;
- private List<Pair<String, ViewElementDescriptor>> mClassNames;
-
- public InputPage(IProject project, String oldType) {
- super("WrapInInputPage"); //$NON-NLS-1$
- mProject = project;
- mOldType = oldType;
- }
-
- @Override
- public void createControl(Composite parent) {
- Composite composite = new Composite(parent, SWT.NONE);
- composite.setLayout(new GridLayout(2, false));
-
- Label typeLabel = new Label(composite, SWT.NONE);
- typeLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
- typeLabel.setText("Type of Container:");
-
- mTypeCombo = new Combo(composite, SWT.READ_ONLY);
- mTypeCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
- mTypeCombo.addSelectionListener(mSelectionValidateListener);
-
- Label idLabel = new Label(composite, SWT.NONE);
- idLabel.setText("New Layout Id:");
- idLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
-
- mIdText = new Text(composite, SWT.BORDER);
- mIdText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
- mIdText.addModifyListener(mModifyValidateListener);
-
- Set<String> exclude = Collections.singleton(VIEW_INCLUDE);
- mClassNames = addLayouts(mProject, mOldType, mTypeCombo, exclude, true);
- mTypeCombo.select(0);
-
- setControl(composite);
- validatePage();
-
- mTypeCombo.setFocus();
- }
-
- @Override
- protected boolean validatePage() {
- boolean ok = true;
-
- String id = mIdText.getText().trim();
-
- if (id.length() == 0) {
- setErrorMessage("ID required");
- ok = false;
- } else {
- // ...but if you do, it has to be valid!
- ResourceNameValidator validator = ResourceNameValidator.create(false, mProject,
- ResourceType.ID);
- String message = validator.isValid(id);
- if (message != null) {
- setErrorMessage(message);
- ok = false;
- }
- }
-
- int selectionIndex = mTypeCombo.getSelectionIndex();
- 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
- }
-
- if (ok) {
- setErrorMessage(null);
-
- // Record state
- WrapInRefactoring refactoring =
- (WrapInRefactoring) getRefactoring();
- refactoring.setId(id);
- refactoring.setType(type);
-
- 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);
- return ok;
- }
- }
-
- static List<Pair<String, ViewElementDescriptor>> addLayouts(IProject project,
- String oldType, Combo combo,
- Set<String> exclude, boolean addGestureOverlay) {
- List<Pair<String, ViewElementDescriptor>> classNames =
- new ArrayList<Pair<String, ViewElementDescriptor>>();
-
- 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(Pair.of(RADIO_GROUP, (ViewElementDescriptor) null));
-
- combo.add(SEPARATOR_LABEL);
- classNames.add(Pair.<String,ViewElementDescriptor>of(null, null));
- }
-
- Pair<List<String>,List<String>> result = CustomViewFinder.findViews(project, true);
- List<String> customViews = result.getFirst();
- List<String> thirdPartyViews = result.getSecond();
- if (customViews.size() > 0) {
- for (String view : customViews) {
- combo.add(view);
- classNames.add(Pair.of(view, (ViewElementDescriptor) null));
- }
- combo.add(SEPARATOR_LABEL);
- classNames.add(Pair.<String,ViewElementDescriptor>of(null, null));
- }
-
- // Populate type combo
- Sdk currentSdk = Sdk.getCurrent();
- if (currentSdk != null) {
- IAndroidTarget target = currentSdk.getTarget(project);
- if (target != null) {
- AndroidTargetData targetData = currentSdk.getTargetData(target);
- if (targetData != null) {
- ViewMetadataRepository repository = ViewMetadataRepository.get();
- List<Pair<String,List<ViewElementDescriptor>>> entries =
- repository.getPaletteEntries(targetData, false, true);
- // Find the layout category - it contains LinearLayout
- List<ViewElementDescriptor> layoutDescriptors = null;
-
- search: for (Pair<String,List<ViewElementDescriptor>> pair : entries) {
- List<ViewElementDescriptor> list = pair.getSecond();
- for (ViewElementDescriptor d : list) {
- if (d.getFullClassName().equals(FQCN_LINEAR_LAYOUT)) {
- // Found - use this list
- layoutDescriptors = list;
- break search;
- }
- }
- }
- if (layoutDescriptors != null) {
- for (ViewElementDescriptor d : layoutDescriptors) {
- String className = d.getFullClassName();
- if (exclude == null || !exclude.contains(className)) {
- combo.add(d.getUiName());
- classNames.add(Pair.of(className, d));
- }
- }
-
- // SWT does not support separators in combo boxes
- combo.add(SEPARATOR_LABEL);
- classNames.add(null);
-
- if (thirdPartyViews.size() > 0) {
- for (String view : thirdPartyViews) {
- combo.add(view);
- classNames.add(Pair.of(view, (ViewElementDescriptor) null));
- }
- combo.add(SEPARATOR_LABEL);
- classNames.add(null);
- }
-
- if (addGestureOverlay) {
- combo.add(GESTURE_OVERLAY_VIEW);
- classNames.add(Pair.<String, ViewElementDescriptor> of(
- FQCN_GESTURE_OVERLAY_VIEW, null));
-
- combo.add(SEPARATOR_LABEL);
- classNames.add(Pair.<String,ViewElementDescriptor>of(null, null));
- }
- }
-
- // Now add ALL known layout descriptors in case the user has
- // a special case
- layoutDescriptors =
- targetData.getLayoutDescriptors().getLayoutDescriptors();
-
- for (ViewElementDescriptor d : layoutDescriptors) {
- String className = d.getFullClassName();
- if (exclude == null || !exclude.contains(className)) {
- combo.add(d.getUiName());
- classNames.add(Pair.of(className, d));
- }
- }
- }
- }
- } else {
- combo.add("SDK not initialized");
- classNames.add(Pair.<String,ViewElementDescriptor>of(null, null));
- }
-
- return classNames;
- }
-}