2929
3030package org .scijava .ui .swing .widget ;
3131
32+ import java .util .ArrayList ;
33+ import java .util .List ;
34+
3235import javax .swing .JOptionPane ;
3336import javax .swing .JPanel ;
3437
38+ import org .scijava .module .ModuleCanceledException ;
39+ import org .scijava .module .ModuleException ;
40+ import org .scijava .module .ModuleItem ;
3541import org .scijava .module .Module ;
3642import org .scijava .module .process .PreprocessorPlugin ;
3743import org .scijava .plugin .Plugin ;
4046import org .scijava .ui .swing .SwingUI ;
4147import org .scijava .widget .InputHarvester ;
4248import org .scijava .widget .InputPanel ;
49+ import org .scijava .widget .InputWidget ;
4350
4451/**
4552 * SwingInputHarvester is an {@link InputHarvester} that collects input
@@ -60,6 +67,53 @@ public SwingInputPanel createInputPanel() {
6067 return new SwingInputPanel ();
6168 }
6269
70+ @ Override
71+ public void harvest (final Module module ) throws ModuleException {
72+ final InputPanel <JPanel , JPanel > inputPanel = createInputPanel ();
73+ buildPanel (inputPanel , module );
74+ if (!inputPanel .hasWidgets ()) return ;
75+
76+ // Validate all inputs now so the dialog opens with accurate styling and
77+ // the OK button already disabled for any initially invalid values.
78+ for (final ModuleItem <?> item : module .getInfo ().inputs ()) {
79+ final InputWidget <?, ?> w = inputPanel .getWidget (item .getName ());
80+ if (w != null ) w .get ().updateValidation ();
81+ }
82+ inputPanel .refresh ();
83+
84+ while (true ) {
85+ // Show the dialog; bail out immediately if canceled.
86+ if (!harvestInputs (inputPanel , module )) throw new ModuleCanceledException ();
87+
88+ // Validate all unresolved inputs and collect any error messages.
89+ final List <String > errors = new ArrayList <>();
90+ for (final ModuleItem <?> item : module .getInfo ().inputs ()) {
91+ if (module .isInputResolved (item .getName ())) continue ;
92+ final String message = item .validateMessage (module );
93+ if (message != null && !message .isEmpty ()) {
94+ // Use the same label logic as DefaultWidgetModel.getWidgetLabel().
95+ String label = item .getLabel ();
96+ if (label == null || label .isEmpty ()) {
97+ final String name = item .getName ();
98+ label = name .substring (0 , 1 ).toUpperCase () + name .substring (1 );
99+ }
100+ errors .add (label + ": " + message );
101+ }
102+ }
103+
104+ if (errors .isEmpty ()) break ; // all inputs valid; proceed
105+
106+ // Show a modal error dialog, then re-open the harvester dialog.
107+ JOptionPane .showMessageDialog (
108+ null ,
109+ String .join ("\n " , errors ),
110+ "Invalid Input" ,
111+ JOptionPane .ERROR_MESSAGE );
112+ }
113+
114+ processResults (inputPanel , module );
115+ }
116+
63117 @ Override
64118 public boolean harvestInputs (final InputPanel <JPanel , JPanel > inputPanel ,
65119 final Module module )
@@ -83,8 +137,21 @@ public boolean harvestInputs(final InputPanel<JPanel, JPanel> inputPanel,
83137 new SwingDialog (pane , optionType , messageType , doScrollBars );
84138 dialog .setTitle (title );
85139 dialog .setModal (modal );
140+
141+ // Wire the OK button to the panel so validation can enable/disable it.
142+ if (inputPanel instanceof SwingInputPanel ) {
143+ final SwingInputPanel swingPanel = (SwingInputPanel ) inputPanel ;
144+ swingPanel .setOkButton (dialog .getOkButton ());
145+ swingPanel .updateOkButton ();
146+ }
147+
86148 final int rval = dialog .show ();
87149
150+ // Detach the OK button once the dialog closes.
151+ if (inputPanel instanceof SwingInputPanel ) {
152+ ((SwingInputPanel ) inputPanel ).setOkButton (null );
153+ }
154+
88155 // verify return value of dialog
89156 return rval == JOptionPane .OK_OPTION ;
90157 }
0 commit comments