<div dir="ltr">Hi Lee,<div><br></div><div><div>> So CellProfiler is all caught up, at least it's at 2.0.0 rc 16 -</div><div><br></div><div>Awesome!</div><div><br></div><div>> hopefully largely locked-down from an API perspective.</div></div><div><br></div><div>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 <a href="http://org.scijava.io">org.scijava.io</a>, but I hope that won't impact most downstream code.</div><div><br></div><div>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.</div><div><br></div><div>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.</div><div><br></div><div>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.</div><div><br></div><div>Regards,</div><div>Curtis</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Nov 5, 2014 at 1:50 PM, Lee Kamentsky <span dir="ltr"><<a href="mailto:leek@broadinstitute.org" target="_blank">leek@broadinstitute.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">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.</div><div class="gmail_extra"><br><div class="gmail_quote"><span class="">On Wed, Nov 5, 2014 at 12:33 PM, Curtis Rueden <span dir="ltr"><<a href="mailto:ctrueden@wisc.edu" target="_blank">ctrueden@wisc.edu</a>></span> wrote:<br></span><div><div class="h5"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">Hi Lee,<div><br></div><div><div>> Please don't quit</div></div><div><br></div><div>I would suggest avoiding a custom service. There are two other (hopefully simpler!) ways you can achieve your goal -- see below.</div><div><br></div><div>First, a summary of the architecture:</div><div><br></div><div>The current DefaultAppService responds to AppQuitEvents as follows:</div><div><br></div><div><div><span style="white-space:pre-wrap"> </span>protected void onEvent(@SuppressWarnings("unused") final AppQuitEvent event) {</div><div><span style="white-space:pre-wrap"> </span>getApp().quit();</div><div><span style="white-space:pre-wrap"> </span>}</div></div><div><br></div><div>Which delegates the operation to the App plugin with the highest priority.</div><div><br></div><div>The following App plugins ship with net.imagej:imagej:</div><div><br></div><div>* org.scijava.app.SciJavaApp [LOW priority] -- bundled with org.scijava:scijava-common</div><div>* io.scif.SCIFIOApp [NORMAL priority] -- bundled with io.scif:scifio</div><div>* net.imagej.legacy.LegacyImageJApp [NORMAL priority] - bundled with net.imagej:imagej-legacy</div><div>* net.imagej.app.ImageJApp [HIGH priority] -- bundled with net.imagej:imagej-common</div><div>* net.imagej.app.ToplevelImageJApp [HIGH+1 priority] -- bundled with net.imagej:imagej<br></div><div><br></div><div>So:</div><div>* If net.imagej:imagej is on the classpath, the ToplevelImageJApp will take precedence.</div><div>Otherwise:</div><div>* If net.imagej:imagej-common is on the classpath, the ImageJApp takes precedence.</div><div><br></div><div>However, ToplevelImageJApp extends ImageJApp and does not override quit(). So either way, the quit behavior will be the same:</div><div><br></div><div> public void quit() {<br></div><div><div> commandService.run(QuitProgram.class, true);</div><div> }</div><div><br></div><div><a href="https://github.com/imagej/imagej-common/blob/imagej-common-0.10.1/src/main/java/net/imagej/app/QuitProgram.java#L79-L96" target="_blank">https://github.com/imagej/imagej-common/blob/imagej-common-0.10.1/src/main/java/net/imagej/app/QuitProgram.java#L79-L96</a><br></div></div><div><br></div><div>Note that the devastating System.exit(0) is only called when exitWhenQuitting is set to true. This is part of OptionsMisc:</div><div><br></div><div><a href="https://github.com/imagej/imagej-common/blob/imagej-common-0.10.1/src/main/java/net/imagej/options/OptionsMisc.java#L75-L76" target="_blank">https://github.com/imagej/imagej-common/blob/imagej-common-0.10.1/src/main/java/net/imagej/options/OptionsMisc.java#L75-L76</a><br></div><div><br></div><div>So, there are two potential ways I would suggest to achieve your goal:</div><div><br></div><div>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.</div><div><br></div><div>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().</div><div><br></div><div><a href="https://github.com/scijava/scijava-common/blob/scijava-common-2.35.0/src/main/java/org/scijava/app/App.java" target="_blank">https://github.com/scijava/scijava-common/blob/scijava-common-2.35.0/src/main/java/org/scijava/app/App.java</a><br></div><div><br></div><div>Regards,</div><div>Curtis</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Nov 5, 2014 at 10:23 AM, Lee Kamentsky <span dir="ltr"><<a href="mailto:leek@broadinstitute.org" target="_blank">leek@broadinstitute.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">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?<div><br><div><div><span style="font-family:'courier new',monospace">@Plugin(type = Service.class, priority = Priority.HIGH_PRIORITY)</span><br></div><div><font face="courier new, monospace">public class CellProfilerAppService extends DefaultAppService {</font></div><div><span style="font-family:'courier new',monospace;white-space:pre-wrap"> </span><span style="font-family:'courier new',monospace">static boolean canQuit = false;</span><br></div><div><span style="font-family:'courier new',monospace;white-space:pre-wrap"> </span><span style="font-family:'courier new',monospace">public static void allowQuit() {</span><br></div><div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>canQuit = true;</font></div><div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>}</font></div><div><span style="font-family:'courier new',monospace;white-space:pre-wrap"> </span><span style="font-family:'courier new',monospace">public static void preventQuit() {</span><br></div><div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>canQuit = false;</font></div><div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>}</font></div><div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>@EventHandler</font></div><div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>public void onEvent(final AppQuitEvent event) {</font></div><div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>if (canQuit) {</font></div><div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>super.onEvent(event);</font></div><div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>} else {</font></div><div><span style="font-family:'courier new',monospace;white-space:pre-wrap"> </span><span style="font-family:'courier new',monospace">final UIService uiService = getContext().getService(</span><span style="font-family:'courier new',monospace">UIService.class);</span><br></div><div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>final LogService logService = getContext().getService(LogService.class);</font></div><div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>if (uiService.isVisible()) {</font></div><div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>UserInterface ui = uiService.getDefaultUI();</font></div><div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>logService.info("Quit action: hide the application frame");</font></div><div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>ui.getApplicationFrame().setVisible(false);</font></div><div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>} else {</font></div><div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>logService.info("Quit action: do nothing");</font></div><div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>}</font></div><div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>event.consume();</font></div><div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>}</font></div><div><font face="courier new, monospace"><span style="white-space:pre-wrap"> </span>}</font></div><div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace">}</font></div></div><div><br></div></div></div><div><div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Nov 5, 2014 at 11:15 AM, Lee Kamentsky <span dir="ltr"><<a href="mailto:leek@broadinstitute.org" target="_blank">leek@broadinstitute.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">Hi all,<div>I had a class (<a href="https://github.com/CellProfiler/CellProfiler/blob/master/java/src/main/java/org/cellprofiler/ijutils/CellProfilerAppEventService.java" target="_blank">https://github.com/CellProfiler/CellProfiler/blob/master/java/src/main/java/org/cellprofiler/ijutils/CellProfilerAppEventService.java</a>) 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.</div><div><br></div><div>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.</div><div><br></div><div>Thanks in advance,</div><div>--Lee</div></div>
</blockquote></div><br></div>
</div></div><br>_______________________________________________<br>
ImageJ-devel mailing list<br>
<a href="mailto:ImageJ-devel@imagej.net" target="_blank">ImageJ-devel@imagej.net</a><br>
<a href="http://imagej.net/mailman/listinfo/imagej-devel" target="_blank">http://imagej.net/mailman/listinfo/imagej-devel</a><br>
<br></blockquote></div><br></div>
</blockquote></div></div></div><br></div>
</blockquote></div><br></div>