ChangeLayoutRefactoring.java revision f5256a38ef2e429b5efd4482808bc902bf7634e3
18dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye/* 28dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * Copyright (C) 2011 The Android Open Source Project 38dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * 48dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * Licensed under the Eclipse Public License, Version 1.0 (the "License"); 58dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * you may not use this file except in compliance with the License. 68dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * You may obtain a copy of the License at 78dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * 88dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * http://www.eclipse.org/org/documents/epl-v10.php 98dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * 108dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * Unless required by applicable law or agreed to in writing, software 118dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * distributed under the License is distributed on an "AS IS" BASIS, 128dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * See the License for the specific language governing permissions and 148dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * limitations under the License. 158dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye */ 168dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbyepackage com.android.ide.eclipse.adt.internal.editors.layout.refactoring; 178dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 188dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbyeimport static com.android.ide.common.layout.LayoutConstants.ANDROID_URI; 198dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbyeimport static com.android.ide.common.layout.LayoutConstants.ANDROID_WIDGET_PREFIX; 208dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbyeimport static com.android.ide.common.layout.LayoutConstants.ATTR_BASELINE_ALIGNED; 218dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbyeimport static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_ALIGN_BASELINE; 228dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbyeimport static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_BELOW; 238dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbyeimport static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_TO_RIGHT_OF; 248dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbyeimport static com.android.ide.common.layout.LayoutConstants.ATTR_ORIENTATION; 250757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbyeimport static com.android.ide.common.layout.LayoutConstants.FQCN_GESTURE_OVERLAY_VIEW; 268dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbyeimport static com.android.ide.common.layout.LayoutConstants.FQCN_LINEAR_LAYOUT; 278dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbyeimport static com.android.ide.common.layout.LayoutConstants.FQCN_RELATIVE_LAYOUT; 288dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbyeimport static com.android.ide.common.layout.LayoutConstants.FQCN_TABLE_LAYOUT; 290757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbyeimport static com.android.ide.common.layout.LayoutConstants.GESTURE_OVERLAY_VIEW; 308dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbyeimport static com.android.ide.common.layout.LayoutConstants.LINEAR_LAYOUT; 318dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbyeimport static com.android.ide.common.layout.LayoutConstants.TABLE_ROW; 328dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbyeimport static com.android.ide.common.layout.LayoutConstants.VALUE_FALSE; 338dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbyeimport static com.android.ide.common.layout.LayoutConstants.VALUE_VERTICAL; 34c3105b949cd2a0f6cbf8a12ec4f30e49b5b5a502Xavier Ducrohetimport static com.android.ide.eclipse.adt.AdtConstants.EXT_XML; 358dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 360757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbyeimport com.android.annotations.VisibleForTesting; 378dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbyeimport com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor; 38f5256a38ef2e429b5efd4482808bc902bf7634e3Tor Norbyeimport com.android.ide.eclipse.adt.internal.editors.formatting.XmlFormatStyle; 398dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbyeimport com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditor; 408dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbyeimport com.android.ide.eclipse.adt.internal.editors.layout.descriptors.ViewElementDescriptor; 410757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbyeimport com.android.ide.eclipse.adt.internal.editors.layout.gle2.CanvasViewInfo; 420757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbyeimport com.android.ide.eclipse.adt.internal.editors.layout.gle2.LayoutCanvas; 430757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbyeimport com.android.ide.eclipse.adt.internal.editors.layout.gle2.ViewHierarchy; 44f5256a38ef2e429b5efd4482808bc902bf7634e3Tor Norbyeimport com.android.ide.eclipse.adt.internal.preferences.AdtPrefs; 458dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 468dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbyeimport org.eclipse.core.resources.IFile; 478dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbyeimport org.eclipse.core.runtime.CoreException; 488dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbyeimport org.eclipse.core.runtime.IProgressMonitor; 498dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbyeimport org.eclipse.core.runtime.OperationCanceledException; 508dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbyeimport org.eclipse.jface.text.ITextSelection; 518dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbyeimport org.eclipse.jface.viewers.ITreeSelection; 528dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbyeimport org.eclipse.ltk.core.refactoring.Change; 538dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbyeimport org.eclipse.ltk.core.refactoring.Refactoring; 548dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbyeimport org.eclipse.ltk.core.refactoring.RefactoringStatus; 558dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbyeimport org.eclipse.ltk.core.refactoring.TextFileChange; 568dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbyeimport org.eclipse.text.edits.MultiTextEdit; 578dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbyeimport org.eclipse.text.edits.ReplaceEdit; 589e6db060854d0e890190919a27a1846f50f69d1aTor Norbyeimport org.eclipse.text.edits.TextEdit; 599e6db060854d0e890190919a27a1846f50f69d1aTor Norbyeimport org.eclipse.wst.sse.core.internal.provisional.IStructuredModel; 608dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbyeimport org.eclipse.wst.sse.core.internal.provisional.IndexedRegion; 619e6db060854d0e890190919a27a1846f50f69d1aTor Norbyeimport org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument; 628dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbyeimport org.w3c.dom.Attr; 638dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbyeimport org.w3c.dom.Element; 648dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbyeimport org.w3c.dom.Node; 658dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbyeimport org.w3c.dom.NodeList; 668dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 678dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbyeimport java.util.ArrayList; 688dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbyeimport java.util.HashSet; 698dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbyeimport java.util.List; 708dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbyeimport java.util.Map; 718dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbyeimport java.util.Set; 728dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 738dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye/** 748dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * Converts the selected layout into a layout of a different type. 758dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye */ 768dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye@SuppressWarnings("restriction") // XML model 778dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbyepublic class ChangeLayoutRefactoring extends VisualRefactoring { 780757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye private static final String KEY_TYPE = "type"; //$NON-NLS-1$ 790757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye private static final String KEY_FLATTEN = "flatten"; //$NON-NLS-1$ 808dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 818dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye private String mTypeFqcn; 820757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye private boolean mFlatten; 838dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 848dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye /** 858dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * This constructor is solely used by {@link Descriptor}, 868dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * to replay a previous refactoring. 878dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * @param arguments argument map created by #createArgumentMap. 888dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye */ 898dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye ChangeLayoutRefactoring(Map<String, String> arguments) { 908dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye super(arguments); 918dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye mTypeFqcn = arguments.get(KEY_TYPE); 920757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye mFlatten = Boolean.parseBoolean(arguments.get(KEY_FLATTEN)); 930757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye } 940757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye 950757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye @VisibleForTesting 960757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye ChangeLayoutRefactoring(List<Element> selectedElements, LayoutEditor editor) { 970757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye super(selectedElements, editor); 988dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 998dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 1008dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye public ChangeLayoutRefactoring(IFile file, LayoutEditor editor, ITextSelection selection, 1018dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye ITreeSelection treeSelection) { 1028dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye super(file, editor, selection, treeSelection); 1038dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 1048dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 1058dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye @Override 1068dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException, 1078dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye OperationCanceledException { 1088dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye RefactoringStatus status = new RefactoringStatus(); 1098dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 1108dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye try { 1118dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye pm.beginTask("Checking preconditions...", 2); 1128dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 1138dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye if (mSelectionStart == -1 || mSelectionEnd == -1) { 1148dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye status.addFatalError("No selection to convert"); 1158dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye return status; 1168dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 1178dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 1188dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye if (mElements.size() != 1) { 1198dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye status.addFatalError("Select precisely one layout to convert"); 1208dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye return status; 1218dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 1228dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 1238dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye pm.worked(1); 1248dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye return status; 1258dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 1268dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } finally { 1278dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye pm.done(); 1288dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 1298dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 1308dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 1318dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye @Override 1328dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye protected VisualRefactoringDescriptor createDescriptor() { 1338dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye String comment = getName(); 1348dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye return new Descriptor( 1358dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye mProject.getName(), //project 1368dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye comment, //description 1378dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye comment, //comment 1388dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye createArgumentMap()); 1398dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 1408dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 1418dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye @Override 1428dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye protected Map<String, String> createArgumentMap() { 1438dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye Map<String, String> args = super.createArgumentMap(); 1448dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye args.put(KEY_TYPE, mTypeFqcn); 1450757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye args.put(KEY_FLATTEN, Boolean.toString(mFlatten)); 1468dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 1478dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye return args; 1488dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 1498dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 1508dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye @Override 1518dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye public String getName() { 1528dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye return "Change Layout"; 1538dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 1548dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 1558dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye void setType(String typeFqcn) { 1568dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye mTypeFqcn = typeFqcn; 1578dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 1588dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 1590757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye void setFlatten(boolean flatten) { 1600757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye mFlatten = flatten; 1610757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye } 1620757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye 1630757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye @Override 1640757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye protected List<Element> initElements() { 1650757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye List<Element> elements = super.initElements(); 1660757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye 1670757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye // Don't convert a root GestureOverlayView; convert its child. This looks for 1680757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye // gesture overlays, and if found, it generates a new child list where the gesture 1690757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye // overlay children are replaced by their first element children 1700757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye for (Element element : elements) { 1710757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye String tagName = element.getTagName(); 1720757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye if (tagName.equals(GESTURE_OVERLAY_VIEW) 1730757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye || tagName.equals(FQCN_GESTURE_OVERLAY_VIEW)) { 1740757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye List<Element> replacement = new ArrayList<Element>(elements.size()); 1750757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye for (Element e : elements) { 1760757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye tagName = e.getTagName(); 1770757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye if (tagName.equals(GESTURE_OVERLAY_VIEW) 1780757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye || tagName.equals(FQCN_GESTURE_OVERLAY_VIEW)) { 1790757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye NodeList children = e.getChildNodes(); 1800757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye Element first = null; 1810757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye for (int i = 0, n = children.getLength(); i < n; i++) { 1820757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye Node node = children.item(i); 1830757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye if (node.getNodeType() == Node.ELEMENT_NODE) { 1840757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye first = (Element) node; 1850757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye break; 1860757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye } 1870757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye } 1880757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye if (first != null) { 1890757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye e = first; 1900757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye } 1910757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye } 1920757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye replacement.add(e); 1930757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye } 1940757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye return replacement; 1950757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye } 1960757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye } 1970757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye 1980757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye return elements; 1990757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye } 2000757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye 2018dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye @Override 202eacf5a536e29b366e6e2dcf6a80d86ad5241734cTor Norbye protected List<Change> computeChanges(IProgressMonitor monitor) { 2038dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye String name = getViewClass(mTypeFqcn); 2048dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 2058dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye IFile file = mEditor.getInputFile(); 2068dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye List<Change> changes = new ArrayList<Change>(); 2078dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye TextFileChange change = new TextFileChange(file.getName(), file); 2088dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye MultiTextEdit rootEdit = new MultiTextEdit(); 2098dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye change.setTextType(EXT_XML); 2108dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye changes.add(change); 2118dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 2128dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye String text = getText(mSelectionStart, mSelectionEnd); 2138dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye Element layout = getPrimaryElement(); 2148dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye String oldName = layout.getNodeName(); 2158dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye int open = text.indexOf(oldName); 2168dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye int close = text.lastIndexOf(oldName); 2178dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 2188dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye if (open != -1 && close != -1) { 2198dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye int oldLength = oldName.length(); 2208dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye rootEdit.addChild(new ReplaceEdit(mSelectionStart + open, oldLength, name)); 2218dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye if (close != open) { // Gracefully handle <FooLayout/> 2228dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye rootEdit.addChild(new ReplaceEdit(mSelectionStart + close, oldLength, name)); 2238dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 2248dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 2258dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 2269e6db060854d0e890190919a27a1846f50f69d1aTor Norbye String oldId = getId(layout); 2279e6db060854d0e890190919a27a1846f50f69d1aTor Norbye String newId = ensureIdMatchesType(layout, mTypeFqcn, rootEdit); 2289e6db060854d0e890190919a27a1846f50f69d1aTor Norbye // Update any layout references to the old id with the new id 2299e6db060854d0e890190919a27a1846f50f69d1aTor Norbye if (oldId != null && newId != null) { 2309e6db060854d0e890190919a27a1846f50f69d1aTor Norbye IStructuredModel model = mEditor.getModelForRead(); 2319e6db060854d0e890190919a27a1846f50f69d1aTor Norbye try { 2329e6db060854d0e890190919a27a1846f50f69d1aTor Norbye IStructuredDocument doc = model.getStructuredDocument(); 2339e6db060854d0e890190919a27a1846f50f69d1aTor Norbye if (doc != null) { 2349e6db060854d0e890190919a27a1846f50f69d1aTor Norbye List<TextEdit> replaceIds = replaceIds(getAndroidNamespacePrefix(), doc, 2359e6db060854d0e890190919a27a1846f50f69d1aTor Norbye mSelectionStart, 2369e6db060854d0e890190919a27a1846f50f69d1aTor Norbye mSelectionEnd, oldId, newId); 2379e6db060854d0e890190919a27a1846f50f69d1aTor Norbye for (TextEdit edit : replaceIds) { 2389e6db060854d0e890190919a27a1846f50f69d1aTor Norbye rootEdit.addChild(edit); 2399e6db060854d0e890190919a27a1846f50f69d1aTor Norbye } 2409e6db060854d0e890190919a27a1846f50f69d1aTor Norbye } 2419e6db060854d0e890190919a27a1846f50f69d1aTor Norbye } finally { 2429e6db060854d0e890190919a27a1846f50f69d1aTor Norbye model.releaseFromRead(); 2439e6db060854d0e890190919a27a1846f50f69d1aTor Norbye } 2449e6db060854d0e890190919a27a1846f50f69d1aTor Norbye } 2450757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye 2468dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye String oldType = getOldType(); 2478dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye String newType = mTypeFqcn; 2480757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye if (newType.equals(FQCN_RELATIVE_LAYOUT)) { 2490757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye if (oldType.equals(FQCN_LINEAR_LAYOUT) && !mFlatten) { 2500757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye // Hand-coded conversion specifically tailored for linear to relative, provided 2510757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye // there is no hierarchy flattening 2520757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye // TODO: use the RelativeLayoutConversionHelper for this; it does a better job 2530757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye // analyzing gravities etc. 2540757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye convertLinearToRelative(rootEdit); 2550757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye removeUndefinedLayoutAttrs(rootEdit, layout); 2560757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye } else { 2570757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye // Generic conversion to relative - can also flatten the hierarchy 2580757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye convertAnyToRelative(rootEdit); 2590757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye // This already handles removing undefined layout attributes -- right? 2600757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye //removeUndefinedLayoutAttrs(rootEdit, layout); 2610757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye } 2628dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } else if (oldType.equals(FQCN_RELATIVE_LAYOUT) && newType.equals(FQCN_LINEAR_LAYOUT)) { 2638dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye convertRelativeToLinear(rootEdit); 2640757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye removeUndefinedLayoutAttrs(rootEdit, layout); 2658dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } else if (oldType.equals(FQCN_LINEAR_LAYOUT) && newType.equals(FQCN_TABLE_LAYOUT)) { 2668dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye convertLinearToTable(rootEdit); 2670757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye removeUndefinedLayoutAttrs(rootEdit, layout); 2688dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } else { 2698dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye convertGeneric(rootEdit, oldType, newType); 2700757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye removeUndefinedLayoutAttrs(rootEdit, layout); 2718dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 2728dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 273f5256a38ef2e429b5efd4482808bc902bf7634e3Tor Norbye if (AdtPrefs.getPrefs().getFormatGuiXml()) { 274f5256a38ef2e429b5efd4482808bc902bf7634e3Tor Norbye MultiTextEdit formatted = reformat(rootEdit, XmlFormatStyle.LAYOUT); 275f5256a38ef2e429b5efd4482808bc902bf7634e3Tor Norbye if (formatted != null) { 276f5256a38ef2e429b5efd4482808bc902bf7634e3Tor Norbye rootEdit = formatted; 277f5256a38ef2e429b5efd4482808bc902bf7634e3Tor Norbye } 278f5256a38ef2e429b5efd4482808bc902bf7634e3Tor Norbye } 279f5256a38ef2e429b5efd4482808bc902bf7634e3Tor Norbye change.setEdit(rootEdit); 280f5256a38ef2e429b5efd4482808bc902bf7634e3Tor Norbye 2818dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye return changes; 2828dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 2838dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 2848dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye /** Hand coded conversion from a LinearLayout to a TableLayout */ 2858dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye private void convertLinearToTable(MultiTextEdit rootEdit) { 2868dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye // This is pretty easy; just switch the root tag (already done by the initial generic 2878dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye // conversion) and then convert all the children into <TableRow> elements. 2888dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye // Finally, get rid of the orientation attribute, if any. 2898dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye Element layout = getPrimaryElement(); 2908dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye removeOrientationAttribute(rootEdit, layout); 2918dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 2928dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye NodeList children = layout.getChildNodes(); 2938dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye for (int i = 0, n = children.getLength(); i < n; i++) { 2948dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye Node node = children.item(i); 2958dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye if (node.getNodeType() == Node.ELEMENT_NODE) { 2968dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye Element child = (Element) node; 2978dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye if (node instanceof IndexedRegion) { 2988dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye IndexedRegion region = (IndexedRegion) node; 2998dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye int start = region.getStartOffset(); 3008dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye int end = region.getEndOffset(); 3018dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye String text = getText(start, end); 3028dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye String oldName = child.getNodeName(); 3038dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye if (oldName.equals(LINEAR_LAYOUT)) { 3048dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye removeOrientationAttribute(rootEdit, child); 3058dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye int open = text.indexOf(oldName); 3068dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye int close = text.lastIndexOf(oldName); 3078dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 3088dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye if (open != -1 && close != -1) { 3098dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye int oldLength = oldName.length(); 3108dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye rootEdit.addChild(new ReplaceEdit(mSelectionStart + open, oldLength, 3118dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye TABLE_ROW)); 3128dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye if (close != open) { // Gracefully handle <FooLayout/> 3138dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye rootEdit.addChild(new ReplaceEdit(mSelectionStart + close, 3148dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye oldLength, TABLE_ROW)); 3158dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 3168dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 3178dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } // else: WRAP in TableLayout! 3188dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 3198dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 3208dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 3218dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 3228dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 3238dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye /** Hand coded conversion from a LinearLayout to a RelativeLayout */ 3248dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye private void convertLinearToRelative(MultiTextEdit rootEdit) { 3258dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye // This can be done accurately. 3268dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye Element layout = getPrimaryElement(); 3278dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye // Horizontal is the default, so if no value is specified it is horizontal. 3288dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye boolean isVertical = VALUE_VERTICAL.equals(layout.getAttributeNS(ANDROID_URI, 3298dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye ATTR_ORIENTATION)); 3308dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 3318dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye removeOrientationAttribute(rootEdit, layout); 3328dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 3338dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye String attributePrefix = getAndroidNamespacePrefix(); 3348dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 3358dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye // TODO: Consider gravity of each element 3368dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye // TODO: Consider weight of each element 3378dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye // Right now it simply makes a single attachment to keep the order. 3388dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 3398dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye if (isVertical) { 3408dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye // Align each child to the bottom and left of its parent 3418dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye NodeList children = layout.getChildNodes(); 3428dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye String prevId = null; 3438dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye for (int i = 0, n = children.getLength(); i < n; i++) { 3448dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye Node node = children.item(i); 3458dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye if (node.getNodeType() == Node.ELEMENT_NODE) { 3468dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye Element child = (Element) node; 3470757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye String id = ensureHasId(rootEdit, child, null); 3488dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye if (prevId != null) { 3490757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye setAttribute(rootEdit, child, ANDROID_URI, attributePrefix, 3508dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye ATTR_LAYOUT_BELOW, prevId); 3518dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 3528dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye prevId = id; 3538dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 3548dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 3558dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } else { 3568dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye // Align each child to the left 3578dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye NodeList children = layout.getChildNodes(); 3588dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye boolean isBaselineAligned = 3598dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye !VALUE_FALSE.equals(layout.getAttributeNS(ANDROID_URI, ATTR_BASELINE_ALIGNED)); 3608dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 3618dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye String prevId = null; 3628dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye for (int i = 0, n = children.getLength(); i < n; i++) { 3638dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye Node node = children.item(i); 3648dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye if (node.getNodeType() == Node.ELEMENT_NODE) { 3658dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye Element child = (Element) node; 3660757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye String id = ensureHasId(rootEdit, child, null); 3678dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye if (prevId != null) { 3680757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye setAttribute(rootEdit, child, ANDROID_URI, attributePrefix, 3698dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye ATTR_LAYOUT_TO_RIGHT_OF, prevId); 3708dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye if (isBaselineAligned) { 3710757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye setAttribute(rootEdit, child, ANDROID_URI, attributePrefix, 3728dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye ATTR_LAYOUT_ALIGN_BASELINE, prevId); 3738dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 3748dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 3758dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye prevId = id; 3768dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 3778dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 3788dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 3798dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 3808dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 3818dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye /** Strips out the android:orientation attribute from the given linear layout element */ 3828dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye private void removeOrientationAttribute(MultiTextEdit rootEdit, Element layout) { 3838dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye assert layout.getTagName().equals(LINEAR_LAYOUT); 3848dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye removeAttribute(rootEdit, layout, ANDROID_URI, ATTR_ORIENTATION); 3858dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 3868dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 3878dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye /** 3888dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * Hand coded conversion from a RelativeLayout to a LinearLayout 3898dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * 3908dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * @param rootEdit the root multi text edit to add edits to 3918dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye */ 3928dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye private void convertRelativeToLinear(MultiTextEdit rootEdit) { 3938dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye // This is going to be lossy... 3948dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye // TODO: Attempt to "order" the items based on their visual positions 3958dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye // and insert them in that order in the LinearLayout. 3968dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye // TODO: Possibly use nesting if necessary, by spatial subdivision, 3978dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye // to accomplish roughly the same layout as the relative layout specifies. 3988dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 3998dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 4008dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye /** 4018dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * Hand coded -generic- conversion from one layout to another. This is not going to be 4028dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * an accurate layout transformation; instead it simply migrates the layout attributes 4038dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * that are supported, and adds defaults for any new required layout attributes. In 4048dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * addition, it attempts to order the children visually based on where they fit in a 4058dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * rendering. (Unsupported layout attributes will be removed by the caller at the 4068dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * end.) 4078dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * <ul> 4088dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * <li>Try to handle nesting. Converting a *hierarchy* of layouts into a flatter 4098dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * layout for powerful layouts that support it, like RelativeLayout. 4108dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * <li>Try to do automatic "inference" about the layout. I can render it and look at 4118dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * the ViewInfo positions and sizes. I can render it multiple times, at different 4128dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * sizes, to infer "stretchiness" and "weight" properties of the children. 4138dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * <li>Try to do indirect transformations. E.g. if I can go from A to B, and B to C, 4148dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * then an attempt to go from A to C should perform conversions A to B and then B to 4158dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * C. 4168dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * </ul> 4178dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * 4188dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * @param rootEdit the root multi text edit to add edits to 4198dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * @param oldType the fully qualified class name of the layout type we are converting 4208dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * from 4218dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * @param newType the fully qualified class name of the layout type we are converting 4228dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye * to 4238dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye */ 4248dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye private void convertGeneric(MultiTextEdit rootEdit, String oldType, String newType) { 4258dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye // TODO: Add hooks for 3rd party conversions getting registered through the 4268dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye // IViewRule interface. 4278dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 4288dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye // For now we simply go with the default behavior, which is to just strip the 4298dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye // layout attributes that aren't supported. 4308dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 4318dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 4328dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye /** Removes all the unused attributes after a conversion */ 4338dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye private void removeUndefinedLayoutAttrs(MultiTextEdit rootEdit, Element layout) { 4340757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye ViewElementDescriptor descriptor = getElementDescriptor(mTypeFqcn); 4358dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye if (descriptor == null) { 4368dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye return; 4378dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 4388dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 4398dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye Set<String> defined = new HashSet<String>(); 4408dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye AttributeDescriptor[] layoutAttributes = descriptor.getLayoutAttributes(); 4418dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye for (AttributeDescriptor attribute : layoutAttributes) { 4428dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye defined.add(attribute.getXmlLocalName()); 4438dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 4448dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 4458dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye NodeList children = layout.getChildNodes(); 4468dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye for (int i = 0, n = children.getLength(); i < n; i++) { 4478dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye Node node = children.item(i); 4488dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye if (node.getNodeType() == Node.ELEMENT_NODE) { 4498dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye Element child = (Element) node; 4508dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 4518dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye List<Attr> attributes = findLayoutAttributes(child); 4528dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye for (Attr attribute : attributes) { 4538dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye String name = attribute.getLocalName(); 4548dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye if (!defined.contains(name)) { 4558dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye // Remove it 4568dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye removeAttribute(rootEdit, child, attribute.getNamespaceURI(), name); 4578dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 4588dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 4598dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 4608dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 4618dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 4628dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 4630757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye /** Hand coded conversion from any layout to a RelativeLayout */ 4640757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye private void convertAnyToRelative(MultiTextEdit rootEdit) { 4650757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye // To perform a conversion from any other layout type, including nested conversion, 4660757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye Element layout = getPrimaryElement(); 4670757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye CanvasViewInfo rootView = mRootView; 4680757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye if (rootView == null) { 4690757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye LayoutCanvas canvas = mEditor.getGraphicalEditor().getCanvasControl(); 4700757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye ViewHierarchy viewHierarchy = canvas.getViewHierarchy(); 4710757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye rootView = viewHierarchy.getRoot(); 4728dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 4738dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 4740757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye RelativeLayoutConversionHelper helper = 4750757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye new RelativeLayoutConversionHelper(this, layout, mFlatten, rootEdit, rootView); 4760757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye helper.convertToRelative(); 4778dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 4788dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 4798dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye public static class Descriptor extends VisualRefactoringDescriptor { 4808dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye public Descriptor(String project, String description, String comment, 4818dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye Map<String, String> arguments) { 4828dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye super("com.android.ide.eclipse.adt.refactoring.convert", //$NON-NLS-1$ 4838dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye project, description, comment, arguments); 4848dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 4858dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 4868dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye @Override 4878dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye protected Refactoring createRefactoring(Map<String, String> args) { 4888dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye return new ChangeLayoutRefactoring(args); 4898dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 4908dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 4918dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 4928dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye String getOldType() { 4938dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye Element primary = getPrimaryElement(); 4948dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye if (primary != null) { 4958dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye String oldType = primary.getTagName(); 4968dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye if (oldType.indexOf('.') == -1) { 4978dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye oldType = ANDROID_WIDGET_PREFIX + oldType; 4988dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 4998dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye return oldType; 5008dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 5018dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye 5028dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye return null; 5038dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye } 5040757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye 5050757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye @VisibleForTesting 5060757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye protected CanvasViewInfo mRootView; 5070757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye 5080757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye @VisibleForTesting 5090757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye public void setRootView(CanvasViewInfo rootView) { 5100757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye mRootView = rootView; 5110757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye } 512891fe684c31864eab0ef4372ea6379f2c3b5fb4fTor Norbye 513891fe684c31864eab0ef4372ea6379f2c3b5fb4fTor Norbye @Override 514891fe684c31864eab0ef4372ea6379f2c3b5fb4fTor Norbye VisualRefactoringWizard createWizard() { 515891fe684c31864eab0ef4372ea6379f2c3b5fb4fTor Norbye return new ChangeLayoutWizard(this, mEditor); 516891fe684c31864eab0ef4372ea6379f2c3b5fb4fTor Norbye } 5178dc4366bbaad39d56e1c2ded4046c86a95a17666Tor Norbye} 518