1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Eclipse Public License, Version 1.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.eclipse.org/org/documents/epl-v10.php 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.ide.eclipse.adt.internal.editors.layout.gle2; 18 19 import com.android.ide.eclipse.adt.internal.editors.layout.uimodel.UiViewElementNode; 20 import com.android.layoutlib.api.ILayoutResult; 21 import com.android.layoutlib.api.ILayoutResult.ILayoutViewInfo; 22 23 import org.eclipse.swt.graphics.Rectangle; 24 import org.eclipse.ui.views.properties.IPropertyDescriptor; 25 import org.eclipse.ui.views.properties.IPropertySheetPage; 26 import org.eclipse.ui.views.properties.IPropertySource; 27 28 import java.util.ArrayList; 29 30 /** 31 * Maps a {@link ILayoutViewInfo} in a structure more adapted to our needs. 32 * The only large difference is that we keep both the original bounds of the view info 33 * and we pre-compute the selection bounds which are absolute to the rendered image 34 * (whereas the original bounds are relative to the parent view.) 35 * <p/> 36 * Each view also knows its parent and children. 37 * <p/> 38 * We can't alter {@link ILayoutViewInfo} as it is part of the LayoutBridge and needs to 39 * have a fixed API. 40 * <p/> 41 * The view info also implements {@link IPropertySource}, which enables a linked 42 * {@link IPropertySheetPage} to display the attributes of the selected element. 43 * This class actually delegates handling of {@link IPropertySource} to the underlying 44 * {@link UiViewElementNode}, if any. 45 */ 46 public class CanvasViewInfo implements IPropertySource { 47 48 /** 49 * Minimal size of the selection, in case an empty view or layout is selected. 50 */ 51 private static final int SELECTION_MIN_SIZE = 6; 52 53 54 private final Rectangle mAbsRect; 55 private final Rectangle mSelectionRect; 56 private final String mName; 57 private final UiViewElementNode mUiViewKey; 58 private final CanvasViewInfo mParent; 59 private final ArrayList<CanvasViewInfo> mChildren = new ArrayList<CanvasViewInfo>(); 60 61 /** 62 * Constructs a {@link CanvasViewInfo} hierarchy based on a given {@link ILayoutViewInfo} 63 * hierarchy. This call is recursive and builds a full tree. 64 * 65 * @param viewInfo The root of the {@link ILayoutViewInfo} hierarchy. 66 */ CanvasViewInfo(ILayoutViewInfo viewInfo)67 public CanvasViewInfo(ILayoutViewInfo viewInfo) { 68 this(viewInfo, null /*parent*/, 0 /*parentX*/, 0 /*parentY*/); 69 } 70 CanvasViewInfo(ILayoutViewInfo viewInfo, CanvasViewInfo parent, int parentX, int parentY)71 private CanvasViewInfo(ILayoutViewInfo viewInfo, CanvasViewInfo parent, int parentX, int parentY) { 72 mParent = parent; 73 mName = viewInfo.getName(); 74 75 // The ILayoutViewInfo#getViewKey() method returns a key which depends on the 76 // IXmlPullParser used to parse the layout files. In this case, the parser is 77 // guaranteed to be an UiElementPullParser, which creates keys that are of type 78 // UiViewElementNode. 79 // We'll simply crash if the type is not right, as this is not supposed to happen 80 // and nothing could work if there's a type mismatch. 81 mUiViewKey = (UiViewElementNode) viewInfo.getViewKey(); 82 83 int x = viewInfo.getLeft(); 84 int y = viewInfo.getTop(); 85 int w = viewInfo.getRight() - x; 86 int h = viewInfo.getBottom() - y; 87 88 if (parent != null) { 89 x += parentX; 90 y += parentY; 91 } 92 93 mAbsRect = new Rectangle(x, y, w - 1, h - 1); 94 95 if (viewInfo.getChildren() != null) { 96 for (ILayoutViewInfo child : viewInfo.getChildren()) { 97 // Only use children which have a ViewKey of the correct type. 98 // We can't interact with those when they have a null key or 99 // an incompatible type. 100 if (child.getViewKey() instanceof UiViewElementNode) { 101 mChildren.add(new CanvasViewInfo(child, this, x, y)); 102 } 103 } 104 } 105 106 // adjust selection bounds for views which are too small to select 107 108 if (w < SELECTION_MIN_SIZE) { 109 int d = (SELECTION_MIN_SIZE - w) / 2; 110 x -= d; 111 w += SELECTION_MIN_SIZE - w; 112 } 113 114 if (h < SELECTION_MIN_SIZE) { 115 int d = (SELECTION_MIN_SIZE - h) / 2; 116 y -= d; 117 h += SELECTION_MIN_SIZE - h; 118 } 119 120 mSelectionRect = new Rectangle(x, y, w - 1, h - 1); 121 } 122 123 /** 124 * Returns the original {@link ILayoutResult} bounds in absolute coordinates 125 * over the whole graphic. 126 */ getAbsRect()127 public Rectangle getAbsRect() { 128 return mAbsRect; 129 } 130 131 /* 132 * Returns the absolute selection bounds of the view info as a rectangle. 133 * The selection bounds will always have a size greater or equal to 134 * {@link #SELECTION_MIN_SIZE}. 135 * The width/height is inclusive (i.e. width = right-left-1). 136 * This is in absolute "screen" coordinates (relative to the rendered bitmap). 137 */ getSelectionRect()138 public Rectangle getSelectionRect() { 139 return mSelectionRect; 140 } 141 142 /** 143 * Returns the view key. Could be null, although unlikely. 144 * @return An {@link UiViewElementNode} that uniquely identifies the object in the XML model. 145 * @see ILayoutViewInfo#getViewKey() 146 */ getUiViewKey()147 public UiViewElementNode getUiViewKey() { 148 return mUiViewKey; 149 } 150 151 /** 152 * Returns the parent {@link CanvasViewInfo}. 153 * It is null for the root and non-null for children. 154 */ getParent()155 public CanvasViewInfo getParent() { 156 return mParent; 157 } 158 159 /** 160 * Returns the list of children of this {@link CanvasViewInfo}. 161 * The list is never null. It can be empty. 162 * By contract, this.getChildren().get(0..n-1).getParent() == this. 163 */ getChildren()164 public ArrayList<CanvasViewInfo> getChildren() { 165 return mChildren; 166 } 167 168 /** 169 * Returns true if the specific {@link CanvasViewInfo} is a parent 170 * of this {@link CanvasViewInfo}. It can be a direct parent or any 171 * grand-parent higher in the hierarchy. 172 */ isParent(CanvasViewInfo potentialParent)173 public boolean isParent(CanvasViewInfo potentialParent) { 174 if (potentialParent == null) { 175 176 } 177 CanvasViewInfo p = mParent; 178 while (p != null) { 179 if (p == potentialParent) { 180 return true; 181 } 182 p = p.getParent(); 183 } 184 return false; 185 } 186 187 /** 188 * Returns the name of the {@link CanvasViewInfo}. 189 * Could be null, although unlikely. 190 * Experience shows this is the full qualified Java name of the View. 191 * 192 * @see ILayoutViewInfo#getName() 193 */ getName()194 public String getName() { 195 return mName; 196 } 197 198 // ---- Implementation of IPropertySource 199 getEditableValue()200 public Object getEditableValue() { 201 UiViewElementNode uiView = getUiViewKey(); 202 if (uiView != null) { 203 return ((IPropertySource) uiView).getEditableValue(); 204 } 205 return null; 206 } 207 getPropertyDescriptors()208 public IPropertyDescriptor[] getPropertyDescriptors() { 209 UiViewElementNode uiView = getUiViewKey(); 210 if (uiView != null) { 211 return ((IPropertySource) uiView).getPropertyDescriptors(); 212 } 213 return null; 214 } 215 getPropertyValue(Object id)216 public Object getPropertyValue(Object id) { 217 UiViewElementNode uiView = getUiViewKey(); 218 if (uiView != null) { 219 return ((IPropertySource) uiView).getPropertyValue(id); 220 } 221 return null; 222 } 223 isPropertySet(Object id)224 public boolean isPropertySet(Object id) { 225 UiViewElementNode uiView = getUiViewKey(); 226 if (uiView != null) { 227 return ((IPropertySource) uiView).isPropertySet(id); 228 } 229 return false; 230 } 231 resetPropertyValue(Object id)232 public void resetPropertyValue(Object id) { 233 UiViewElementNode uiView = getUiViewKey(); 234 if (uiView != null) { 235 ((IPropertySource) uiView).resetPropertyValue(id); 236 } 237 } 238 setPropertyValue(Object id, Object value)239 public void setPropertyValue(Object id, Object value) { 240 UiViewElementNode uiView = getUiViewKey(); 241 if (uiView != null) { 242 ((IPropertySource) uiView).setPropertyValue(id, value); 243 } 244 } 245 } 246