12047
|
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 |
}
|