1 /*
2  * Copyright (C) 2010 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.annotations.NonNull;
20 import com.android.annotations.Nullable;
21 import com.android.ide.common.api.IViewRule;
22 import com.android.ide.common.api.Rect;
23 
24 
25 /**
26  * This singleton is used to keep track of drag'n'drops initiated within this
27  * session of Eclipse. A drag can be initiated from a palette or from a canvas
28  * and its content is an Android View fully-qualified class name.
29  * <p/>
30  * Overall this is a workaround: the issue is that the drag'n'drop SWT API does not
31  * allow us to know the transfered data during the initial drag -- only when the
32  * data is dropped do we know what it is about (and to be more exact there is a workaround
33  * to do just that which works on Windows but not on Linux/Mac SWT).
34  * <p/>
35  * In the GLE we'd like to adjust drag feedback to the data being actually dropped.
36  * The singleton instance of this class will be used to track the data currently dragged
37  * off a canvas or its palette and then set back to null when the drag'n'drop is finished.
38  * <p/>
39  * Note that when a drag starts in one instance of Eclipse and the dragOver/drop is done
40  * in a <em>separate</em> instance of Eclipse, the dragged FQCN won't be registered here
41  * and will be null.
42  */
43 final class GlobalCanvasDragInfo {
44 
45     private static final GlobalCanvasDragInfo sInstance = new GlobalCanvasDragInfo();
46 
47     private SimpleElement[] mCurrentElements = null;
48     private SelectionItem[] mCurrentSelection;
49     private Object mSourceCanvas = null;
50     private Runnable mRemoveSourceHandler;
51     private Rect mDragBounds;
52     private int mDragBaseline = -1;
53 
54     /** Private constructor. Use {@link #getInstance()} to retrieve the singleton. */
GlobalCanvasDragInfo()55     private GlobalCanvasDragInfo() {
56         // pass
57     }
58 
59     /** Returns the singleton instance. */
getInstance()60     public static GlobalCanvasDragInfo getInstance() {
61         return sInstance;
62     }
63 
64     /**
65      * Registers the XML elements being dragged.
66      *
67      * @param elements The elements being dragged
68      * @param primary the "primary" element among the elements; when there is a
69      *            single item dragged this will be the same, but in
70      *            multi-selection it will be the element under the mouse as the
71      *            selection was initiated
72      * @param selection The selection (which can be null, for example when the
73      *            user drags from the palette)
74      * @param sourceCanvas An object representing the source we are dragging
75      *            from (used for identity comparisons only)
76      * @param removeSourceHandler A runnable (or null) which can clean up the
77      *            source. It should only be invoked if the drag operation is a
78      *            move, not a copy.
79      */
startDrag( @onNull SimpleElement[] elements, @Nullable SelectionItem[] selection, @Nullable Object sourceCanvas, @Nullable Runnable removeSourceHandler)80     public void startDrag(
81             @NonNull SimpleElement[] elements,
82             @Nullable SelectionItem[] selection,
83             @Nullable Object sourceCanvas,
84             @Nullable Runnable removeSourceHandler) {
85         mCurrentElements = elements;
86         mCurrentSelection = selection;
87         mSourceCanvas = sourceCanvas;
88         mRemoveSourceHandler = removeSourceHandler;
89     }
90 
91     /** Unregisters elements being dragged. */
stopDrag()92     public void stopDrag() {
93         mCurrentElements = null;
94         mCurrentSelection = null;
95         mSourceCanvas = null;
96         mRemoveSourceHandler = null;
97         mDragBounds = null;
98     }
99 
isDragging()100     public boolean isDragging() {
101         return mCurrentElements != null;
102     }
103 
104     /** Returns the elements being dragged. */
105     @NonNull
getCurrentElements()106     public SimpleElement[] getCurrentElements() {
107         return mCurrentElements;
108     }
109 
110     /** Returns the selection originally dragged.
111      * Can be null if the drag did not start in a canvas.
112      */
getCurrentSelection()113     public SelectionItem[] getCurrentSelection() {
114         return mCurrentSelection;
115     }
116 
117     /**
118      * Returns the object that call {@link #startDrag(SimpleElement[], SelectionItem[], Object)}.
119      * Can be null.
120      * This is not meant to access the object indirectly, it is just meant to compare if the
121      * source and the destination of the drag'n'drop are the same, so object identity
122      * is all what matters.
123      */
getSourceCanvas()124     public Object getSourceCanvas() {
125         return mSourceCanvas;
126     }
127 
128     /**
129      * Removes source of the drag. This should only be called when the drag and
130      * drop operation is a move (not a copy).
131      */
removeSource()132     public void removeSource() {
133         if (mRemoveSourceHandler != null) {
134             mRemoveSourceHandler.run();
135             mRemoveSourceHandler = null;
136         }
137     }
138 
139     /**
140      * Get the bounds of the drag, relative to the starting mouse position. For example,
141      * if you have a rectangular view of size 100x80, and you start dragging at position
142      * (15,20) from the top left corner of this rectangle, then the drag bounds would be
143      * (-15,-20, 100x80).
144      * <p>
145      * NOTE: The coordinate units will be in SWT/control pixels, not Android view pixels.
146      * In other words, they are affected by the canvas zoom: If you zoom the view and the
147      * bounds of a view grow, the drag bounds will be larger.
148      *
149      * @return the drag bounds, or null if there are no bounds for the current drag
150      */
getDragBounds()151     public Rect getDragBounds() {
152         return mDragBounds;
153     }
154 
155     /**
156      * Set the bounds of the drag, relative to the starting mouse position. See
157      * {@link #getDragBounds()} for details on the semantics of the drag bounds.
158      *
159      * @param dragBounds the new drag bounds, or null if there are no drag bounds
160      */
setDragBounds(Rect dragBounds)161     public void setDragBounds(Rect dragBounds) {
162         mDragBounds = dragBounds;
163     }
164 
165     /**
166      * Returns the baseline of the drag, or -1 if not applicable
167      *
168      * @return the current SWT modifier key mask as an {@link IViewRule} modifier mask
169      */
getDragBaseline()170     public int getDragBaseline() {
171         return mDragBaseline;
172     }
173 
174     /**
175      * Sets the baseline of the drag
176      *
177      * @param baseline the new baseline
178      */
setDragBaseline(int baseline)179     public void setDragBaseline(int baseline) {
180         mDragBaseline = baseline;
181     }
182 }
183