CDropTarget.m revision 4730
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
//#define DND_DEBUG TRUE
#import "CDropTarget.h"
#import "AWTView.h"
#import "sun_lwawt_macosx_CDropTarget.h"
#import "java_awt_dnd_DnDConstants.h"
#import <JavaRuntimeSupport/JavaRuntimeSupport.h>
#import "CDragSource.h"
#import "CDataTransferer.h"
#import "DnDUtilities.h"
#import "ThreadUtilities.h"
static NSDragOperation sDragOperation;
static NSDragOperation sUpdateOperation;
static jint sJavaDropOperation;
static NSPoint sDraggingLocation;
static BOOL sDraggingExited;
static BOOL sDraggingError;
static CDropTarget* sCurrentDropTarget;
+ (CDropTarget *) currentDropTarget {
return sCurrentDropTarget;
}
- (id)init:(jobject)jdropTarget component:(jobject)jcomponent peer:(jobject)jpeer control:(id)control
{
fComponent = nil;
fDropTarget = nil;
} else {
// This would be an error.
}
return self;
}
// When [CDropTarget init] is called the ControlModel's fView may not have been set up yet. ControlModel
// (soon after) calls [CDropTarget controlModelControlValid] on the native event thread, once per CDropTarget,
// to let it know it's been set up now.
- (void)controlModelControlValid
{
// 9-30-02 Note: [Radar 3065621]
// List all known pasteboard types here (see AppKit's NSPasteboard.h)
// How to register for non-standard data types remains to be determined.
nil];
// Enable dragging events over this object:
}
- (void)releaseDraggingData
{
// Release any old pasteboard types, data and properties:
if (sDraggingFormats != NULL) {
}
sDraggingSequenceNumber = -1;
}
{
// Remove this dragging destination from the view:
// Clean up JNI refs
if (fComponent != NULL) {
fComponent = NULL;
}
if (fDropTarget != NULL) {
fDropTarget = NULL;
}
if (fDropTargetContextPeer != NULL) {
}
}
- (void)dealloc
{
[super dealloc];
}
//- (void)finalize { [super finalize]; }
{
return sDraggingSequenceNumber;
}
// Debugging help:
{
NSUInteger i;
// For each flavor on the pasteboard show the type, its data, and its property if there is one:
for (i = 0; i < pasteboardItemsCount; i++) {
}
}
}
{
// Release any old pasteboard data:
if (sPasteboardItemsCount == 0)
return FALSE;
return FALSE;
if (sDraggingFormats == nil)
return FALSE;
return FALSE;
}
// Copy all data formats and properties. In case of properties, if they are nil, we need to use
// a special NilProperty since [NSArray addObject] would crash on adding a nil object.
DLog2(@"[CDropTarget copyDraggingTypes]: typesCount = %lu\n", (unsigned long) sPasteboardItemsCount);
NSUInteger i;
for (i = 0; i < sPasteboardItemsCount; i++) {
// 01-10-03 Note: until we need data properties for doing something useful don't copy them.
// They're often copies of their flavor's data and copying them for all available pasteboard flavors
// If this is a remote object type (not a pre-defined format) register it with the pasteboard:
}
return TRUE;
}
{
if (sPasteboardData == nil)
return FALSE;
// Copy all data items to a safe place since the pasteboard may go away before we'll need them:
NSUInteger i;
for (i = 0; i < sPasteboardItemsCount; i++) {
// Get a type and its data and save the data:
// 01-10-03 Note: copying only NS-type data (until Java-specified types can make it through the AppKit)
// would be a good idea since we can't do anything with those CoreFoundation unknown types anyway.
// But I'm worried that it would break something in Fuller so I'm leaving this here as a reminder,
// to be evaluated later.
//id pbData = [pbType hasPrefix:@"NS"] ? [pb dataForType:pbType] : nil; // Copy only NS-type data!
// If the data is null we can't store it in the array - an exception would be thrown.
// We use the special object NSNull instead which is kosher.
}
return TRUE;
}
{
// Convert data into a property list if possible:
id propertyList = [NSPropertyListSerialization propertyListFromData:data mutabilityOption:NSPropertyListImmutable
// URL types have only a single URL string in an array:
}
}
return result;
}
{
JNIEnv* env = [ThreadUtilities getJNIEnvUncached]; // Join the main thread by requesting uncached environment
// Convert the Java format (datatransferer int index) to a pasteboard format (NSString):
// format == 8 (CF_URL in CDataTransferer): we need a URL-to-String conversion:
}
// Get NS data:
// Create a global byte array:
if (lbyteArray == nil)
return nil;
if (gbyteArray == nil)
return nil;
// Get byte array elements:
return nil;
// Copy data to byte array and release elements:
// In case of an error make sure to return nil:
gbyteArray = nil;
}
return gbyteArray;
}
{
// Make sure dragging data is released only if no new drag is under way. If a new drag
// has been initiated it has released the old dragging data already. This has to be called
// on the native event thread - otherwise we'd need to start synchronizing.
}
- (void)javaDraggingEnded:(jlong)draggingSequenceNumber success:(BOOL)jsuccess action:(jint)jdropaction
{
// Report back actual Swing success, not what AppKit thinks
// Release dragging data if any when Java's AWT event thread is all finished.
// Make sure dragging data is released on the native event thread.
}
- (jint)currentJavaActions {
}
/******************************** BEGIN NSDraggingDestination Interface ********************************/
// Private API to calculate the current Java actions
{
// Get the raw (unmodified by keys) source actions
NSDragOperation rawDragActions = (NSDragOperation) [jrsDrag performSelector:@selector(currentAllowableActions)];
if (rawDragActions != NSDragOperationNone) {
// Both actions and dropAction default to the rawActions
*dropAction = *actions;
// Get the current key modifiers.
// Either the drop action is narrowed as per Java rules (MOVE, COPY, LINK, NONE) or by the drag modifiers
if (dragModifiers) {
// Get the user selected operation based on the drag modifiers, then return the intersection
}
}
}
}
{
// Set the initial drag operation return value:
// We could probably special-case some stuff if drag and drop objects match:
//if ([sender dragSource] == fView)
// Delete any drop target context peer left over from a previous drag:
if (fDropTargetContextPeer != NULL) {
}
// Look up the CDropTargetContextPeer class:
JNF_STATIC_MEMBER_CACHE(getDropTargetContextPeerMethod, jc_CDropTargetContextPeer, "getDropTargetContextPeer", "()Lsun/lwawt/macosx/CDropTargetContextPeer;");
if (sDraggingError == FALSE) {
// Create a new drop target context peer:
if (dropTargetContextPeer != nil) {
}
}
// Get dragging types (dragging data is only copied if dropped):
}
if (sDraggingError == FALSE) {
DLog5(@"+ dragEnter: loc native %f, %f, java %f, %f\n", sDraggingLocation.x, sDraggingLocation.y, javaLocation.x, javaLocation.y);
////////// BEGIN Calculate the current drag actions //////////
////////// END Calculate the current drag actions //////////
JNF_MEMBER_CACHE(handleEnterMessageMethod, jc_CDropTargetContextPeer, "handleEnterMessage", "(Ljava/awt/Component;IIII[JJ)I");
if (sDraggingError == FALSE) {
// Double-casting self gets rid of 'different size' compiler warning:
actions = JNFCallIntMethod(env, fDropTargetContextPeer, handleEnterMessageMethod, fComponent, (jint) javaLocation.x, (jint) javaLocation.y, dropAction, actions, formats, ptr_to_jlong(self)); // AWT_THREADING Safe (CToolkitThreadBlockedHandler)
}
if (sDraggingError == FALSE) {
// Initialize drag operation:
// Map Java actions back to NSDragOperation.
// 1-6-03 Note: if the entry point of this CDropTarget isn't covered by a droppable component
// (as can be the case with lightweight children) we must not return NSDragOperationNone
// since that would prevent dropping into any of the contained drop targets.
// Unfortunately there is no easy way to test this so we just test actions and override them
// with GENERIC if necessary. Proper drag operations will be returned by draggingUpdated: which is
// called right away, taking care of setting the right cursor and snap-back action.
// Remember the dragOp for no-op'd update messages:
}
// If we are in the same process as the sender, make the sender post the appropriate message
if (sender) {
}
}
// 9-11-02 Note: the native event thread would not handle an exception gracefully:
//if (sDraggingError == TRUE)
// [NSException raise:NSGenericException format:@"[CDropTarget draggingEntered] failed."];
return dragOp;
}
{
//DLog2(@"[CDropTarget draggingUpdated]: %@\n", self);
// Set the initial drag operation return value:
// There are two things we would be interested in:
// a) mouse pointer has moved
// b) drag actions (key modifiers) have changed
// a) mouse pointer has moved:
//DLog2(@"[CDropTarget draggingUpdated]: mouse moved, %@\n", self);
notifyJava = TRUE;
}
// b) drag actions (key modifiers) have changed (handleMotionMessage() will do proper notifications):
////////// BEGIN Calculate the current drag actions //////////
if (sJavaDropOperation != dropAction) {
notifyJava = TRUE;
}
////////// END Calculate the current drag actions //////////
// Should we notify Java things have changed?
// For some reason even after the convertPoint drag events come with the y coordinate reverted
//DLog5(@" : dragMoved: loc native %f, %f, java %f, %f\n", sDraggingLocation.x, sDraggingLocation.y, javaLocation.x, javaLocation.y);
JNF_MEMBER_CACHE(handleMotionMessageMethod, jc_CDropTargetContextPeer, "handleMotionMessage", "(Ljava/awt/Component;IIII[JJ)I");
if (sDraggingError == FALSE) {
userAction = JNFCallIntMethod(env, fDropTargetContextPeer, handleMotionMessageMethod, fComponent, (jint) javaLocation.x, (jint) javaLocation.y, dropAction, actions, formats, ptr_to_jlong(self)); // AWT_THREADING Safe (CToolkitThreadBlockedHandler)
}
if (sDraggingError == FALSE) {
// Remember the dragOp for no-op'd update messages:
} else {
}
}
return dragOp;
}
{
JNF_MEMBER_CACHE(handleExitMessageMethod, jc_CDropTargetContextPeer, "handleExitMessage", "(Ljava/awt/Component;J)V");
if (sDraggingError == FALSE) {
JNFCallVoidMethod(env, fDropTargetContextPeer, handleExitMessageMethod, fComponent, ptr_to_jlong(self)); // AWT_THREADING Safe (CToolkitThreadBlockedHandler)
// If we are in the same process as the sender, make the sender post the appropriate message
if (sender) {
}
}
// 5-27-03 Note: [Radar 3270455]
// -draggingExited: can be called both by the AppKit and by -performDragOperation: but shouldn't execute
// twice per drop since cleanup code like that in swing/plaf/basic/BasicDropTargetListener would throw NPEs.
}
DLog(@"[CDropTarget draggingExited]: returning.\n");
}
{
}
{
// Now copy dragging data:
if (sDraggingError == FALSE) {
JNF_MEMBER_CACHE(handleDropMessageMethod, jc_CDropTargetContextPeer, "handleDropMessage", "(Ljava/awt/Component;IIII[JJ)V");
if (sDraggingError == FALSE) {
JNFCallVoidMethod(env, fDropTargetContextPeer, handleDropMessageMethod, fComponent, (jint) javaLocation.x, (jint) javaLocation.y, dropAction, actions, formats, ptr_to_jlong(self)); // AWT_THREADING Safe (event)
}
if (sDraggingError == FALSE) {
JNF_MEMBER_CACHE(flushEventsMethod, jc_CDropTargetContextPeer, "flushEvents", "(Ljava/awt/Component;)V");
if (sDraggingError == FALSE) {
JNFCallVoidMethod(env, fDropTargetContextPeer, flushEventsMethod, fComponent); // AWT_THREADING Safe (AWTRunLoopMode)
}
}
} else {
// 8-19-03 Note: [Radar 3368754]
// draggingExited: is not called after a drop - we must do that here ... but only in case
// of an error, instead of drop(). Otherwise we get twice the cleanup in shared code.
}
// TODO:BG
// [(id)sender _setLastDragDestinationOperation:sDragOperation];
return !sDraggingError;
}
{
DLog(@"[CDropTarget concludeDragOperation]: returning.\n");
}
// 9-11-02 Note: draggingEnded is not yet implemented by the AppKit.
{
DLog(@"[CDropTarget draggingEnded]: returning.\n");
}
/******************************** END NSDraggingDestination Interface ********************************/
@end
/*
* Class: sun_lwawt_macosx_CDropTarget
* Method: createNativeDropTarget
*/
(JNIEnv *env, jobject jthis, jobject jdroptarget, jobject jcomponent, jobject jpeer, jlong jnativepeer)
{
dropTarget = [[CDropTarget alloc] init:jdroptarget component:jcomponent peer:jpeer control:controlObj];
if (dropTarget) {
}
return ptr_to_jlong(dropTarget);
}
/*
* Class: sun_lwawt_macosx_CDropTarget
* Method: releaseNativeDropTarget
* Signature: (J)V
*/
{
}