• 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.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