001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Pavel Dolgov
019: * @version $Revision$
020: */package org.apache.harmony.awt.datatransfer.windows;
021:
022: import java.awt.EventQueue;
023: import java.awt.Point;
024: import java.awt.datatransfer.DataFlavor;
025: import java.awt.datatransfer.Transferable;
026: import java.awt.dnd.DnDConstants;
027: import java.awt.dnd.DropTarget;
028: import java.awt.dnd.DropTargetContext;
029: import java.awt.dnd.DropTargetDragEvent;
030: import java.awt.dnd.DropTargetDropEvent;
031: import java.awt.dnd.DropTargetEvent;
032: import java.awt.dnd.InvalidDnDOperationException;
033: import java.awt.dnd.peer.DropTargetContextPeer;
034:
035: import org.apache.harmony.awt.ComponentInternals;
036: import org.apache.harmony.awt.datatransfer.DataProxy;
037: import org.apache.harmony.awt.datatransfer.DataSnapshot;
038: import org.apache.harmony.awt.internal.nls.Messages;
039: import org.apache.harmony.awt.nativebridge.windows.WinDataTransfer;
040: import org.apache.harmony.awt.nativebridge.windows.WindowsDefs;
041: import org.apache.harmony.awt.wtk.NativeWindow;
042: import org.apache.harmony.awt.wtk.NativeEventQueue.Task;
043:
044: /**
045: * Handles OLE drop opreration on particular heavyweight component,
046: * and dispatches DropTarget events. The drop operation runs on
047: * DataTransferThread because DropTarget events are dispatched
048: * synchronously. While handling the OLE callback the data transfer thread
049: * is blocked until event dispatch thread handles the DropTargetEvent.
050: * It is done due to synchronous nature of OLE IDropTarget callbacks.
051: */
052: public class WinDropTarget implements DropTargetContextPeer, Runnable {
053:
054: private final DropTargetContext context;
055: private final long hwnd;
056: private final long dropTargetPtr;
057:
058: private WinDataTransfer.IDataObject dataObject;
059: private DataProxy transferable;
060:
061: private static final int DRAG_NONE = 0;
062: private static final int DRAG_ENTER = 1;
063: private static final int DRAG_OVER = 2;
064: private static final int DRAG_DROP = 3;
065: private static final int DRAG_LEAVE = 4;
066: private int dragState;
067: private int dropAction;
068: private DropTargetEvent currentEvent;
069:
070: private class DropMonitor {
071: }
072:
073: private final Object dropMonitor = new DropMonitor();
074:
075: private final WinDTK dtk;
076:
077: public WinDropTarget(WinDTK dtk, DropTargetContext context) {
078: this .dtk = dtk;
079: this .context = context;
080:
081: ComponentInternals ci = ComponentInternals
082: .getComponentInternals();
083: NativeWindow w = ci.getNativeWindow(context.getComponent());
084: hwnd = w.getId();
085: dropTargetPtr = registerDropTarget();
086: }
087:
088: private long registerDropTarget() {
089: Task task = new Task() {
090: @Override
091: public void perform() {
092: long ret = WinDataTransfer.registerDropTarget(hwnd,
093: WinDropTarget.this );
094: returnValue = new Long(ret);
095: }
096: };
097: dtk.performTask(task);
098: return ((Long) task.returnValue).longValue();
099: }
100:
101: public int getTargetActions() {
102: return context.getDropTarget().getDefaultActions();
103: }
104:
105: public void setTargetActions(int actions) {
106: context.getDropTarget().setDefaultActions(actions);
107: }
108:
109: public DropTarget getDropTarget() {
110: return context.getDropTarget();
111: }
112:
113: public DataFlavor[] getTransferDataFlavors() {
114: return (transferable != null) ? transferable
115: .getTransferDataFlavors() : new DataFlavor[0];
116: }
117:
118: public Transferable getTransferable()
119: throws InvalidDnDOperationException {
120: if (transferable == null) {
121: // awt.14=Transfer data is not available
122: throw new InvalidDnDOperationException(Messages
123: .getString("awt.14")); //$NON-NLS-1$
124: }
125: return transferable;
126: }
127:
128: public boolean isTransferableJVMLocal() {
129: return false;
130: }
131:
132: public void acceptDrag(int dragAction) {
133: // TODO: update dropAction
134: }
135:
136: public void rejectDrag() {
137: // TODO: set dropAction to zero
138: }
139:
140: public void acceptDrop(int dropAction) {
141: // TODO: update dropAction
142: }
143:
144: public void rejectDrop() {
145: }
146:
147: public void dropComplete(boolean success) {
148: }
149:
150: /**
151: * Called from native method WinDropTarget::DragEnter()
152: * @return bit mask of DROPEFFECT_* constants according to dropAction
153: */
154: public int dragEnter(long dataObjectPtr, int x, int y,
155: int userAction, int sourceActions) {
156: dataObject = new WinDataTransfer.IDataObject(dataObjectPtr);
157:
158: DataSnapshot snapshot = new DataSnapshot(dataObject);
159: transferable = new DataProxy(snapshot);
160:
161: DropTargetDragEvent e = new DropTargetDragEvent(context,
162: new Point(x, y), WinDragSource
163: .getDndActions(userAction), WinDragSource
164: .getDndActions(sourceActions));
165:
166: return dispatchEvent(e, DRAG_ENTER);
167: }
168:
169: /**
170: * Called from native method WinDropTarget::DragLeave()
171: */
172: public void dragLeave() {
173: DropTargetEvent e = new DropTargetEvent(context);
174: dispatchEvent(e, DRAG_LEAVE);
175: dataObject = null;
176: transferable = null;
177: }
178:
179: /**
180: * Called from native method WinDropTarget::DragOver()
181: * @return bit mask of DROPEFFECT_* constants according to dropAction
182: */
183: public int dragOver(int x, int y, int userAction, int sourceActions) {
184: DropTargetDragEvent e = new DropTargetDragEvent(context,
185: new Point(x, y), WinDragSource
186: .getDndActions(userAction), WinDragSource
187: .getDndActions(sourceActions));
188:
189: return dispatchEvent(e, DRAG_OVER);
190: }
191:
192: /**
193: * Called from native method WinDropTarget::Drop()
194: * @return bit mask of DROPEFFECT_* constants according to dropAction
195: */
196: public int drop(long dataObjectPtr, int x, int y, int userAction,
197: int sourceActions) {
198: if (dataObjectPtr != dataObject.pointer) {
199: dataObject = new WinDataTransfer.IDataObject(dataObjectPtr);
200: DataSnapshot snapshot = new DataSnapshot(dataObject);
201: transferable = new DataProxy(snapshot);
202: }
203:
204: DropTargetDropEvent e = new DropTargetDropEvent(context,
205: new Point(x, y), WinDragSource
206: .getDndActions(userAction), WinDragSource
207: .getDndActions(sourceActions));
208:
209: int ret = dispatchEvent(e, DRAG_DROP);
210: dataObject = null;
211: transferable = null;
212: return ret;
213: }
214:
215: /**
216: * Call this method from {@link DropTargetContext#removeNotify()}
217: */
218: public void dispose() {
219: WinDataTransfer.revokeDropTarget(hwnd, dropTargetPtr);
220: }
221:
222: /**
223: * Dispatch DropTargetEvent on event dispatch thread.
224: * {@link EventQueue#invokeLater(Runnable)} is used to invoke this method.
225: */
226: public void run() {
227: synchronized (dropMonitor) {
228: switch (dragState) {
229: case DRAG_ENTER: {
230: DropTargetDragEvent e = (DropTargetDragEvent) currentEvent;
231: context.getDropTarget().dragEnter(e);
232: dropAction = e.getDropAction();
233: break;
234: }
235: case DRAG_OVER: {
236: DropTargetDragEvent e = (DropTargetDragEvent) currentEvent;
237: context.getDropTarget().dragOver(e);
238: dropAction = e.getDropAction();
239: break;
240: }
241: case DRAG_DROP: {
242: DropTargetDropEvent e = (DropTargetDropEvent) currentEvent;
243: context.getDropTarget().drop(e);
244: dropAction = e.getDropAction();
245: break;
246: }
247: case DRAG_LEAVE: {
248: context.getDropTarget().dragExit(currentEvent);
249: dropAction = DnDConstants.ACTION_NONE;
250: break;
251: }
252: default:
253: dropAction = DnDConstants.ACTION_NONE;
254: break;
255: }
256: dragState = DRAG_NONE;
257:
258: dropMonitor.notify();
259: }
260: }
261:
262: private int dispatchEvent(DropTargetEvent e, int state) {
263: synchronized (dropMonitor) {
264: try {
265: dragState = state;
266: currentEvent = e;
267: dropAction = DnDConstants.ACTION_NONE;
268: EventQueue.invokeLater(this );
269: while (dragState != DRAG_NONE) {
270: dropMonitor.wait();
271: }
272: return WinDragSource.getWinActions(dropAction);
273: } catch (InterruptedException ex) {
274: return WindowsDefs.DROPEFFECT_NONE;
275: }
276: }
277: }
278: }
|