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