• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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