aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UseCompoundDrawableRefactoring.java
diff options
context:
space:
mode:
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UseCompoundDrawableRefactoring.java')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UseCompoundDrawableRefactoring.java452
1 files changed, 0 insertions, 452 deletions
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);
- }
- }
-}