PDA

View Full Version : Display sheet after drag?




reikon
Jan 16, 2006, 01:54 AM
I'm trying to display a window as a sheet after a drag operation onto my main window. I'm not sure what the problem is, but the error 'Modal session requires modal window' makes me think that calling a method in another class to call the sheet from the dragOperationConclusion method is a bad idea (i.e the operation hasn't concluded, therefore it's not modal and can't display a sheet. But then, how do you get it to display a sheet if you can't call out from the conclusion method?).

I am writing this using cocoa-java, but I have no problem accepting code in the form of ObjC for me to translate.

Thanks.



caveman_uk
Jan 16, 2006, 02:27 AM
I'm trying to display a window as a sheet after a drag operation onto my main window. I'm not sure what the problem is, but the error 'Modal session requires modal window' makes me think that calling a method in another class to call the sheet from the dragOperationConclusion method is a bad idea (i.e the operation hasn't concluded, therefore it's not modal and can't display a sheet. But then, how do you get it to display a sheet if you can't call out from the conclusion method?).

I am writing this using cocoa-java, but I have no problem accepting code in the form of ObjC for me to translate.

Thanks.
Can you show us the bit of code where you show the sheet?

reikon
Jan 16, 2006, 04:47 AM
Of course.

I use Apple's JDragNDrop example's code in a custom view, and in the concludeDragOperation method i call

DropHandler instanceHandler = new DropHandler();
instanceHandler.ProcessDroppedFiles(filenames);

And in the ProcessDroppedFilenames method I've tried several ways of calling the sheet.

This is what i'm using the call the sheet as an "IBAction".

NSApplication nsapp=NSApplication.sharedApplication();
nsapp.beginSheet(encipherPanel, mainWindow, null, null, null);
nsapp.runModalForWindow(encipherPanel);
nsapp.endSheet(encipherPanel);
encipherPanel.orderOut(this);

This works when I put it as an action to a button...but as stated, not on a drag. Even if I create a new instance of my sheetcontroller class and call the sheet with a null argument.

Thanks for the reply.

robbieduncan
Jan 16, 2006, 05:03 AM
1) Are you sure encipherPanel!=null? Can you start a modal session for a sheet? Do you not start it for the window the sheet is attached to?

2) The docs (http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Java/Classes/NSApplication.html#//apple_ref/java/instm/com.apple.cocoa.application.NSApplication/beginSheet) do not say that the third parameter is optional.

reikon
Jan 16, 2006, 05:07 AM
1) Are you sure encipherPanel!=null? Can you start a modal session for a sheet? Do you not start it for the window the sheet is attached to?

2) The docs (http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Java/Classes/NSApplication.html#//apple_ref/java/instm/com.apple.cocoa.application.NSApplication/beginSheet) do not say that the third parameter is optional.

As stated previously, the code works like a dream when used as an action attached to an object (read as: button). Therefore i think it has to be something to do with the drag not being concluded. encipherPanel isn't null, and is an NSPanel Object. Thanks for the reply.

EDIT: Supposedly I hav eot use performSelector..but I can't find any actual examples of use anywhere...anyone have any ideas?

HiRez
Jan 16, 2006, 04:23 PM
As stated previously, the code works like a dream when used as an action attached to an object (read as: button). Therefore i think it has to be something to do with the drag not being concluded. encipherPanel isn't null, and is an NSPanel Object. Thanks for the reply.

EDIT: Supposedly I hav eot use performSelector..but I can't find any actual examples of use anywhere...anyone have any ideas?The performSelector: methods simply send a message to an object just like you were calling the method directly, but they can do it after a delay, after the current method has exited the current scope, or from other threads and modes. I think you are right in thinking it's because you're inside a callback of an unconcluded drag operation. I have had instances where I needed to use this technique to get around calling from a method invoked by something else, including during sheet operations. In one app, I have a method that takes an NSTimer, invalidates it, and destroys it. But, it fails if I call that method from the method that the timer itself calls. That sounds like something similar to your drag callbacks. I would try using
[self performSelector:@selector(myDoStuffHereMethod) withObject:nil afterDelay:0];

-- or --

[[NSRunLoop currentRunLoop] performSelector:@selector(myDoStuffHereMethod) target:self argument:nil order:0 modes:[NSArray arrayWithObject:NSDefaultRunLoopMode]];

reikon
Jan 17, 2006, 03:37 AM
The performSelector: methods simply send a message to an object just like you were calling the method directly, but they can do it after a delay, after the current method has exited the current scope, or from other threads and modes. I think you are right in thinking it's because you're inside a callback of an unconcluded drag operation. I have had instances where I needed to use this technique to get around calling from a method invoked by something else, including during sheet operations. In one app, I have a method that takes an NSTimer, invalidates it, and destroys it. But, it fails if I call that method from the method that the timer itself calls. That sounds like something similar to your drag callbacks. I would try using
[self performSelector:@selector(myDoStuffHereMethod) withObject:nil afterDelay:0];

-- or --

[[NSRunLoop currentRunLoop] performSelector:@selector(myDoStuffHereMethod) target:self argument:nil order:0 modes:[NSArray arrayWithObject:NSDefaultRunLoopMode]];

Thanks a lot! The problem I find, is...I can't find the performSelector method...I don't think Cocoa Java has it...The only documentation I can find is it using com.webobjects.foundation, which I don't have and can't install since I don't have iLife 05 which is required. It looks like I'm going to have to either figure out where Apple is hiding this crap (I don't think I've seen more poor documentation for an API than Cocoa Java) or write a method that wraps the performSelector method in Java, allowing me to call it. This is getting to be a lot more harder than I thougth it would be.

whooleytoo
Jan 17, 2006, 06:18 AM
Thanks a lot! The problem I find, is...I can't find the performSelector method...I don't think Cocoa Java has it...The only documentation I can find is it using com.webobjects.foundation, which I don't have and can't install since I don't have iLife 05 which is required. It looks like I'm going to have to either figure out where Apple is hiding this crap (I don't think I've seen more poor documentation for an API than Cocoa Java) or write a method that wraps the performSelector method in Java, allowing me to call it. This is getting to be a lot more harder than I thougth it would be.

I think you're right, it doesn't seem to be available in Java.

You could probably achieve the same result using an NSTimer, just start a timer with a short interval, and when it fires, you can call the method in the normal way then.

caveman_uk
Jan 17, 2006, 06:20 AM
Having checked the NSObject docs for Java and Objective-C there's a load missing from the Java version. The thing is Apple doesn't really care about the 'Java bridge' anymore. See this quote


Cocoa-Java technology is only a learning tool. Applications targeted for release to customers must be developed using Objective-C to take advantage of all the programming interfaces available in Cocoa. Programming interfaces added to Cocoa in Mac OS X versions later than 10.4 will not be available to Cocoa-Java applications.


which can be found here. (http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaObjects/Articles/JavaCocoa.html)

HiRez
Jan 17, 2006, 07:20 AM
If performSelector: is not available, and using a timer doesn't work, maybe try to schedule the window action on the AWT event thread using the Java method SwingUtilities.invokeLater()? I know that (at least in the old days) there were some issues with calling Swing GUI components from the event thread. How Cocoa-Java works in this regard I have no idea, but maybe try something like this (called from your drag method):Runnable doStuff = new Runnable() {
public void run() {
// do stuff here
}
};

SwingUtilities.invokeLater(doStuff);

reikon
Jan 17, 2006, 09:11 AM
This is really killing me. Using a NSTimer does nothing. I delay the timer for as long as 10 seconds and the thing fires and gives me an error. The same error to boot.

I'll try using Swing's invokeLater.

Having checked the NSObject docs for Java and Objective-C there's a load missing from the Java version. The thing is Apple doesn't really care about the 'Java bridge' anymore. See this quote

I am aware Apple is trying to force everyone who wants to do almost anything in Cocoa to use Objective-C/++ (or AppleScript). I think thats stupid, personally.

gekko513
Jan 17, 2006, 10:45 AM
If it doesn't work with a timer, then something else must be wrong. You're definitely no longer in some kind of drag-mode.

caveman_uk
Jan 17, 2006, 10:54 AM
I am aware Apple is trying to force everyone who wants to do almost anything in Cocoa to use Objective-C/++ (or AppleScript). I think thats stupid, personally.
Because you're a Java programmer? If you're Apple, wasting your time keeping up a Java bridge that very few people use for production apps seems a waste of time and money. Should they maintain a Cobol-bridge as well just to keep cobol old-timers happy?

gekko513
Jan 17, 2006, 11:02 AM
NSApplication nsapp=NSApplication.sharedApplication();
nsapp.beginSheet(encipherPanel, mainWindow, null, null, null);
nsapp.runModalForWindow(encipherPanel);
nsapp.endSheet(encipherPanel);
encipherPanel.orderOut(this);
According to Apple's "How to use Sheets documentation" your code isn't as it should be. Docs -> Cocoa -> User Experience -> Sheets

To show the sheet, just the two first lines should be sufficient.

To close the sheet, listen to actions from a button or something similar and call nsapp.endSheet(encipherPanel) there.

Then you need to order the sheet out when the endSheet is done, in Objective C you would have set a didEndSelector where this is done, but I don't know how to do that in Java.

Your third line shouldn't be anywhere at all if I read the docs correctly.

whooleytoo
Jan 17, 2006, 11:07 AM
I'm not at all familiar with Java-Cocoa (nor much with sheets either), but the code above looks a little strange to me. runModalForWindow has been deprecated, and in the example above looks redundant. What occurs if you comment out that line?

Oops, gekko513 beat me to it..

reikon
Jan 17, 2006, 12:50 PM
According to Apple's "How to use Sheets documentation" your code isn't as it should be. Docs -> Cocoa -> User Experience -> Sheets

To show the sheet, just the two first lines should be sufficient.

To close the sheet, listen to actions from a button or something similar and call nsapp.endSheet(encipherPanel) there.

Then you need to order the sheet out when the endSheet is done, in Objective C you would have set a didEndSelector where this is done, but I don't know how to do that in Java.

Your third line shouldn't be anywhere at all if I read the docs correctly.

Like I said...it works fine when called from a button. Even if it is depreciated, so is the Cocoa-Java bridge, and therefore it may require it.

Because you're a Java programmer? If you're Apple, wasting your time keeping up a Java bridge that very few people use for production apps seems a waste of time and money. Should they maintain a Cobol-bridge as well just to keep cobol old-timers happy?

I'm not just a Java programmer. I'm using Java because I already wrote the implementation of the cipher I'm using, and cipher mode in Java, and I don't want to mess with endians or pointers doing it in C, and then wrapping it in Objective-C objects.

I find it very odd for you to compare a legacy language to Java.

If you look at a company like Microsoft, they have C#, J#, etc which they not only maintain, but document thoroughly.

I just feel that by limiting the languages that can access the primary API, you're limiting the number of applications for your platform.

In addition, very few people use it because there is no documentation for it. There are no real examples. I've talked to dozons of Java programmers who've tried and given up on Cocoa Java...not because they didn't know Java well, but because they couldn't figure out Cocoa Java due to lack of documentation and examples.

I have an idea of what is wrong with my program. I'll re-do a few things, and see if I can get it to work.

Thanks to all who have replied up to this point. I'll keep you informed on how it goes.

gekko513
Jan 17, 2006, 12:56 PM
Like I said...it works fine when called from a button. Even if it is depreciated, so is the Cocoa-Java bridge, and therefore it may require it.
Yeah, but have you tried writing it the way Apple describes on those pages?

whooleytoo
Jan 17, 2006, 01:18 PM
Like I said...it works fine when called from a button. Even if it is depreciated, so is the Cocoa-Java bridge, and therefore it may require it.


But runModalForWindow was superceded by beginSheet; according to the documentation there's no need to call both. Even though the code you have may work in some cases, it still doesn't necessarily mean it's correct.

I'd try it as per Apple's docs, as gekko513 advises.

reikon
Jan 18, 2006, 06:52 AM
I found my problem, but still have no solution. After the NSTimer fires all my UI objects are set to null. So in effect I'm telling a null object to display a sheet on a null object.

When I derrive the windows from the array of windows, it works smooth as a hot knife through butter. Any ideas why all my UI objects become null, and how to fix that without going to the NSApp's window array and choosing them specifically? (I've been told you can't relay on the ordering of the windows in the array, etc)

Thanks for the replies.

gekko513
Jan 18, 2006, 06:59 AM
How do you keep the reference to the Window in question? Does the Cocoa-Java bridge require you to retain Cocoa objects you want to keep or is it all handled by Java's garbage collection?

reikon
Jan 18, 2006, 07:16 AM
How do you keep the reference to the Window in question? Does the Cocoa-Java bridge require you to retain Cocoa objects you want to keep or is it all handled by Java's garbage collection?

You link the objects through outlets in IB and they're declared in the instance you connect them to.

So I have a list of objects in my Controller class..

public NSWindow window; /* IBOutlet */
public NSImageView imageWell;
public NSPanel progressPanel; /* IBOutlet */

and so on.

I _hope_ they're not getting picked up by Java's gc. I don't see any reason why they would be...

I've tried setting it back using an object in the window on awakeFromNib. aka

window = imageWell.window()

And it goes null as soon as the timer fires.

Right now I'm stuck doing this:

But I least I know the actual code for calling the sheet isn't wrong.

NSArray windows = NSApplication.sharedApplication().windows();
NSWindow window = (NSWindow) windows.objectAtIndex(0);
NSWindow window1 = (NSWindow) windows.objectAtIndex(1);
NSApplication nsapp=NSApplication.sharedApplication();
nsapp.beginSheet(window1, window, this, null, null);
nsapp.runModalForWindow(window1);
nsapp.endSheet(window1);
window1.orderOut(this);

gekko513
Jan 18, 2006, 07:28 AM
Then I also see no reason why the references should all of a sudden be null. I can't see more solutions without seeing and playing with the code I think.

I still think the sheet code is a bit weird even if it works. Are you sure you need the line: nsapp.runModalForWindow(window1);?

reikon
Jan 18, 2006, 07:31 AM
Then I also see no reason why the references should all of a sudden be null. I can't see more solutions without seeing and playing with the code I think.

I still think the sheet code is a bit weird even if it works. Are you sure you need the line: nsapp.runModalForWindow(window1);?

PM your e-mail to me and I'll send you my project if you like, I can't guarantee it'll be pretty seeing as I've been at this for a while and have tried lots of things.

I'll try removing the runModalForWindow to see if it works without it.

EDIT: removing runModalForWindow causes the app to crash. Or rather exit with status 0 without notice :P

gekko513
Jan 18, 2006, 07:43 AM
PM your e-mail to me and I'll send you my project if you like, I can't guarantee it'll be pretty seeing as I've been at this for a while and have tried lots of things.

I'll try removing the runModalForWindow to see if it works without it.

EDIT: removing runModalForWindow causes the app to crash. Or rather exit with status 0 without notice :P
How rude of it. ;) Well, then I guess you have to keep it there. It's still strange, since it doesn't seem to be right according to the docs. (I sent you a PM)

caveman_uk
Jan 18, 2006, 08:05 AM
I find it very odd for you to compare a legacy language to Java.

If you look at a company like Microsoft, they have C#, J#, etc which they not only maintain, but document thoroughly.

I just feel that by limiting the languages that can access the primary API, you're limiting the number of applications for your platform.

I wasn't saying cobol was as modern as Java. I was trying to point out where do you draw the line on what languages you support. Apple supports two API's (Cocoa and Carbon) - one primarily for objective-C and the other primarily for C and C++ (I know you can mix and match if you want). There are a number of third party bridges to the Apple APIs (for example PyObjC) so you aren't exactly limited to just the languages Apple chooses to support. It is also worth bearing in mind that Microsoft has an awful lot more developers and money to throw at keeping their range of languages maintained. They also charge for their developer tools - hundreds of dollars if you want the grown up editions - whilst Apple gives it all away for nothing.

Besides I would have thought the main reason for using Java (other than you know it already or have assets already written in it) would be it's platform independence. By using java with Cocoa you've lost that advantage so all you're left with is it's disadvantages. There are alternatives to Cocoa you could use in Java that would retain your platform independence.

Cocoa is designed to be used by objective-C and it's littered with design decisions made on that assumption. Those assumptions don't necessarily apply to Java which has it's own way of doing things. Consequently the Java-cocoa bridge was always going to be the bastard child that no-one loved.

reikon
Jan 18, 2006, 08:13 AM
In addition Java has a crapload of built in libraries that Objective-C doesn't have.

:P

gekko513
Jan 18, 2006, 08:15 AM
In addition Java has a crapload of built in libraries that Objective-C doesn't have.

:P
Yeah, I must admit that I love the libraries that come with Java.

I sent a PM that should solve the problem if I was able to explain the culprit clearly enough.

caveman_uk
Jan 18, 2006, 08:55 AM
In addition Java has a crapload of built in libraries that Objective-C doesn't have.

:P
Use those then.

{edit}Maybe I should make that sound less beligerent. Are there alternatives to cocoa you could use? Maybe not now but in future projects...

reikon
Jan 18, 2006, 09:40 AM
Use those then.

{edit}Maybe I should make that sound less beligerent. Are there alternatives to cocoa you could use? Maybe not now but in future projects...

Of course, theres Swing, AWT, SWT, even wxWidgets if I wanted. But I want a sheetlicious Cocoa app. :P I familiar with Java's other interfaces fine, I just wanted to make a mac-only app, and make it sexy.

HiRez
Jan 18, 2006, 04:59 PM
Of course, theres Swing, AWT, SWT, even wxWidgets if I wanted. But I want a sheetlicious Cocoa app. :P I familiar with Java's other interfaces fine, I just wanted to make a mac-only app, and make it sexy.If you want to just use Java libraries, I would probably make the project Objective-C, do everything you can in the Nib, then just use the Cocoa-Java bridge from the other side, by calling into your Java methods to do back-end work.

EDIT: Not sure how this works in terms of setting up your project because if you create an Objective-C project, you won't have the Java libraries and runtime loaded by default.