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.common.api; 18 19 import java.util.List; 20 21 22 /** 23 * An {@link IViewRule} describes the rules that apply to a given Layout or View object 24 * in the Graphical Layout Editor. 25 * <p/> 26 * Rules are implemented by builtin layout helpers, or 3rd party layout rule implementations 27 * provided with or for a given 3rd party widget. 28 * <p/> 29 * A 3rd party layout rule should use the same fully qualified class name as the layout it 30 * represents, plus "Rule" as a suffix. For example, the layout rule for the 31 * LinearLayout class is LinearLayoutRule, in the same package. 32 * <p/> 33 * Rule instances are stateless. They are created once per View class to handle and are shared 34 * across platforms or editor instances. As such, rules methods should never cache editor-specific 35 * arguments that they might receive. 36 * <p/> 37 * <b>NOTE: This is not a public or final API; if you rely on this be prepared 38 * to adjust your code for the next tools release.</b> 39 * </p> 40 */ 41 public interface IViewRule { 42 43 /** 44 * This method is called by the rule engine when the script is first loaded. 45 * It gives the rule a chance to initialize itself. 46 * 47 * @param fqcn The fully qualified class name of the Layout or View that will be managed by 48 * this rule. This can be cached as it will never change for the lifetime of this rule 49 * instance. This may or may not match the script's filename as it may be the fqcn of a 50 * class derived from the one this rule can handle. 51 * @param engine The engine that is managing the rules. A rule can store a reference to 52 * the engine during initialization and then use it later to invoke some of the 53 * {@link IClientRulesEngine} methods for example to request user input. 54 * @return True if this rule can handle the given FQCN. False if the rule can't handle the 55 * given FQCN, in which case the rule engine will find another rule matching a parent class. 56 */ onInitialize(String fqcn, IClientRulesEngine engine)57 boolean onInitialize(String fqcn, IClientRulesEngine engine); 58 59 /** 60 * This method is called by the rules engine just before the script is unloaded. 61 */ onDispose()62 void onDispose(); 63 64 /** 65 * Returns the class name to display when an element is selected in the GLE. 66 * <p/> 67 * If null is returned, the GLE will automatically shorten the class name using its 68 * own heuristic, which is to keep the first 2 package components and the class name. 69 * The class name is the <code>fqcn</code> argument that was given 70 * to {@link #onInitialize(String,IClientRulesEngine)}. 71 * 72 * @return Null for the default behavior or a shortened string. 73 */ getDisplayName()74 String getDisplayName(); 75 76 /** 77 * Invoked by the Rules Engine to produce a set of actions to customize 78 * the context menu displayed for this view. The result is not cached and the 79 * method is invoked every time the context menu is about to be shown. 80 * <p> 81 * The order of the menu items is determined by the sort priority set on 82 * the actions. 83 * <p/> 84 * Most rules should consider calling super.{@link #addContextMenuActions(List, INode)} 85 * as well. 86 * <p/> 87 * Menu actions are either toggles or fixed lists with one currently-selected 88 * item. It is expected that the rule will need to recreate the actions with 89 * different selections when a menu is going to shown, which is why the result 90 * is not cached. However rules are encouraged to cache some or all of the result 91 * to speed up following calls if it makes sense. 92 * 93 * @param actions a list of actions to add new context menu actions into. The order 94 * of the actions in this list is not important; it will be sorted by 95 * {@link RuleAction#getSortPriority()} later. 96 * @param node the node to add actions for. 97 */ addContextMenuActions(List<RuleAction> actions, INode node)98 void addContextMenuActions(List<RuleAction> actions, INode node); 99 100 /** 101 * Invoked by the Rules Engine to ask the parent layout for the set of layout actions 102 * to display in the layout bar. The layout rule should add these into the provided 103 * list. The order the items are added in does not matter; the 104 * {@link RuleAction#getSortPriority()} values will be used to sort the actions prior 105 * to display, which makes it easier for parent rules and deriving rules to interleave 106 * their respective actions. 107 * 108 * @param actions the list of actions to add newly registered actions into 109 * @param parentNode the parent of the selection, or the selection itself if the root 110 * @param targets the targeted/selected nodes, if any 111 */ addLayoutActions(List<RuleAction> actions, INode parentNode, List<? extends INode> targets)112 void addLayoutActions(List<RuleAction> actions, 113 INode parentNode, List<? extends INode> targets); 114 115 // ==== Selection ==== 116 117 /** 118 * Returns a list of strings that will be displayed when a single child is being 119 * selected in a layout corresponding to this rule. This gives the container a chance 120 * to describe the child's layout attributes or other relevant information. 121 * <p/> 122 * Note that this is called only for single selections. 123 * <p/> 124 * 125 * @param parentNode The parent of the node selected. Never null. 126 * @param childNode The child node that was selected. Never null. 127 * @return a list of strings to be displayed, or null or empty to display nothing 128 */ getSelectionHint(INode parentNode, INode childNode)129 List<String> getSelectionHint(INode parentNode, INode childNode); 130 131 /** 132 * Paints any layout-specific selection feedback for the given parent layout. 133 * 134 * @param graphics the graphics context to paint into 135 * @param parentNode the parent layout node 136 * @param childNodes the child nodes selected in the parent layout 137 * @param view An instance of the view to be painted (may be null) 138 */ paintSelectionFeedback(IGraphics graphics, INode parentNode, List<? extends INode> childNodes, Object view)139 void paintSelectionFeedback(IGraphics graphics, INode parentNode, 140 List<? extends INode> childNodes, Object view); 141 142 // ==== Drag'n'drop support ==== 143 144 /** 145 * Called when the d'n'd starts dragging over the target node. If 146 * interested, returns a DropFeedback passed to onDrop/Move/Leave/Paint. If 147 * not interested in drop, return null. Followed by a paint. 148 * 149 * @param targetNode the {@link INode} for the target layout receiving a 150 * drop event 151 * @param targetView the corresponding View object for the target layout, or 152 * null if not known 153 * @param elements an array of {@link IDragElement} element descriptors for 154 * the dragged views 155 * @return a {@link DropFeedback} object with drop state (which will be 156 * supplied to a follow-up {@link #onDropMove} call), or null if the 157 * drop should be ignored 158 */ onDropEnter(INode targetNode, Object targetView, IDragElement[] elements)159 DropFeedback onDropEnter(INode targetNode, Object targetView, IDragElement[] elements); 160 161 /** 162 * Called after onDropEnter. Returns a DropFeedback passed to 163 * onDrop/Move/Leave/Paint (typically same as input one). Returning null 164 * will invalidate the drop workflow. 165 * 166 * @param targetNode the {@link INode} for the target layout receiving a 167 * drop event 168 * @param elements an array of {@link IDragElement} element descriptors for 169 * the dragged views 170 * @param feedback the {@link DropFeedback} object created by 171 * {@link #onDropEnter(INode, Object, IDragElement[])} 172 * @param where the current mouse drag position 173 * @return a {@link DropFeedback} (which is usually just the same one passed 174 * into this method) 175 */ onDropMove(INode targetNode, IDragElement[] elements, DropFeedback feedback, Point where)176 DropFeedback onDropMove(INode targetNode, 177 IDragElement[] elements, 178 DropFeedback feedback, 179 Point where); 180 181 /** 182 * Called when drop leaves the target without actually dropping. 183 * <p/> 184 * When switching between views, onDropLeave is called on the old node *after* onDropEnter 185 * is called after a new node that returned a non-null feedback. The feedback received here 186 * is the one given by the previous onDropEnter on the same target. 187 * <p/> 188 * E.g. call order is: 189 * <pre> 190 * - onDropEnter(node1) => feedback1 191 * <i>...user moves to new view...</i> 192 * - onDropEnter(node2) => feedback2 193 * - onDropLeave(node1, feedback1) 194 * <i>...user leaves canvas...</i> 195 * - onDropLeave(node2, feedback2) 196 * </pre> 197 * @param targetNode the {@link INode} for the target layout receiving a 198 * drop event 199 * @param elements an array of {@link IDragElement} element descriptors for 200 * the dragged views 201 * @param feedback the {@link DropFeedback} object created by 202 * {@link #onDropEnter(INode, Object, IDragElement[])} 203 */ onDropLeave(INode targetNode, IDragElement[] elements, DropFeedback feedback)204 void onDropLeave(INode targetNode, 205 IDragElement[] elements, 206 DropFeedback feedback); 207 208 /** 209 * Called when drop is released over the target to perform the actual drop. 210 * <p> 211 * TODO: Document that this method will be called under an edit lock so you can 212 * directly manipulate the nodes without wrapping it in an 213 * {@link INode#editXml(String, INodeHandler)} call. 214 * 215 * @param targetNode the {@link INode} for the target layout receiving a 216 * drop event 217 * @param elements an array of {@link IDragElement} element descriptors for 218 * the dragged views 219 * @param feedback the {@link DropFeedback} object created by 220 * {@link #onDropEnter(INode, Object, IDragElement[])} 221 * @param where the mouse drop position 222 */ onDropped(INode targetNode, IDragElement[] elements, DropFeedback feedback, Point where)223 void onDropped(INode targetNode, 224 IDragElement[] elements, 225 DropFeedback feedback, 226 Point where); 227 228 /** 229 * Called when pasting elements in an existing document on the selected target. 230 * 231 * @param targetNode The first node selected. 232 * @param targetView the corresponding View object for the target layout, or 233 * null if not known 234 * @param pastedElements The elements being pasted. 235 */ onPaste(INode targetNode, Object targetView, IDragElement[] pastedElements)236 void onPaste(INode targetNode, Object targetView, IDragElement[] pastedElements); 237 238 // ==== XML Creation ==== 239 240 /** 241 * Called when a view for this rule is being created. This allows for the rule to 242 * customize the newly created object. Note that this method is called not just when a 243 * view is created from a palette drag, but when views are constructed via a drag-move 244 * (where views are created in the destination and then deleted from the source), and 245 * even when views are constructed programmatically from other view rules. The 246 * {@link InsertType} parameter can be used to distinguish the context for the 247 * insertion. For example, the <code>DialerFilterRule</code> will insert EditText children 248 * when a DialerFilter is first created, but not during a copy/paste or a move. 249 * 250 * @param node the newly created node (which will always be a View that applies to 251 * this {@link IViewRule}) 252 * @param parent the parent of the node (which may not yet contain the newly created 253 * node in its child list) 254 * @param insertType whether this node was created as part of a newly created view, or 255 * as a copy, or as a move, etc. 256 */ onCreate(INode node, INode parent, InsertType insertType)257 void onCreate(INode node, INode parent, InsertType insertType); 258 259 /** 260 * Called when a child for this view has been created and is being inserted into the 261 * view parent for which this {@link IViewRule} applies. Allows the parent to perform 262 * customizations of the object. As with {@link #onCreate}, the {@link InsertType} 263 * parameter can be used to handle new creation versus moves versus copy/paste 264 * operations differently. 265 * 266 * @param child the newly created node 267 * @param parent the parent of the newly created node (which may not yet contain the 268 * newly created node in its child list) 269 * @param insertType whether this node was created as part of a newly created view, or 270 * as a copy, or as a move, etc. 271 */ onChildInserted(INode child, INode parent, InsertType insertType)272 void onChildInserted(INode child, INode parent, InsertType insertType); 273 274 /** 275 * Called when one or more children are about to be deleted by the user. Note that 276 * children deleted programmatically from view rules (via 277 * {@link INode#removeChild(INode)}) will not notify about deletion. 278 * <p> 279 * Note that this method will be called under an edit lock, so rules can directly 280 * add/remove nodes and attributes as part of the deletion handling (and their 281 * actions will be part of the same undo-unit.) 282 * 283 * @param deleted a nonempty list of children about to be deleted 284 * @param parent the parent of the deleted children (which still contains the children 285 * since this method is called before the deletion is performed) 286 */ onRemovingChildren(List<INode> deleted, INode parent)287 void onRemovingChildren(List<INode> deleted, INode parent); 288 289 /** 290 * Called by the IDE on the parent layout when a child widget is being resized. This 291 * is called once at the beginning of the resizing operation. A horizontal edge, 292 * or a vertical edge, or both, can be resized simultaneously. 293 * 294 * @param child the widget being resized 295 * @param parent the layout containing the child 296 * @param horizEdge The horizontal edge being resized, or null 297 * @param verticalEdge the vertical edge being resized, or null 298 * @param childView an instance of the resized node view, or null if not known 299 * @param parentView an instance of the parent layout view object, or null if not known 300 * @return a {@link DropFeedback} object which performs an update painter callback 301 * etc. 302 */ onResizeBegin( INode child, INode parent, SegmentType horizEdge, SegmentType verticalEdge, Object childView, Object parentView)303 DropFeedback onResizeBegin( 304 INode child, INode parent, 305 SegmentType horizEdge, SegmentType verticalEdge, 306 Object childView, Object parentView); 307 308 /** 309 * Called by the IDE on the parent layout when a child widget is being resized. This 310 * is called repeatedly during the resize as the mouse is dragged to update the drag 311 * bounds, recompute guidelines, etc. The resize has not yet been "committed" so the 312 * XML should not be edited yet. 313 * 314 * @param feedback the {@link DropFeedback} object created in {@link #onResizeBegin} 315 * @param child the widget being resized 316 * @param parent the layout containing the child 317 * @param newBounds the new bounds the user has chosen to resize the widget to, 318 * in absolute coordinates 319 * @param modifierMask The modifier keys currently pressed by the user, as a bitmask 320 * of the constants {@link DropFeedback#MODIFIER1}, {@link DropFeedback#MODIFIER2} 321 * and {@link DropFeedback#MODIFIER3}. 322 */ onResizeUpdate(DropFeedback feedback, INode child, INode parent, Rect newBounds, int modifierMask)323 void onResizeUpdate(DropFeedback feedback, INode child, INode parent, Rect newBounds, 324 int modifierMask); 325 326 /** 327 * Called by the IDE on the parent layout when a child widget is being resized. This 328 * is called once at the end of the resize operation, if it was not canceled. 329 * This method can call {@link INode#editXml} to update the node to reflect the 330 * new bounds. 331 * 332 * @param feedback the {@link DropFeedback} object created in {@link #onResizeBegin} 333 * @param child the widget being resized 334 * @param parent the layout containing the child 335 * @param newBounds the new bounds the user has chosen to resize the widget to, 336 * in absolute coordinates 337 */ onResizeEnd(DropFeedback feedback, INode child, INode parent, Rect newBounds)338 void onResizeEnd(DropFeedback feedback, INode child, INode parent, Rect newBounds); 339 } 340