Please don't quit

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

Please don't quit

Lee Kamentsky
Hi all,
I had a class (https://github.com/CellProfiler/CellProfiler/blob/master/java/src/main/java/org/cellprofiler/ijutils/CellProfilerAppEventService.java) that implemented the deprecated AppEventService whose purpose was to prevent ImageJ from quitting if a user closed its window by overriding AppEventService.quit(). Quitting is pretty devastating for CellProfiler since the process closes when the user's probable intent was to hide the window.

I'm hoping someone can give me a hint about how to do it now - I thought I'd cheat by asking instead of figuring it out myself.

Thanks in advance,
--Lee

_______________________________________________
ImageJ-devel mailing list
[hidden email]
http://imagej.net/mailman/listinfo/imagej-devel
Reply | Threaded
Open this post in threaded view
|

Re: Please don't quit

Lee Kamentsky
Oops never mind, what I tried actually worked. AppQuitEvent.consume() did the trick. Go figure - you guys really threw the whole kitchen sink into it, didn't you?

@Plugin(type = Service.class, priority = Priority.HIGH_PRIORITY)
public class CellProfilerAppService extends DefaultAppService {
static boolean canQuit = false;
public static void allowQuit() {
canQuit = true;
}
public static void preventQuit() {
canQuit = false;
}
@EventHandler
public void onEvent(final AppQuitEvent event) {
if (canQuit) {
super.onEvent(event);
} else {
final UIService uiService = getContext().getService(UIService.class);
final LogService logService = getContext().getService(LogService.class);
if (uiService.isVisible()) {
UserInterface ui = uiService.getDefaultUI();
logService.info("Quit action: hide the application frame");
ui.getApplicationFrame().setVisible(false);
} else {
logService.info("Quit action: do nothing");
}
event.consume();
}
}

}


On Wed, Nov 5, 2014 at 11:15 AM, Lee Kamentsky <[hidden email]> wrote:
Hi all,
I had a class (https://github.com/CellProfiler/CellProfiler/blob/master/java/src/main/java/org/cellprofiler/ijutils/CellProfilerAppEventService.java) that implemented the deprecated AppEventService whose purpose was to prevent ImageJ from quitting if a user closed its window by overriding AppEventService.quit(). Quitting is pretty devastating for CellProfiler since the process closes when the user's probable intent was to hide the window.

I'm hoping someone can give me a hint about how to do it now - I thought I'd cheat by asking instead of figuring it out myself.

Thanks in advance,
--Lee


_______________________________________________
ImageJ-devel mailing list
[hidden email]
http://imagej.net/mailman/listinfo/imagej-devel
Reply | Threaded
Open this post in threaded view
|

Re: Please don't quit

Curtis Rueden
Hi Lee,

> Please don't quit

I would suggest avoiding a custom service. There are two other (hopefully simpler!) ways you can achieve your goal -- see below.

First, a summary of the architecture:

The current DefaultAppService responds to AppQuitEvents as follows:

protected void onEvent(@SuppressWarnings("unused") final AppQuitEvent event) {
getApp().quit();
}

Which delegates the operation to the App plugin with the highest priority.

The following App plugins ship with net.imagej:imagej:

* org.scijava.app.SciJavaApp [LOW priority] -- bundled with org.scijava:scijava-common
* io.scif.SCIFIOApp [NORMAL priority] -- bundled with io.scif:scifio
* net.imagej.legacy.LegacyImageJApp [NORMAL priority] - bundled with net.imagej:imagej-legacy
* net.imagej.app.ImageJApp [HIGH priority] -- bundled with net.imagej:imagej-common
* net.imagej.app.ToplevelImageJApp [HIGH+1 priority] -- bundled with net.imagej:imagej

So:
* If net.imagej:imagej is on the classpath, the ToplevelImageJApp will take precedence.
Otherwise:
* If net.imagej:imagej-common is on the classpath, the ImageJApp takes precedence.

However, ToplevelImageJApp extends ImageJApp and does not override quit(). So either way, the quit behavior will be the same:

  public void quit() {

Note that the devastating System.exit(0) is only called when exitWhenQuitting is set to true. This is part of OptionsMisc:


So, there are two potential ways I would suggest to achieve your goal:

1) Set the OptionsMisc exitWhenQuitting to false. This is handy if you don't need a lot of control over exactly what happens when quit() is called, but you just want to stop the System.exit(0) from firing.

2) Create a CellProfilerApp plugin and set it to a higher priority than ImageJ. This solution makes the most sense to me because it gives you more flexibility over the behavior of a couple other operations, too: about() and prefs().


Regards,
Curtis

On Wed, Nov 5, 2014 at 10:23 AM, Lee Kamentsky <[hidden email]> wrote:
Oops never mind, what I tried actually worked. AppQuitEvent.consume() did the trick. Go figure - you guys really threw the whole kitchen sink into it, didn't you?

@Plugin(type = Service.class, priority = Priority.HIGH_PRIORITY)
public class CellProfilerAppService extends DefaultAppService {
static boolean canQuit = false;
public static void allowQuit() {
canQuit = true;
}
public static void preventQuit() {
canQuit = false;
}
@EventHandler
public void onEvent(final AppQuitEvent event) {
if (canQuit) {
super.onEvent(event);
} else {
final UIService uiService = getContext().getService(UIService.class);
final LogService logService = getContext().getService(LogService.class);
if (uiService.isVisible()) {
UserInterface ui = uiService.getDefaultUI();
logService.info("Quit action: hide the application frame");
ui.getApplicationFrame().setVisible(false);
} else {
logService.info("Quit action: do nothing");
}
event.consume();
}
}

}


On Wed, Nov 5, 2014 at 11:15 AM, Lee Kamentsky <[hidden email]> wrote:
Hi all,
I had a class (https://github.com/CellProfiler/CellProfiler/blob/master/java/src/main/java/org/cellprofiler/ijutils/CellProfilerAppEventService.java) that implemented the deprecated AppEventService whose purpose was to prevent ImageJ from quitting if a user closed its window by overriding AppEventService.quit(). Quitting is pretty devastating for CellProfiler since the process closes when the user's probable intent was to hide the window.

I'm hoping someone can give me a hint about how to do it now - I thought I'd cheat by asking instead of figuring it out myself.

Thanks in advance,
--Lee


_______________________________________________
ImageJ-devel mailing list
[hidden email]
http://imagej.net/mailman/listinfo/imagej-devel



_______________________________________________
ImageJ-devel mailing list
[hidden email]
http://imagej.net/mailman/listinfo/imagej-devel
Reply | Threaded
Open this post in threaded view
|

Re: Please don't quit

Lee Kamentsky
Thanks, Curtis:

On Wed, Nov 5, 2014 at 12:33 PM, Curtis Rueden <[hidden email]> wrote:
Hi Lee,

So, there are two potential ways I would suggest to achieve your goal:

1) Set the OptionsMisc exitWhenQuitting to false. This is handy if you don't need a lot of control over exactly what happens when quit() is called, but you just want to stop the System.exit(0) from firing.

I have code to do this, but in the upgrade to the latest, perhaps I'm not running it and setting exitWhenQuitting to false. 
2) Create a CellProfilerApp plugin and set it to a higher priority than ImageJ. This solution makes the most sense to me because it gives you more flexibility over the behavior of a couple other operations, too: about() and prefs().
It looks like I have to do this, because we don't want to lose the context. I think that will work out OK.

On Wed, Nov 5, 2014 at 10:23 AM, Lee Kamentsky <[hidden email]> wrote:
Oops never mind, what I tried actually worked. AppQuitEvent.consume() did the trick. Go figure - you guys really threw the whole kitchen sink into it, didn't you?

@Plugin(type = Service.class, priority = Priority.HIGH_PRIORITY)
public class CellProfilerAppService extends DefaultAppService {
static boolean canQuit = false;
public static void allowQuit() {
canQuit = true;
}
public static void preventQuit() {
canQuit = false;
}
@EventHandler
public void onEvent(final AppQuitEvent event) {
if (canQuit) {
super.onEvent(event);
} else {
final UIService uiService = getContext().getService(UIService.class);
final LogService logService = getContext().getService(LogService.class);
if (uiService.isVisible()) {
UserInterface ui = uiService.getDefaultUI();
logService.info("Quit action: hide the application frame");
ui.getApplicationFrame().setVisible(false);
} else {
logService.info("Quit action: do nothing");
}
event.consume();
}
}

}


On Wed, Nov 5, 2014 at 11:15 AM, Lee Kamentsky <[hidden email]> wrote:
Hi all,
I had a class (https://github.com/CellProfiler/CellProfiler/blob/master/java/src/main/java/org/cellprofiler/ijutils/CellProfilerAppEventService.java) that implemented the deprecated AppEventService whose purpose was to prevent ImageJ from quitting if a user closed its window by overriding AppEventService.quit(). Quitting is pretty devastating for CellProfiler since the process closes when the user's probable intent was to hide the window.

I'm hoping someone can give me a hint about how to do it now - I thought I'd cheat by asking instead of figuring it out myself.

Thanks in advance,
--Lee


_______________________________________________
ImageJ-devel mailing list
[hidden email]
http://imagej.net/mailman/listinfo/imagej-devel




_______________________________________________
ImageJ-devel mailing list
[hidden email]
http://imagej.net/mailman/listinfo/imagej-devel
Reply | Threaded
Open this post in threaded view
|

Re: Please don't quit

Curtis Rueden
Hi Lee,

> > 2) Create a CellProfilerApp plugin
>  
> It looks like I have to do this

It is nice for other reasons, too: then CellProfiler will have a "presence" in the context, so if you run e.g. the SystemInformation command [1], you will see CellProfiler in the output! :-)

Also, if you didn't see my blog post on quitting a couple of months, that may be worth a read:

<a href="http://imagej.net/2014-07-11_-_Fiji_won&#39;t_quit!#Other_complications">http://imagej.net/2014-07-11_-_Fiji_won't_quit!#Other_complications

Especially the "Other complications" section which explains that there are multiple very different code paths for quitting.

So depending on what code CellProfiler is invoking -- A) ij.ImageJ#quit() vs. B) org.scijava.Context#dispose() vs. C) publication of an AppQuitEvent -- you may experience different behavior.

It has been long enough now that all the details do not spring to mind, but please reply back with any further questions and we can iron out the details. I'd _like_ to believe that the quit architecture is as elegant & configurable as possible now, but feel free to prove me wrong if there are any roadblocks.

Regards,
Curtis


On Wed, Nov 5, 2014 at 11:44 AM, Lee Kamentsky <[hidden email]> wrote:
Thanks, Curtis:

On Wed, Nov 5, 2014 at 12:33 PM, Curtis Rueden <[hidden email]> wrote:
Hi Lee,

So, there are two potential ways I would suggest to achieve your goal:

1) Set the OptionsMisc exitWhenQuitting to false. This is handy if you don't need a lot of control over exactly what happens when quit() is called, but you just want to stop the System.exit(0) from firing.

I have code to do this, but in the upgrade to the latest, perhaps I'm not running it and setting exitWhenQuitting to false. 
2) Create a CellProfilerApp plugin and set it to a higher priority than ImageJ. This solution makes the most sense to me because it gives you more flexibility over the behavior of a couple other operations, too: about() and prefs().
It looks like I have to do this, because we don't want to lose the context. I think that will work out OK.

On Wed, Nov 5, 2014 at 10:23 AM, Lee Kamentsky <[hidden email]> wrote:
Oops never mind, what I tried actually worked. AppQuitEvent.consume() did the trick. Go figure - you guys really threw the whole kitchen sink into it, didn't you?

@Plugin(type = Service.class, priority = Priority.HIGH_PRIORITY)
public class CellProfilerAppService extends DefaultAppService {
static boolean canQuit = false;
public static void allowQuit() {
canQuit = true;
}
public static void preventQuit() {
canQuit = false;
}
@EventHandler
public void onEvent(final AppQuitEvent event) {
if (canQuit) {
super.onEvent(event);
} else {
final UIService uiService = getContext().getService(UIService.class);
final LogService logService = getContext().getService(LogService.class);
if (uiService.isVisible()) {
UserInterface ui = uiService.getDefaultUI();
logService.info("Quit action: hide the application frame");
ui.getApplicationFrame().setVisible(false);
} else {
logService.info("Quit action: do nothing");
}
event.consume();
}
}

}


On Wed, Nov 5, 2014 at 11:15 AM, Lee Kamentsky <[hidden email]> wrote:
Hi all,
I had a class (https://github.com/CellProfiler/CellProfiler/blob/master/java/src/main/java/org/cellprofiler/ijutils/CellProfilerAppEventService.java) that implemented the deprecated AppEventService whose purpose was to prevent ImageJ from quitting if a user closed its window by overriding AppEventService.quit(). Quitting is pretty devastating for CellProfiler since the process closes when the user's probable intent was to hide the window.

I'm hoping someone can give me a hint about how to do it now - I thought I'd cheat by asking instead of figuring it out myself.

Thanks in advance,
--Lee


_______________________________________________
ImageJ-devel mailing list
[hidden email]
http://imagej.net/mailman/listinfo/imagej-devel





_______________________________________________
ImageJ-devel mailing list
[hidden email]
http://imagej.net/mailman/listinfo/imagej-devel
Reply | Threaded
Open this post in threaded view
|

Re: Please don't quit

Lee Kamentsky
In reply to this post by Curtis Rueden
Great Curtis, I even made it say "ImageJ for CellProfiler" in the system info. So CellProfiler is all caught up, at least it's at 2.0.0 rc 16 - hopefully largely locked-down from an API perspective.

On Wed, Nov 5, 2014 at 12:33 PM, Curtis Rueden <[hidden email]> wrote:
Hi Lee,

> Please don't quit

I would suggest avoiding a custom service. There are two other (hopefully simpler!) ways you can achieve your goal -- see below.

First, a summary of the architecture:

The current DefaultAppService responds to AppQuitEvents as follows:

protected void onEvent(@SuppressWarnings("unused") final AppQuitEvent event) {
getApp().quit();
}

Which delegates the operation to the App plugin with the highest priority.

The following App plugins ship with net.imagej:imagej:

* org.scijava.app.SciJavaApp [LOW priority] -- bundled with org.scijava:scijava-common
* io.scif.SCIFIOApp [NORMAL priority] -- bundled with io.scif:scifio
* net.imagej.legacy.LegacyImageJApp [NORMAL priority] - bundled with net.imagej:imagej-legacy
* net.imagej.app.ImageJApp [HIGH priority] -- bundled with net.imagej:imagej-common
* net.imagej.app.ToplevelImageJApp [HIGH+1 priority] -- bundled with net.imagej:imagej

So:
* If net.imagej:imagej is on the classpath, the ToplevelImageJApp will take precedence.
Otherwise:
* If net.imagej:imagej-common is on the classpath, the ImageJApp takes precedence.

However, ToplevelImageJApp extends ImageJApp and does not override quit(). So either way, the quit behavior will be the same:

  public void quit() {

Note that the devastating System.exit(0) is only called when exitWhenQuitting is set to true. This is part of OptionsMisc:


So, there are two potential ways I would suggest to achieve your goal:

1) Set the OptionsMisc exitWhenQuitting to false. This is handy if you don't need a lot of control over exactly what happens when quit() is called, but you just want to stop the System.exit(0) from firing.

2) Create a CellProfilerApp plugin and set it to a higher priority than ImageJ. This solution makes the most sense to me because it gives you more flexibility over the behavior of a couple other operations, too: about() and prefs().


Regards,
Curtis

On Wed, Nov 5, 2014 at 10:23 AM, Lee Kamentsky <[hidden email]> wrote:
Oops never mind, what I tried actually worked. AppQuitEvent.consume() did the trick. Go figure - you guys really threw the whole kitchen sink into it, didn't you?

@Plugin(type = Service.class, priority = Priority.HIGH_PRIORITY)
public class CellProfilerAppService extends DefaultAppService {
static boolean canQuit = false;
public static void allowQuit() {
canQuit = true;
}
public static void preventQuit() {
canQuit = false;
}
@EventHandler
public void onEvent(final AppQuitEvent event) {
if (canQuit) {
super.onEvent(event);
} else {
final UIService uiService = getContext().getService(UIService.class);
final LogService logService = getContext().getService(LogService.class);
if (uiService.isVisible()) {
UserInterface ui = uiService.getDefaultUI();
logService.info("Quit action: hide the application frame");
ui.getApplicationFrame().setVisible(false);
} else {
logService.info("Quit action: do nothing");
}
event.consume();
}
}

}


On Wed, Nov 5, 2014 at 11:15 AM, Lee Kamentsky <[hidden email]> wrote:
Hi all,
I had a class (https://github.com/CellProfiler/CellProfiler/blob/master/java/src/main/java/org/cellprofiler/ijutils/CellProfilerAppEventService.java) that implemented the deprecated AppEventService whose purpose was to prevent ImageJ from quitting if a user closed its window by overriding AppEventService.quit(). Quitting is pretty devastating for CellProfiler since the process closes when the user's probable intent was to hide the window.

I'm hoping someone can give me a hint about how to do it now - I thought I'd cheat by asking instead of figuring it out myself.

Thanks in advance,
--Lee


_______________________________________________
ImageJ-devel mailing list
[hidden email]
http://imagej.net/mailman/listinfo/imagej-devel




_______________________________________________
ImageJ-devel mailing list
[hidden email]
http://imagej.net/mailman/listinfo/imagej-devel
Reply | Threaded
Open this post in threaded view
|

Re: Please don't quit

Curtis Rueden
Hi Lee,

> So CellProfiler is all caught up, at least it's at 2.0.0 rc 16 -

Awesome!

> hopefully largely locked-down from an API perspective.

Yeah, the API is pretty solid at this point -- especially SciJava Common, which is thoroughly out of beta. The only backwards-incompatible change planned is a rework of org.scijava.io, but I hope that won't impact most downstream code.

The other big eventual changes on the ImageJ2 side will be unification of the net.imglib2.meta and net.imagej data structures, as well as net.imglib2.ops and net.imagej.ops APIs. If you are a heavy user of imagej-common or imagej-ops, you may see some disruption there in a few months' time.

In general, if you see breakages and disruption while keeping things up to date, you're welcome to complain. Especially if the migration path is not obvious.

We are going through some related pain on the ImgLib2 front right now, with imglib2 coming out of beta a couple weeks ago. We still haven't sent the release announcement because it is not uploaded to the ImageJ update site yet -- we have to first upgrade all affected Fiji components to the new version. But after this point the imglib2 API will be extremely stable, so ultimately it's a good thing.

Regards,
Curtis

On Wed, Nov 5, 2014 at 1:50 PM, Lee Kamentsky <[hidden email]> wrote:
Great Curtis, I even made it say "ImageJ for CellProfiler" in the system info. So CellProfiler is all caught up, at least it's at 2.0.0 rc 16 - hopefully largely locked-down from an API perspective.

On Wed, Nov 5, 2014 at 12:33 PM, Curtis Rueden <[hidden email]> wrote:
Hi Lee,

> Please don't quit

I would suggest avoiding a custom service. There are two other (hopefully simpler!) ways you can achieve your goal -- see below.

First, a summary of the architecture:

The current DefaultAppService responds to AppQuitEvents as follows:

protected void onEvent(@SuppressWarnings("unused") final AppQuitEvent event) {
getApp().quit();
}

Which delegates the operation to the App plugin with the highest priority.

The following App plugins ship with net.imagej:imagej:

* org.scijava.app.SciJavaApp [LOW priority] -- bundled with org.scijava:scijava-common
* io.scif.SCIFIOApp [NORMAL priority] -- bundled with io.scif:scifio
* net.imagej.legacy.LegacyImageJApp [NORMAL priority] - bundled with net.imagej:imagej-legacy
* net.imagej.app.ImageJApp [HIGH priority] -- bundled with net.imagej:imagej-common
* net.imagej.app.ToplevelImageJApp [HIGH+1 priority] -- bundled with net.imagej:imagej

So:
* If net.imagej:imagej is on the classpath, the ToplevelImageJApp will take precedence.
Otherwise:
* If net.imagej:imagej-common is on the classpath, the ImageJApp takes precedence.

However, ToplevelImageJApp extends ImageJApp and does not override quit(). So either way, the quit behavior will be the same:

  public void quit() {

Note that the devastating System.exit(0) is only called when exitWhenQuitting is set to true. This is part of OptionsMisc:


So, there are two potential ways I would suggest to achieve your goal:

1) Set the OptionsMisc exitWhenQuitting to false. This is handy if you don't need a lot of control over exactly what happens when quit() is called, but you just want to stop the System.exit(0) from firing.

2) Create a CellProfilerApp plugin and set it to a higher priority than ImageJ. This solution makes the most sense to me because it gives you more flexibility over the behavior of a couple other operations, too: about() and prefs().


Regards,
Curtis

On Wed, Nov 5, 2014 at 10:23 AM, Lee Kamentsky <[hidden email]> wrote:
Oops never mind, what I tried actually worked. AppQuitEvent.consume() did the trick. Go figure - you guys really threw the whole kitchen sink into it, didn't you?

@Plugin(type = Service.class, priority = Priority.HIGH_PRIORITY)
public class CellProfilerAppService extends DefaultAppService {
static boolean canQuit = false;
public static void allowQuit() {
canQuit = true;
}
public static void preventQuit() {
canQuit = false;
}
@EventHandler
public void onEvent(final AppQuitEvent event) {
if (canQuit) {
super.onEvent(event);
} else {
final UIService uiService = getContext().getService(UIService.class);
final LogService logService = getContext().getService(LogService.class);
if (uiService.isVisible()) {
UserInterface ui = uiService.getDefaultUI();
logService.info("Quit action: hide the application frame");
ui.getApplicationFrame().setVisible(false);
} else {
logService.info("Quit action: do nothing");
}
event.consume();
}
}

}


On Wed, Nov 5, 2014 at 11:15 AM, Lee Kamentsky <[hidden email]> wrote:
Hi all,
I had a class (https://github.com/CellProfiler/CellProfiler/blob/master/java/src/main/java/org/cellprofiler/ijutils/CellProfilerAppEventService.java) that implemented the deprecated AppEventService whose purpose was to prevent ImageJ from quitting if a user closed its window by overriding AppEventService.quit(). Quitting is pretty devastating for CellProfiler since the process closes when the user's probable intent was to hide the window.

I'm hoping someone can give me a hint about how to do it now - I thought I'd cheat by asking instead of figuring it out myself.

Thanks in advance,
--Lee


_______________________________________________
ImageJ-devel mailing list
[hidden email]
http://imagej.net/mailman/listinfo/imagej-devel





_______________________________________________
ImageJ-devel mailing list
[hidden email]
http://imagej.net/mailman/listinfo/imagej-devel