18fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael/* 28fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael * Copyright (C) 2009 The Android Open Source Project 38fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael * 48fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael * Licensed under the Eclipse Public License, Version 1.0 (the "License"); 58fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael * you may not use this file except in compliance with the License. 68fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael * You may obtain a copy of the License at 78fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael * 88fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael * http://www.eclipse.org/org/documents/epl-v10.php 98fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael * 108fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael * Unless required by applicable law or agreed to in writing, software 118fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael * distributed under the License is distributed on an "AS IS" BASIS, 128fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael * See the License for the specific language governing permissions and 148fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael * limitations under the License. 158fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael */ 168fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael 178fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphaelpackage com.android.ide.eclipse.adt.internal.editors.layout.gle2; 188fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael 1912d4581faa6438941e65a9dc83213be34c6ca970Tor Norbyeimport static com.android.SdkConstants.FQCN_SPACE; 2012d4581faa6438941e65a9dc83213be34c6ca970Tor Norbyeimport static com.android.SdkConstants.FQCN_SPACE_V7; 2112d4581faa6438941e65a9dc83213be34c6ca970Tor Norbyeimport static com.android.SdkConstants.GESTURE_OVERLAY_VIEW; 2212d4581faa6438941e65a9dc83213be34c6ca970Tor Norbyeimport static com.android.SdkConstants.VIEW_MERGE; 239155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye 2412d4581faa6438941e65a9dc83213be34c6ca970Tor Norbyeimport com.android.SdkConstants; 259bd06947302ca6ca3e0b90eef894e553c6c3e067Tor Norbyeimport com.android.annotations.NonNull; 269bd06947302ca6ca3e0b90eef894e553c6c3e067Tor Norbyeimport com.android.annotations.Nullable; 2780d9301c2e874b29889c41adb0623666cf534fa0Tor Norbyeimport com.android.ide.common.api.Margins; 2883dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbyeimport com.android.ide.common.api.Rect; 294eacdfbcc84ad11f599020b12ad76aebed70537fTor Norbyeimport com.android.ide.common.layout.GridLayoutRule; 308386da5e451eec396d0e71576e7366a98017674fTor Norbyeimport com.android.ide.common.rendering.api.Capability; 319155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbyeimport com.android.ide.common.rendering.api.MergeCookie; 3295b17a5e62eeeb7b38ef668508df43a1ee9e0880Xavier Ducrohetimport com.android.ide.common.rendering.api.ViewInfo; 3383dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbyeimport com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor; 3423258d5ae21d164049eef14eebb2ef28a43a7b40Tor Norbyeimport com.android.ide.eclipse.adt.internal.editors.layout.UiElementPullParser; 358fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphaelimport com.android.ide.eclipse.adt.internal.editors.layout.uimodel.UiViewElementNode; 3683dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbyeimport com.android.ide.eclipse.adt.internal.editors.uimodel.UiAttributeNode; 3783dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbyeimport com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode; 3885e4a1a9dd133abb879ec211ce8dd385004edf22Xavier Ducrohetimport com.android.utils.Pair; 398fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael 408fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphaelimport org.eclipse.swt.graphics.Rectangle; 41f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Mollimport org.eclipse.ui.views.properties.IPropertyDescriptor; 42f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Mollimport org.eclipse.ui.views.properties.IPropertySheetPage; 43f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Mollimport org.eclipse.ui.views.properties.IPropertySource; 4499fd7eee15c89fd45b884842c44371326f851930Tor Norbyeimport org.w3c.dom.Element; 4576bbc57fcc07859cd1d7f1c9be102b1dc5218f27Tor Norbyeimport org.w3c.dom.Node; 468fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael 478fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphaelimport java.util.ArrayList; 489155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbyeimport java.util.Collections; 499155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbyeimport java.util.HashMap; 508386da5e451eec396d0e71576e7366a98017674fTor Norbyeimport java.util.LinkedList; 518386da5e451eec396d0e71576e7366a98017674fTor Norbyeimport java.util.List; 529155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbyeimport java.util.Map; 538fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael 548fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael/** 55f29be828de51dbe2f55508cd620142e35cd19cbdXavier Ducrohet * Maps a {@link ViewInfo} in a structure more adapted to our needs. 568fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael * The only large difference is that we keep both the original bounds of the view info 57f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll * and we pre-compute the selection bounds which are absolute to the rendered image 58f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll * (whereas the original bounds are relative to the parent view.) 598fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael * <p/> 60f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll * Each view also knows its parent and children. 618fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael * <p/> 62f29be828de51dbe2f55508cd620142e35cd19cbdXavier Ducrohet * We can't alter {@link ViewInfo} as it is part of the LayoutBridge and needs to 638fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael * have a fixed API. 64f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll * <p/> 65f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll * The view info also implements {@link IPropertySource}, which enables a linked 66f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll * {@link IPropertySheetPage} to display the attributes of the selected element. 67f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll * This class actually delegates handling of {@link IPropertySource} to the underlying 68f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll * {@link UiViewElementNode}, if any. 698fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael */ 70f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Mollpublic class CanvasViewInfo implements IPropertySource { 718fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael 728fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael /** 738fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael * Minimal size of the selection, in case an empty view or layout is selected. 748fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael */ 759bd06947302ca6ca3e0b90eef894e553c6c3e067Tor Norbye public static final int SELECTION_MIN_SIZE = 6; 768fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael 778fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael private final Rectangle mAbsRect; 788fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael private final Rectangle mSelectionRect; 798fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael private final String mName; 80d9881e4b0ed00c7f7fd529f482cfd08b7d9ec396Xavier Ducrohet private final Object mViewObject; 8171f1ce4538caa9f7d0824c7f2090d95a6c6b7d71Xavier Ducrohet private final UiViewElementNode mUiViewNode; 829155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye private CanvasViewInfo mParent; 8380d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye private ViewInfo mViewInfo; 844e9c7b5df119dda3acd516fcea2ff59c22a19565Tor Norbye private final List<CanvasViewInfo> mChildren = new ArrayList<CanvasViewInfo>(); 858fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael 868fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael /** 8723258d5ae21d164049eef14eebb2ef28a43a7b40Tor Norbye * Is this view info an individually exploded view? This is the case for views 8823258d5ae21d164049eef14eebb2ef28a43a7b40Tor Norbye * that were specially inflated by the {@link UiElementPullParser} and assigned 8923258d5ae21d164049eef14eebb2ef28a43a7b40Tor Norbye * fixed padding because they were invisible and somebody requested visibility. 9023258d5ae21d164049eef14eebb2ef28a43a7b40Tor Norbye */ 9123258d5ae21d164049eef14eebb2ef28a43a7b40Tor Norbye private boolean mExploded; 9223258d5ae21d164049eef14eebb2ef28a43a7b40Tor Norbye 9323258d5ae21d164049eef14eebb2ef28a43a7b40Tor Norbye /** 949155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * Node sibling. This is usually null, but it's possible for a single node in the 959155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * model to have <b>multiple</b> separate views in the canvas, for example 969155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * when you {@code <include>} a view that has multiple widgets inside a 979155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * {@code <merge>} tag. In this case, all the views have the same node model, 989155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * the include tag, and selecting the include should highlight all the separate 999155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * views that are linked to this node. That's what this field is all about: it is 1009155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * a <b>circular</b> list of all the siblings that share the same node. 1019155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye */ 1029155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye private List<CanvasViewInfo> mNodeSiblings; 1039155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye 1049155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye /** 1058386da5e451eec396d0e71576e7366a98017674fTor Norbye * Constructs a {@link CanvasViewInfo} initialized with the given initial values. 1068fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael */ 1078386da5e451eec396d0e71576e7366a98017674fTor Norbye private CanvasViewInfo(CanvasViewInfo parent, String name, 1088386da5e451eec396d0e71576e7366a98017674fTor Norbye Object viewObject, UiViewElementNode node, Rectangle absRect, 10980d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye Rectangle selectionRect, ViewInfo viewInfo) { 1108fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael mParent = parent; 1118386da5e451eec396d0e71576e7366a98017674fTor Norbye mName = name; 1128386da5e451eec396d0e71576e7366a98017674fTor Norbye mViewObject = viewObject; 11380d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye mViewInfo = viewInfo; 1148386da5e451eec396d0e71576e7366a98017674fTor Norbye mUiViewNode = node; 1158386da5e451eec396d0e71576e7366a98017674fTor Norbye mAbsRect = absRect; 1168386da5e451eec396d0e71576e7366a98017674fTor Norbye mSelectionRect = selectionRect; 1178fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael } 1188fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael 1198fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael /** 120f29be828de51dbe2f55508cd620142e35cd19cbdXavier Ducrohet * Returns the original {@link ViewInfo} bounds in absolute coordinates 1218fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael * over the whole graphic. 1228386da5e451eec396d0e71576e7366a98017674fTor Norbye * 1238386da5e451eec396d0e71576e7366a98017674fTor Norbye * @return the bounding box in absolute coordinates 1248fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael */ 1259bd06947302ca6ca3e0b90eef894e553c6c3e067Tor Norbye @NonNull 1268fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael public Rectangle getAbsRect() { 1278fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael return mAbsRect; 1288fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael } 1298fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael 1309bd06947302ca6ca3e0b90eef894e553c6c3e067Tor Norbye /** 1319bd06947302ca6ca3e0b90eef894e553c6c3e067Tor Norbye * Returns the absolute selection bounds of the view info as a rectangle. 1329bd06947302ca6ca3e0b90eef894e553c6c3e067Tor Norbye * The selection bounds will always have a size greater or equal to 1339bd06947302ca6ca3e0b90eef894e553c6c3e067Tor Norbye * {@link #SELECTION_MIN_SIZE}. 1349bd06947302ca6ca3e0b90eef894e553c6c3e067Tor Norbye * The width/height is inclusive (i.e. width = right-left-1). 1359bd06947302ca6ca3e0b90eef894e553c6c3e067Tor Norbye * This is in absolute "screen" coordinates (relative to the rendered bitmap). 1369bd06947302ca6ca3e0b90eef894e553c6c3e067Tor Norbye * 1379bd06947302ca6ca3e0b90eef894e553c6c3e067Tor Norbye * @return the absolute selection bounds 1389bd06947302ca6ca3e0b90eef894e553c6c3e067Tor Norbye */ 1399bd06947302ca6ca3e0b90eef894e553c6c3e067Tor Norbye @NonNull 1408fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael public Rectangle getSelectionRect() { 1418fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael return mSelectionRect; 1428fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael } 1438fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael 1448fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael /** 14571f1ce4538caa9f7d0824c7f2090d95a6c6b7d71Xavier Ducrohet * Returns the view node. Could be null, although unlikely. 1468fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael * @return An {@link UiViewElementNode} that uniquely identifies the object in the XML model. 14771f1ce4538caa9f7d0824c7f2090d95a6c6b7d71Xavier Ducrohet * @see ViewInfo#getCookie() 1488fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael */ 1499bd06947302ca6ca3e0b90eef894e553c6c3e067Tor Norbye @Nullable 15071f1ce4538caa9f7d0824c7f2090d95a6c6b7d71Xavier Ducrohet public UiViewElementNode getUiViewNode() { 15171f1ce4538caa9f7d0824c7f2090d95a6c6b7d71Xavier Ducrohet return mUiViewNode; 1528fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael } 1538fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael 1548fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael /** 1558fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael * Returns the parent {@link CanvasViewInfo}. 1568fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael * It is null for the root and non-null for children. 1578386da5e451eec396d0e71576e7366a98017674fTor Norbye * 1588386da5e451eec396d0e71576e7366a98017674fTor Norbye * @return the parent {@link CanvasViewInfo}, which can be null 1598fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael */ 1609bd06947302ca6ca3e0b90eef894e553c6c3e067Tor Norbye @Nullable 1618fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael public CanvasViewInfo getParent() { 1628fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael return mParent; 1638fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael } 1648fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael 1658fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael /** 1668fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael * Returns the list of children of this {@link CanvasViewInfo}. 1678fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael * The list is never null. It can be empty. 1688fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael * By contract, this.getChildren().get(0..n-1).getParent() == this. 1698386da5e451eec396d0e71576e7366a98017674fTor Norbye * 1708386da5e451eec396d0e71576e7366a98017674fTor Norbye * @return the children, never null 1718fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael */ 1729bd06947302ca6ca3e0b90eef894e553c6c3e067Tor Norbye @NonNull 1738386da5e451eec396d0e71576e7366a98017674fTor Norbye public List<CanvasViewInfo> getChildren() { 1748fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael return mChildren; 1758fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael } 1768fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael 1778fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael /** 1789155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * For nodes that have multiple views rendered from a single node, such as the 1799155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * children of a {@code <merge>} tag included into a separate layout, return the 1809155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * "primary" view, the first view that is rendered 1819155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye */ 1829bd06947302ca6ca3e0b90eef894e553c6c3e067Tor Norbye @Nullable 1839155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye private CanvasViewInfo getPrimaryNodeSibling() { 1849155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (mNodeSiblings == null || mNodeSiblings.size() == 0) { 1859155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye return null; 1869155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 1879155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye 1889155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye return mNodeSiblings.get(0); 1899155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 1909155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye 1919155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye /** 1929155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * Returns true if this view represents one view of many linked to a single node, and 1939155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * where this is the primary view. The primary view is the one that will be shown 1949155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * in the outline for example (since we only show nodes, not views, in the outline, 1959155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * and therefore don't want repetitions when a view has more than one view info.) 1969155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * 1979155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * @return true if this is the primary view among more than one linked to a single 1989155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * node 1999155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye */ 2009155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye private boolean isPrimaryNodeSibling() { 2019155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye return getPrimaryNodeSibling() == this; 2029155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 2039155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye 2049155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye /** 2059155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * Returns the list of node sibling of this view (which <b>will include this 2069155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * view</b>). For most views this is going to be null, but for views that share a 2079155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * single node (such as widgets inside a {@code <merge>} tag included into another 2089155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * layout), this will provide all the views that correspond to the node. 2099155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * 2109155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * @return a non-empty list of siblings (including this), or null 2119155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye */ 2129bd06947302ca6ca3e0b90eef894e553c6c3e067Tor Norbye @Nullable 2139155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye public List<CanvasViewInfo> getNodeSiblings() { 2149155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye return mNodeSiblings; 2159155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 2169155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye 2179155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye /** 2189155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * Returns all the children of the canvas view info where each child corresponds to a 2198925febd3beb31e4c5e1a3329ed1e73291dd3936Tor Norbye * unique node that the user can see and select. This is intended for use by the 2208925febd3beb31e4c5e1a3329ed1e73291dd3936Tor Norbye * outline for example, where only the actual nodes are displayed, not the views 2218925febd3beb31e4c5e1a3329ed1e73291dd3936Tor Norbye * themselves. 2229155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * <p> 2239155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * Most views have their own nodes, so this is generally the same as 2249155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * {@link #getChildren}, except in the case where you for example include a view that 2259155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * has multiple widgets inside a {@code <merge>} tag, where all these widgets have the 2269155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * same node (the {@code <merge>} tag). 2279155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * 2289155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * @return list of {@link CanvasViewInfo} objects that are children of this view, 2299155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * never null 2309155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye */ 2319bd06947302ca6ca3e0b90eef894e553c6c3e067Tor Norbye @NonNull 2329155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye public List<CanvasViewInfo> getUniqueChildren() { 2338925febd3beb31e4c5e1a3329ed1e73291dd3936Tor Norbye boolean haveHidden = false; 2348925febd3beb31e4c5e1a3329ed1e73291dd3936Tor Norbye 2359155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye for (CanvasViewInfo info : mChildren) { 2369155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (info.mNodeSiblings != null) { 2379155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // We have secondary children; must create a new collection containing 2389155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // only non-secondary children 2399155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye List<CanvasViewInfo> children = new ArrayList<CanvasViewInfo>(); 2409155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye for (CanvasViewInfo vi : mChildren) { 2419155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (vi.mNodeSiblings == null) { 2429155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye children.add(vi); 2439155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } else if (vi.isPrimaryNodeSibling()) { 2449155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye children.add(vi); 2459155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 2469155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 2479155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye return children; 2489155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 2498925febd3beb31e4c5e1a3329ed1e73291dd3936Tor Norbye 2508925febd3beb31e4c5e1a3329ed1e73291dd3936Tor Norbye haveHidden |= info.isHidden(); 2518925febd3beb31e4c5e1a3329ed1e73291dd3936Tor Norbye } 2528925febd3beb31e4c5e1a3329ed1e73291dd3936Tor Norbye 2538925febd3beb31e4c5e1a3329ed1e73291dd3936Tor Norbye if (haveHidden) { 2548925febd3beb31e4c5e1a3329ed1e73291dd3936Tor Norbye List<CanvasViewInfo> children = new ArrayList<CanvasViewInfo>(mChildren.size()); 2558925febd3beb31e4c5e1a3329ed1e73291dd3936Tor Norbye for (CanvasViewInfo vi : mChildren) { 2568925febd3beb31e4c5e1a3329ed1e73291dd3936Tor Norbye if (!vi.isHidden()) { 2578925febd3beb31e4c5e1a3329ed1e73291dd3936Tor Norbye children.add(vi); 2588925febd3beb31e4c5e1a3329ed1e73291dd3936Tor Norbye } 2598925febd3beb31e4c5e1a3329ed1e73291dd3936Tor Norbye } 2608925febd3beb31e4c5e1a3329ed1e73291dd3936Tor Norbye 2618925febd3beb31e4c5e1a3329ed1e73291dd3936Tor Norbye return children; 2629155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 2639155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye 2649155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye return mChildren; 2659155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 2669155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye 2679155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye /** 268671636a1a16dbe4fb73509b5e3cb92ca96a778c7Raphael * Returns true if the specific {@link CanvasViewInfo} is a parent 269671636a1a16dbe4fb73509b5e3cb92ca96a778c7Raphael * of this {@link CanvasViewInfo}. It can be a direct parent or any 270671636a1a16dbe4fb73509b5e3cb92ca96a778c7Raphael * grand-parent higher in the hierarchy. 2718386da5e451eec396d0e71576e7366a98017674fTor Norbye * 2728386da5e451eec396d0e71576e7366a98017674fTor Norbye * @param potentialParent the view info to check 2738386da5e451eec396d0e71576e7366a98017674fTor Norbye * @return true if the given info is a parent of this view 274671636a1a16dbe4fb73509b5e3cb92ca96a778c7Raphael */ 2759bd06947302ca6ca3e0b90eef894e553c6c3e067Tor Norbye public boolean isParent(@NonNull CanvasViewInfo potentialParent) { 276671636a1a16dbe4fb73509b5e3cb92ca96a778c7Raphael CanvasViewInfo p = mParent; 277671636a1a16dbe4fb73509b5e3cb92ca96a778c7Raphael while (p != null) { 278671636a1a16dbe4fb73509b5e3cb92ca96a778c7Raphael if (p == potentialParent) { 279671636a1a16dbe4fb73509b5e3cb92ca96a778c7Raphael return true; 280671636a1a16dbe4fb73509b5e3cb92ca96a778c7Raphael } 281671636a1a16dbe4fb73509b5e3cb92ca96a778c7Raphael p = p.getParent(); 282671636a1a16dbe4fb73509b5e3cb92ca96a778c7Raphael } 283671636a1a16dbe4fb73509b5e3cb92ca96a778c7Raphael return false; 284671636a1a16dbe4fb73509b5e3cb92ca96a778c7Raphael } 285671636a1a16dbe4fb73509b5e3cb92ca96a778c7Raphael 286671636a1a16dbe4fb73509b5e3cb92ca96a778c7Raphael /** 2878fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael * Returns the name of the {@link CanvasViewInfo}. 2888fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael * Could be null, although unlikely. 2898fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael * Experience shows this is the full qualified Java name of the View. 2908925febd3beb31e4c5e1a3329ed1e73291dd3936Tor Norbye * TODO: Rename this method to getFqcn. 291f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll * 2929bd06947302ca6ca3e0b90eef894e553c6c3e067Tor Norbye * @return the name of the view info 2938386da5e451eec396d0e71576e7366a98017674fTor Norbye * 294f29be828de51dbe2f55508cd620142e35cd19cbdXavier Ducrohet * @see ViewInfo#getClassName() 2958fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael */ 2969bd06947302ca6ca3e0b90eef894e553c6c3e067Tor Norbye @NonNull 2978fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael public String getName() { 2988fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael return mName; 2998fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael } 300f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll 301d9881e4b0ed00c7f7fd529f482cfd08b7d9ec396Xavier Ducrohet /** 302d9881e4b0ed00c7f7fd529f482cfd08b7d9ec396Xavier Ducrohet * Returns the View object associated with the {@link CanvasViewInfo}. 303d9881e4b0ed00c7f7fd529f482cfd08b7d9ec396Xavier Ducrohet * @return the view object or null. 304d9881e4b0ed00c7f7fd529f482cfd08b7d9ec396Xavier Ducrohet */ 3059bd06947302ca6ca3e0b90eef894e553c6c3e067Tor Norbye @Nullable 306d9881e4b0ed00c7f7fd529f482cfd08b7d9ec396Xavier Ducrohet public Object getViewObject() { 307d9881e4b0ed00c7f7fd529f482cfd08b7d9ec396Xavier Ducrohet return mViewObject; 308d9881e4b0ed00c7f7fd529f482cfd08b7d9ec396Xavier Ducrohet } 309d9881e4b0ed00c7f7fd529f482cfd08b7d9ec396Xavier Ducrohet 3109bd06947302ca6ca3e0b90eef894e553c6c3e067Tor Norbye /** 3119bd06947302ca6ca3e0b90eef894e553c6c3e067Tor Norbye * Returns the baseline of this object, or -1 if it does not support a baseline 3129bd06947302ca6ca3e0b90eef894e553c6c3e067Tor Norbye * 3139bd06947302ca6ca3e0b90eef894e553c6c3e067Tor Norbye * @return the baseline or -1 3149bd06947302ca6ca3e0b90eef894e553c6c3e067Tor Norbye */ 31580d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye public int getBaseline() { 31680d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye if (mViewInfo != null) { 31780d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye int baseline = mViewInfo.getBaseLine(); 31880d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye if (baseline != Integer.MIN_VALUE) { 31980d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye return baseline; 32080d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye } 32180d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye } 32280d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye 32380d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye return -1; 32480d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye } 32580d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye 32680d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye /** 32780d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye * Returns the {@link Margins} for this {@link CanvasViewInfo} 32880d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye * 32980d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye * @return the {@link Margins} for this {@link CanvasViewInfo} 33080d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye */ 3319bd06947302ca6ca3e0b90eef894e553c6c3e067Tor Norbye @Nullable 33280d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye public Margins getMargins() { 33380d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye if (mViewInfo != null) { 33480d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye int leftMargin = mViewInfo.getLeftMargin(); 33580d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye int topMargin = mViewInfo.getTopMargin(); 33680d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye int rightMargin = mViewInfo.getRightMargin(); 33780d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye int bottomMargin = mViewInfo.getBottomMargin(); 33880d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye return new Margins( 33980d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye leftMargin != Integer.MIN_VALUE ? leftMargin : 0, 34080d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye rightMargin != Integer.MIN_VALUE ? rightMargin : 0, 34180d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye topMargin != Integer.MIN_VALUE ? topMargin : 0, 34280d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye bottomMargin != Integer.MIN_VALUE ? bottomMargin : 0 34380d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye ); 34480d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye } 34580d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye 34680d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye return null; 34780d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye } 34880d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye 349f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll // ---- Implementation of IPropertySource 3509bd06947302ca6ca3e0b90eef894e553c6c3e067Tor Norbye // TODO: Get rid of this once the old propertysheet implementation is fully gone 351f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll 352ab36f4e7488358dea4ab6b54ee2b7bef3da0232bTor Norbye @Override 353f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll public Object getEditableValue() { 35471f1ce4538caa9f7d0824c7f2090d95a6c6b7d71Xavier Ducrohet UiViewElementNode uiView = getUiViewNode(); 355f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll if (uiView != null) { 356f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll return ((IPropertySource) uiView).getEditableValue(); 357f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll } 358f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll return null; 359f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll } 360f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll 361ab36f4e7488358dea4ab6b54ee2b7bef3da0232bTor Norbye @Override 362f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll public IPropertyDescriptor[] getPropertyDescriptors() { 36371f1ce4538caa9f7d0824c7f2090d95a6c6b7d71Xavier Ducrohet UiViewElementNode uiView = getUiViewNode(); 364f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll if (uiView != null) { 365f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll return ((IPropertySource) uiView).getPropertyDescriptors(); 366f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll } 367f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll return null; 368f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll } 369f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll 370ab36f4e7488358dea4ab6b54ee2b7bef3da0232bTor Norbye @Override 371f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll public Object getPropertyValue(Object id) { 37271f1ce4538caa9f7d0824c7f2090d95a6c6b7d71Xavier Ducrohet UiViewElementNode uiView = getUiViewNode(); 373f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll if (uiView != null) { 374f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll return ((IPropertySource) uiView).getPropertyValue(id); 375f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll } 376f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll return null; 377f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll } 378f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll 379ab36f4e7488358dea4ab6b54ee2b7bef3da0232bTor Norbye @Override 380f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll public boolean isPropertySet(Object id) { 38171f1ce4538caa9f7d0824c7f2090d95a6c6b7d71Xavier Ducrohet UiViewElementNode uiView = getUiViewNode(); 382f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll if (uiView != null) { 383f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll return ((IPropertySource) uiView).isPropertySet(id); 384f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll } 385f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll return false; 386f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll } 387f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll 388ab36f4e7488358dea4ab6b54ee2b7bef3da0232bTor Norbye @Override 389f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll public void resetPropertyValue(Object id) { 39071f1ce4538caa9f7d0824c7f2090d95a6c6b7d71Xavier Ducrohet UiViewElementNode uiView = getUiViewNode(); 391f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll if (uiView != null) { 392f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll ((IPropertySource) uiView).resetPropertyValue(id); 393f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll } 394f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll } 395f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll 396ab36f4e7488358dea4ab6b54ee2b7bef3da0232bTor Norbye @Override 397f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll public void setPropertyValue(Object id, Object value) { 39871f1ce4538caa9f7d0824c7f2090d95a6c6b7d71Xavier Ducrohet UiViewElementNode uiView = getUiViewNode(); 399f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll if (uiView != null) { 400f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll ((IPropertySource) uiView).setPropertyValue(id, value); 401f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll } 402f3199b3448c9c80d68a3bce8b3166632d9b3e767Raphael Moll } 40376bbc57fcc07859cd1d7f1c9be102b1dc5218f27Tor Norbye 40476bbc57fcc07859cd1d7f1c9be102b1dc5218f27Tor Norbye /** 40576bbc57fcc07859cd1d7f1c9be102b1dc5218f27Tor Norbye * Returns the XML node corresponding to this info, or null if there is no 40676bbc57fcc07859cd1d7f1c9be102b1dc5218f27Tor Norbye * such XML node. 40776bbc57fcc07859cd1d7f1c9be102b1dc5218f27Tor Norbye * 40876bbc57fcc07859cd1d7f1c9be102b1dc5218f27Tor Norbye * @return The XML node corresponding to this info object, or null 40976bbc57fcc07859cd1d7f1c9be102b1dc5218f27Tor Norbye */ 4109bd06947302ca6ca3e0b90eef894e553c6c3e067Tor Norbye @Nullable 41176bbc57fcc07859cd1d7f1c9be102b1dc5218f27Tor Norbye public Node getXmlNode() { 41271f1ce4538caa9f7d0824c7f2090d95a6c6b7d71Xavier Ducrohet UiViewElementNode uiView = getUiViewNode(); 41376bbc57fcc07859cd1d7f1c9be102b1dc5218f27Tor Norbye if (uiView != null) { 41476bbc57fcc07859cd1d7f1c9be102b1dc5218f27Tor Norbye return uiView.getXmlNode(); 41576bbc57fcc07859cd1d7f1c9be102b1dc5218f27Tor Norbye } 41676bbc57fcc07859cd1d7f1c9be102b1dc5218f27Tor Norbye 41776bbc57fcc07859cd1d7f1c9be102b1dc5218f27Tor Norbye return null; 41876bbc57fcc07859cd1d7f1c9be102b1dc5218f27Tor Norbye } 41983dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye 42083dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye /** 42183dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye * Returns true iff this view info corresponds to a root element. 42283dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye * 42383dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye * @return True iff this is a root view info. 42483dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye */ 42583dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye public boolean isRoot() { 42683dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye // Select the visual element -- unless it's the root. 42783dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye // The root element is the one whose GRAND parent 42883dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye // is null (because the parent will be a -document- 42983dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye // node). 4303cf5ce58a324efb926b862b16ad8b18d033f5be9Tor Norbye 4313cf5ce58a324efb926b862b16ad8b18d033f5be9Tor Norbye // Special case: a gesture overlay is sometimes added as the root, but for all intents 4323cf5ce58a324efb926b862b16ad8b18d033f5be9Tor Norbye // and purposes it is its layout child that is the real root so treat that one as the 4333cf5ce58a324efb926b862b16ad8b18d033f5be9Tor Norbye // root as well (such that the whole layout canvas does not highlight as part of hovers 4343cf5ce58a324efb926b862b16ad8b18d033f5be9Tor Norbye // etc) 4353cf5ce58a324efb926b862b16ad8b18d033f5be9Tor Norbye if (mParent != null 4360757ce4af2764e4dd564acc0b1a013e910abc8daTor Norbye && mParent.mName.endsWith(GESTURE_OVERLAY_VIEW) 4374e9c7b5df119dda3acd516fcea2ff59c22a19565Tor Norbye && mParent.isRoot() 4384e9c7b5df119dda3acd516fcea2ff59c22a19565Tor Norbye && mParent.mChildren.size() == 1) { 4393cf5ce58a324efb926b862b16ad8b18d033f5be9Tor Norbye return true; 4403cf5ce58a324efb926b862b16ad8b18d033f5be9Tor Norbye } 4413cf5ce58a324efb926b862b16ad8b18d033f5be9Tor Norbye 44271f1ce4538caa9f7d0824c7f2090d95a6c6b7d71Xavier Ducrohet return mUiViewNode == null || mUiViewNode.getUiParent() == null || 44371f1ce4538caa9f7d0824c7f2090d95a6c6b7d71Xavier Ducrohet mUiViewNode.getUiParent().getUiParent() == null; 44483dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye } 44583dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye 44683dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye /** 4474563c4e2f168df1d6c97206a4ac6444dfa2264baTor Norbye * Returns true if this {@link CanvasViewInfo} represents an invisible widget that 4484563c4e2f168df1d6c97206a4ac6444dfa2264baTor Norbye * should be highlighted when selected. This is the case for any layout that is less than the minimum 4494563c4e2f168df1d6c97206a4ac6444dfa2264baTor Norbye * threshold ({@link #SELECTION_MIN_SIZE}), or any other view that has -0- bounds. 45023258d5ae21d164049eef14eebb2ef28a43a7b40Tor Norbye * 4514563c4e2f168df1d6c97206a4ac6444dfa2264baTor Norbye * @return True if this is a tiny layout or invisible view 45223258d5ae21d164049eef14eebb2ef28a43a7b40Tor Norbye */ 4534563c4e2f168df1d6c97206a4ac6444dfa2264baTor Norbye public boolean isInvisible() { 4548925febd3beb31e4c5e1a3329ed1e73291dd3936Tor Norbye if (isHidden()) { 4558925febd3beb31e4c5e1a3329ed1e73291dd3936Tor Norbye // Don't expand and highlight hidden widgets 4568925febd3beb31e4c5e1a3329ed1e73291dd3936Tor Norbye return false; 4578925febd3beb31e4c5e1a3329ed1e73291dd3936Tor Norbye } 4588925febd3beb31e4c5e1a3329ed1e73291dd3936Tor Norbye 45923258d5ae21d164049eef14eebb2ef28a43a7b40Tor Norbye if (mAbsRect.width < SELECTION_MIN_SIZE || mAbsRect.height < SELECTION_MIN_SIZE) { 4604563c4e2f168df1d6c97206a4ac6444dfa2264baTor Norbye return mUiViewNode != null && (mUiViewNode.getDescriptor().hasChildren() || 4614563c4e2f168df1d6c97206a4ac6444dfa2264baTor Norbye mAbsRect.width <= 0 || mAbsRect.height <= 0); 46223258d5ae21d164049eef14eebb2ef28a43a7b40Tor Norbye } 46323258d5ae21d164049eef14eebb2ef28a43a7b40Tor Norbye 46423258d5ae21d164049eef14eebb2ef28a43a7b40Tor Norbye return false; 46523258d5ae21d164049eef14eebb2ef28a43a7b40Tor Norbye } 46623258d5ae21d164049eef14eebb2ef28a43a7b40Tor Norbye 46723258d5ae21d164049eef14eebb2ef28a43a7b40Tor Norbye /** 4688925febd3beb31e4c5e1a3329ed1e73291dd3936Tor Norbye * Returns true if this {@link CanvasViewInfo} represents a widget that should be 4698925febd3beb31e4c5e1a3329ed1e73291dd3936Tor Norbye * hidden, such as a {@code <Space>} which are typically not manipulated by the user 4708925febd3beb31e4c5e1a3329ed1e73291dd3936Tor Norbye * through dragging etc. 4718925febd3beb31e4c5e1a3329ed1e73291dd3936Tor Norbye * 4728925febd3beb31e4c5e1a3329ed1e73291dd3936Tor Norbye * @return true if this is a hidden view 4738925febd3beb31e4c5e1a3329ed1e73291dd3936Tor Norbye */ 4748925febd3beb31e4c5e1a3329ed1e73291dd3936Tor Norbye public boolean isHidden() { 4754eacdfbcc84ad11f599020b12ad76aebed70537fTor Norbye if (GridLayoutRule.sDebugGridLayout) { 4764eacdfbcc84ad11f599020b12ad76aebed70537fTor Norbye return false; 4774eacdfbcc84ad11f599020b12ad76aebed70537fTor Norbye } 4784eacdfbcc84ad11f599020b12ad76aebed70537fTor Norbye 4793e75d4f79a8328ed18505830c786402369082efaTor Norbye return FQCN_SPACE.equals(mName) || FQCN_SPACE_V7.equals(mName); 4808925febd3beb31e4c5e1a3329ed1e73291dd3936Tor Norbye } 4818925febd3beb31e4c5e1a3329ed1e73291dd3936Tor Norbye 4828925febd3beb31e4c5e1a3329ed1e73291dd3936Tor Norbye /** 48323258d5ae21d164049eef14eebb2ef28a43a7b40Tor Norbye * Is this {@link CanvasViewInfo} a view that has had its padding inflated in order to 48423258d5ae21d164049eef14eebb2ef28a43a7b40Tor Norbye * make it visible during selection or dragging? Note that this is NOT considered to 48523258d5ae21d164049eef14eebb2ef28a43a7b40Tor Norbye * be the case in the explode-all-views mode where all nodes have their padding 48623258d5ae21d164049eef14eebb2ef28a43a7b40Tor Norbye * increased; it's only used for views that individually exploded because they were 4874563c4e2f168df1d6c97206a4ac6444dfa2264baTor Norbye * requested visible and they returned true for {@link #isInvisible()}. 48823258d5ae21d164049eef14eebb2ef28a43a7b40Tor Norbye * 48923258d5ae21d164049eef14eebb2ef28a43a7b40Tor Norbye * @return True if this is an exploded node. 49023258d5ae21d164049eef14eebb2ef28a43a7b40Tor Norbye */ 49123258d5ae21d164049eef14eebb2ef28a43a7b40Tor Norbye public boolean isExploded() { 49223258d5ae21d164049eef14eebb2ef28a43a7b40Tor Norbye return mExploded; 49323258d5ae21d164049eef14eebb2ef28a43a7b40Tor Norbye } 49423258d5ae21d164049eef14eebb2ef28a43a7b40Tor Norbye 49523258d5ae21d164049eef14eebb2ef28a43a7b40Tor Norbye /** 49623258d5ae21d164049eef14eebb2ef28a43a7b40Tor Norbye * Mark this {@link CanvasViewInfo} as having been exploded or not. See the 49723258d5ae21d164049eef14eebb2ef28a43a7b40Tor Norbye * {@link #isExploded()} method for details on what this property means. 49823258d5ae21d164049eef14eebb2ef28a43a7b40Tor Norbye * 49923258d5ae21d164049eef14eebb2ef28a43a7b40Tor Norbye * @param exploded New value of the exploded property to mark this info with. 50023258d5ae21d164049eef14eebb2ef28a43a7b40Tor Norbye */ 5019bd06947302ca6ca3e0b90eef894e553c6c3e067Tor Norbye void setExploded(boolean exploded) { 502a21b9b44b0db30f497b3507c8b97683387960b59Tor Norbye mExploded = exploded; 50323258d5ae21d164049eef14eebb2ef28a43a7b40Tor Norbye } 50423258d5ae21d164049eef14eebb2ef28a43a7b40Tor Norbye 50523258d5ae21d164049eef14eebb2ef28a43a7b40Tor Norbye /** 50683dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye * Returns the info represented as a {@link SimpleElement}. 50783dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye * 50883dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye * @return A {@link SimpleElement} wrapping this info. 50983dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye */ 5109bd06947302ca6ca3e0b90eef894e553c6c3e067Tor Norbye @NonNull 5119bd06947302ca6ca3e0b90eef894e553c6c3e067Tor Norbye SimpleElement toSimpleElement() { 51283dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye 51371f1ce4538caa9f7d0824c7f2090d95a6c6b7d71Xavier Ducrohet UiViewElementNode uiNode = getUiViewNode(); 51483dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye 51583dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye String fqcn = SimpleXmlTransfer.getFqcn(uiNode.getDescriptor()); 51683dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye String parentFqcn = null; 517a2d7874ed23bfc2fa7665cc84901e0f4781b4e51Tor Norbye Rect bounds = SwtUtils.toRect(getAbsRect()); 51883dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye Rect parentBounds = null; 51983dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye 52083dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye UiElementNode uiParent = uiNode.getUiParent(); 52183dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye if (uiParent != null) { 52283dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye parentFqcn = SimpleXmlTransfer.getFqcn(uiParent.getDescriptor()); 52383dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye } 52483dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye if (getParent() != null) { 525a2d7874ed23bfc2fa7665cc84901e0f4781b4e51Tor Norbye parentBounds = SwtUtils.toRect(getParent().getAbsRect()); 52683dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye } 52783dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye 52883dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye SimpleElement e = new SimpleElement(fqcn, parentFqcn, bounds, parentBounds); 52983dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye 53086618cc78fb2f207c477527b4413ff234f474431Raphael Moll for (UiAttributeNode attr : uiNode.getAllUiAttributes()) { 53183dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye String value = attr.getCurrentValue(); 53283dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye if (value != null && value.length() > 0) { 53383dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye AttributeDescriptor attrDesc = attr.getDescriptor(); 53483dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye SimpleAttribute a = new SimpleAttribute( 53583dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye attrDesc.getNamespaceUri(), 53683dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye attrDesc.getXmlLocalName(), 53783dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye value); 53883dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye e.addAttribute(a); 53983dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye } 54083dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye } 54183dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye 54283dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye for (CanvasViewInfo childVi : getChildren()) { 54383dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye SimpleElement e2 = childVi.toSimpleElement(); 54483dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye if (e2 != null) { 54583dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye e.addInnerElement(e2); 54683dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye } 54783dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye } 54883dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye 54983dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye return e; 55083dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye } 55183dba505e22985fd2f9414e7c6ef14ce29d31713Tor Norbye 55299fd7eee15c89fd45b884842c44371326f851930Tor Norbye /** 553c4674db5cbd9216d5793a004ef158d5ba98cdc40Tor Norbye * Returns the layout url attribute value for the closest surrounding include or 554c4674db5cbd9216d5793a004ef158d5ba98cdc40Tor Norbye * fragment element parent, or null if this {@link CanvasViewInfo} is not rendered as 555c4674db5cbd9216d5793a004ef158d5ba98cdc40Tor Norbye * part of an include or fragment tag. 55699fd7eee15c89fd45b884842c44371326f851930Tor Norbye * 55799fd7eee15c89fd45b884842c44371326f851930Tor Norbye * @return the layout url attribute value for the surrounding include tag, or null if 55899fd7eee15c89fd45b884842c44371326f851930Tor Norbye * not applicable 55999fd7eee15c89fd45b884842c44371326f851930Tor Norbye */ 5609bd06947302ca6ca3e0b90eef894e553c6c3e067Tor Norbye @Nullable 56199fd7eee15c89fd45b884842c44371326f851930Tor Norbye public String getIncludeUrl() { 56299fd7eee15c89fd45b884842c44371326f851930Tor Norbye CanvasViewInfo curr = this; 56399fd7eee15c89fd45b884842c44371326f851930Tor Norbye while (curr != null) { 56499fd7eee15c89fd45b884842c44371326f851930Tor Norbye if (curr.mUiViewNode != null) { 56599fd7eee15c89fd45b884842c44371326f851930Tor Norbye Node node = curr.mUiViewNode.getXmlNode(); 566c4674db5cbd9216d5793a004ef158d5ba98cdc40Tor Norbye if (node != null && node.getNodeType() == Node.ELEMENT_NODE) { 567c4674db5cbd9216d5793a004ef158d5ba98cdc40Tor Norbye String nodeName = node.getNodeName(); 568c4674db5cbd9216d5793a004ef158d5ba98cdc40Tor Norbye if (node.getNamespaceURI() == null 56912d4581faa6438941e65a9dc83213be34c6ca970Tor Norbye && SdkConstants.VIEW_INCLUDE.equals(nodeName)) { 570c4674db5cbd9216d5793a004ef158d5ba98cdc40Tor Norbye // Note: the layout attribute is NOT in the Android namespace 571c4674db5cbd9216d5793a004ef158d5ba98cdc40Tor Norbye Element element = (Element) node; 57212d4581faa6438941e65a9dc83213be34c6ca970Tor Norbye String url = element.getAttribute(SdkConstants.ATTR_LAYOUT); 573c4674db5cbd9216d5793a004ef158d5ba98cdc40Tor Norbye if (url.length() > 0) { 574c4674db5cbd9216d5793a004ef158d5ba98cdc40Tor Norbye return url; 575c4674db5cbd9216d5793a004ef158d5ba98cdc40Tor Norbye } 57612d4581faa6438941e65a9dc83213be34c6ca970Tor Norbye } else if (SdkConstants.VIEW_FRAGMENT.equals(nodeName)) { 577c4674db5cbd9216d5793a004ef158d5ba98cdc40Tor Norbye String url = FragmentMenu.getFragmentLayout(node); 578c4674db5cbd9216d5793a004ef158d5ba98cdc40Tor Norbye if (url != null) { 579c4674db5cbd9216d5793a004ef158d5ba98cdc40Tor Norbye return url; 580c4674db5cbd9216d5793a004ef158d5ba98cdc40Tor Norbye } 58199fd7eee15c89fd45b884842c44371326f851930Tor Norbye } 58299fd7eee15c89fd45b884842c44371326f851930Tor Norbye } 58399fd7eee15c89fd45b884842c44371326f851930Tor Norbye } 58499fd7eee15c89fd45b884842c44371326f851930Tor Norbye curr = curr.mParent; 58599fd7eee15c89fd45b884842c44371326f851930Tor Norbye } 58699fd7eee15c89fd45b884842c44371326f851930Tor Norbye 58799fd7eee15c89fd45b884842c44371326f851930Tor Norbye return null; 58899fd7eee15c89fd45b884842c44371326f851930Tor Norbye } 5898386da5e451eec396d0e71576e7366a98017674fTor Norbye 5909155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye /** Adds the given {@link CanvasViewInfo} as a new last child of this view */ 5919bd06947302ca6ca3e0b90eef894e553c6c3e067Tor Norbye private void addChild(@NonNull CanvasViewInfo child) { 5929155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye mChildren.add(child); 5939155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 5949155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye 5959155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye /** Adds the given {@link CanvasViewInfo} as a child at the given index */ 5969bd06947302ca6ca3e0b90eef894e553c6c3e067Tor Norbye private void addChildAt(int index, @NonNull CanvasViewInfo child) { 5979155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye mChildren.add(index, child); 5989155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 5999155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye 6009155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye /** 6019155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * Removes the given {@link CanvasViewInfo} from the child list of this view, and 6029155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * returns true if it was successfully removed 6039155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * 6049155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * @param child the child to be removed 6059155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * @return true if it was a child and was removed 6069155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye */ 6079bd06947302ca6ca3e0b90eef894e553c6c3e067Tor Norbye public boolean removeChild(@NonNull CanvasViewInfo child) { 6089155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye return mChildren.remove(child); 6099155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 6109155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye 6119155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye @Override 6129155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye public String toString() { 6139155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye return "CanvasViewInfo [name=" + mName + ", node=" + mUiViewNode + "]"; 6149155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 6159155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye 6168386da5e451eec396d0e71576e7366a98017674fTor Norbye // ---- Factory functionality ---- 6178386da5e451eec396d0e71576e7366a98017674fTor Norbye 6188386da5e451eec396d0e71576e7366a98017674fTor Norbye /** 6198386da5e451eec396d0e71576e7366a98017674fTor Norbye * Creates a new {@link CanvasViewInfo} hierarchy based on the given {@link ViewInfo} 6208386da5e451eec396d0e71576e7366a98017674fTor Norbye * hierarchy. Note that this will not necessarily create one {@link CanvasViewInfo} 6218386da5e451eec396d0e71576e7366a98017674fTor Norbye * for each {@link ViewInfo}. It will generally only create {@link CanvasViewInfo} 6228386da5e451eec396d0e71576e7366a98017674fTor Norbye * objects for {@link ViewInfo} objects that contain a reference to an 6238386da5e451eec396d0e71576e7366a98017674fTor Norbye * {@link UiViewElementNode}, meaning that it corresponds to an element in the XML 6248386da5e451eec396d0e71576e7366a98017674fTor Norbye * file for this layout file. This is not always the case, such as in the following 6258386da5e451eec396d0e71576e7366a98017674fTor Norbye * scenarios: 6268386da5e451eec396d0e71576e7366a98017674fTor Norbye * <ul> 6278386da5e451eec396d0e71576e7366a98017674fTor Norbye * <li>we link to other layouts with {@code <include>} 6288386da5e451eec396d0e71576e7366a98017674fTor Norbye * <li>the current view is rendered within another view ("Show Included In") such that 6298386da5e451eec396d0e71576e7366a98017674fTor Norbye * the outer file does not correspond to elements in the current included XML layout 6308386da5e451eec396d0e71576e7366a98017674fTor Norbye * <li>on older platforms that don't support {@link Capability#EMBEDDED_LAYOUT} there 6318386da5e451eec396d0e71576e7366a98017674fTor Norbye * is no reference to the {@code <include>} tag 6328386da5e451eec396d0e71576e7366a98017674fTor Norbye * <li>with the {@code <merge>} tag we don't get a reference to the corresponding 6338386da5e451eec396d0e71576e7366a98017674fTor Norbye * element 6348386da5e451eec396d0e71576e7366a98017674fTor Norbye * <ul> 6358386da5e451eec396d0e71576e7366a98017674fTor Norbye * <p> 6368386da5e451eec396d0e71576e7366a98017674fTor Norbye * This method will build up a set of {@link CanvasViewInfo} that corresponds to the 6378386da5e451eec396d0e71576e7366a98017674fTor Norbye * actual <b>selectable</b> views (which are also shown in the Outline). 6388386da5e451eec396d0e71576e7366a98017674fTor Norbye * 6392fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye * @param layoutlib5 if true, the {@link ViewInfo} hierarchy was created by layoutlib 6402fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye * version 5 or higher, which means this algorithm can make certain assumptions 6412fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye * (for example that {@code <merge>} siblings will provide {@link MergeCookie} 6422fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye * references, so we don't have to search for them.) 6438386da5e451eec396d0e71576e7366a98017674fTor Norbye * @param root the root {@link ViewInfo} to build from 6448386da5e451eec396d0e71576e7366a98017674fTor Norbye * @return a {@link CanvasViewInfo} hierarchy 6458386da5e451eec396d0e71576e7366a98017674fTor Norbye */ 6469bd06947302ca6ca3e0b90eef894e553c6c3e067Tor Norbye @NonNull 6472fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye public static Pair<CanvasViewInfo,List<Rectangle>> create(ViewInfo root, boolean layoutlib5) { 6482fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye return new Builder(layoutlib5).create(root); 6498386da5e451eec396d0e71576e7366a98017674fTor Norbye } 6508386da5e451eec396d0e71576e7366a98017674fTor Norbye 6519155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye /** Builder object which walks over a tree of {@link ViewInfo} objects and builds 6529155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * up a corresponding {@link CanvasViewInfo} hierarchy. */ 6539155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye private static class Builder { 6542fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye public Builder(boolean layoutlib5) { 6552fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye mLayoutLib5 = layoutlib5; 6562fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye } 6579155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye 6582fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye /** 6592fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye * The mapping from nodes that have a {@code <merge>} as a parent in the node 6602fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye * model to their corresponding views 6612fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye */ 6622fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye private Map<UiViewElementNode, List<CanvasViewInfo>> mMergeNodeMap; 6632fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye 6642fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye /** 6652fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye * Whether the ViewInfos are provided by a layout library that is version 5 or 6662fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye * later, since that will allow us to take several shortcuts 6672fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye */ 6682fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye private boolean mLayoutLib5; 6692fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye 6702fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye /** 6712fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye * Creates a hierarchy of {@link CanvasViewInfo} objects and merge bounding 6722fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye * rectangles from the given {@link ViewInfo} hierarchy 6732fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye */ 6742fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye private Pair<CanvasViewInfo,List<Rectangle>> create(ViewInfo root) { 6759155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye Object cookie = root.getCookie(); 6769155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (cookie == null) { 6779155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // Special case: If the root-most view does not have a view cookie, 6789155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // then we are rendering some outer layout surrounding this layout, and in 6799155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // that case we must search down the hierarchy for the (possibly multiple) 6809155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // sub-roots that correspond to elements in this layout, and place them inside 6819155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // an outer view that has no node. In the outline this item will be used to 6829155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // show the inclusion-context. 6839155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye CanvasViewInfo rootView = createView(null, root, 0, 0); 6849155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye addKeyedSubtrees(rootView, root, 0, 0); 6859155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye 6869155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye List<Rectangle> includedBounds = new ArrayList<Rectangle>(); 6879155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye for (CanvasViewInfo vi : rootView.getChildren()) { 688e7a41238a05f9b4a992b0d2631620c1d07bfee8aTor Norbye if (vi.getNodeSiblings() == null || vi.isPrimaryNodeSibling()) { 6899155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye includedBounds.add(vi.getAbsRect()); 6909155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 6919155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 6928386da5e451eec396d0e71576e7366a98017674fTor Norbye 6939155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // There are <merge> nodes here; see if we can insert it into the hierarchy 6949155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (mMergeNodeMap != null) { 6959155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // Locate all the nodes that have a <merge> as a parent in the node model, 6969155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // and where the view sits at the top level inside the include-context node. 6979155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye UiViewElementNode merge = null; 6989155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye List<CanvasViewInfo> merged = new ArrayList<CanvasViewInfo>(); 6999155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye for (Map.Entry<UiViewElementNode, List<CanvasViewInfo>> entry : mMergeNodeMap 7009155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye .entrySet()) { 7019155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye UiViewElementNode node = entry.getKey(); 7029155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (!hasMergeParent(node)) { 7039155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye continue; 7049155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 7059155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye List<CanvasViewInfo> views = entry.getValue(); 7069155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye assert views.size() > 0; 7079155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye CanvasViewInfo view = views.get(0); // primary 7089155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (view.getParent() != rootView) { 7099155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye continue; 7109155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 7119155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye UiElementNode parent = node.getUiParent(); 7129155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (merge != null && parent != merge) { 7139155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye continue; 7149155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 7159155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye merge = (UiViewElementNode) parent; 7169155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye merged.add(view); 7179155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 7189155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (merged.size() > 0) { 7199155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // Compute a bounding box for the merged views 7209155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye Rectangle absRect = null; 7219155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye for (CanvasViewInfo child : merged) { 7229155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye Rectangle rect = child.getAbsRect(); 7239155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (absRect == null) { 7249155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye absRect = rect; 7259155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } else { 7269155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye absRect = absRect.union(rect); 7279155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 7289155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 7298386da5e451eec396d0e71576e7366a98017674fTor Norbye 7309155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye CanvasViewInfo mergeView = new CanvasViewInfo(rootView, VIEW_MERGE, null, 73180d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye merge, absRect, absRect, null /* viewInfo */); 7329155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye for (CanvasViewInfo view : merged) { 7339155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (rootView.removeChild(view)) { 7349155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye mergeView.addChild(view); 7359155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 7369155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 7379155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye rootView.addChild(mergeView); 7389155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 7399155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 7408386da5e451eec396d0e71576e7366a98017674fTor Norbye 7419155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye return Pair.of(rootView, includedBounds); 7429155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } else { 7439155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // We have a view key at the top, so just go and create {@link CanvasViewInfo} 7449155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // objects for each {@link ViewInfo} until we run into a null key. 7459155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye CanvasViewInfo rootView = addKeyedSubtrees(null, root, 0, 0); 7469155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye 7479155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // Special case: look to see if the root element is really a <merge>, and if so, 7489155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // manufacture a view for it such that we can target this root element 7499155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // in drag & drop operations, such that we can show it in the outline, etc 7509155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (rootView != null && hasMergeParent(rootView.getUiViewNode())) { 7519155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye CanvasViewInfo merge = new CanvasViewInfo(null, VIEW_MERGE, null, 7529155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye (UiViewElementNode) rootView.getUiViewNode().getUiParent(), 75380d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye rootView.getAbsRect(), rootView.getSelectionRect(), 75480d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye null /* viewInfo */); 7559155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // Insert the <merge> as the new real root 7569155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye rootView.mParent = merge; 7579155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye merge.addChild(rootView); 7589155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye rootView = merge; 7599155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 7608386da5e451eec396d0e71576e7366a98017674fTor Norbye 7619155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye return Pair.of(rootView, null); 7629155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 7639155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 7648386da5e451eec396d0e71576e7366a98017674fTor Norbye 7659155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye private boolean hasMergeParent(UiViewElementNode rootNode) { 7669155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye UiElementNode rootParent = rootNode.getUiParent(); 7679155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye return (rootParent instanceof UiViewElementNode 7689155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye && VIEW_MERGE.equals(rootParent.getDescriptor().getXmlName())); 7698386da5e451eec396d0e71576e7366a98017674fTor Norbye } 7708386da5e451eec396d0e71576e7366a98017674fTor Norbye 7719155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye /** Creates a {@link CanvasViewInfo} for a given {@link ViewInfo} but does not recurse */ 7729155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye private CanvasViewInfo createView(CanvasViewInfo parent, ViewInfo root, int parentX, 7739155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye int parentY) { 7749155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye Object cookie = root.getCookie(); 7759155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye UiViewElementNode node = null; 7769155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (cookie instanceof UiViewElementNode) { 7779155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye node = (UiViewElementNode) cookie; 7789155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } else if (cookie instanceof MergeCookie) { 7799155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye cookie = ((MergeCookie) cookie).getCookie(); 7809155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (cookie instanceof UiViewElementNode) { 7819155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye node = (UiViewElementNode) cookie; 7829155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye CanvasViewInfo view = createView(parent, root, parentX, parentY, node); 7839155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (root.getCookie() instanceof MergeCookie && view.mNodeSiblings == null) { 7849155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye List<CanvasViewInfo> v = mMergeNodeMap == null ? 7859155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye null : mMergeNodeMap.get(node); 7869155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (v != null) { 7879155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye v.add(view); 7889155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } else { 7899155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye v = new ArrayList<CanvasViewInfo>(); 7909155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye v.add(view); 7919155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (mMergeNodeMap == null) { 7929155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye mMergeNodeMap = 7939155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye new HashMap<UiViewElementNode, List<CanvasViewInfo>>(); 7949155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 7959155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye mMergeNodeMap.put(node, v); 7969155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 7979155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye view.mNodeSiblings = v; 7989155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 7999155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye 8009155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye return view; 8019155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 8029155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 8039155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye 8049155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye return createView(parent, root, parentX, parentY, node); 8058386da5e451eec396d0e71576e7366a98017674fTor Norbye } 8068386da5e451eec396d0e71576e7366a98017674fTor Norbye 8079155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye /** 8089155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * Creates a {@link CanvasViewInfo} for a given {@link ViewInfo} but does not recurse. 8099155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * This method specifies an explicit {@link UiViewElementNode} to use rather than 8109155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * relying on the view cookie in the info object. 8119155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye */ 8129155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye private CanvasViewInfo createView(CanvasViewInfo parent, ViewInfo root, int parentX, 8139155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye int parentY, UiViewElementNode node) { 8148386da5e451eec396d0e71576e7366a98017674fTor Norbye 8159155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye int x = root.getLeft(); 8169155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye int y = root.getTop(); 8179155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye int w = root.getRight() - x; 8189155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye int h = root.getBottom() - y; 8198386da5e451eec396d0e71576e7366a98017674fTor Norbye 8209155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye x += parentX; 8219155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye y += parentY; 8228386da5e451eec396d0e71576e7366a98017674fTor Norbye 8239155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye Rectangle absRect = new Rectangle(x, y, w - 1, h - 1); 8248386da5e451eec396d0e71576e7366a98017674fTor Norbye 8259155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (w < SELECTION_MIN_SIZE) { 8269155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye int d = (SELECTION_MIN_SIZE - w) / 2; 8279155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye x -= d; 8289155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye w += SELECTION_MIN_SIZE - w; 8299155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 8308386da5e451eec396d0e71576e7366a98017674fTor Norbye 8319155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (h < SELECTION_MIN_SIZE) { 8329155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye int d = (SELECTION_MIN_SIZE - h) / 2; 8339155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye y -= d; 8349155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye h += SELECTION_MIN_SIZE - h; 8358386da5e451eec396d0e71576e7366a98017674fTor Norbye } 8369155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye 8379155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye Rectangle selectionRect = new Rectangle(x, y, w - 1, h - 1); 8389155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye 8399155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye return new CanvasViewInfo(parent, root.getClassName(), root.getViewObject(), node, 84080d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye absRect, selectionRect, root); 8418386da5e451eec396d0e71576e7366a98017674fTor Norbye } 8428386da5e451eec396d0e71576e7366a98017674fTor Norbye 8439155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye /** Create a subtree recursively until you run out of keys */ 8449155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye private CanvasViewInfo createSubtree(CanvasViewInfo parent, ViewInfo viewInfo, 8459155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye int parentX, int parentY) { 8469155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye assert viewInfo.getCookie() != null; 8479155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye 8489155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye CanvasViewInfo view = createView(parent, viewInfo, parentX, parentY); 8498f21dc3e82c298e727b8813e10896e55f82406f9Tor Norbye // Bug workaround: Ensure that we never have a child node identical 8508f21dc3e82c298e727b8813e10896e55f82406f9Tor Norbye // to its parent node: this can happen for example when rendering a 8518f21dc3e82c298e727b8813e10896e55f82406f9Tor Norbye // ZoomControls view where the merge cookies point to the parent. 8528f21dc3e82c298e727b8813e10896e55f82406f9Tor Norbye if (parent != null && view.mUiViewNode == parent.mUiViewNode) { 8538f21dc3e82c298e727b8813e10896e55f82406f9Tor Norbye return null; 8548f21dc3e82c298e727b8813e10896e55f82406f9Tor Norbye } 8559155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye 8569155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // Process children: 8579155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye parentX += viewInfo.getLeft(); 8589155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye parentY += viewInfo.getTop(); 8599155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye 8602fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye List<ViewInfo> children = viewInfo.getChildren(); 8612fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye 8622fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye if (mLayoutLib5) { 8632fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye for (ViewInfo child : children) { 8642fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye Object cookie = child.getCookie(); 8652fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye if (cookie instanceof UiViewElementNode || cookie instanceof MergeCookie) { 8662fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye CanvasViewInfo childView = createSubtree(view, child, 8672fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye parentX, parentY); 8688f21dc3e82c298e727b8813e10896e55f82406f9Tor Norbye if (childView != null) { 8698f21dc3e82c298e727b8813e10896e55f82406f9Tor Norbye view.addChild(childView); 8708f21dc3e82c298e727b8813e10896e55f82406f9Tor Norbye } 8712fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye } // else: null cookies, adapter item references, etc: No child views. 8722fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye } 8732fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye 8742fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye return view; 8752fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye } 8762fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye 8779155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // See if we have any missing keys at this level 8789155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye int missingNodes = 0; 8799155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye int mergeNodes = 0; 8808386da5e451eec396d0e71576e7366a98017674fTor Norbye for (ViewInfo child : children) { 8819155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // Only use children which have a ViewKey of the correct type. 8829155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // We can't interact with those when they have a null key or 8839155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // an incompatible type. 8849155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye Object cookie = child.getCookie(); 8859155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (!(cookie instanceof UiViewElementNode)) { 8869155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (cookie instanceof MergeCookie) { 8879155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye mergeNodes++; 8889155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } else { 8899155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye missingNodes++; 8908386da5e451eec396d0e71576e7366a98017674fTor Norbye } 8918386da5e451eec396d0e71576e7366a98017674fTor Norbye } 8929155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 8939155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye 8949155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (missingNodes == 0 && mergeNodes == 0) { 8959155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // No missing nodes; this is the normal case, and we can just continue to 8969155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // recursively add our children 8978386da5e451eec396d0e71576e7366a98017674fTor Norbye for (ViewInfo child : children) { 8989155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye CanvasViewInfo childView = createSubtree(view, child, 8999155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye parentX, parentY); 9009155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye view.addChild(childView); 9018386da5e451eec396d0e71576e7366a98017674fTor Norbye } 9029155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye 9039155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // TBD: Emit placeholder views for keys that have no views? 9049155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } else { 9059155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // We don't have keys for one or more of the ViewInfos. There are many 9069155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // possible causes: we are on an SDK platform that does not support 9079155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // embedded_layout rendering, or we are including a view with a <merge> 9089155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // as the root element. 9099155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye 9102fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye UiViewElementNode uiViewNode = view.getUiViewNode(); 9112fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye String containerName = uiViewNode != null 9122fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye ? uiViewNode.getDescriptor().getXmlLocalName() : ""; //$NON-NLS-1$ 91312d4581faa6438941e65a9dc83213be34c6ca970Tor Norbye if (containerName.equals(SdkConstants.VIEW_INCLUDE)) { 9149155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // This is expected -- we don't WANT to get node keys for the content 9159155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // of an include since it's in a different file and should be treated 9169155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // as a single unit that cannot be edited (hence, no CanvasViewInfo 9179155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // children) 9189155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } else { 9199155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // We are getting children with null keys where we don't expect it; 9209155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // this usually means that we are dealing with an Android platform 9219155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // that does not support {@link Capability#EMBEDDED_LAYOUT}, or 9229155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // that there are <merge> tags which are doing surprising things 9239155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // to the view hierarchy 9249155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye LinkedList<UiViewElementNode> unused = new LinkedList<UiViewElementNode>(); 9252fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye if (uiViewNode != null) { 9262fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye for (UiElementNode child : uiViewNode.getUiChildren()) { 9272fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye if (child instanceof UiViewElementNode) { 9282fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye unused.addLast((UiViewElementNode) child); 9292fa8370664b25f391eb15dc22a3daa2d55d2b883Tor Norbye } 9309155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 9319155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 9329155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye for (ViewInfo child : children) { 9339155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye Object cookie = child.getCookie(); 9349155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (mergeNodes > 0 && cookie instanceof MergeCookie) { 9359155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye cookie = ((MergeCookie) cookie).getCookie(); 9369155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 9379155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (cookie != null) { 9389155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye unused.remove(cookie); 9399155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 9409155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 9419155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye 9429155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (unused.size() > 0 || mergeNodes > 0) { 9439155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (unused.size() == missingNodes) { 9449155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // The number of unmatched elements and ViewInfos are identical; 9459155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // it's very likely that they match one to one, so just use these 9469155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye for (ViewInfo child : children) { 9479155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (child.getCookie() == null) { 9489155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // Only create a flat (non-recursive) view 9499155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye CanvasViewInfo childView = createView(view, child, parentX, 9509155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye parentY, unused.removeFirst()); 9519155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye view.addChild(childView); 9529155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } else { 9539155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye CanvasViewInfo childView = createSubtree(view, child, parentX, 9549155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye parentY); 9559155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye view.addChild(childView); 9569155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 9579155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 9589155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } else { 9599155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // We have an uneven match. In this case we might be dealing 9609155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // with <merge> etc. 9619155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // We have no way to associate elements back with the 9629155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // corresponding <include> tags if there are more than one of 9639155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // them. That's not a huge tragedy since visually you are not 9649155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // allowed to edit these anyway; we just need to make a visual 9659155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // block for these for selection and outline purposes. 9669155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye addMismatched(view, parentX, parentY, children, unused); 9679155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 9689155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } else { 9699155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // No unused keys, but there are views without keys. 9709155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // We can't represent these since all views must have node keys 9719155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // such that you can operate on them. Just ignore these. 9728386da5e451eec396d0e71576e7366a98017674fTor Norbye for (ViewInfo child : children) { 9739155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (child.getCookie() != null) { 9749155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye CanvasViewInfo childView = createSubtree(view, child, 9759155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye parentX, parentY); 9768386da5e451eec396d0e71576e7366a98017674fTor Norbye view.addChild(childView); 9778386da5e451eec396d0e71576e7366a98017674fTor Norbye } 9788386da5e451eec396d0e71576e7366a98017674fTor Norbye } 9798386da5e451eec396d0e71576e7366a98017674fTor Norbye } 9808386da5e451eec396d0e71576e7366a98017674fTor Norbye } 9818386da5e451eec396d0e71576e7366a98017674fTor Norbye } 9828386da5e451eec396d0e71576e7366a98017674fTor Norbye 9839155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye return view; 9849155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 9858386da5e451eec396d0e71576e7366a98017674fTor Norbye 9869155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye /** 9879155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * We have various {@link ViewInfo} children with null keys, and/or nodes in 9889155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * the corresponding UI model that are not referenced by any of the {@link ViewInfo} 9899155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * objects. This method attempts to account for this, by matching the views in 9909155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye * the right order. 9919155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye */ 9929155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye private void addMismatched(CanvasViewInfo parentView, int parentX, int parentY, 9939155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye List<ViewInfo> children, LinkedList<UiViewElementNode> unused) { 9949155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye UiViewElementNode afterNode = null; 9959155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye UiViewElementNode beforeNode = null; 9969155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // We have one important clue we can use when matching unused nodes 9979155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // with views: if we have a view V1 with node N1, and a view V2 with node N2, 9989155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // then we can only match unknown node UN with unknown node UV if 9999155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // V1 < UV < V2 and N1 < UN < N2. 10009155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // We can use these constraints to do the matching, for example by 10019155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // a simple DAG traversal. However, since the number of unmatched nodes 10029155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // will typically be very small, we'll just do a simple algorithm here 10039155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // which checks forwards/backwards whether a match is valid. 10049155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye for (int index = 0, size = children.size(); index < size; index++) { 10059155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye ViewInfo child = children.get(index); 10069155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (child.getCookie() != null) { 10079155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye CanvasViewInfo childView = createSubtree(parentView, child, parentX, parentY); 10088f21dc3e82c298e727b8813e10896e55f82406f9Tor Norbye if (childView != null) { 10098f21dc3e82c298e727b8813e10896e55f82406f9Tor Norbye parentView.addChild(childView); 10108f21dc3e82c298e727b8813e10896e55f82406f9Tor Norbye } 10119155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (child.getCookie() instanceof UiViewElementNode) { 10129155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye afterNode = (UiViewElementNode) child.getCookie(); 10139155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 10148386da5e451eec396d0e71576e7366a98017674fTor Norbye } else { 10159155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye beforeNode = nextViewNode(children, index); 10169155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye 10179155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // Find first eligible node from unused 10189155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // TOD: What if there are more eligible? We need to process ALL views 10199155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // and all nodes in one go here 10209155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye 10219155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye UiViewElementNode matching = null; 10229155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye for (UiViewElementNode candidate : unused) { 10239155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (afterNode == null || isAfter(afterNode, candidate)) { 10249155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (beforeNode == null || isBefore(beforeNode, candidate)) { 10259155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye matching = candidate; 10269155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye break; 10279155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 10289155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 10299155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 10309155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye 10319155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (matching != null) { 10329155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye unused.remove(matching); 10339155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye CanvasViewInfo childView = createView(parentView, child, parentX, parentY, 10349155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye matching); 10359155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye parentView.addChild(childView); 10369155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye afterNode = matching; 10379155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } else { 10389155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // We have no node for the view -- what do we do?? 10399155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // Nothing - we only represent stuff in the outline that is in the 10409155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // source model, not in the render 10419155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 10429155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 10439155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 10449155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye 10459155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // Add zero-bounded boxes for all remaining nodes since they need to show 10469155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // up in the outline, need to be selectable so you can press Delete, etc. 10479155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (unused.size() > 0) { 10489155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye Map<UiViewElementNode, Integer> rankMap = 10499155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye new HashMap<UiViewElementNode, Integer>(); 10509155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye Map<UiViewElementNode, CanvasViewInfo> infoMap = 10519155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye new HashMap<UiViewElementNode, CanvasViewInfo>(); 10529155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye UiElementNode parent = unused.get(0).getUiParent(); 10539155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (parent != null) { 10549155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye int index = 0; 10559155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye for (UiElementNode child : parent.getUiChildren()) { 10569155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye UiViewElementNode node = (UiViewElementNode) child; 10579155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye rankMap.put(node, index++); 10589155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 10599155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye for (CanvasViewInfo child : parentView.getChildren()) { 10609155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye infoMap.put(child.getUiViewNode(), child); 10619155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 10629155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye List<Integer> usedIndexes = new ArrayList<Integer>(); 10639155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye for (UiViewElementNode node : unused) { 10649155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye Integer rank = rankMap.get(node); 10659155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (rank != null) { 10669155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye usedIndexes.add(rank); 10679155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 10689155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 10699155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye Collections.sort(usedIndexes); 10709155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye for (int i = usedIndexes.size() - 1; i >= 0; i--) { 10719155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye Integer rank = usedIndexes.get(i); 10729155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye UiViewElementNode found = null; 10739155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye for (UiViewElementNode node : unused) { 10749155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (rankMap.get(node) == rank) { 10759155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye found = node; 10769155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye break; 10779155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 10789155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 10799155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (found != null) { 10809155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye Rectangle absRect = new Rectangle(parentX, parentY, 0, 0); 10819155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye String name = found.getDescriptor().getXmlLocalName(); 10829155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye CanvasViewInfo v = new CanvasViewInfo(parentView, name, null, found, 108380d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye absRect, absRect, null /* viewInfo */); 10849155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // Find corresponding index in the parent view 10859155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye List<CanvasViewInfo> siblings = parentView.getChildren(); 10869155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye int insertPosition = siblings.size(); 10879155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye for (int j = siblings.size() - 1; j >= 0; j--) { 10889155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye CanvasViewInfo sibling = siblings.get(j); 10899155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye UiViewElementNode siblingNode = sibling.getUiViewNode(); 10909155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (siblingNode != null) { 10919155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye Integer siblingRank = rankMap.get(siblingNode); 10929155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (siblingRank != null && siblingRank < rank) { 10939155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye insertPosition = j + 1; 10949155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye break; 10959155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 10969155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 10979155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 10989155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye parentView.addChildAt(insertPosition, v); 10999155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye unused.remove(found); 11009155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 11019155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 11029155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 11039155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // Add in any remaining 11049155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye for (UiViewElementNode node : unused) { 11059155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye Rectangle absRect = new Rectangle(parentX, parentY, 0, 0); 11069155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye String name = node.getDescriptor().getXmlLocalName(); 11079155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye CanvasViewInfo v = new CanvasViewInfo(parentView, name, null, node, absRect, 110880d9301c2e874b29889c41adb0623666cf534fa0Tor Norbye absRect, null /* viewInfo */); 11099155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye parentView.addChild(v); 11108386da5e451eec396d0e71576e7366a98017674fTor Norbye } 11118386da5e451eec396d0e71576e7366a98017674fTor Norbye } 11128386da5e451eec396d0e71576e7366a98017674fTor Norbye } 11139155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye 11149155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye private boolean isBefore(UiViewElementNode beforeNode, UiViewElementNode candidate) { 11159155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye UiElementNode parent = candidate.getUiParent(); 11169155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (parent != null) { 11179155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye for (UiElementNode sibling : parent.getUiChildren()) { 11189155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (sibling == beforeNode) { 11199155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye return false; 11209155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } else if (sibling == candidate) { 11219155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye return true; 11229155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 11239155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 11249155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 11259155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye return false; 11268386da5e451eec396d0e71576e7366a98017674fTor Norbye } 11278386da5e451eec396d0e71576e7366a98017674fTor Norbye 11289155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye private boolean isAfter(UiViewElementNode afterNode, UiViewElementNode candidate) { 11299155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye UiElementNode parent = candidate.getUiParent(); 11308386da5e451eec396d0e71576e7366a98017674fTor Norbye if (parent != null) { 11319155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye for (UiElementNode sibling : parent.getUiChildren()) { 11329155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (sibling == afterNode) { 11339155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye return true; 11349155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } else if (sibling == candidate) { 11359155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye return false; 11369155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 11379155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 11388386da5e451eec396d0e71576e7366a98017674fTor Norbye } 11399155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye return false; 11409155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 11419155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye 11429155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye private UiViewElementNode nextViewNode(List<ViewInfo> children, int index) { 11439155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye int size = children.size(); 11449155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye for (; index < size; index++) { 11459155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye ViewInfo child = children.get(index); 11469155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (child.getCookie() instanceof UiViewElementNode) { 11479155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye return (UiViewElementNode) child.getCookie(); 11489155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 11498386da5e451eec396d0e71576e7366a98017674fTor Norbye } 11508386da5e451eec396d0e71576e7366a98017674fTor Norbye 11518386da5e451eec396d0e71576e7366a98017674fTor Norbye return null; 11528386da5e451eec396d0e71576e7366a98017674fTor Norbye } 11538386da5e451eec396d0e71576e7366a98017674fTor Norbye 11549155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye /** Search for a subtree with valid keys and add those subtrees */ 11559155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye private CanvasViewInfo addKeyedSubtrees(CanvasViewInfo parent, ViewInfo viewInfo, 11569155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye int parentX, int parentY) { 11579155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // We don't include MergeCookies when searching down for the first non-null key, 11589155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // since this means we are in a "Show Included In" context, and the include tag itself 11599155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // (which the merge cookie is pointing to) is still in the including-document rather 11609155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // than the included document. Therefore, we only accept real UiViewElementNodes here, 11619155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye // not MergeCookies. 11629155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye if (viewInfo.getCookie() != null) { 11639155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye CanvasViewInfo subtree = createSubtree(parent, viewInfo, parentX, parentY); 11648f21dc3e82c298e727b8813e10896e55f82406f9Tor Norbye if (parent != null && subtree != null) { 11659155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye parent.mChildren.add(subtree); 11669155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 11679155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye return subtree; 11689155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } else { 11699155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye for (ViewInfo child : viewInfo.getChildren()) { 11709155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye addKeyedSubtrees(parent, child, parentX + viewInfo.getLeft(), parentY 11719155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye + viewInfo.getTop()); 11729155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 11738386da5e451eec396d0e71576e7366a98017674fTor Norbye 11749155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye return null; 11759155df4effaf2079215d5f77dc2e70dd145a6fdfTor Norbye } 11768386da5e451eec396d0e71576e7366a98017674fTor Norbye } 11778386da5e451eec396d0e71576e7366a98017674fTor Norbye } 11788fbb33e21e7b6c0d13c9b368c4a24f6c13809027Raphael} 1179