2525import com .intellij .openapi .ui .TextBrowseFolderListener ;
2626import com .intellij .openapi .ui .TextFieldWithBrowseButton ;
2727import com .intellij .openapi .util .Disposer ;
28+ import com .intellij .ui .DocumentAdapter ;
2829import com .intellij .ui .components .ActionLink ;
2930import com .intellij .ui .components .JBTextArea ;
3031import com .intellij .ui .components .JBTextField ;
4748import javax .swing .JLabel ;
4849import javax .swing .JPanel ;
4950import javax .swing .JTextArea ;
51+ import javax .swing .event .DocumentEvent ;
5052import org .jetbrains .annotations .Nls ;
5153import org .jetbrains .annotations .NotNull ;
5254
@@ -61,9 +63,8 @@ class PalantirJavaFormatConfigurable extends BaseConfigurable implements Searcha
6163 private final JLabel embeddedStatus ;
6264 private final ActionLink embeddedAction ;
6365 private final TextFieldWithBrowseButton nativeImagePath ;
64- private final JTextArea formatterType ;
65- private final JLabel formatterVersion ;
66- private final JLabel pluginVersion ;
66+ private final JPanel activeFormatterRow ;
67+ private final JTextArea activeFormatter ;
6768
6869 // Lives from createComponent() to disposeUIResources(): the download reports its progress to the page.
6970 @ Nullable
@@ -88,9 +89,7 @@ public PalantirJavaFormatConfigurable(Project project) {
8889 this .nativeImagePath = new TextFieldWithBrowseButton (pathField );
8990 nativeImagePath .addBrowseFolderListener (new TextBrowseFolderListener (
9091 FileChooserDescriptorFactory .createSingleFileNoJarsDescriptor ().withTitle ("Native Binary" ), project ));
91- this .pluginVersion = new JLabel ();
92- this .formatterVersion = new JLabel ();
93- this .formatterType = selectableText ();
92+ this .activeFormatter = selectableText ();
9493
9594 var statusRow = new JPanel (new FlowLayout (FlowLayout .LEADING , 0 , 0 ));
9695 statusRow .add (embeddedStatus );
@@ -101,7 +100,22 @@ public PalantirJavaFormatConfigurable(Project project) {
101100 .addComponent (statusRow )
102101 .addLabeledComponent ("Binary" , nativeImagePath )
103102 .getPanel ();
104- useNativeImage .addItemListener (event -> nativeImageOptions .setVisible (useNativeImage .isSelected ()));
103+ // Filling its own form vertically: only then does the form put the label above the text, rather than beside
104+ // the middle of a wrapped path.
105+ this .activeFormatterRow = FormBuilder .createFormBuilder ()
106+ .addSeparator ()
107+ .addLabeledComponentFillVertically ("Active formatter" , activeFormatter )
108+ .getPanel ();
109+
110+ // The page shows what runs once it is applied, so it follows every box and the path as they change.
111+ enable .addItemListener (event -> showPage ());
112+ useNativeImage .addItemListener (event -> showPage ());
113+ nativeImagePath .getTextField ().getDocument ().addDocumentListener (new DocumentAdapter () {
114+ @ Override
115+ protected void textChanged (DocumentEvent event ) {
116+ showActiveFormatter ();
117+ }
118+ });
105119
106120 // Laid out here rather than by the IntelliJ GUI designer. A .form is woven into the class at build
107121 // time, and this build does not instrument bytecode (see build.gradle), which left every field
@@ -110,11 +124,9 @@ public PalantirJavaFormatConfigurable(Project project) {
110124 .addComponent (enable )
111125 .addComponent (useNativeImage )
112126 .addComponent (nativeImageOptions )
113- .addLabeledComponent ("Plugin version" , pluginVersion )
114- .addLabeledComponent ("Implementation version" , formatterVersion )
115- // Last, and filling the rest of the page: only then does the form put the label at the text's first
116- // line rather than in the middle of a wrapped path.
117- .addLabeledComponentFillVertically ("Formatter type" , formatterType )
127+ .addComponent (activeFormatterRow )
128+ // Takes the rest of the page, so the rows stay at the top whichever of them are hidden.
129+ .addComponentFillVertically (new JPanel (), 0 )
118130 .getPanel ();
119131 }
120132
@@ -167,7 +179,6 @@ public void apply() throws ConfigurationException {
167179 settings .setEnabled (enable .isSelected () ? EnabledState .ENABLED : getDisabledState ());
168180 settings .setUseNativeImage (useNativeImage .isSelected ());
169181 settings .setNativeImagePath (path );
170- showEmbeddedNativeImage ();
171182 }
172183
173184 private EnabledState getDisabledState () {
@@ -182,12 +193,9 @@ public void reset() {
182193 PalantirJavaFormatSettings settings = PalantirJavaFormatSettings .getInstance (project );
183194 enable .setSelected (settings .isEnabled ());
184195 useNativeImage .setSelected (settings .useNativeImage ());
185- nativeImageOptions .setVisible (settings .useNativeImage ());
186196 nativeImagePath .setText (
187197 settings .getNativeImagePath ().map (Path ::toString ).orElse ("" ));
188- pluginVersion .setText (settings .getImplementationVersion ().orElse ("unknown" ));
189- formatterVersion .setText (getFormatterVersionText (settings ));
190- showEmbeddedNativeImage ();
198+ showPage ();
191199 }
192200
193201 @ Override
@@ -236,15 +244,47 @@ static StatusLine statusLine(Status status) {
236244 };
237245 }
238246
247+ private void showPage () {
248+ useNativeImage .setVisible (enable .isSelected ());
249+ nativeImageOptions .setVisible (enable .isSelected () && useNativeImage .isSelected ());
250+ activeFormatterRow .setVisible (enable .isSelected ());
251+ showEmbeddedNativeImage ();
252+ }
253+
239254 private void showEmbeddedNativeImage () {
240255 var line = statusLine (embeddedNativeImage .status (pluginVersion ()));
241256 embeddedStatus .setText (line .text ());
242257 embeddedAction .setText (line .action ().orElse ("" ));
243258 embeddedAction .setVisible (line .action ().isPresent ());
244- // What runs with the settings as applied: the embedded binary can arrive while the page is open.
245- formatterType .setText (FormatterSelection .of (
246- PalantirJavaFormatSettings .getInstance (project ), embeddedNativeImage ::installedPath )
247- .describe ());
259+ // The embedded binary can arrive while the page is open.
260+ showActiveFormatter ();
261+ }
262+
263+ /**
264+ * The formatter the page would run once applied, chosen as FormatterProvider chooses it: the path typed in Binary,
265+ * else the embedded binary, else the Java-based formatter.
266+ */
267+ private void showActiveFormatter () {
268+ var pending = new PalantirJavaFormatSettings ();
269+ pending .setUseNativeImage (useNativeImage .isSelected ());
270+ try {
271+ pending .setNativeImagePath (enteredNativeImagePath ());
272+ } catch (ConfigurationException e ) {
273+ // Not a path at all: shown as typed, and Apply says what is wrong with it.
274+ activeFormatter .setText (nativeImagePath .getText ().strip ());
275+ return ;
276+ }
277+ activeFormatter .setText (
278+ switch (FormatterSelection .of (pending , embeddedNativeImage ::installedPath )) {
279+ case FormatterSelection .NativeImage nativeImage ->
280+ nativeImage .path ().toString ();
281+ case FormatterSelection .JavaBased javaBased
282+ when !javaBased .nativeImageMissing () -> "Java-based formatter" ;
283+ case FormatterSelection .JavaBased missing ->
284+ embeddedNativeImage .status (pluginVersion ()) instanceof Status .NoImageForPlatform
285+ ? "Choose a native binary: none is published for this platform"
286+ : "Need to download version " + pluginVersion () + " from Maven Central" ;
287+ });
248288 }
249289
250290 private String pluginVersion () {
@@ -266,9 +306,9 @@ private Optional<Path> enteredNativeImagePath() throws ConfigurationException {
266306 }
267307
268308 /**
269- * Read-only text that wraps at the page's width and can be selected and copied: the formatter type names the
270- * binary that runs , and the embedded one's path , deep in the IDE's system directory, would otherwise widen the
271- * page past the dialog.
309+ * Read-only text that wraps at the page's width and can be selected and copied: the active formatter is often a
310+ * path , and the embedded binary's , deep in the IDE's system directory, would otherwise widen the page past the
311+ * dialog.
272312 */
273313 private static JTextArea selectableText () {
274314 var text = new JBTextArea () {
@@ -296,8 +336,4 @@ public void componentResized(ComponentEvent event) {
296336 return text ;
297337 }
298338
299- private static String getFormatterVersionText (PalantirJavaFormatSettings settings ) {
300- String suffix = settings .injectedVersionIsOutdated () ? " (using bundled)" : " (using injected)" ;
301- return settings .computeFormatterVersion ().orElse ("(bundled)" ) + suffix ;
302- }
303339}
0 commit comments