Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to create a copy constructor #74

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ private void writeBuilderIfNecessary(
List<PsiElementClassMember> selectedElements = memberChooserDialog.getSelectedElements();
PsiFieldsForBuilder psiFieldsForBuilder = psiFieldsForBuilderFactory.createPsiFieldsForBuilder(selectedElements, psiClassFromEditor);
BuilderContext context = new BuilderContext(
project, psiFieldsForBuilder, targetDirectory, className, psiClassFromEditor, methodPrefix, createBuilderDialog.isInnerBuilder(), createBuilderDialog.hasButMethod(), createBuilderDialog.useSingleField());
project, psiFieldsForBuilder, targetDirectory, className, psiClassFromEditor, methodPrefix, createBuilderDialog.isInnerBuilder(), createBuilderDialog.hasButMethod(), createBuilderDialog.useSingleField(), createBuilderDialog.hasAddCopyConstructor());
builderWriter.writeBuilder(context, existingBuilder);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ public class CreateBuilderDialog extends DialogWrapper {
private JCheckBox innerBuilder;
private JCheckBox butMethod;
private JCheckBox useSingleField;
private JCheckBox copyConstructor;
private ReferenceEditorComboWithBrowseButton targetPackageField;
private PsiClass existingBuilder;

Expand Down Expand Up @@ -211,7 +212,6 @@ public void actionPerformed(ActionEvent e) {
panel.add(innerBuilder, gbConstraints);
// Inner builder


// but method
gbConstraints.insets = new Insets(4, 8, 4, 8);
gbConstraints.gridx = 0;
Expand All @@ -232,7 +232,6 @@ public void actionPerformed(ActionEvent e) {
panel.add(butMethod, gbConstraints);
// but method


// useSingleField
gbConstraints.insets = new Insets(4, 8, 4, 8);
gbConstraints.gridx = 0;
Expand All @@ -253,6 +252,26 @@ public void actionPerformed(ActionEvent e) {
panel.add(useSingleField, gbConstraints);
// useSingleField

// copy constructor
gbConstraints.insets = new Insets(4, 8, 4, 8);
gbConstraints.gridx = 0;
gbConstraints.weightx = 0;
gbConstraints.gridy = 7;
gbConstraints.fill = GridBagConstraints.HORIZONTAL;
gbConstraints.anchor = GridBagConstraints.WEST;
panel.add(new JLabel("Add copy constructor"), gbConstraints);

gbConstraints.insets = new Insets(4, 8, 4, 8);
gbConstraints.gridx = 1;
gbConstraints.weightx = 1;
gbConstraints.gridwidth = 1;
gbConstraints.fill = GridBagConstraints.HORIZONTAL;
gbConstraints.anchor = GridBagConstraints.WEST;
copyConstructor = new JCheckBox();
copyConstructor.setSelected(defaultStates.isAddCopyConstructor);
panel.add(copyConstructor, gbConstraints);
// copy constructor

return panel;
}

Expand Down Expand Up @@ -347,6 +366,10 @@ public boolean useSingleField() {
return useSingleField.isSelected();
}

public boolean hasAddCopyConstructor() {
return copyConstructor.isSelected();
}

public PsiDirectory getTargetDirectory() {
return targetDirectory;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,6 @@
package pl.mjedynak.idea.plugins.builder.psi;

import com.intellij.psi.JavaDirectoryService;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElementFactory;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiModifierList;
import com.intellij.psi.PsiParameter;
import com.intellij.psi.PsiType;
import com.intellij.psi.*;
import org.apache.commons.lang.StringUtils;
import pl.mjedynak.idea.plugins.builder.settings.CodeStyleSettings;
import pl.mjedynak.idea.plugins.builder.verifier.PsiFieldVerifier;
Expand All @@ -24,7 +16,6 @@

public class BuilderPsiClassBuilder {

private static final String PRIVATE_STRING = "private";
private static final String SPACE = " ";
private static final String A_PREFIX = " a";
private static final String AN_PREFIX = " an";
Expand All @@ -37,6 +28,7 @@ public class BuilderPsiClassBuilder {
private PsiFieldVerifier psiFieldVerifier = new PsiFieldVerifier();
private CodeStyleSettings codeStyleSettings = new CodeStyleSettings();
private ButMethodCreator butMethodCreator;
private CopyConstructorCreator copyConstructorCreator;
private MethodCreator methodCreator;

private PsiClass srcClass = null;
Expand Down Expand Up @@ -87,6 +79,7 @@ private void initializeFields(BuilderContext context) {
bestConstructor = context.getPsiFieldsForBuilder().getBestConstructor();
methodCreator = new MethodCreator(elementFactory, builderClassName);
butMethodCreator = new ButMethodCreator(elementFactory);
copyConstructorCreator = new CopyConstructorCreator(elementFactory);
isInline = allSelectedPsiFields.size() == psiFieldsForConstructor.size();
}

Expand All @@ -103,14 +96,14 @@ public BuilderPsiClassBuilder withFields() {
return this;
}

public BuilderPsiClassBuilder withPrivateConstructor() {
public BuilderPsiClassBuilder withConstructor() {
PsiMethod constructor;
if (useSingleField) {
constructor = elementFactory.createMethodFromText(builderClassName + "(){ " + srcClassFieldName + " = new " + srcClassName + "(); }", srcClass);
} else {
constructor = elementFactory.createConstructor();
}
constructor.getModifierList().setModifierProperty(PRIVATE_STRING, true);
constructor.getModifierList().setModifierProperty(PsiModifier.PUBLIC, true);
builderClass.add(constructor);
return this;
}
Expand Down Expand Up @@ -149,6 +142,12 @@ public BuilderPsiClassBuilder withButMethod() {
return this;
}

public BuilderPsiClassBuilder withCopyConstructor() {
final PsiMethod method = copyConstructorCreator.copyConstructor(builderClass, srcClass, isInnerBuilder(builderClass));
builderClass.add(method);
return this;
}

private void createAndAddMethod(PsiField psiField, String methodPrefix) {
builderClass.add(methodCreator.createMethod(psiField, methodPrefix, srcClassFieldName, useSingleField));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package pl.mjedynak.idea.plugins.builder.psi;

import com.intellij.psi.*;
import com.intellij.psi.util.PropertyUtilBase;
import com.intellij.util.IncorrectOperationException;

import java.util.Arrays;

import static java.util.Objects.nonNull;

public class CopyConstructorCreator {

private final PsiElementFactory elementFactory;

public CopyConstructorCreator(final PsiElementFactory elementFactory) {
this.elementFactory = elementFactory;
}

public PsiMethod copyConstructor(final PsiClass builderClass, final PsiClass srcClass, final boolean isInnerBuilder) {
final PsiField[] fields = builderClass.getAllFields();
final StringBuilder text = new StringBuilder("public " + builderClass.getNameIdentifier().getText() + "(" + srcClass.getQualifiedName() + " other) { ");

Arrays.stream(fields).forEach(field -> {
text.append("this.").append(field.getName()).append(" = other.");

if (srcClass.isRecord()) {
text.append(field.getName()).append("();");
} else if (isInnerBuilder) {
text.append(field.getName()).append(";");
} else {
text.append(findFieldGetter(srcClass, field).getName()).append("();");
}
});
text.append(" }");

return elementFactory.createMethodFromText(text.toString(), srcClass);
}

private PsiMethod findFieldGetter(final PsiClass srcClass, final PsiField field) {
final PsiMethod method = srcClass.findMethodBySignature(PropertyUtilBase.generateGetterPrototype(field), true);

if (nonNull(method)) {
return method;
}

throw new IncorrectOperationException("Could not create copy constructor as cannot get field getters");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,60 +11,74 @@

public class BuilderGeneratorSettingsComponent {

private final JPanel myMainPanel;
private final JBTextField defaultMethodPrefixText = new JBTextField();
private final JBCheckBox innerBuilderCheckBox = new JBCheckBox("Inner builder");
private final JBCheckBox butMethodCheckBox = new JBCheckBox("'but' method'");
private final JBCheckBox useSinglePrefixCheckBox = new JBCheckBox("Use single prefix");

public BuilderGeneratorSettingsComponent() {
myMainPanel = FormBuilder.createFormBuilder()
.addLabeledComponent(new JBLabel("Default prefix: "), defaultMethodPrefixText, 1, false)
.addComponent(innerBuilderCheckBox, 1)
.addComponent(butMethodCheckBox, 1)
.addComponent(useSinglePrefixCheckBox, 1)
.addComponentFillVertically(new JPanel(), 0)
.getPanel();
}

public JPanel getPanel() {
return myMainPanel;
}

public JComponent getPreferredFocusedComponent() {
return defaultMethodPrefixText;
}

@NotNull
public String getDefaultMethodPrefixText() {
return defaultMethodPrefixText.getText();
}

public void setDefaultMethodPrefixText(@NotNull String newText) {
defaultMethodPrefixText.setText(newText);
}

public boolean isInnerBuilder() {
return innerBuilderCheckBox.isSelected();
}

public void setInnerBuilder(boolean isInnerBuilder) {
innerBuilderCheckBox.setSelected(isInnerBuilder);
}

public boolean isButMethod() {
return butMethodCheckBox.isSelected();
}

public void setButMethod(boolean isButMethod) {
butMethodCheckBox.setSelected(isButMethod);
}

public boolean isUseSinglePrefix() {
return useSinglePrefixCheckBox.isSelected();
}

public void setUseSinglePrefix(boolean isUseSinglePrefix) {
useSinglePrefixCheckBox.setSelected(isUseSinglePrefix);
}
private final JPanel myMainPanel;
private final JBTextField defaultMethodPrefixText = new JBTextField();
private final JBCheckBox innerBuilderCheckBox = new JBCheckBox("Inner builder");
private final JBCheckBox butMethodCheckBox = new JBCheckBox("'but' method'");
private final JBCheckBox useSinglePrefixCheckBox = new JBCheckBox("Use single prefix");
private final JBCheckBox addCopyConstructorCheckBox = new JBCheckBox("Add copy constructor");

public BuilderGeneratorSettingsComponent() {
myMainPanel = FormBuilder.createFormBuilder()
.addLabeledComponent(new JBLabel("Default prefix: "), defaultMethodPrefixText, 1, false)
.addComponent(innerBuilderCheckBox, 1)
.addComponent(butMethodCheckBox, 1)
.addComponent(useSinglePrefixCheckBox, 1)
.addComponent(addCopyConstructorCheckBox, 1)
.addComponentFillVertically(new JPanel(), 0)
.getPanel();
}

public JPanel getPanel() {
return myMainPanel;
}

public JComponent getPreferredFocusedComponent() {
return defaultMethodPrefixText;
}

@NotNull
public String getDefaultMethodPrefixText() {
return defaultMethodPrefixText.getText();
}

public void setDefaultMethodPrefixText(@NotNull String newText) {
defaultMethodPrefixText.setText(newText);
}

public boolean isInnerBuilder() {
return innerBuilderCheckBox.isSelected();
}

public void setInnerBuilder(boolean isInnerBuilder) {
innerBuilderCheckBox.setSelected(isInnerBuilder);
}

public boolean isButMethod() {
return butMethodCheckBox.isSelected();
}

public void setButMethod(boolean isButMethod) {
butMethodCheckBox.setSelected(isButMethod);
}

public boolean isUseSinglePrefix() {
return useSinglePrefixCheckBox.isSelected();
}

public void setUseSinglePrefix(boolean isUseSinglePrefix) {
useSinglePrefixCheckBox.setSelected(isUseSinglePrefix);
}

public boolean isAddCopyConstructor() {
return addCopyConstructorCheckBox.isSelected();
}

public void setAddCopyConstructor(boolean addCopyConstructor) {
addCopyConstructorCheckBox.setSelected(addCopyConstructor);
}

public void setAddCopyConstructorEnabled(boolean enabled) {
addCopyConstructorCheckBox.setEnabled(enabled);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public boolean isModified() {
modified |= mySettingsComponent.isInnerBuilder() != settings.isInnerBuilder;
modified |= mySettingsComponent.isButMethod() != settings.isButMethod;
modified |= mySettingsComponent.isUseSinglePrefix() != settings.isUseSinglePrefix;
modified |= mySettingsComponent.isAddCopyConstructor() != settings.isAddCopyConstructor;
return modified;
}

Expand All @@ -48,6 +49,7 @@ public void apply() {
settings.isInnerBuilder = mySettingsComponent.isInnerBuilder();
settings.isButMethod = mySettingsComponent.isButMethod();
settings.isUseSinglePrefix = mySettingsComponent.isUseSinglePrefix();
settings.isAddCopyConstructor = mySettingsComponent.isAddCopyConstructor();
}

@Override
Expand All @@ -57,6 +59,7 @@ public void reset() {
mySettingsComponent.setInnerBuilder(settings.isInnerBuilder);
mySettingsComponent.setButMethod(settings.isButMethod);
mySettingsComponent.setUseSinglePrefix(settings.isUseSinglePrefix);
mySettingsComponent.setAddCopyConstructor(settings.isAddCopyConstructor);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public class BuilderGeneratorSettingsState implements PersistentStateComponent<B
public boolean isInnerBuilder = false;
public boolean isButMethod = false;
public boolean isUseSinglePrefix = false;
public boolean isAddCopyConstructor = false;

public BuilderGeneratorSettingsState() {}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ public class BuilderContext {
private final boolean isInner;
private final boolean hasButMethod;
private final boolean useSingleField;
private final boolean addCopyConstructor;

public BuilderContext(Project project, PsiFieldsForBuilder psiFieldsForBuilder,
PsiDirectory targetDirectory, String className, PsiClass psiClassFromEditor,
String methodPrefix, boolean isInner, boolean hasButMethod, boolean useSingleField) {
String methodPrefix, boolean isInner, boolean hasButMethod, boolean useSingleField,
boolean addCopyConstructor) {
this.project = project;
this.psiFieldsForBuilder = psiFieldsForBuilder;
this.targetDirectory = targetDirectory;
Expand All @@ -30,6 +32,7 @@ public BuilderContext(Project project, PsiFieldsForBuilder psiFieldsForBuilder,
this.isInner = isInner;
this.hasButMethod = hasButMethod;
this.useSingleField = useSingleField;
this.addCopyConstructor = addCopyConstructor;
}

public Project getProject() {
Expand Down Expand Up @@ -68,6 +71,10 @@ public boolean useSingleField() {
return useSingleField;
}

public boolean hasAddCopyConstructor() {
return addCopyConstructor;
}

@Override
public int hashCode() {
return Objects.hashCode(project, psiFieldsForBuilder, targetDirectory, className, psiClassFromEditor, methodPrefix);
Expand Down
Loading
Loading