|
1 /* |
|
2 * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. Oracle designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Oracle in the LICENSE file that accompanied this code. |
|
10 * |
|
11 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 * version 2 for more details (a copy is included in the LICENSE file that |
|
15 * accompanied this code). |
|
16 * |
|
17 * You should have received a copy of the GNU General Public License version |
|
18 * 2 along with this work; if not, write to the Free Software Foundation, |
|
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 * |
|
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
22 * or visit www.oracle.com if you need additional information or have any |
|
23 * questions. |
|
24 */ |
|
25 |
|
26 //#define DND_DEBUG TRUE |
|
27 |
|
28 #import "CDropTarget.h" |
|
29 #import "AWTView.h" |
|
30 |
|
31 #import "sun_lwawt_macosx_CDropTarget.h" |
|
32 #import "java_awt_dnd_DnDConstants.h" |
|
33 |
|
34 #import <JavaNativeFoundation/JavaNativeFoundation.h> |
|
35 #import <JavaRuntimeSupport/JavaRuntimeSupport.h> |
|
36 #include <objc/objc-runtime.h> |
|
37 |
|
38 |
|
39 #import "CDragSource.h" |
|
40 #import "CDataTransferer.h" |
|
41 #import "DnDUtilities.h" |
|
42 #import "ThreadUtilities.h" |
|
43 |
|
44 |
|
45 static NSInteger sDraggingSequenceNumber = -1; |
|
46 static NSDragOperation sDragOperation; |
|
47 static NSDragOperation sUpdateOperation; |
|
48 static jint sJavaDropOperation; |
|
49 static NSPoint sDraggingLocation; |
|
50 static BOOL sDraggingExited; |
|
51 static BOOL sDraggingError; |
|
52 |
|
53 static NSUInteger sPasteboardItemsCount = 0; |
|
54 static NSArray* sPasteboardTypes = nil; |
|
55 static NSArray* sPasteboardData = nil; |
|
56 static jlongArray sDraggingFormats = nil; |
|
57 |
|
58 static CDropTarget* sCurrentDropTarget; |
|
59 |
|
60 extern JNFClassInfo jc_CDropTargetContextPeer; |
|
61 |
|
62 @implementation CDropTarget |
|
63 |
|
64 + (CDropTarget *) currentDropTarget { |
|
65 return sCurrentDropTarget; |
|
66 } |
|
67 |
|
68 - (id)init:(jobject)jdropTarget component:(jobject)jcomponent peer:(jobject)jpeer control:(id)control |
|
69 { |
|
70 self = [super init]; |
|
71 DLog2(@"[CDropTarget init]: %@\n", self); |
|
72 |
|
73 fView = nil; |
|
74 fComponent = nil; |
|
75 fDropTarget = nil; |
|
76 fDropTargetContextPeer = nil; |
|
77 |
|
78 |
|
79 if (control != nil) { |
|
80 JNIEnv *env = [ThreadUtilities getJNIEnvUncached]; |
|
81 fComponent = JNFNewGlobalRef(env, jcomponent); |
|
82 fDropTarget = JNFNewGlobalRef(env, jdropTarget); |
|
83 |
|
84 AWTView *awtView = [((NSWindow *) control) contentView]; |
|
85 fView = [awtView retain]; |
|
86 [awtView setDropTarget:self]; |
|
87 |
|
88 |
|
89 } else { |
|
90 // This would be an error. |
|
91 [self release]; |
|
92 self = nil; |
|
93 } |
|
94 return self; |
|
95 } |
|
96 |
|
97 // When [CDropTarget init] is called the ControlModel's fView may not have been set up yet. ControlModel |
|
98 // (soon after) calls [CDropTarget controlModelControlValid] on the native event thread, once per CDropTarget, |
|
99 // to let it know it's been set up now. |
|
100 - (void)controlModelControlValid |
|
101 { |
|
102 // 9-30-02 Note: [Radar 3065621] |
|
103 // List all known pasteboard types here (see AppKit's NSPasteboard.h) |
|
104 // How to register for non-standard data types remains to be determined. |
|
105 NSArray* dataTypes = [[NSArray alloc] initWithObjects: |
|
106 NSStringPboardType, |
|
107 NSFilenamesPboardType, |
|
108 NSPostScriptPboardType, |
|
109 NSTIFFPboardType, |
|
110 NSRTFPboardType, |
|
111 NSTabularTextPboardType, |
|
112 NSFontPboardType, |
|
113 NSRulerPboardType, |
|
114 NSFileContentsPboardType, |
|
115 NSColorPboardType, |
|
116 NSRTFDPboardType, |
|
117 NSHTMLPboardType, |
|
118 NSURLPboardType, |
|
119 NSPDFPboardType, |
|
120 NSVCardPboardType, |
|
121 NSFilesPromisePboardType, |
|
122 [DnDUtilities javaPboardType], |
|
123 nil]; |
|
124 |
|
125 // Enable dragging events over this object: |
|
126 [fView registerForDraggedTypes:dataTypes]; |
|
127 |
|
128 [dataTypes release]; |
|
129 } |
|
130 |
|
131 - (void)releaseDraggingData |
|
132 { |
|
133 DLog2(@"[CDropTarget releaseDraggingData]: %@\n", self); |
|
134 |
|
135 // Release any old pasteboard types, data and properties: |
|
136 [sPasteboardTypes release]; |
|
137 sPasteboardTypes = nil; |
|
138 |
|
139 [sPasteboardData release]; |
|
140 sPasteboardData = nil; |
|
141 |
|
142 if (sDraggingFormats != NULL) { |
|
143 JNIEnv *env = [ThreadUtilities getJNIEnv]; |
|
144 JNFDeleteGlobalRef(env, sDraggingFormats); |
|
145 sDraggingFormats = NULL; |
|
146 } |
|
147 |
|
148 sPasteboardItemsCount = 0; |
|
149 sDraggingSequenceNumber = -1; |
|
150 } |
|
151 |
|
152 - (void)removeFromView:(JNIEnv *)env |
|
153 { |
|
154 DLog2(@"[CDropTarget removeFromView]: %@\n", self); |
|
155 |
|
156 // Remove this dragging destination from the view: |
|
157 [((AWTView *) fView) setDropTarget:nil]; |
|
158 |
|
159 // Clean up JNI refs |
|
160 if (fComponent != NULL) { |
|
161 JNFDeleteGlobalRef(env, fComponent); |
|
162 fComponent = NULL; |
|
163 } |
|
164 if (fDropTarget != NULL) { |
|
165 JNFDeleteGlobalRef(env, fDropTarget); |
|
166 fDropTarget = NULL; |
|
167 } |
|
168 if (fDropTargetContextPeer != NULL) { |
|
169 JNFDeleteGlobalRef(env, fDropTargetContextPeer); |
|
170 fDropTargetContextPeer = NULL; |
|
171 } |
|
172 |
|
173 CFRelease(self); |
|
174 } |
|
175 |
|
176 - (void)dealloc |
|
177 { |
|
178 DLog2(@"[CDropTarget dealloc]: %@\n", self); |
|
179 |
|
180 [fView release]; |
|
181 fView = nil; |
|
182 |
|
183 [super dealloc]; |
|
184 } |
|
185 //- (void)finalize { [super finalize]; } |
|
186 |
|
187 - (NSInteger) getDraggingSequenceNumber |
|
188 { |
|
189 return sDraggingSequenceNumber; |
|
190 } |
|
191 |
|
192 // Debugging help: |
|
193 - (void)dumpPasteboard:(NSPasteboard*)pasteboard |
|
194 { |
|
195 NSArray* pasteboardTypes = [pasteboard types]; |
|
196 NSUInteger pasteboardItemsCount = [pasteboardTypes count]; |
|
197 NSUInteger i; |
|
198 |
|
199 // For each flavor on the pasteboard show the type, its data, and its property if there is one: |
|
200 for (i = 0; i < pasteboardItemsCount; i++) { |
|
201 NSString* pbType = [pasteboardTypes objectAtIndex:i]; |
|
202 CFShow(pbType); |
|
203 |
|
204 NSData* pbData = [pasteboard dataForType:pbType]; |
|
205 CFShow(pbData); |
|
206 |
|
207 if ([pbType hasPrefix:@"CorePasteboardFlavorType"] == NO) { |
|
208 id pbDataProperty = [pasteboard propertyListForType:pbType]; |
|
209 CFShow(pbDataProperty); |
|
210 } |
|
211 } |
|
212 } |
|
213 |
|
214 - (BOOL)copyDraggingTypes:(id<NSDraggingInfo>)sender |
|
215 { |
|
216 DLog2(@"[CDropTarget copyDraggingTypes]: %@\n", self); |
|
217 JNIEnv* env = [ThreadUtilities getJNIEnv]; |
|
218 |
|
219 // Release any old pasteboard data: |
|
220 [self releaseDraggingData]; |
|
221 |
|
222 NSPasteboard* pb = [sender draggingPasteboard]; |
|
223 sPasteboardTypes = [[pb types] retain]; |
|
224 sPasteboardItemsCount = [sPasteboardTypes count]; |
|
225 if (sPasteboardItemsCount == 0) |
|
226 return FALSE; |
|
227 |
|
228 jlongArray formats = (*env)->NewLongArray(env, sPasteboardItemsCount); |
|
229 if (formats == nil) |
|
230 return FALSE; |
|
231 |
|
232 sDraggingFormats = (jlongArray) JNFNewGlobalRef(env, formats); |
|
233 (*env)->DeleteLocalRef(env, formats); |
|
234 if (sDraggingFormats == nil) |
|
235 return FALSE; |
|
236 |
|
237 jboolean isCopy; |
|
238 jlong* jformats = (*env)->GetLongArrayElements(env, sDraggingFormats, &isCopy); |
|
239 if (jformats == nil) { |
|
240 return FALSE; |
|
241 } |
|
242 |
|
243 // Copy all data formats and properties. In case of properties, if they are nil, we need to use |
|
244 // a special NilProperty since [NSArray addObject] would crash on adding a nil object. |
|
245 DLog2(@"[CDropTarget copyDraggingTypes]: typesCount = %lu\n", (unsigned long) sPasteboardItemsCount); |
|
246 NSUInteger i; |
|
247 for (i = 0; i < sPasteboardItemsCount; i++) { |
|
248 NSString* pbType = [sPasteboardTypes objectAtIndex:i]; |
|
249 DLog3(@"[CDropTarget copyDraggingTypes]: type[%lu] = %@\n", (unsigned long) i, pbType); |
|
250 |
|
251 // 01-10-03 Note: until we need data properties for doing something useful don't copy them. |
|
252 // They're often copies of their flavor's data and copying them for all available pasteboard flavors |
|
253 // (which are often auto-translation of one another) can be a significant time/space hit. |
|
254 |
|
255 // If this is a remote object type (not a pre-defined format) register it with the pasteboard: |
|
256 jformats[i] = indexForFormat(pbType); |
|
257 if (jformats[i] == -1 && [pbType hasPrefix:@"JAVA_DATAFLAVOR:application/x-java-remote-object;"]) |
|
258 jformats[i] = registerFormatWithPasteboard(pbType); |
|
259 } |
|
260 |
|
261 (*env)->ReleaseLongArrayElements(env, sDraggingFormats, jformats, JNI_COMMIT); |
|
262 |
|
263 return TRUE; |
|
264 } |
|
265 |
|
266 - (BOOL)copyDraggingData:(id<NSDraggingInfo>)sender |
|
267 { |
|
268 DLog2(@"[CDropTarget copyDraggingData]: %@\n", self); |
|
269 |
|
270 sPasteboardData = [[NSMutableArray alloc] init]; |
|
271 if (sPasteboardData == nil) |
|
272 return FALSE; |
|
273 |
|
274 // Copy all data items to a safe place since the pasteboard may go away before we'll need them: |
|
275 NSPasteboard* pb = [sender draggingPasteboard]; |
|
276 NSUInteger i; |
|
277 for (i = 0; i < sPasteboardItemsCount; i++) { |
|
278 // Get a type and its data and save the data: |
|
279 NSString* pbType = [sPasteboardTypes objectAtIndex:i]; |
|
280 // 01-10-03 Note: copying only NS-type data (until Java-specified types can make it through the AppKit) |
|
281 // would be a good idea since we can't do anything with those CoreFoundation unknown types anyway. |
|
282 // But I'm worried that it would break something in Fuller so I'm leaving this here as a reminder, |
|
283 // to be evaluated later. |
|
284 //id pbData = [pbType hasPrefix:@"NS"] ? [pb dataForType:pbType] : nil; // Copy only NS-type data! |
|
285 id pbData = [pb dataForType:pbType]; |
|
286 |
|
287 // If the data is null we can't store it in the array - an exception would be thrown. |
|
288 // We use the special object NSNull instead which is kosher. |
|
289 if (pbData == nil) |
|
290 pbData = [NSNull null]; |
|
291 |
|
292 [((NSMutableArray*) sPasteboardData) addObject:pbData]; |
|
293 } |
|
294 |
|
295 return TRUE; |
|
296 } |
|
297 |
|
298 - (NSData*) getDraggingDataForURL:(NSData*)data |
|
299 { |
|
300 NSData* result = nil; |
|
301 |
|
302 // Convert data into a property list if possible: |
|
303 NSPropertyListFormat propertyListFormat; |
|
304 NSString* errorString = nil; |
|
305 id propertyList = [NSPropertyListSerialization propertyListFromData:data mutabilityOption:NSPropertyListImmutable |
|
306 format:&propertyListFormat errorDescription:&errorString]; |
|
307 |
|
308 // URL types have only a single URL string in an array: |
|
309 if (propertyList != nil && errorString == nil && [propertyList isKindOfClass:[NSArray class]]) { |
|
310 NSArray* array = (NSArray*) propertyList; |
|
311 if ([array count] > 0) { |
|
312 NSString* url = (NSString*) [array objectAtIndex:0]; |
|
313 if (url != nil && [url length] > 0) |
|
314 result = [url dataUsingEncoding:[url fastestEncoding]]; |
|
315 } |
|
316 } |
|
317 |
|
318 return result; |
|
319 } |
|
320 |
|
321 - (jobject) copyDraggingDataForFormat:(jlong)format |
|
322 { |
|
323 JNIEnv* env = [ThreadUtilities getJNIEnvUncached]; // Join the main thread by requesting uncached environment |
|
324 |
|
325 NSData* data = nil; |
|
326 |
|
327 // Convert the Java format (datatransferer int index) to a pasteboard format (NSString): |
|
328 NSString* pbType = formatForIndex(format); |
|
329 if ([sPasteboardTypes containsObject:pbType]) { |
|
330 NSUInteger dataIndex = [sPasteboardTypes indexOfObject:pbType]; |
|
331 data = [sPasteboardData objectAtIndex:dataIndex]; |
|
332 |
|
333 if ((id) data == [NSNull null]) |
|
334 data = nil; |
|
335 |
|
336 // format == 8 (CF_URL in CDataTransferer): we need a URL-to-String conversion: |
|
337 else if ([pbType isEqualToString:@"Apple URL pasteboard type"]) |
|
338 data = [self getDraggingDataForURL:data]; |
|
339 } |
|
340 |
|
341 // Get NS data: |
|
342 char* dataBytes = (data != nil) ? (char*) [data bytes] : "Unsupported type"; |
|
343 NSUInteger dataLength = (data != nil) ? [data length] : sizeof("Unsupported type"); |
|
344 |
|
345 // Create a global byte array: |
|
346 jbyteArray lbyteArray = (*env)->NewByteArray(env, dataLength); |
|
347 if (lbyteArray == nil) |
|
348 return nil; |
|
349 jbyteArray gbyteArray = (jbyteArray) JNFNewGlobalRef(env, lbyteArray); |
|
350 (*env)->DeleteLocalRef(env, lbyteArray); |
|
351 if (gbyteArray == nil) |
|
352 return nil; |
|
353 |
|
354 // Get byte array elements: |
|
355 jboolean isCopy; |
|
356 jbyte* jbytes = (*env)->GetByteArrayElements(env, gbyteArray, &isCopy); |
|
357 if (jbytes == nil) |
|
358 return nil; |
|
359 |
|
360 // Copy data to byte array and release elements: |
|
361 memcpy(jbytes, dataBytes, dataLength); |
|
362 (*env)->ReleaseByteArrayElements(env, gbyteArray, jbytes, JNI_COMMIT); |
|
363 |
|
364 // In case of an error make sure to return nil: |
|
365 if ((*env)->ExceptionOccurred(env)) { |
|
366 (*env)->ExceptionDescribe(env); |
|
367 gbyteArray = nil; |
|
368 } |
|
369 |
|
370 return gbyteArray; |
|
371 } |
|
372 |
|
373 - (void)safeReleaseDraggingData:(NSNumber *)arg |
|
374 { |
|
375 jlong draggingSequenceNumber = [arg longLongValue]; |
|
376 |
|
377 // Make sure dragging data is released only if no new drag is under way. If a new drag |
|
378 // has been initiated it has released the old dragging data already. This has to be called |
|
379 // on the native event thread - otherwise we'd need to start synchronizing. |
|
380 if (draggingSequenceNumber == sDraggingSequenceNumber) |
|
381 [self releaseDraggingData]; |
|
382 } |
|
383 |
|
384 - (void)javaDraggingEnded:(jlong)draggingSequenceNumber success:(BOOL)jsuccess action:(jint)jdropaction |
|
385 { |
|
386 NSNumber *draggingSequenceNumberID = [NSNumber numberWithLongLong:draggingSequenceNumber]; |
|
387 // Report back actual Swing success, not what AppKit thinks |
|
388 sDraggingError = !jsuccess; |
|
389 sDragOperation = [DnDUtilities mapJavaDragOperationToNS:jdropaction]; |
|
390 |
|
391 // Release dragging data if any when Java's AWT event thread is all finished. |
|
392 // Make sure dragging data is released on the native event thread. |
|
393 [ThreadUtilities performOnMainThread:@selector(safeReleaseDraggingData:) onObject:self |
|
394 withObject:draggingSequenceNumberID waitUntilDone:NO awtMode:NO]; |
|
395 } |
|
396 |
|
397 - (jint)currentJavaActions { |
|
398 return [DnDUtilities mapNSDragOperationToJava:sUpdateOperation]; |
|
399 } |
|
400 |
|
401 /******************************** BEGIN NSDraggingDestination Interface ********************************/ |
|
402 |
|
403 |
|
404 // Private API to calculate the current Java actions |
|
405 - (void) calculateCurrentSourceActions:(jint *)actions dropAction:(jint *)dropAction |
|
406 { |
|
407 // Get the raw (unmodified by keys) source actions |
|
408 id jrsDrag = objc_lookUpClass("JRSDrag"); |
|
409 if (jrsDrag != nil) { |
|
410 NSDragOperation rawDragActions = (NSDragOperation) [jrsDrag performSelector:@selector(currentAllowableActions)]; |
|
411 if (rawDragActions != NSDragOperationNone) { |
|
412 // Both actions and dropAction default to the rawActions |
|
413 *actions = [DnDUtilities mapNSDragOperationMaskToJava:rawDragActions]; |
|
414 *dropAction = *actions; |
|
415 |
|
416 // Get the current key modifiers. |
|
417 NSUInteger dragModifiers = (NSUInteger) [jrsDrag performSelector:@selector(currentModifiers)]; |
|
418 // Either the drop action is narrowed as per Java rules (MOVE, COPY, LINK, NONE) or by the drag modifiers |
|
419 if (dragModifiers) { |
|
420 // Get the user selected operation based on the drag modifiers, then return the intersection |
|
421 NSDragOperation currentOp = [DnDUtilities nsDragOperationForModifiers:dragModifiers]; |
|
422 NSDragOperation allowedOp = rawDragActions & currentOp; |
|
423 |
|
424 *dropAction = [DnDUtilities mapNSDragOperationToJava:allowedOp]; |
|
425 } |
|
426 } |
|
427 } |
|
428 *dropAction = [DnDUtilities narrowJavaDropActions:*dropAction]; |
|
429 } |
|
430 |
|
431 - (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender |
|
432 { |
|
433 DLog2(@"[CDropTarget draggingEntered]: %@\n", self); |
|
434 |
|
435 sCurrentDropTarget = self; |
|
436 |
|
437 JNIEnv* env = [ThreadUtilities getJNIEnv]; |
|
438 NSInteger draggingSequenceNumber = [sender draggingSequenceNumber]; |
|
439 |
|
440 // Set the initial drag operation return value: |
|
441 NSDragOperation dragOp = NSDragOperationNone; |
|
442 sJavaDropOperation = java_awt_dnd_DnDConstants_ACTION_NONE; |
|
443 |
|
444 // We could probably special-case some stuff if drag and drop objects match: |
|
445 //if ([sender dragSource] == fView) |
|
446 |
|
447 if (draggingSequenceNumber != sDraggingSequenceNumber) { |
|
448 sDraggingSequenceNumber = draggingSequenceNumber; |
|
449 sDraggingError = FALSE; |
|
450 |
|
451 // Delete any drop target context peer left over from a previous drag: |
|
452 if (fDropTargetContextPeer != NULL) { |
|
453 JNFDeleteGlobalRef(env, fDropTargetContextPeer); |
|
454 fDropTargetContextPeer = NULL; |
|
455 } |
|
456 |
|
457 // Look up the CDropTargetContextPeer class: |
|
458 JNF_STATIC_MEMBER_CACHE(getDropTargetContextPeerMethod, jc_CDropTargetContextPeer, "getDropTargetContextPeer", "()Lsun/lwawt/macosx/CDropTargetContextPeer;"); |
|
459 if (sDraggingError == FALSE) { |
|
460 // Create a new drop target context peer: |
|
461 jobject dropTargetContextPeer = JNFCallStaticObjectMethod(env, getDropTargetContextPeerMethod); |
|
462 |
|
463 if (dropTargetContextPeer != nil) { |
|
464 fDropTargetContextPeer = JNFNewGlobalRef(env, dropTargetContextPeer); |
|
465 (*env)->DeleteLocalRef(env, dropTargetContextPeer); |
|
466 } |
|
467 } |
|
468 |
|
469 // Get dragging types (dragging data is only copied if dropped): |
|
470 if (sDraggingError == FALSE && [self copyDraggingTypes:sender] == FALSE) |
|
471 sDraggingError = TRUE; |
|
472 } |
|
473 |
|
474 if (sDraggingError == FALSE) { |
|
475 sDraggingExited = FALSE; |
|
476 sDraggingLocation = [sender draggingLocation]; |
|
477 NSPoint javaLocation = [fView convertPoint:sDraggingLocation fromView:nil]; |
|
478 DLog5(@"+ dragEnter: loc native %f, %f, java %f, %f\n", sDraggingLocation.x, sDraggingLocation.y, javaLocation.x, javaLocation.y); |
|
479 |
|
480 ////////// BEGIN Calculate the current drag actions ////////// |
|
481 jint actions = java_awt_dnd_DnDConstants_ACTION_NONE; |
|
482 jint dropAction = actions; |
|
483 |
|
484 [self calculateCurrentSourceActions:&actions dropAction:&dropAction]; |
|
485 |
|
486 sJavaDropOperation = dropAction; |
|
487 ////////// END Calculate the current drag actions ////////// |
|
488 |
|
489 jlongArray formats = sDraggingFormats; |
|
490 |
|
491 JNF_MEMBER_CACHE(handleEnterMessageMethod, jc_CDropTargetContextPeer, "handleEnterMessage", "(Ljava/awt/Component;IIII[JJ)I"); |
|
492 if (sDraggingError == FALSE) { |
|
493 // Double-casting self gets rid of 'different size' compiler warning: |
|
494 actions = JNFCallIntMethod(env, fDropTargetContextPeer, handleEnterMessageMethod, fComponent, (jint) javaLocation.x, (jint) javaLocation.y, dropAction, actions, formats, ptr_to_jlong(self)); // AWT_THREADING Safe (CToolkitThreadBlockedHandler) |
|
495 } |
|
496 |
|
497 if (sDraggingError == FALSE) { |
|
498 // Initialize drag operation: |
|
499 sDragOperation = NSDragOperationNone; |
|
500 |
|
501 // Map Java actions back to NSDragOperation. |
|
502 // 1-6-03 Note: if the entry point of this CDropTarget isn't covered by a droppable component |
|
503 // (as can be the case with lightweight children) we must not return NSDragOperationNone |
|
504 // since that would prevent dropping into any of the contained drop targets. |
|
505 // Unfortunately there is no easy way to test this so we just test actions and override them |
|
506 // with GENERIC if necessary. Proper drag operations will be returned by draggingUpdated: which is |
|
507 // called right away, taking care of setting the right cursor and snap-back action. |
|
508 dragOp = ((actions != java_awt_dnd_DnDConstants_ACTION_NONE) ? |
|
509 [DnDUtilities mapJavaDragOperationToNS:dropAction] : NSDragOperationGeneric); |
|
510 |
|
511 // Remember the dragOp for no-op'd update messages: |
|
512 sUpdateOperation = dragOp; |
|
513 } |
|
514 |
|
515 // If we are in the same process as the sender, make the sender post the appropriate message |
|
516 if (sender) { |
|
517 [[CDragSource currentDragSource] postDragEnter]; |
|
518 } |
|
519 } |
|
520 |
|
521 // 9-11-02 Note: the native event thread would not handle an exception gracefully: |
|
522 //if (sDraggingError == TRUE) |
|
523 // [NSException raise:NSGenericException format:@"[CDropTarget draggingEntered] failed."]; |
|
524 |
|
525 DLog2(@"[CDropTarget draggingEntered]: returning %lu\n", (unsigned long) dragOp); |
|
526 |
|
527 return dragOp; |
|
528 } |
|
529 |
|
530 - (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender |
|
531 { |
|
532 //DLog2(@"[CDropTarget draggingUpdated]: %@\n", self); |
|
533 |
|
534 sCurrentDropTarget = self; |
|
535 |
|
536 // Set the initial drag operation return value: |
|
537 NSDragOperation dragOp = (sDraggingError == FALSE ? sUpdateOperation : NSDragOperationNone); |
|
538 |
|
539 // There are two things we would be interested in: |
|
540 // a) mouse pointer has moved |
|
541 // b) drag actions (key modifiers) have changed |
|
542 |
|
543 NSPoint draggingLocation = [sender draggingLocation]; |
|
544 JNIEnv* env = [ThreadUtilities getJNIEnv]; |
|
545 |
|
546 BOOL notifyJava = FALSE; |
|
547 |
|
548 // a) mouse pointer has moved: |
|
549 if (NSEqualPoints(draggingLocation, sDraggingLocation) == FALSE) { |
|
550 //DLog2(@"[CDropTarget draggingUpdated]: mouse moved, %@\n", self); |
|
551 sDraggingLocation = draggingLocation; |
|
552 notifyJava = TRUE; |
|
553 } |
|
554 |
|
555 // b) drag actions (key modifiers) have changed (handleMotionMessage() will do proper notifications): |
|
556 ////////// BEGIN Calculate the current drag actions ////////// |
|
557 jint actions = java_awt_dnd_DnDConstants_ACTION_NONE; |
|
558 jint dropAction = actions; |
|
559 |
|
560 [self calculateCurrentSourceActions:&actions dropAction:&dropAction]; |
|
561 |
|
562 if (sJavaDropOperation != dropAction) { |
|
563 sJavaDropOperation = dropAction; |
|
564 notifyJava = TRUE; |
|
565 } |
|
566 ////////// END Calculate the current drag actions ////////// |
|
567 |
|
568 jint userAction = dropAction; |
|
569 |
|
570 // Should we notify Java things have changed? |
|
571 if (sDraggingError == FALSE && notifyJava) { |
|
572 NSPoint javaLocation = [fView convertPoint:sDraggingLocation fromView:nil]; |
|
573 // For some reason even after the convertPoint drag events come with the y coordinate reverted |
|
574 javaLocation.y = fView.window.frame.size.height - javaLocation.y; |
|
575 //DLog5(@" : dragMoved: loc native %f, %f, java %f, %f\n", sDraggingLocation.x, sDraggingLocation.y, javaLocation.x, javaLocation.y); |
|
576 |
|
577 jlongArray formats = sDraggingFormats; |
|
578 |
|
579 JNF_MEMBER_CACHE(handleMotionMessageMethod, jc_CDropTargetContextPeer, "handleMotionMessage", "(Ljava/awt/Component;IIII[JJ)I"); |
|
580 if (sDraggingError == FALSE) { |
|
581 DLog3(@" >> posting handleMotionMessage, point %f, %f", javaLocation.x, javaLocation.y); |
|
582 userAction = JNFCallIntMethod(env, fDropTargetContextPeer, handleMotionMessageMethod, fComponent, (jint) javaLocation.x, (jint) javaLocation.y, dropAction, actions, formats, ptr_to_jlong(self)); // AWT_THREADING Safe (CToolkitThreadBlockedHandler) |
|
583 } |
|
584 |
|
585 if (sDraggingError == FALSE) { |
|
586 dragOp = [DnDUtilities mapJavaDragOperationToNS:userAction]; |
|
587 |
|
588 // Remember the dragOp for no-op'd update messages: |
|
589 sUpdateOperation = dragOp; |
|
590 } else { |
|
591 dragOp = NSDragOperationNone; |
|
592 } |
|
593 } |
|
594 |
|
595 DLog2(@"[CDropTarget draggingUpdated]: returning %lu\n", (unsigned long) dragOp); |
|
596 |
|
597 return dragOp; |
|
598 } |
|
599 |
|
600 - (void)draggingExited:(id<NSDraggingInfo>)sender |
|
601 { |
|
602 DLog2(@"[CDropTarget draggingExited]: %@\n", self); |
|
603 |
|
604 sCurrentDropTarget = nil; |
|
605 |
|
606 JNIEnv* env = [ThreadUtilities getJNIEnv]; |
|
607 |
|
608 if (sDraggingExited == FALSE && sDraggingError == FALSE) { |
|
609 JNF_MEMBER_CACHE(handleExitMessageMethod, jc_CDropTargetContextPeer, "handleExitMessage", "(Ljava/awt/Component;J)V"); |
|
610 if (sDraggingError == FALSE) { |
|
611 DLog3(@" - dragExit: loc native %f, %f\n", sDraggingLocation.x, sDraggingLocation.y); |
|
612 JNFCallVoidMethod(env, fDropTargetContextPeer, handleExitMessageMethod, fComponent, ptr_to_jlong(self)); // AWT_THREADING Safe (CToolkitThreadBlockedHandler) |
|
613 // If we are in the same process as the sender, make the sender post the appropriate message |
|
614 if (sender) { |
|
615 [[CDragSource currentDragSource] postDragExit]; |
|
616 } |
|
617 } |
|
618 |
|
619 // 5-27-03 Note: [Radar 3270455] |
|
620 // -draggingExited: can be called both by the AppKit and by -performDragOperation: but shouldn't execute |
|
621 // twice per drop since cleanup code like that in swing/plaf/basic/BasicDropTargetListener would throw NPEs. |
|
622 sDraggingExited = TRUE; |
|
623 } |
|
624 |
|
625 DLog(@"[CDropTarget draggingExited]: returning.\n"); |
|
626 } |
|
627 |
|
628 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender |
|
629 { |
|
630 DLog2(@"[CDropTarget prepareForDragOperation]: %@\n", self); |
|
631 DLog2(@"[CDropTarget prepareForDragOperation]: returning %@\n", (sDraggingError ? @"NO" : @"YES")); |
|
632 |
|
633 return sDraggingError ? NO : YES; |
|
634 } |
|
635 |
|
636 - (BOOL)performDragOperation:(id<NSDraggingInfo>)sender |
|
637 { |
|
638 DLog2(@"[CDropTarget performDragOperation]: %@\n", self); |
|
639 |
|
640 sCurrentDropTarget = nil; |
|
641 |
|
642 JNIEnv* env = [ThreadUtilities getJNIEnv]; |
|
643 |
|
644 // Now copy dragging data: |
|
645 if (sDraggingError == FALSE && [self copyDraggingData:sender] == FALSE) |
|
646 sDraggingError = TRUE; |
|
647 |
|
648 if (sDraggingError == FALSE) { |
|
649 sDraggingLocation = [sender draggingLocation]; |
|
650 NSPoint javaLocation = [fView convertPoint:sDraggingLocation fromView:nil]; |
|
651 |
|
652 jint actions = [DnDUtilities mapNSDragOperationMaskToJava:[sender draggingSourceOperationMask]]; |
|
653 jint dropAction = sJavaDropOperation; |
|
654 |
|
655 jlongArray formats = sDraggingFormats; |
|
656 |
|
657 JNF_MEMBER_CACHE(handleDropMessageMethod, jc_CDropTargetContextPeer, "handleDropMessage", "(Ljava/awt/Component;IIII[JJ)V"); |
|
658 |
|
659 if (sDraggingError == FALSE) { |
|
660 JNFCallVoidMethod(env, fDropTargetContextPeer, handleDropMessageMethod, fComponent, (jint) javaLocation.x, (jint) javaLocation.y, dropAction, actions, formats, ptr_to_jlong(self)); // AWT_THREADING Safe (event) |
|
661 } |
|
662 |
|
663 if (sDraggingError == FALSE) { |
|
664 JNF_MEMBER_CACHE(flushEventsMethod, jc_CDropTargetContextPeer, "flushEvents", "(Ljava/awt/Component;)V"); |
|
665 if (sDraggingError == FALSE) { |
|
666 JNFCallVoidMethod(env, fDropTargetContextPeer, flushEventsMethod, fComponent); // AWT_THREADING Safe (AWTRunLoopMode) |
|
667 } |
|
668 } |
|
669 } else { |
|
670 // 8-19-03 Note: [Radar 3368754] |
|
671 // draggingExited: is not called after a drop - we must do that here ... but only in case |
|
672 // of an error, instead of drop(). Otherwise we get twice the cleanup in shared code. |
|
673 [self draggingExited:sender]; |
|
674 } |
|
675 |
|
676 // TODO:BG |
|
677 // [(id)sender _setLastDragDestinationOperation:sDragOperation]; |
|
678 |
|
679 |
|
680 DLog2(@"[CDropTarget performDragOperation]: returning %@\n", (sDraggingError ? @"NO" : @"YES")); |
|
681 |
|
682 return !sDraggingError; |
|
683 } |
|
684 |
|
685 - (void)concludeDragOperation:(id<NSDraggingInfo>)sender |
|
686 { |
|
687 sCurrentDropTarget = nil; |
|
688 |
|
689 DLog2(@"[CDropTarget concludeDragOperation]: %@\n", self); |
|
690 DLog(@"[CDropTarget concludeDragOperation]: returning.\n"); |
|
691 } |
|
692 |
|
693 // 9-11-02 Note: draggingEnded is not yet implemented by the AppKit. |
|
694 - (void)draggingEnded:(id<NSDraggingInfo>)sender |
|
695 { |
|
696 sCurrentDropTarget = nil; |
|
697 |
|
698 DLog2(@"[CDropTarget draggingEnded]: %@\n", self); |
|
699 DLog(@"[CDropTarget draggingEnded]: returning.\n"); |
|
700 } |
|
701 |
|
702 /******************************** END NSDraggingDestination Interface ********************************/ |
|
703 |
|
704 @end |
|
705 |
|
706 |
|
707 /* |
|
708 * Class: sun_lwawt_macosx_CDropTarget |
|
709 * Method: createNativeDropTarget |
|
710 * Signature: (Ljava/awt/dnd/DropTarget;Ljava/awt/Component;Ljava/awt/peer/ComponentPeer;J)J |
|
711 */ |
|
712 JNIEXPORT jlong JNICALL Java_sun_lwawt_macosx_CDropTarget_createNativeDropTarget |
|
713 (JNIEnv *env, jobject jthis, jobject jdroptarget, jobject jcomponent, jobject jpeer, jlong jnativepeer) |
|
714 { |
|
715 CDropTarget* dropTarget = nil; |
|
716 |
|
717 JNF_COCOA_ENTER(env); |
|
718 id controlObj = (id) jlong_to_ptr(jnativepeer); |
|
719 dropTarget = [[CDropTarget alloc] init:jdroptarget component:jcomponent peer:jpeer control:controlObj]; |
|
720 JNF_COCOA_EXIT(env); |
|
721 |
|
722 if (dropTarget) { |
|
723 CFRetain(dropTarget); // GC |
|
724 [dropTarget release]; |
|
725 } |
|
726 return ptr_to_jlong(dropTarget); |
|
727 } |
|
728 |
|
729 /* |
|
730 * Class: sun_lwawt_macosx_CDropTarget |
|
731 * Method: releaseNativeDropTarget |
|
732 * Signature: (J)V |
|
733 */ |
|
734 JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CDropTarget_releaseNativeDropTarget |
|
735 (JNIEnv *env, jobject jthis, jlong nativeDropTargetVal) |
|
736 { |
|
737 id dropTarget = (id)jlong_to_ptr(nativeDropTargetVal); |
|
738 |
|
739 JNF_COCOA_ENTER(env); |
|
740 [dropTarget removeFromView:env]; |
|
741 JNF_COCOA_EXIT(env); |
|
742 } |