diff --git a/src/main/java/com/github/junkfactory/innerbuilder/JavaInnerBuilderHandler.java b/src/main/java/com/github/junkfactory/innerbuilder/JavaInnerBuilderHandler.java index 724ce22..1731a9d 100644 --- a/src/main/java/com/github/junkfactory/innerbuilder/JavaInnerBuilderHandler.java +++ b/src/main/java/com/github/junkfactory/innerbuilder/JavaInnerBuilderHandler.java @@ -17,6 +17,7 @@ import com.intellij.psi.JavaPsiFacade; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiJavaFile; +import com.intellij.psi.PsiManager; import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.util.AstLoadingFilter; import org.jetbrains.annotations.NotNull; @@ -91,6 +92,7 @@ public void invoke(@NotNull final Project project, @NotNull final Editor editor, .selectedFields(selectedFields) .factory(JavaPsiFacade.getElementFactory(project)) .codeStyleManager(JavaCodeStyleManager.getInstance(project)) + .psiManager(PsiManager.getInstance(project)) .build(); var generatorParams = GeneratorParams.builder() .project(project) @@ -108,17 +110,21 @@ private Set currentOptions() { final var options = EnumSet.noneOf(JavaInnerBuilderOption.class); final var propertiesComponent = PropertiesComponent.getInstance(); for (var option : JavaInnerBuilderOption.values()) { - - if (Boolean.TRUE.equals(option.isBooleanProperty())) { - final boolean currentSetting = propertiesComponent.getBoolean(option.getProperty(), false); - if (currentSetting) { - options.add(option); - } - } else { - String currentValue = String.valueOf(propertiesComponent.getValue(option.getProperty())); - if (currentValue != null) { + switch (option.getType()) { + case BOOLEAN: + if (propertiesComponent.getBoolean(option.getProperty(), false)) { + options.add(option); + } + break; + case LIST: + var list = propertiesComponent.getList(option.getProperty()); + if (null != list && !list.isEmpty()) { + options.add(option); + } + break; + default: + String currentValue = String.valueOf(propertiesComponent.getValue(option.getProperty())); JavaInnerBuilderOption.findValue(currentValue).ifPresent(options::add); - } } } return options; diff --git a/src/main/java/com/github/junkfactory/innerbuilder/generators/AbstractGenerator.java b/src/main/java/com/github/junkfactory/innerbuilder/generators/AbstractGenerator.java index 47db588..46ca2d1 100644 --- a/src/main/java/com/github/junkfactory/innerbuilder/generators/AbstractGenerator.java +++ b/src/main/java/com/github/junkfactory/innerbuilder/generators/AbstractGenerator.java @@ -31,10 +31,12 @@ abstract class AbstractGenerator { protected final GeneratorFactory generatorFactory; protected final GeneratorParams generatorParams; + protected final GenerationResult generationResult; protected AbstractGenerator(GeneratorFactory generatorFactory, GeneratorParams generatorParams) { this.generatorFactory = generatorFactory; this.generatorParams = generatorParams; + this.generationResult = new GenerationResult(); } protected PsiElement addElement(PsiElement target, PsiElement element, PsiElement after) { diff --git a/src/main/java/com/github/junkfactory/innerbuilder/generators/BuilderClassGenerator.java b/src/main/java/com/github/junkfactory/innerbuilder/generators/BuilderClassGenerator.java index 176f7a3..86050a9 100644 --- a/src/main/java/com/github/junkfactory/innerbuilder/generators/BuilderClassGenerator.java +++ b/src/main/java/com/github/junkfactory/innerbuilder/generators/BuilderClassGenerator.java @@ -27,7 +27,7 @@ public GenerationResult generate() { var methodsGenerator = generatorFactory.createBuilderMethodsGenerator(generatorParams, builderClassParams, fieldsGenerator); - return methodsGenerator.generate(); + return generationResult.merge(methodsGenerator.generate()); } private PsiMethod generateBuilderConstructor() { diff --git a/src/main/java/com/github/junkfactory/innerbuilder/generators/BuilderMethodsGenerator.java b/src/main/java/com/github/junkfactory/innerbuilder/generators/BuilderMethodsGenerator.java index 102467f..064311d 100644 --- a/src/main/java/com/github/junkfactory/innerbuilder/generators/BuilderMethodsGenerator.java +++ b/src/main/java/com/github/junkfactory/innerbuilder/generators/BuilderMethodsGenerator.java @@ -16,7 +16,6 @@ class BuilderMethodsGenerator extends AbstractGenerator implements MethodsGenera private final BuilderClassParams builderClassParams; private final FieldsGenerator fieldsGenerator; - private final GenerationResult generationResult; private boolean isPublic; @@ -27,7 +26,6 @@ class BuilderMethodsGenerator extends AbstractGenerator implements MethodsGenera super(generatorFactory, generatorParams); this.builderClassParams = builderClassParams; this.fieldsGenerator = fieldsGenerator; - this.generationResult = new GenerationResult(); } @Override diff --git a/src/main/java/com/github/junkfactory/innerbuilder/generators/GenerationResult.java b/src/main/java/com/github/junkfactory/innerbuilder/generators/GenerationResult.java index a35a636..8c4286a 100644 --- a/src/main/java/com/github/junkfactory/innerbuilder/generators/GenerationResult.java +++ b/src/main/java/com/github/junkfactory/innerbuilder/generators/GenerationResult.java @@ -34,4 +34,9 @@ public void when(Code code, Runnable runnable) { runnable.run(); } } + + public GenerationResult merge(GenerationResult other) { + result.or(other.result); + return this; + } } diff --git a/src/main/java/com/github/junkfactory/innerbuilder/generators/InnerBuilderGenerator.java b/src/main/java/com/github/junkfactory/innerbuilder/generators/InnerBuilderGenerator.java index d422a73..075fd28 100644 --- a/src/main/java/com/github/junkfactory/innerbuilder/generators/InnerBuilderGenerator.java +++ b/src/main/java/com/github/junkfactory/innerbuilder/generators/InnerBuilderGenerator.java @@ -2,6 +2,7 @@ import com.github.junkfactory.innerbuilder.ui.JavaInnerBuilderOption; import com.intellij.codeInsight.generation.PsiFieldMember; +import com.intellij.ide.util.PropertiesComponent; import com.intellij.psi.PsiClass; import com.intellij.psi.PsiField; import com.intellij.psi.PsiJavaFile; @@ -59,12 +60,13 @@ public GenerationResult generate() { .builderType(builderType) .build(); var result = generatorFactory.createBuilderClassGenerator(generatorParams, params).generate(); - + generationResult.merge(result); + targetClass.add(builderClass); var codeStyleManager = generatorParams.psi().codeStyleManager(); - result.when(ANNOTATIONS_ADDED, () -> codeStyleManager.shortenClassReferences(file)); - result.when(IMPORTS_ADDED, () -> codeStyleManager.removeRedundantImports((PsiJavaFile) file)); + generationResult.when(ANNOTATIONS_ADDED, () -> codeStyleManager.shortenClassReferences(targetClass)); + generationResult.when(IMPORTS_ADDED, () -> codeStyleManager.removeRedundantImports((PsiJavaFile) file)); CodeStyleManager.getInstance(generatorParams.project()).reformat(builderClass); - return result; + return generationResult; } private PsiMethod generateToBuilderMethod(PsiClass targetClass, @@ -162,11 +164,22 @@ private PsiClass findOrCreateBuilderClass(final PsiClass targetClass) { @NotNull private PsiClass createBuilderClass(final PsiClass targetClass) { - var builderClass = (PsiClass) targetClass.add(generatorParams.psi().factory() - .createClass(BUILDER_CLASS_NAME)); - PsiUtil.setModifierProperty(builderClass, PsiModifier.STATIC, true); - PsiUtil.setModifierProperty(builderClass, PsiModifier.FINAL, true); - return builderClass; + var classDef = new StringBuilder(); + if (generatorParams.options().contains(JavaInnerBuilderOption.WITH_BUILDER_CLASS_ANNOTATIONS)) { + var propertiesComponent = PropertiesComponent.getInstance(); + var annotationOptions = + propertiesComponent.getList(JavaInnerBuilderOption.WITH_BUILDER_CLASS_ANNOTATIONS.getProperty()); + if (annotationOptions != null) { + annotationOptions.forEach(a -> classDef.append('@').append(a).append(System.lineSeparator())); + generationResult.set(GenerationResult.Code.ANNOTATIONS_ADDED); + } + } + classDef.append("public static final class ") + .append(BUILDER_CLASS_NAME) + .append(" {}") + .append(System.lineSeparator()); + return generatorParams.psi().factory().createClassFromText(classDef.toString(), targetClass) + .getInnerClasses()[0]; } } diff --git a/src/main/java/com/github/junkfactory/innerbuilder/generators/PsiParams.java b/src/main/java/com/github/junkfactory/innerbuilder/generators/PsiParams.java index d1569b0..463632b 100644 --- a/src/main/java/com/github/junkfactory/innerbuilder/generators/PsiParams.java +++ b/src/main/java/com/github/junkfactory/innerbuilder/generators/PsiParams.java @@ -3,6 +3,7 @@ import com.intellij.codeInsight.generation.PsiFieldMember; import com.intellij.psi.PsiElementFactory; import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiManager; import com.intellij.psi.codeStyle.JavaCodeStyleManager; import java.util.List; @@ -10,7 +11,8 @@ public record PsiParams(PsiFile file, List selectedFields, PsiElementFactory factory, - JavaCodeStyleManager codeStyleManager) { + JavaCodeStyleManager codeStyleManager, + PsiManager psiManager) { public static Builder builder() { return new Builder(); @@ -21,6 +23,7 @@ public static final class Builder { private List selectedFields; private PsiElementFactory factory; private JavaCodeStyleManager codeStyleManager; + private PsiManager psiManager; private Builder() { } @@ -45,8 +48,13 @@ public Builder codeStyleManager(JavaCodeStyleManager codeStyleManager) { return this; } + public Builder psiManager(PsiManager psiManager) { + this.psiManager = psiManager; + return this; + } + public PsiParams build() { - return new PsiParams(file, selectedFields, factory, codeStyleManager); + return new PsiParams(file, selectedFields, factory, codeStyleManager, psiManager); } } } diff --git a/src/main/java/com/github/junkfactory/innerbuilder/generators/Utils.java b/src/main/java/com/github/junkfactory/innerbuilder/generators/Utils.java index 0d0e621..097574a 100644 --- a/src/main/java/com/github/junkfactory/innerbuilder/generators/Utils.java +++ b/src/main/java/com/github/junkfactory/innerbuilder/generators/Utils.java @@ -14,7 +14,10 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.Nullable; +import java.util.Arrays; +import java.util.List; import java.util.Optional; +import java.util.function.Predicate; public class Utils { @NonNls @@ -134,5 +137,19 @@ public static boolean isFieldInitializedWithImmutableInstance(PsiField field) { return null != initializerClass && initializerClass.hasModifierProperty(PsiModifier.ABSTRACT); } + public static List stringToList(String str) { + if (null == str || str.isBlank()) { + return List.of(); + } + return Arrays.stream(str.split(System.lineSeparator())) + .map(String::trim) + .filter(Predicate.not(String::isBlank)) + .toList(); + } + + public static String parseType(String text) { + var parenthesisIndex = text.indexOf('('); + return parenthesisIndex == -1 ? text : text.substring(0, parenthesisIndex); + } } diff --git a/src/main/java/com/github/junkfactory/innerbuilder/ui/JavaInnerBuilderOption.java b/src/main/java/com/github/junkfactory/innerbuilder/ui/JavaInnerBuilderOption.java index 5061f1b..b5740cd 100644 --- a/src/main/java/com/github/junkfactory/innerbuilder/ui/JavaInnerBuilderOption.java +++ b/src/main/java/com/github/junkfactory/innerbuilder/ui/JavaInnerBuilderOption.java @@ -1,43 +1,96 @@ package com.github.junkfactory.innerbuilder.ui; +import com.github.junkfactory.innerbuilder.generators.Utils; +import com.intellij.openapi.Disposable; +import com.intellij.openapi.ui.ComponentValidator; +import com.intellij.openapi.ui.LabeledComponent; +import com.intellij.openapi.ui.ValidationInfo; +import com.intellij.psi.PsiManager; +import com.intellij.psi.util.ClassUtil; +import com.intellij.ui.JBColor; +import com.intellij.ui.border.CustomLineBorder; +import com.intellij.util.ui.JBUI; + +import javax.swing.JComponent; +import javax.swing.JTextArea; import java.util.Arrays; import java.util.Objects; import java.util.Optional; public enum JavaInnerBuilderOption { - WITH_TO_BUILDER_METHOD("toBuilder", "Generate 'toBuilder()' method"), - WITH_VALIDATE_METHOD("validate", "Generate 'validate()' method"); + WITH_TO_BUILDER_METHOD("JavaInnerBuilderOption.toBuilder", + "Generate 'toBuilder()' method", + Type.BOOLEAN), + WITH_VALIDATE_METHOD("JavaInnerBuilderOption.validate", + "Generate 'validate()' method", + Type.BOOLEAN), + WITH_BUILDER_CLASS_ANNOTATIONS("JavaInnerBuilderOption.builderClassAnnotations", + "Generate annotations for the builder class", + Type.LIST, + (p, d, j) -> new ComponentValidator(d).withValidator(() -> { + if (j instanceof JTextArea textArea) { + var errors = new StringBuilder(); + var annotations = Utils.stringToList(textArea.getText()); + for (var annotationText : annotations) { + var annotation = Utils.parseType(annotationText); + if (ClassUtil.findPsiClass(p, annotation) == null) { + errors.append(" - ").append(annotation).append("\n"); + } + } + if (!errors.isEmpty()) { + textArea.setBorder(new CustomLineBorder(JBColor.RED, JBUI.insets(1))); + return new ValidationInfo(errors.insert(0, "Annotations not found") + .append(System.lineSeparator()).toString(), textArea); + } + textArea.setBorder(new CustomLineBorder(JBColor.border(), JBUI.insets(1))); + } + return null; + }).installOn(j)); private final String property; private final String description; - private final Boolean booleanProperty; + private final Type type; + private final OptionValidatorFactory validatorFactory; - JavaInnerBuilderOption(final String property, String description) { - this(property, description, true); + JavaInnerBuilderOption(String property, String description, Type type) { + this(property, description, type, (p, d, j) -> { + }); } - JavaInnerBuilderOption(final String property, String description, final Boolean booleanProperty) { + JavaInnerBuilderOption(String property, String description, Type type, + OptionValidatorFactory validatorFactory) { this.property = String.format("JavaInnerBuilder.%s", property); this.description = description; - this.booleanProperty = booleanProperty; + this.type = type; + this.validatorFactory = validatorFactory; } public String getProperty() { return property; } - public Boolean isBooleanProperty() { - return booleanProperty; + public Type getType() { + return type; } public String getDescription() { return description; } + public void createValidator(PsiManager psiManager, Disposable disposable, JComponent component) { + if (component instanceof LabeledComponent labeledComponent) { + component = labeledComponent.getComponent(); + } + validatorFactory.create(psiManager, disposable, component); + } + public static Optional findValue(String value) { return Arrays.stream(values()) .filter(it -> Objects.equals(it.getProperty(), value)) .findFirst(); } + public enum Type { + BOOLEAN, LIST + } } diff --git a/src/main/java/com/github/junkfactory/innerbuilder/ui/JavaInnerBuilderOptionSelector.java b/src/main/java/com/github/junkfactory/innerbuilder/ui/JavaInnerBuilderOptionSelector.java index ea95583..318405f 100644 --- a/src/main/java/com/github/junkfactory/innerbuilder/ui/JavaInnerBuilderOptionSelector.java +++ b/src/main/java/com/github/junkfactory/innerbuilder/ui/JavaInnerBuilderOptionSelector.java @@ -1,16 +1,21 @@ package com.github.junkfactory.innerbuilder.ui; +import com.github.junkfactory.innerbuilder.generators.Utils; import com.intellij.codeInsight.generation.PsiFieldMember; -import com.intellij.ide.util.MemberChooser; import com.intellij.ide.util.PropertiesComponent; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.ComboBox; import com.intellij.openapi.ui.LabeledComponent; +import com.intellij.psi.PsiManager; +import com.intellij.ui.JBColor; import com.intellij.ui.NonFocusableCheckBox; +import com.intellij.ui.border.CustomLineBorder; +import com.intellij.util.ui.JBUI; +import org.jetbrains.annotations.NotNull; import javax.swing.JComponent; -import java.awt.event.ItemEvent; +import javax.swing.JTextArea; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -41,6 +46,12 @@ private List createGeneratorOptions() { JavaInnerBuilderOption.WITH_VALIDATE_METHOD, 'v' )); + options.add(new TextAreaOption( + JavaInnerBuilderOption.WITH_BUILDER_CLASS_ANNOTATIONS, + 5, + 40, + "Use fully qualified class names separated by new lines." + )); return options; } @@ -53,31 +64,60 @@ public List selectFieldsAndOptions() { return members; } - final JComponent[] optionCheckBoxes = buildOptions(); - - final PsiFieldMember[] memberArray = members.toArray(new PsiFieldMember[0]); - - final MemberChooser chooser = new MemberChooser<>(memberArray, + var optionsArray = buildOptions(); + var memberArray = members.toArray(new PsiFieldMember[0]); + var chooser = new ValidatingFieldMemberChooser(memberArray, false, // allowEmptySelection true, // allowMultiSelection - project, null, optionCheckBoxes); + project, null, optionsArray) { + }; + for (var optionComponent : optionsArray) { + var builderOption = (JavaInnerBuilderOption) optionComponent.getClientProperty( + JavaInnerBuilderOption.class); + builderOption.createValidator(PsiManager.getInstance(project), chooser.getDisposable(), optionComponent); + } chooser.setTitle("Select Fields and Options for the Builder"); chooser.selectElements(memberArray); if (chooser.showAndGet()) { + var optionControls = chooser.getOptionControls(); + setPropertyValuesFromOptions(optionControls); return chooser.getSelectedElements(); } - return List.of(); } + private void setPropertyValuesFromOptions(JComponent[] optionComponents) { + var propertiesComponent = PropertiesComponent.getInstance(); + for (var component : optionComponents) { + var option = (JavaInnerBuilderOption) component.getClientProperty(JavaInnerBuilderOption.class); + if (component instanceof LabeledComponent labeledComponent && + labeledComponent.getComponent() instanceof JTextArea textArea) { + var annotations = Utils.stringToList(textArea.getText()); + propertiesComponent.setList(option.getProperty(), annotations); + } else if (component instanceof NonFocusableCheckBox checkBox) { + propertiesComponent.setValue(option.getProperty(), + Boolean.toString(checkBox.isSelected())); + } else if (component instanceof LabeledComponent labeledComponent && + labeledComponent.getComponent() instanceof ComboBox comboBox) { + var selectedValue = (DropdownSelectorOptionValue) comboBox.getSelectedItem(); + if (null != selectedValue) { + propertiesComponent.setValue(option.getProperty(), selectedValue.option().getProperty()); + } + } + } + } + private JComponent[] buildOptions() { var propertiesComponent = PropertiesComponent.getInstance(); var options = createGeneratorOptions(); var optionCount = options.size(); var checkBoxesArray = new JComponent[optionCount]; for (int i = 0; i < optionCount; i++) { - checkBoxesArray[i] = buildOptions(propertiesComponent, options.get(i)); + var option = options.get(i); + var optionComponent = buildOptions(propertiesComponent, option); + optionComponent.putClientProperty(JavaInnerBuilderOption.class, option.option()); + checkBoxesArray[i] = optionComponent; } return checkBoxesArray; } @@ -85,10 +125,30 @@ private JComponent[] buildOptions() { private JComponent buildOptions(PropertiesComponent propertiesComponent, SelectorOption selectorOption) { if (selectorOption instanceof CheckboxSelectorOption checkboxSelectorOption) { return buildCheckbox(propertiesComponent, checkboxSelectorOption); + } else if (selectorOption instanceof TextAreaOption textAreaOption) { + return buildTextArea(propertiesComponent, textAreaOption); } return buildDropdown(propertiesComponent, (DropdownSelectorOption) selectorOption); } + @NotNull + private LabeledComponent buildTextArea(PropertiesComponent propertiesComponent, + TextAreaOption textAreaOption) { + var textArea = new JTextArea(textAreaOption.numLines(), textAreaOption.numColumns()); + if (textAreaOption.option().getType() == JavaInnerBuilderOption.Type.LIST) { + var annotations = propertiesComponent.getList(textAreaOption.option().getProperty()); + if (null != annotations) { + textArea.setText(String.join("\n", annotations)); + } + } else { + textArea.setText(propertiesComponent.getValue(textAreaOption.option().getProperty())); + } + textArea.setBorder(new CustomLineBorder(JBColor.border(), JBUI.insets(1))); + var labeledComponent = LabeledComponent.create(textArea, textAreaOption.caption()); + labeledComponent.setToolTipText(textAreaOption.toolTip()); + return labeledComponent; + } + private JComponent buildCheckbox(PropertiesComponent propertiesComponent, CheckboxSelectorOption selectorOption) { var optionCheckBox = new NonFocusableCheckBox(selectorOption.caption()); @@ -97,8 +157,6 @@ private JComponent buildCheckbox(PropertiesComponent propertiesComponent, var optionProperty = selectorOption.option().getProperty(); optionCheckBox.setSelected(propertiesComponent.isTrueValue(optionProperty)); - optionCheckBox.addItemListener( - event -> propertiesComponent.setValue(optionProperty, Boolean.toString(optionCheckBox.isSelected()))); return optionCheckBox; } @@ -110,20 +168,12 @@ private JComponent buildDropdown(PropertiesComponent propertiesComponent, selectorOption.values().forEach(comboBox::addItem); comboBox.setSelectedItem(setSelectedComboBoxItem(propertiesComponent, selectorOption)); - comboBox.addItemListener(event -> setPropertiesComponentValue(propertiesComponent, selectorOption, event)); var labeledComponent = LabeledComponent.create(comboBox, selectorOption.caption()); labeledComponent.setToolTipText(selectorOption.toolTip()); - return labeledComponent; } - private void setPropertiesComponentValue(PropertiesComponent propertiesComponent, - DropdownSelectorOption selectorOption, ItemEvent itemEvent) { - var value = (DropdownSelectorOptionValue) itemEvent.getItem(); - propertiesComponent.setValue(selectorOption.option().getProperty(), value.option().getProperty()); - } - private DropdownSelectorOptionValue setSelectedComboBoxItem(PropertiesComponent propertiesComponent, DropdownSelectorOption selectorOption) { var selectedValue = propertiesComponent.getValue(selectorOption.option().getProperty()); diff --git a/src/main/java/com/github/junkfactory/innerbuilder/ui/OptionValidatorFactory.java b/src/main/java/com/github/junkfactory/innerbuilder/ui/OptionValidatorFactory.java new file mode 100644 index 0000000..8af5f30 --- /dev/null +++ b/src/main/java/com/github/junkfactory/innerbuilder/ui/OptionValidatorFactory.java @@ -0,0 +1,11 @@ +package com.github.junkfactory.innerbuilder.ui; + +import com.intellij.openapi.Disposable; +import com.intellij.psi.PsiManager; + +import javax.swing.JComponent; + +@FunctionalInterface +interface OptionValidatorFactory { + void create(PsiManager psiManager, Disposable disposable, JComponent optionComponent); +} diff --git a/src/main/java/com/github/junkfactory/innerbuilder/ui/TextAreaOption.java b/src/main/java/com/github/junkfactory/innerbuilder/ui/TextAreaOption.java new file mode 100644 index 0000000..c46e264 --- /dev/null +++ b/src/main/java/com/github/junkfactory/innerbuilder/ui/TextAreaOption.java @@ -0,0 +1,11 @@ +package com.github.junkfactory.innerbuilder.ui; + +public record TextAreaOption(JavaInnerBuilderOption option, + int numLines, + int numColumns, + String toolTip) implements SelectorOption { + @Override + public String caption() { + return option.getDescription(); + } +} diff --git a/src/main/java/com/github/junkfactory/innerbuilder/ui/ValidatingFieldMemberChooser.java b/src/main/java/com/github/junkfactory/innerbuilder/ui/ValidatingFieldMemberChooser.java new file mode 100644 index 0000000..3fad365 --- /dev/null +++ b/src/main/java/com/github/junkfactory/innerbuilder/ui/ValidatingFieldMemberChooser.java @@ -0,0 +1,37 @@ +package com.github.junkfactory.innerbuilder.ui; + +import com.intellij.codeInsight.generation.PsiFieldMember; +import com.intellij.ide.util.MemberChooser; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.ComponentValidator; +import com.intellij.openapi.ui.LabeledComponent; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.JComponent; + +class ValidatingFieldMemberChooser extends MemberChooser { + ValidatingFieldMemberChooser(PsiFieldMember[] elements, boolean allowEmptySelection, boolean allowMultiSelection, + @NotNull Project project, @Nullable JComponent headerPanel, + JComponent[] optionControls) { + super(elements, allowEmptySelection, allowMultiSelection, project, headerPanel, optionControls); + } + + @Override + protected void doOKAction() { + boolean hasErrors = false; + for (var optionComponent : getOptionControls()) { + optionComponent = optionComponent instanceof LabeledComponent labeledComponent ? + labeledComponent.getComponent() : optionComponent; + var optionalValidator = ComponentValidator.getInstance(optionComponent); + if (optionalValidator.isPresent()) { + var validator = optionalValidator.get(); + validator.revalidate(); + hasErrors |= null != validator.getValidationInfo(); + } + } + if (!hasErrors) { + super.doOKAction(); + } + } +}