diff --git a/resources/magento2/validation.properties b/resources/magento2/validation.properties index df750cfae..77afecd47 100644 --- a/resources/magento2/validation.properties +++ b/resources/magento2/validation.properties @@ -1,4 +1,5 @@ validator.notEmpty=The {0} field must not be empty +validator.box.notEmpty=The {0} field must contain a valid selection from the dropdown validator.package.validPath=Please specify a valid Magento 2 installation path validator.alphaNumericCharacters=The {0} field must contain letters and numbers only validator.alphaNumericAndUnderscoreCharacters={0} must contain letters, numbers and underscores only @@ -21,8 +22,8 @@ validator.file.noDocumentAssociations={0} file is binary or has no document asso validator.class.alreadyDeclared={0} already declared in the target module validator.magentoVersionInvalid=Please specify valid Magento version or use 'any' keyword as default validator.class.targetClassNotFound=Target class is not found. Check the di.xml file -validator.cronSchedule.invalidExpression={0} has invalid cron schedule expression (e.g. * * * * *) -validator.configPath.invalidFormat={0} has invalid config path format (e.g. section/group/field) +validator.cronSchedule.invalidExpression=The {0} field has does not contain a valid cron schedule expression (e.g. * * * * *) +validator.configPath.invalidFormat=The {0} field has does not contain a valid config path format (e.g. section/group/field) validator.moduleNameIsTheSameAsPackage=Module name must be different from the package name validator.mustNotBeEmptyShouldContainLettersOrNumbers=Must not be empty, should contain letters or numbers validator.magentoRouteIdInvalid=The route id is invalid diff --git a/src/com/magento/idea/magento2plugin/actions/generation/dialog/AbstractDialog.java b/src/com/magento/idea/magento2plugin/actions/generation/dialog/AbstractDialog.java index 12112338a..f340c83a7 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/dialog/AbstractDialog.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/dialog/AbstractDialog.java @@ -183,9 +183,13 @@ private void addFieldValidationRuleMessageAssociation( private String resolveFieldValueByComponentType(final Object field) { if (field instanceof JTextField) { - return ((JTextField) field).getText(); + return ((JTextField) field).isEditable() ? ((JTextField) field).getText() : null; } else if (field instanceof JComboBox) { - return ((JComboBox) field).getSelectedItem().toString(); + if (((JComboBox) field).getSelectedIndex() == -1) { + return ""; + } else { + return ((JComboBox) field).getSelectedItem().toString(); + } } else if (field instanceof JTextArea) { return ((JTextArea) field).getText(); } diff --git a/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewCronjobDialog.java b/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewCronjobDialog.java index bfec0f82b..d17a86581 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewCronjobDialog.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewCronjobDialog.java @@ -10,7 +10,15 @@ import com.magento.idea.magento2plugin.actions.generation.NewCronjobAction; import com.magento.idea.magento2plugin.actions.generation.data.CronjobClassData; import com.magento.idea.magento2plugin.actions.generation.data.CrontabXmlData; -import com.magento.idea.magento2plugin.actions.generation.dialog.validator.NewCronjobValidator; +import com.magento.idea.magento2plugin.actions.generation.dialog.validator.annotation.FieldValidation; +import com.magento.idea.magento2plugin.actions.generation.dialog.validator.annotation.RuleRegistry; +import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.BoxNotEmptyRule; +import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.ConfigPathRule; +import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.CronScheduleRule; +import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.DirectoryRule; +import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.IdentifierRule; +import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.NotEmptyRule; +import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.PhpClassRule; import com.magento.idea.magento2plugin.actions.generation.generator.CronjobClassGenerator; import com.magento.idea.magento2plugin.actions.generation.generator.CrontabXmlGenerator; import com.magento.idea.magento2plugin.actions.generation.generator.util.NamespaceBuilder; @@ -19,7 +27,6 @@ import com.magento.idea.magento2plugin.util.CamelCaseToSnakeCase; import com.magento.idea.magento2plugin.util.magento.GetModuleNameByDirectoryUtil; import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.KeyEvent; @@ -44,28 +51,64 @@ "PMD.AvoidCatchingGenericException", "PMD.ImmutableField", "PMD.AccessorMethodGeneration", + "PMD.ExcessiveImports", }) public class NewCronjobDialog extends AbstractDialog { private JPanel contentPane; private JButton buttonOK; private JButton buttonCancel; - private JTextField cronjobClassNameField; - private JTextField cronjobDirectoryField; private JRadioButton fixedScheduleRadioButton; private JRadioButton configurableScheduleRadioButton; private JRadioButton everyMinuteRadioButton; private JRadioButton customScheduleRadioButton; - private JTextField cronjobScheduleField; private JRadioButton atMidnightRadioButton; private JPanel fixedSchedulePanel; - private JTextField configPathField; private JPanel configurableSchedulePanel; - private FilteredComboBox cronGroupComboBox; + private static final String CLASS_NAME = "class name"; + private static final String DIRECTORY = "directory"; + private static final String CRON_NAME = "name"; + private static final String SCHEDULE = "schedule"; + private static final String CONFIG_PATH = "config path"; + private static final String CRON_GROUP = "cron group"; + + @FieldValidation(rule = RuleRegistry.NOT_EMPTY, + message = {NotEmptyRule.MESSAGE, CLASS_NAME}) + @FieldValidation(rule = RuleRegistry.PHP_CLASS, + message = {PhpClassRule.MESSAGE, CLASS_NAME}) + private JTextField cronjobClassNameField; + + @FieldValidation(rule = RuleRegistry.NOT_EMPTY, + message = {NotEmptyRule.MESSAGE, DIRECTORY}) + @FieldValidation(rule = RuleRegistry.DIRECTORY, + message = {DirectoryRule.MESSAGE, DIRECTORY}) + private JTextField cronjobDirectoryField; + + @FieldValidation(rule = RuleRegistry.NOT_EMPTY, + message = {NotEmptyRule.MESSAGE, CRON_NAME}) + @FieldValidation(rule = RuleRegistry.IDENTIFIER, + message = {IdentifierRule.MESSAGE, CRON_NAME}) private JTextField cronjobNameField; + @FieldValidation(rule = RuleRegistry.NOT_EMPTY, + message = {NotEmptyRule.MESSAGE, SCHEDULE}) + @FieldValidation(rule = RuleRegistry.CRON_SCHEDULE, + message = {CronScheduleRule.MESSAGE, SCHEDULE}) + private JTextField cronjobScheduleField; + + @FieldValidation(rule = RuleRegistry.NOT_EMPTY, + message = {NotEmptyRule.MESSAGE, CONFIG_PATH}) + @FieldValidation(rule = RuleRegistry.CONFIG_PATH, + message = {ConfigPathRule.MESSAGE, CONFIG_PATH}) + private JTextField configPathField; + + @FieldValidation(rule = RuleRegistry.BOX_NOT_EMPTY, + message = {BoxNotEmptyRule.MESSAGE, CRON_GROUP}) + @FieldValidation(rule = RuleRegistry.NOT_EMPTY, + message = {NotEmptyRule.MESSAGE, CRON_GROUP}) + private FilteredComboBox cronGroupComboBox; + private Project project; private String moduleName; - private NewCronjobValidator validator; private CamelCaseToSnakeCase camelCaseToSnakeCase; /** @@ -78,13 +121,13 @@ public NewCronjobDialog(final Project project, final PsiDirectory directory) { super(); this.project = project; this.moduleName = GetModuleNameByDirectoryUtil.execute(directory, project); - this.validator = NewCronjobValidator.getInstance(); this.camelCaseToSnakeCase = CamelCaseToSnakeCase.getInstance(); setContentPane(contentPane); setModal(true); getRootPane().setDefaultButton(buttonOK); setTitle("Create a new Magento 2 cronjob.."); + configPathField.setEditable(false); buttonOK.addActionListener(e -> onOK()); buttonCancel.addActionListener(e -> onCancel()); @@ -92,12 +135,15 @@ public NewCronjobDialog(final Project project, final PsiDirectory directory) { fixedScheduleRadioButton.addActionListener(e -> { configurableSchedulePanel.setVisible(false); fixedSchedulePanel.setVisible(true); + configPathField.setEditable(false); }); configurableScheduleRadioButton.addActionListener(e -> { fixedSchedulePanel.setVisible(false); configurableSchedulePanel.setVisible(true); + configPathField.setEditable(true); configPathField.grabFocus(); + everyMinuteRadioButton.doClick(); }); everyMinuteRadioButton.addActionListener(e -> { @@ -139,16 +185,9 @@ public void windowClosing(final WindowEvent event) { } }); - final ActionListener actionListener = new ActionListener() { - @Override - public void actionPerformed(final ActionEvent event) { - onCancel(); - } - }; - // call onCancel() on ESCAPE contentPane.registerKeyboardAction( - actionListener, + (final ActionEvent event) -> onCancel(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT ); @@ -237,7 +276,7 @@ private String suggestCronjobName(final String cronjobClassname) { * When new cronjob dialog is filled, validate the input data and generate a new cronjob. */ private void onOK() { - if (!validator.validate(this.project,this)) { + if (!validateFormFields()) { return; } diff --git a/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/NewCronjobValidator.java b/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/NewCronjobValidator.java deleted file mode 100644 index 131c37a5f..000000000 --- a/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/NewCronjobValidator.java +++ /dev/null @@ -1,285 +0,0 @@ -/* - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -package com.magento.idea.magento2plugin.actions.generation.dialog.validator; - -import com.intellij.openapi.project.Project; -import com.jetbrains.php.lang.psi.elements.PhpClass; -import com.jetbrains.php.refactoring.PhpNameUtil; -import com.magento.idea.magento2plugin.actions.generation.dialog.NewCronjobDialog; -import com.magento.idea.magento2plugin.actions.generation.generator.util.NamespaceBuilder; -import com.magento.idea.magento2plugin.bundles.CommonBundle; -import com.magento.idea.magento2plugin.bundles.ValidatorBundle; -import com.magento.idea.magento2plugin.util.GetPhpClassByFQN; -import com.magento.idea.magento2plugin.util.RegExUtil; -import javax.swing.JOptionPane; - -@SuppressWarnings({ - "PMD.OnlyOneReturn", - "PMD.FieldNamingConventions", - "PMD.DataflowAnomalyAnalysis", - "PMD.CyclomaticComplexity", - "PMD.NonThreadSafeSingleton", - "PMD.ExcessiveMethodLength", - "PMD.NcssCount", - "PMD.NPathComplexity" -}) -public class NewCronjobValidator { - private static final String NOT_EMPTY = "validator.notEmpty"; - private static final String CRONJOB_CLASS_NAME = "Cronjob ClassName"; - private static NewCronjobValidator INSTANCE; - private final ValidatorBundle validatorBundle; - private final CommonBundle commonBundle; - - /** - * Get instance of a class. - * - * @return NewCronjobValidator - */ - public static NewCronjobValidator getInstance() { - if (null == INSTANCE) { - INSTANCE = new NewCronjobValidator(); - } - - return INSTANCE; - } - - public NewCronjobValidator() { - this.validatorBundle = new ValidatorBundle(); - this.commonBundle = new CommonBundle(); - } - - /** - * Validate whenever new cronjob dialog data is ready for generation. - * - * @param project Project - * @param dialog NewCronjobDialog - * - * @return boolean - */ - public boolean validate(final Project project, final NewCronjobDialog dialog) { - final String errorTitle = commonBundle.message("common.error"); - final String cronjobClassName = dialog.getCronjobClassName(); - - if (!PhpNameUtil.isValidClassName(cronjobClassName)) { - final String errorMessage = this.validatorBundle.message( - "validator.class.isNotValid", - CRONJOB_CLASS_NAME - ); - JOptionPane.showMessageDialog( - null, - errorMessage, - errorTitle, - JOptionPane.ERROR_MESSAGE - ); - - return false; - } - - if (cronjobClassName.length() == 0) { - final String errorMessage = validatorBundle.message( - NOT_EMPTY, - CRONJOB_CLASS_NAME - ); - JOptionPane.showMessageDialog( - null, - errorMessage, - errorTitle, - JOptionPane.ERROR_MESSAGE - ); - - return false; - } - if (!cronjobClassName.matches(RegExUtil.ALPHANUMERIC)) { - final String errorMessage = validatorBundle.message( - "validator.alphaNumericCharacters", - CRONJOB_CLASS_NAME - ); - JOptionPane.showMessageDialog( - null, - errorMessage, - errorTitle, - JOptionPane.ERROR_MESSAGE - ); - - return false; - } - if (!Character.isUpperCase(cronjobClassName.charAt(0)) - && !Character.isDigit(cronjobClassName.charAt(0)) - ) { - final String errorMessage = validatorBundle.message( - "validator.startWithNumberOrCapitalLetter", - CRONJOB_CLASS_NAME - ); - JOptionPane.showMessageDialog( - null, - errorMessage, - errorTitle, - JOptionPane.ERROR_MESSAGE - ); - - return false; - } - - final String cronjobName = dialog.getCronjobName(); - - if (cronjobName.length() == 0) { - final String errorMessage = validatorBundle.message( - NOT_EMPTY, - "Cronjob Name" - ); - JOptionPane.showMessageDialog( - null, - errorMessage, - errorTitle, - JOptionPane.ERROR_MESSAGE - ); - - return false; - } - if (!cronjobName.matches(RegExUtil.IDENTIFIER)) { - final String errorMessage = validatorBundle.message( - "validator.identifier", - "Cronjob Name" - ); - JOptionPane.showMessageDialog( - null, - errorMessage, - errorTitle, - JOptionPane.ERROR_MESSAGE - ); - - return false; - } - - final String cronjobDirectory = dialog.getCronjobDirectory(); - - if (cronjobDirectory.length() == 0) { - final String errorMessage = validatorBundle.message( - NOT_EMPTY, - "Cronjob Directory" - ); - JOptionPane.showMessageDialog( - null, - errorMessage, - errorTitle, - JOptionPane.ERROR_MESSAGE - ); - - return false; - } - if (!cronjobDirectory.matches(RegExUtil.DIRECTORY)) { - final String errorMessage = validatorBundle.message( - "validator.directory.isNotValid", - "Cronjob Directory" - ); - JOptionPane.showMessageDialog( - null, - errorMessage, - errorTitle, - JOptionPane.ERROR_MESSAGE - ); - - return false; - } - - final boolean isFixedScheduleType = dialog.isFixedScheduleType(); - final String cronjobSchedule = dialog.getCronjobSchedule(); - - if (isFixedScheduleType) { - if (cronjobSchedule.length() == 0) { - final String errorMessage = validatorBundle.message( - NOT_EMPTY, - "Cronjob Schedule" - ); - JOptionPane.showMessageDialog( - null, - errorMessage, - errorTitle, - JOptionPane.ERROR_MESSAGE - ); - - return false; - } - if (!cronjobSchedule.matches(RegExUtil.Magento.CRON_SCHEDULE)) { - final String errorMessage = validatorBundle.message( - "validator.cronSchedule.invalidExpression", - "Cronjob Schedule" - ); - JOptionPane.showMessageDialog( - null, - errorMessage, - errorTitle, - JOptionPane.ERROR_MESSAGE - ); - - return false; - } - } - - final boolean isConfigurableScheduleType = dialog.isConfigurableScheduleType(); - final String scheduleConfigPath = dialog.getCronjobScheduleConfigPath(); - - if (isConfigurableScheduleType) { - if (scheduleConfigPath.length() == 0) { - final String errorMessage = validatorBundle.message( - NOT_EMPTY, - "Schedule Config Path" - ); - JOptionPane.showMessageDialog( - null, - errorMessage, - errorTitle, - JOptionPane.ERROR_MESSAGE - ); - - return false; - } - - if (scheduleConfigPath.matches(RegExUtil.Magento.CONFIG_PATH)) { - final String errorMessage = validatorBundle.message( - "validator.configPath.invalidFormat", - "Schedule Config Path" - ); - JOptionPane.showMessageDialog( - null, - errorMessage, - errorTitle, - JOptionPane.ERROR_MESSAGE - ); - - return false; - } - } - - final String moduleName = dialog.getCronjobModule(); - final NamespaceBuilder namespaceBuilder = new NamespaceBuilder( - moduleName, - cronjobClassName, - cronjobDirectory - ); - final PhpClass cronjobClassFile = GetPhpClassByFQN.getInstance(project).execute( - namespaceBuilder.getClassFqn() - ); - - if (cronjobClassFile != null) { - final String errorMessage = validatorBundle.message( - "validator.file.alreadyExists", - "Cronjob Class" - ); - - JOptionPane.showMessageDialog( - null, - errorMessage, - errorTitle, - JOptionPane.ERROR_MESSAGE - ); - - return false; - } - - return true; - } -} diff --git a/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/annotation/RuleRegistry.java b/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/annotation/RuleRegistry.java index 28c522914..e0b7fa5bd 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/annotation/RuleRegistry.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/annotation/RuleRegistry.java @@ -8,7 +8,10 @@ import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.AclResourceIdRule; import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.AlphanumericRule; import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.AlphanumericWithUnderscoreRule; +import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.BoxNotEmptyRule; import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.CliCommandRule; +import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.ConfigPathRule; +import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.CronScheduleRule; import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.DirectoryRule; import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.IdentifierRule; import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.Lowercase; @@ -22,6 +25,7 @@ public enum RuleRegistry { NOT_EMPTY(NotEmptyRule.class), + BOX_NOT_EMPTY(BoxNotEmptyRule.class), PHP_CLASS(PhpClassRule.class), ROUTE_ID(RouteIdRule.class), ALPHANUMERIC(AlphanumericRule.class), @@ -33,6 +37,8 @@ public enum RuleRegistry { START_WITH_NUMBER_OR_CAPITAL_LETTER(StartWithNumberOrCapitalLetterRule.class), ACL_RESOURCE_ID(AclResourceIdRule.class), LOWERCASE(Lowercase.class), + CRON_SCHEDULE(CronScheduleRule.class), + CONFIG_PATH(ConfigPathRule.class), CLI_COMMAND(CliCommandRule.class), NUMERIC(NumericRule.class); diff --git a/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/rule/BoxNotEmptyRule.java b/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/rule/BoxNotEmptyRule.java new file mode 100644 index 000000000..b6bbad1ab --- /dev/null +++ b/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/rule/BoxNotEmptyRule.java @@ -0,0 +1,20 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +package com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule; + +public class BoxNotEmptyRule implements ValidationRule { + public static final String MESSAGE = "validator.box.notEmpty"; + private static final ValidationRule INSTANCE = new BoxNotEmptyRule(); + + @Override + public boolean check(final String value) { + return !value.isEmpty(); + } + + public static ValidationRule getInstance() { + return INSTANCE; + } +} diff --git a/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/rule/ConfigPathRule.java b/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/rule/ConfigPathRule.java new file mode 100644 index 000000000..317a85fe4 --- /dev/null +++ b/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/rule/ConfigPathRule.java @@ -0,0 +1,22 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +package com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule; + +import com.magento.idea.magento2plugin.util.RegExUtil; + +public class ConfigPathRule implements ValidationRule { + public static final String MESSAGE = "validator.configPath.invalidFormat"; + private static final ValidationRule INSTANCE = new ConfigPathRule(); + + @Override + public boolean check(final String value) { + return value.matches(RegExUtil.Magento.CONFIG_PATH); + } + + public static ValidationRule getInstance() { + return INSTANCE; + } +} diff --git a/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/rule/CronScheduleRule.java b/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/rule/CronScheduleRule.java new file mode 100644 index 000000000..8bcb32502 --- /dev/null +++ b/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/rule/CronScheduleRule.java @@ -0,0 +1,22 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +package com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule; + +import com.magento.idea.magento2plugin.util.RegExUtil; + +public class CronScheduleRule implements ValidationRule { + public static final String MESSAGE = "validator.cronSchedule.invalidExpression"; + private static final ValidationRule INSTANCE = new CronScheduleRule(); + + @Override + public boolean check(final String value) { + return value.matches(RegExUtil.Magento.CRON_SCHEDULE); + } + + public static ValidationRule getInstance() { + return INSTANCE; + } +} diff --git a/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/rule/NotEmptyRule.java b/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/rule/NotEmptyRule.java index c0772853c..4120118a3 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/rule/NotEmptyRule.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/rule/NotEmptyRule.java @@ -11,7 +11,7 @@ public class NotEmptyRule implements ValidationRule { @Override public boolean check(final String value) { - return value.length() != 0; + return !value.isEmpty(); } public static ValidationRule getInstance() {