Skip to content

Commit a570ba7

Browse files
committed
GUI: Better handling of interactive commands
1 parent 50bb803 commit a570ba7

4 files changed

Lines changed: 66 additions & 22 deletions

File tree

‎src/main/java/sc/fiji/snt/gui/cmds/CommonDynamicCmd.java‎

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@
3434
import sc.fiji.snt.SNTUI;
3535
import sc.fiji.snt.viewer.Viewer3D;
3636

37+
import javax.swing.*;
38+
import java.awt.*;
39+
import java.awt.event.WindowAdapter;
40+
import java.awt.event.WindowEvent;
41+
3742
/**
3843
* Command class for GUI commands extending DynamicCommand
3944
*
@@ -149,6 +154,57 @@ protected void resetUI(final boolean validateDimensions, final int state) {
149154
statusService.clearStatus();
150155
}
151156

157+
/**
158+
* Finds the SciJava-generated prompt dialog by its title and attaches a
159+
* {@link WindowAdapter} that resets the UI state to {@link SNTUI#READY} when
160+
* the dialog is closed. This is necessary because {@link #init(boolean)} sets
161+
* the state to {@link SNTUI#RUNNING_CMD}, but if the user dismisses the
162+
* dialog without running the command, nothing else resets it.
163+
* <p>
164+
* Subclasses implementing {@link org.scijava.command.Interactive} should call
165+
* this method early (e.g., from {@link #run()}) to ensure the listener is
166+
* attached before the user can close the dialog. The dialog is cached: repeated
167+
* calls are no-ops once it has been found.
168+
*
169+
* @param title the exact title set via {@code getInfo().setLabel()} — must be
170+
* unique across open dialogs
171+
* @return the dialog, or {@code null} if not yet created by SciJava
172+
*/
173+
protected JDialog getPromptWithCloseHandler(final String title) {
174+
return getPromptWithCloseHandler(title, null);
175+
}
176+
177+
/**
178+
* Variant of {@link #getPromptWithCloseHandler(String)} that runs an extra
179+
* action when the dialog is closing (e.g., cleaning up listeners).
180+
*
181+
* @param title the dialog title
182+
* @param extraOnClose additional action to run on {@code windowClosing}, or
183+
* {@code null} for none. Runs <em>before</em> the UI
184+
* state is reset.
185+
* @return the dialog, or {@code null} if not yet created
186+
*/
187+
protected JDialog getPromptWithCloseHandler(final String title, final Runnable extraOnClose) {
188+
if (cachedPrompt == null) {
189+
for (final Window w : JDialog.getWindows()) {
190+
if (w instanceof JDialog && title.equals(((JDialog) w).getTitle())) {
191+
cachedPrompt = (JDialog) w;
192+
cachedPrompt.addWindowListener(new WindowAdapter() {
193+
@Override
194+
public void windowClosing(final WindowEvent ignored) {
195+
if (extraOnClose != null) extraOnClose.run();
196+
if (ui != null) ui.changeState(SNTUI.READY);
197+
}
198+
});
199+
break;
200+
}
201+
}
202+
}
203+
return cachedPrompt;
204+
}
205+
206+
private JDialog cachedPrompt;
207+
152208
protected void notifyExternalDataLoaded() { //TODO: Implement listener
153209
// If a display canvas is being used notify plugin
154210
snt.updateDisplayCanvases();

‎src/main/java/sc/fiji/snt/plugin/GWDTMultiSomaCmd.java‎

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,6 @@ public class GWDTMultiSomaCmd extends GWDTMultiSomaCommonCmd implements Interact
4848
@Parameter(label = " Run ", callback = "runTrace", description = "<HTML>Run multi-soma autotracing")
4949
private Button run;
5050

51-
private JDialog prompt;
52-
5351
@SuppressWarnings("unused")
5452
private void init() {
5553
getInfo().setLabel(PROMPT_TITLE);
@@ -78,24 +76,19 @@ protected boolean isFileMode() {
7876
}
7977

8078
private JDialog getPrompt() {
81-
if (prompt == null) {
82-
for (final Window w : JDialog.getWindows()) {
83-
if (w instanceof JDialog && PROMPT_TITLE.equals(((JDialog) w).getTitle())) {
84-
prompt = ((JDialog) w);
85-
}
86-
}
87-
}
88-
return prompt;
79+
return getPromptWithCloseHandler(PROMPT_TITLE);
8980
}
9081

9182
@Override
9283
public void run() {
9384
// Called on widget change; do nothing. Tracing triggered by runTrace().
85+
getPrompt(); // ensure close handler is attached early
9486
}
9587

9688
@SuppressWarnings("unused")
9789
private void runTrace() {
98-
if (getPrompt() != null) prompt.dispose();
90+
final JDialog prompt = getPrompt();
91+
if (prompt != null) prompt.dispose();
9992
new SwingWorker<Void, Void>() {
10093
@Override
10194
protected Void doInBackground() {

‎src/main/java/sc/fiji/snt/plugin/GWDTTracerCmd.java‎

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,6 @@ public class GWDTTracerCmd extends GWDTTracerCommonCmd implements Interactive {
6969
@Parameter(label = " Run ", callback = "runTrace", description = "<HTML>Run autotracing")
7070
private Button run;
7171

72-
private JDialog prompt;
7372
private AutoTraceConfigDialog configDialog;
7473

7574
@SuppressWarnings("unused")
@@ -100,27 +99,21 @@ protected boolean isFileMode() {
10099
}
101100

102101
private JDialog getPrompt() {
103-
// HACK: See ComputeSecondaryImg#getPrompt()
104-
if (prompt == null) {
105-
for (final Window w : JDialog.getWindows()) {
106-
if (w instanceof JDialog && PROMPT_TITLE.equals(((JDialog) w).getTitle())) {
107-
prompt = ((JDialog) w);
108-
}
109-
}
110-
}
111-
return prompt;
102+
return getPromptWithCloseHandler(PROMPT_TITLE);
112103
}
113104

114105
@Override
115106
public void run() {
116107
// Called every time a widget changes in the prompt: Do nothing by default.
117108
// The actual run is triggered by the runTrace() callback.
109+
getPrompt(); // ensure close handler is attached early
118110
}
119111

120112
@SuppressWarnings("unused")
121113
private void runTrace() {
122114
if (configDialog != null) configDialog.dispose();
123-
if (getPrompt() != null) prompt.dispose();
115+
final JDialog prompt = getPrompt();
116+
if (prompt != null) prompt.dispose();
124117
// Button callbacks in Interactive commands run on the EDT,
125118
// so we must offload the heavy tracing work to a background
126119
// thread; otherwise setCanvasLabelAllPanes() can never repaint.

‎src/main/java/sc/fiji/snt/plugin/ShollAnalysisTreeInteractiveCmd.java‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.scijava.plugin.Parameter;
3131
import org.scijava.plugin.Plugin;
3232
import org.scijava.widget.Button;
33+
import sc.fiji.snt.SNTUtils;
3334
import sc.fiji.snt.Tree;
3435

3536
/**
@@ -63,6 +64,7 @@ public void run() {
6364
// There is no "OK" button in the prompt, so we don't need anything here. All functionality is run from callbacks
6465
// The code here gets called once the prompt is displayed and when CommandService.run() is called, so we'll only
6566
// run analysis if called from a (legacy!?) pre-recorded macro
67+
getPromptWithCloseHandler("Sholl Analysis SNT" + SNTUtils.VERSION); // ensure close button resets UI state
6668
if (ij.IJ.macroRunning()) {
6769
try {
6870
runAnalysis();

0 commit comments

Comments
 (0)