From 9dfa41a3411253c8cc227935873c43bc80babc69 Mon Sep 17 00:00:00 2001 From: Vitaliy Boyko <v.boyko@atwix.com> Date: Tue, 24 Mar 2020 19:48:12 +0200 Subject: [PATCH 1/3] MVP implementation of the New Magento 2 Module action --- resources/META-INF/plugin.xml | 6 + .../internal/Magento Module Composer.html | 4 + .../internal/Magento Module Composer.json.ft | 17 ++ .../Magento Module Registration Php.html | 4 + .../Magento Module Registration Php.php.ft | 6 + .../internal/Magento Module XML.html | 4 + .../internal/Magento Module XML.xml.ft | 10 + .../{magento2-module.png => icons/module.png} | Bin .../icons/webapi.png | Bin .../idea/magento2plugin/MagentoIcons.java | 1 + .../actions/generation/NewModuleAction.java | 61 ++++++ .../dialog/NewMagentoModuleDialog.form | 145 ++++++++++++++ .../dialog/NewMagentoModuleDialog.java | 185 ++++++++++++++++++ .../NewMagentoModuleDialogValidator.java | 66 +++++++ .../generator/DirectoryGenerator.java | 33 ++++ .../generator/FileFromTemplateGenerator.java | 122 ++++++++++++ .../generator/data/ModuleDirectoriesData.java | 30 +++ .../magento/files/ComposerJson.java | 36 ++++ .../magento/files/ModuleFileInterface.java | 13 ++ .../magento/files/ModuleXml.java | 36 ++++ .../magento/files/RegistrationPhp.java | 36 ++++ .../magento/packages/MagentoPackages.java | 9 + .../util/CamelCaseToHyphen.java | 31 +++ .../idea/magento2plugin/util/Regex.java | 11 ++ 24 files changed, 866 insertions(+) create mode 100644 resources/fileTemplates/internal/Magento Module Composer.html create mode 100644 resources/fileTemplates/internal/Magento Module Composer.json.ft create mode 100644 resources/fileTemplates/internal/Magento Module Registration Php.html create mode 100644 resources/fileTemplates/internal/Magento Module Registration Php.php.ft create mode 100644 resources/fileTemplates/internal/Magento Module XML.html create mode 100644 resources/fileTemplates/internal/Magento Module XML.xml.ft rename resources/{magento2-module.png => icons/module.png} (100%) rename {src/com/magento/idea/magento2plugin => resources}/icons/webapi.png (100%) create mode 100644 src/com/magento/idea/magento2plugin/actions/generation/NewModuleAction.java create mode 100644 src/com/magento/idea/magento2plugin/actions/generation/dialog/NewMagentoModuleDialog.form create mode 100644 src/com/magento/idea/magento2plugin/actions/generation/dialog/NewMagentoModuleDialog.java create mode 100644 src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/NewMagentoModuleDialogValidator.java create mode 100644 src/com/magento/idea/magento2plugin/actions/generation/generator/DirectoryGenerator.java create mode 100644 src/com/magento/idea/magento2plugin/actions/generation/generator/FileFromTemplateGenerator.java create mode 100644 src/com/magento/idea/magento2plugin/actions/generation/generator/data/ModuleDirectoriesData.java create mode 100644 src/com/magento/idea/magento2plugin/magento/files/ComposerJson.java create mode 100644 src/com/magento/idea/magento2plugin/magento/files/ModuleFileInterface.java create mode 100644 src/com/magento/idea/magento2plugin/magento/files/ModuleXml.java create mode 100644 src/com/magento/idea/magento2plugin/magento/files/RegistrationPhp.java create mode 100644 src/com/magento/idea/magento2plugin/magento/packages/MagentoPackages.java create mode 100644 src/com/magento/idea/magento2plugin/util/CamelCaseToHyphen.java create mode 100644 src/com/magento/idea/magento2plugin/util/Regex.java diff --git a/resources/META-INF/plugin.xml b/resources/META-INF/plugin.xml index d888fd90f..77c70843e 100644 --- a/resources/META-INF/plugin.xml +++ b/resources/META-INF/plugin.xml @@ -53,6 +53,10 @@ description="Create Magento around plugin method."/> <add-to-group group-id="PhpGenerateGroup" anchor="last"/> </group> + <group id="MagentoNewGroup"> + <action id="Magento2NewModule" class="com.magento.idea.magento2plugin.actions.generation.NewModuleAction"/> + <add-to-group group-id="NewGroup" anchor="after" relative-to-action="NewDir"/> + </group> </actions> @@ -104,6 +108,7 @@ groupName="Magento" enabledByDefault="true" level="ERROR" implementationClass="com.magento.idea.magento2plugin.inspections.php.PluginInspection"/> <libraryRoot id=".phpstorm.meta.php" path=".phpstorm.meta.php/" runtime="false"/> + </extensions> <application-components> @@ -118,4 +123,5 @@ <!-- Add your actions here --> </actions> + </idea-plugin> diff --git a/resources/fileTemplates/internal/Magento Module Composer.html b/resources/fileTemplates/internal/Magento Module Composer.html new file mode 100644 index 000000000..6bfc7988e --- /dev/null +++ b/resources/fileTemplates/internal/Magento Module Composer.html @@ -0,0 +1,4 @@ +<html> +<body> +</body> +</html> \ No newline at end of file diff --git a/resources/fileTemplates/internal/Magento Module Composer.json.ft b/resources/fileTemplates/internal/Magento Module Composer.json.ft new file mode 100644 index 000000000..5bf88ab4a --- /dev/null +++ b/resources/fileTemplates/internal/Magento Module Composer.json.ft @@ -0,0 +1,17 @@ +{ + "name": "${COMPOSER_PACKAGE_NAME}", + "version": "${MODULE_VERSION}", + "description": "${MODULE_DESCRIPTION}", + "type": "magento2-module", + #if (${DEPENDENCIES}) "require": { + ${DEPENDENCIES} }, #end +#if (${LICENSE}) ${LICENSE}, #end + "autoload": { + "files": [ + "registration.php" + ], + "psr-4": { + "${PACKAGE}\\\\${MODULE_NAME}\\": "" + } + } +} \ No newline at end of file diff --git a/resources/fileTemplates/internal/Magento Module Registration Php.html b/resources/fileTemplates/internal/Magento Module Registration Php.html new file mode 100644 index 000000000..6bfc7988e --- /dev/null +++ b/resources/fileTemplates/internal/Magento Module Registration Php.html @@ -0,0 +1,4 @@ +<html> +<body> +</body> +</html> \ No newline at end of file diff --git a/resources/fileTemplates/internal/Magento Module Registration Php.php.ft b/resources/fileTemplates/internal/Magento Module Registration Php.php.ft new file mode 100644 index 000000000..77b88d501 --- /dev/null +++ b/resources/fileTemplates/internal/Magento Module Registration Php.php.ft @@ -0,0 +1,6 @@ +<?php +#parse("PHP File Header.php") + +use Magento\Framework\Component\ComponentRegistrar; + +ComponentRegistrar::register(ComponentRegistrar::MODULE, '${PACKAGE}_${MODULE_NAME}', __DIR__); diff --git a/resources/fileTemplates/internal/Magento Module XML.html b/resources/fileTemplates/internal/Magento Module XML.html new file mode 100644 index 000000000..6bfc7988e --- /dev/null +++ b/resources/fileTemplates/internal/Magento Module XML.html @@ -0,0 +1,4 @@ +<html> +<body> +</body> +</html> \ No newline at end of file diff --git a/resources/fileTemplates/internal/Magento Module XML.xml.ft b/resources/fileTemplates/internal/Magento Module XML.xml.ft new file mode 100644 index 000000000..895b81744 --- /dev/null +++ b/resources/fileTemplates/internal/Magento Module XML.xml.ft @@ -0,0 +1,10 @@ +<?xml version="1.0"?> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> + #if (${SEQUENCES}) + <module name="${PACKAGE}_${MODULE_NAME}"> + ${SEQUENCES} + </module> + #else + <module name="${PACKAGE}_${MODULE_NAME}" /> + #end +</config> diff --git a/resources/magento2-module.png b/resources/icons/module.png similarity index 100% rename from resources/magento2-module.png rename to resources/icons/module.png diff --git a/src/com/magento/idea/magento2plugin/icons/webapi.png b/resources/icons/webapi.png similarity index 100% rename from src/com/magento/idea/magento2plugin/icons/webapi.png rename to resources/icons/webapi.png diff --git a/src/com/magento/idea/magento2plugin/MagentoIcons.java b/src/com/magento/idea/magento2plugin/MagentoIcons.java index ae139608a..82de250f1 100644 --- a/src/com/magento/idea/magento2plugin/MagentoIcons.java +++ b/src/com/magento/idea/magento2plugin/MagentoIcons.java @@ -13,4 +13,5 @@ */ public class MagentoIcons { public static final Icon WEB_API = IconLoader.getIcon("icons/webapi.png"); + public static final Icon MODULE = IconLoader.getIcon("/icons/module.png"); } diff --git a/src/com/magento/idea/magento2plugin/actions/generation/NewModuleAction.java b/src/com/magento/idea/magento2plugin/actions/generation/NewModuleAction.java new file mode 100644 index 000000000..e8f1b7887 --- /dev/null +++ b/src/com/magento/idea/magento2plugin/actions/generation/NewModuleAction.java @@ -0,0 +1,61 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +package com.magento.idea.magento2plugin.actions.generation; + +import com.intellij.ide.IdeView; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.CommonDataKeys; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.actionSystem.LangDataKeys; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiDirectory; +import com.intellij.psi.PsiFile; +import com.magento.idea.magento2plugin.MagentoIcons; +import com.magento.idea.magento2plugin.actions.generation.dialog.NewMagentoModuleDialog; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class NewModuleAction extends com.intellij.openapi.actionSystem.AnAction { + public static String ACTION_NAME = "New Magento 2 Module"; + public static String ACTION_DESCRIPTION = "Create a new Magento 2 module"; + + NewModuleAction() { + super(ACTION_NAME, ACTION_DESCRIPTION, MagentoIcons.MODULE); + } + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + DataContext dataContext = e.getDataContext(); + IdeView view = LangDataKeys.IDE_VIEW.getData(dataContext); + if (view != null) { + Project project = CommonDataKeys.PROJECT.getData(dataContext); + if (project != null) { + PsiDirectory initialBaseDir = view.getOrChooseDirectory(); + if (initialBaseDir != null) { + this.invoke(project, initialBaseDir, this.getFile(dataContext), view, CommonDataKeys.EDITOR.getData(dataContext)); + } + } + } + } + + public void invoke(@NotNull Project project, @NotNull PsiDirectory initialBaseDir, @Nullable PsiFile file, @Nullable IdeView view, @Nullable Editor editor) { + NewMagentoModuleDialog.open(project, initialBaseDir, file, view, editor); + } + + @Override + public boolean isDumbAware() { + return false; + } + + @NotNull + private String getActionName() { + return this.getTemplatePresentation().getText(); + } + + public PsiFile getFile(DataContext dataContext) { + return CommonDataKeys.PSI_FILE.getData(dataContext); + } +} + diff --git a/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewMagentoModuleDialog.form b/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewMagentoModuleDialog.form new file mode 100644 index 000000000..cd3eca240 --- /dev/null +++ b/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewMagentoModuleDialog.form @@ -0,0 +1,145 @@ +<?xml version="1.0" encoding="UTF-8"?> +<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.magento.idea.magento2plugin.actions.generation.dialog.NewMagentoModuleDialog"> + <grid id="cbd77" binding="contentPane" layout-manager="GridLayoutManager" row-count="4" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> + <margin top="10" left="10" bottom="10" right="10"/> + <constraints> + <xy x="48" y="54" width="462" height="297"/> + </constraints> + <properties/> + <border type="none"/> + <children> + <grid id="94766" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> + <margin top="0" left="0" bottom="0" right="0"/> + <constraints> + <grid row="3" column="0" row-span="1" col-span="2" vsize-policy="1" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/> + </constraints> + <properties/> + <border type="none"/> + <children> + <hspacer id="98af6"> + <constraints> + <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/> + </constraints> + </hspacer> + <grid id="9538f" layout-manager="GridLayoutManager" row-count="1" column-count="2" same-size-horizontally="true" same-size-vertically="false" hgap="-1" vgap="-1"> + <margin top="0" left="0" bottom="0" right="0"/> + <constraints> + <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/> + </constraints> + <properties/> + <border type="none"/> + <children> + <component id="e7465" class="javax.swing.JButton" binding="buttonOK"> + <constraints> + <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/> + </constraints> + <properties> + <text value="OK"/> + </properties> + </component> + <component id="5723f" class="javax.swing.JButton" binding="buttonCancel"> + <constraints> + <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/> + </constraints> + <properties> + <text value="Cancel"/> + </properties> + </component> + </children> + </grid> + </children> + </grid> + <grid id="e3588" layout-manager="GridLayoutManager" row-count="3" column-count="4" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> + <margin top="0" left="0" bottom="0" right="0"/> + <constraints> + <grid row="0" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/> + </constraints> + <properties/> + <border type="none"/> + <children> + <component id="ad3ba" class="javax.swing.JTextField" binding="packageName" default-binding="true"> + <constraints> + <grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false"> + <preferred-size width="150" height="-1"/> + </grid> + </constraints> + <properties/> + <clientProperties> + <html.disable class="java.lang.Boolean" value="true"/> + </clientProperties> + </component> + <component id="3fe2b" class="javax.swing.JLabel" binding="packageNameLabel"> + <constraints> + <grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/> + </constraints> + <properties> + <text value="Package Name"/> + </properties> + </component> + <component id="e4858" class="javax.swing.JTextField" binding="moduleName"> + <constraints> + <grid row="1" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false"> + <preferred-size width="150" height="-1"/> + </grid> + </constraints> + <properties/> + <clientProperties> + <html.disable class="java.lang.Boolean" value="true"/> + </clientProperties> + </component> + <component id="22b5e" class="javax.swing.JLabel" binding="moduleNameLabel"> + <constraints> + <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/> + </constraints> + <properties> + <text value="Module Name"/> + </properties> + </component> + <component id="423dc" class="javax.swing.JTextField" binding="moduleVersion"> + <constraints> + <grid row="2" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="6" anchor="8" fill="1" indent="0" use-parent-layout="false"> + <preferred-size width="150" height="-1"/> + </grid> + </constraints> + <properties> + <text value="1.0.0"/> + </properties> + <clientProperties> + <html.disable class="java.lang.Boolean" value="true"/> + </clientProperties> + </component> + <component id="2af8d" class="javax.swing.JLabel" binding="moduleVersionLabel"> + <constraints> + <grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/> + </constraints> + <properties> + <text value="Module Version"/> + </properties> + </component> + </children> + </grid> + <component id="4c5ac" class="javax.swing.JTextArea" binding="moduleDescription"> + <constraints> + <grid row="2" column="0" row-span="1" col-span="2" vsize-policy="6" hsize-policy="6" anchor="0" fill="3" indent="0" use-parent-layout="false"> + <preferred-size width="150" height="50"/> + </grid> + </constraints> + <properties> + <text value="N/A"/> + <toolTipText value="Module Description"/> + </properties> + <clientProperties> + <html.disable class="java.lang.Boolean" value="true"/> + </clientProperties> + </component> + <component id="ec98d" class="javax.swing.JLabel" binding="moduleDescriptionLabel"> + <constraints> + <grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/> + </constraints> + <properties> + <text value="Module Description"/> + </properties> + </component> + </children> + </grid> +</form> diff --git a/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewMagentoModuleDialog.java b/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewMagentoModuleDialog.java new file mode 100644 index 000000000..fa3cdd74d --- /dev/null +++ b/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewMagentoModuleDialog.java @@ -0,0 +1,185 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +package com.magento.idea.magento2plugin.actions.generation.dialog; + +import com.intellij.ide.IdeView; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiDirectory; +import com.intellij.psi.PsiFile; +import com.magento.idea.magento2plugin.actions.generation.NewModuleAction; +import com.magento.idea.magento2plugin.actions.generation.dialog.validator.NewMagentoModuleDialogValidator; +import com.magento.idea.magento2plugin.actions.generation.generator.DirectoryGenerator; +import com.magento.idea.magento2plugin.actions.generation.generator.FileFromTemplateGenerator; +import com.magento.idea.magento2plugin.actions.generation.generator.data.ModuleDirectoriesData; +import com.magento.idea.magento2plugin.magento.files.ComposerJson; +import com.magento.idea.magento2plugin.magento.files.ModuleXml; +import com.magento.idea.magento2plugin.magento.files.RegistrationPhp; +import com.magento.idea.magento2plugin.magento.packages.MagentoPackages; +import com.magento.idea.magento2plugin.util.CamelCaseToHyphen; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import javax.swing.*; +import java.awt.*; +import java.awt.event.*; +import java.util.Properties; + +public class NewMagentoModuleDialog extends JDialog { + @NotNull + private final Project project; + @NotNull + private final PsiDirectory initialBaseDir; + @Nullable + private final PsiFile file; + @Nullable + private final IdeView view; + @Nullable + private final Editor editor; + private final DirectoryGenerator directoryGenerator; + private final FileFromTemplateGenerator fileFromTemplateGenerator; + private final NewMagentoModuleDialogValidator validator; + private final CamelCaseToHyphen camelCaseToHyphen; + private JPanel contentPane; + private JButton buttonOK; + private JButton buttonCancel; + private JTextField packageName; + private JLabel packageNameLabel; + private JTextField moduleName; + private JLabel moduleNameLabel; + private JTextArea moduleDescription; + private JLabel moduleDescriptionLabel; + private JTextField moduleVersion; + private JLabel moduleVersionLabel; + private String detectedPackageName; + + public NewMagentoModuleDialog(@NotNull Project project, @NotNull PsiDirectory initialBaseDir, @Nullable PsiFile file, @Nullable IdeView view, @Nullable Editor editor) { + this.project = project; + this.initialBaseDir = initialBaseDir; + this.file = file; + this.view = view; + this.editor = editor; + this.directoryGenerator = DirectoryGenerator.getInstance(); + this.fileFromTemplateGenerator = FileFromTemplateGenerator.getInstance(project); + this.camelCaseToHyphen = CamelCaseToHyphen.getInstance(); + this.validator = NewMagentoModuleDialogValidator.getInstance(this); + detectPackageName(initialBaseDir); + setContentPane(contentPane); + setModal(true); + getRootPane().setDefaultButton(buttonOK); + pushToMiddle(); + + buttonOK.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + onOK(); + } + }); + + buttonCancel.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + onCancel(); + } + }); + + setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); + addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + onCancel(); + } + }); + + contentPane.registerKeyboardAction(new ActionListener() { + public void actionPerformed(ActionEvent e) { + onCancel(); + } + }, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + } + + private void detectPackageName(@NotNull PsiDirectory initialBaseDir) { + PsiDirectory parentDir = initialBaseDir.getParent(); + if (parentDir != null && parentDir.toString().endsWith(MagentoPackages.PACKAGES_ROOT)) { + packageName.setVisible(false); + packageNameLabel.setVisible(false); + this.detectedPackageName = initialBaseDir.getName(); + } + } + + private void pushToMiddle() { + Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); + this.setLocation(dim.width / 2 -this.getSize().width / 2, dim.height / 2 - this.getSize().height / 2); + } + + private void onOK() { + if (!validator.validate()) { + return; + } + generateFiles(); + this.setVisible(false); + } + + private void generateFiles() { + PsiDirectory baseDir = detectedPackageName != null ? this.initialBaseDir.getParent() : this.initialBaseDir; + ModuleDirectoriesData moduleDirectoriesData = directoryGenerator.createModuleDirectories(getPackageName(), getModuleName(), baseDir); + Properties attributes = getAttributes(); + PsiFile composerJson = fileFromTemplateGenerator.generate(ComposerJson.getInstance(), attributes, moduleDirectoriesData.getModuleDirectory(), NewModuleAction.ACTION_NAME); + if (composerJson == null) { + return; + } + PsiFile registrationPhp = fileFromTemplateGenerator.generate(RegistrationPhp.getInstance(), attributes, moduleDirectoriesData.getModuleDirectory(), NewModuleAction.ACTION_NAME); + if (registrationPhp == null) { + return; + } + fileFromTemplateGenerator.generate(ModuleXml.getInstance(), attributes, moduleDirectoriesData.getModuleEtcDirectory(), NewModuleAction.ACTION_NAME); + } + + public String getPackageName() { + if (detectedPackageName != null) { + return detectedPackageName; + } + return this.packageName.getText().trim(); + } + + public String getModuleName() { + return this.moduleName.getText().trim(); + } + + public String getModuleDescription() { + return this.moduleDescription.getText().trim(); + } + + public String getModuleVersion() { + return this.moduleVersion.getText().trim(); + } + + private void onCancel() { + this.setVisible(false); + } + + public static void open(@NotNull Project project, @NotNull PsiDirectory initialBaseDir, @Nullable PsiFile file, @Nullable IdeView view, @Nullable Editor editor) { + NewMagentoModuleDialog dialog = new NewMagentoModuleDialog(project, initialBaseDir, file, view, editor); + dialog.pack(); + dialog.setVisible(true); + } + + private Properties getAttributes() { + Properties attributes = new Properties(); + this.fillAttributes(attributes); + return attributes; + } + + private void fillAttributes(Properties attributes) { + attributes.setProperty("PACKAGE", getPackageName()); + attributes.setProperty("MODULE_NAME", getModuleName()); + attributes.setProperty("MODULE_DESCRIPTION", getModuleDescription()); + attributes.setProperty("COMPOSER_PACKAGE_NAME", getComposerPackageName()); + attributes.setProperty("MODULE_VERSION", getModuleVersion()); + } + + @NotNull + private String getComposerPackageName() { + return camelCaseToHyphen.convert(getPackageName()) + .concat("/") + .concat(camelCaseToHyphen.convert(getModuleName())); + } +} diff --git a/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/NewMagentoModuleDialogValidator.java b/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/NewMagentoModuleDialogValidator.java new file mode 100644 index 000000000..9c6c05fe3 --- /dev/null +++ b/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/NewMagentoModuleDialogValidator.java @@ -0,0 +1,66 @@ +package com.magento.idea.magento2plugin.actions.generation.dialog.validator; + +import com.magento.idea.magento2plugin.actions.generation.dialog.NewMagentoModuleDialog; +import com.magento.idea.magento2plugin.util.Regex; +import javax.swing.*; + +public class NewMagentoModuleDialogValidator { + private static NewMagentoModuleDialogValidator INSTANCE = null; + private NewMagentoModuleDialog dialog; + + public static NewMagentoModuleDialogValidator getInstance(NewMagentoModuleDialog dialog) { + if (null == INSTANCE) { + INSTANCE = new NewMagentoModuleDialogValidator(); + } + INSTANCE.dialog = dialog; + return INSTANCE; + } + + public boolean validate() + { + String errorTitle = "Error"; + String packageName = dialog.getPackageName(); + if (packageName.length() == 0) { + JOptionPane.showMessageDialog(null, "Package Name must not be empty.", errorTitle, JOptionPane.ERROR_MESSAGE); + return false; + } + + if (!packageName.matches(Regex.ALPHANUMERIC)) { + JOptionPane.showMessageDialog(null, "Package Name must contain letters and numbers only.", errorTitle, JOptionPane.ERROR_MESSAGE); + return false; + } + + if (!Character.isUpperCase(packageName.charAt(0)) && !Character.isDigit(packageName.charAt(0))) { + JOptionPane.showMessageDialog(null, "Package Name must start from a number or a capital letter", errorTitle, JOptionPane.ERROR_MESSAGE); + return false; + } + + String moduleName = dialog.getModuleName(); + if (moduleName.length() == 0) { + JOptionPane.showMessageDialog(null, "Module Name must not be empty.", errorTitle, JOptionPane.ERROR_MESSAGE); + return false; + } + + if (!moduleName.matches(Regex.ALPHANUMERIC)) { + JOptionPane.showMessageDialog(null, "Module Name must contain letters and numbers only.", errorTitle, JOptionPane.ERROR_MESSAGE); + return false; + } + + if (!Character.isUpperCase(moduleName.charAt(0)) && !Character.isDigit(moduleName.charAt(0))) { + JOptionPane.showMessageDialog(null, "Module Name must start from a number or a capital letter", errorTitle, JOptionPane.ERROR_MESSAGE); + return false; + } + + if (dialog.getModuleVersion().length() == 0) { + JOptionPane.showMessageDialog(null, "Module Version must not be empty.", errorTitle, JOptionPane.ERROR_MESSAGE); + return false; + } + + if (dialog.getModuleDescription().length() == 0) { + JOptionPane.showMessageDialog(null, "Module Version must not be empty.", errorTitle, JOptionPane.ERROR_MESSAGE); + return false; + } + + return true; + } +} diff --git a/src/com/magento/idea/magento2plugin/actions/generation/generator/DirectoryGenerator.java b/src/com/magento/idea/magento2plugin/actions/generation/generator/DirectoryGenerator.java new file mode 100644 index 000000000..a2037adaa --- /dev/null +++ b/src/com/magento/idea/magento2plugin/actions/generation/generator/DirectoryGenerator.java @@ -0,0 +1,33 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +package com.magento.idea.magento2plugin.actions.generation.generator; + +import com.intellij.openapi.application.WriteAction; +import com.intellij.psi.PsiDirectory; +import com.magento.idea.magento2plugin.actions.generation.generator.data.ModuleDirectoriesData; +import org.jetbrains.annotations.NotNull; + +public class DirectoryGenerator { + private static DirectoryGenerator INSTANCE = null; + + public static DirectoryGenerator getInstance() { + if (null == INSTANCE) { + INSTANCE = new DirectoryGenerator(); + } + return INSTANCE; + } + + public ModuleDirectoriesData createModuleDirectories(@NotNull String packageName, @NotNull String moduleName, @NotNull PsiDirectory baseDirectory){ + PsiDirectory packageDirectory = findOrCreateSubdirectory(baseDirectory, packageName); + PsiDirectory moduleDirectory = findOrCreateSubdirectory(packageDirectory, moduleName); + PsiDirectory moduleEtcDirectory = findOrCreateSubdirectory(moduleDirectory, "etc"); + return new ModuleDirectoriesData(moduleDirectory, moduleEtcDirectory); + } + + public PsiDirectory findOrCreateSubdirectory(@NotNull PsiDirectory parent, @NotNull String subdirName) { + final PsiDirectory sub = parent.findSubdirectory(subdirName); + return sub == null ? WriteAction.compute(() -> parent.createSubdirectory(subdirName)) : sub; + } +} diff --git a/src/com/magento/idea/magento2plugin/actions/generation/generator/FileFromTemplateGenerator.java b/src/com/magento/idea/magento2plugin/actions/generation/generator/FileFromTemplateGenerator.java new file mode 100644 index 000000000..83d270524 --- /dev/null +++ b/src/com/magento/idea/magento2plugin/actions/generation/generator/FileFromTemplateGenerator.java @@ -0,0 +1,122 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +package com.magento.idea.magento2plugin.actions.generation.generator; + +import com.intellij.ide.fileTemplates.DefaultTemplatePropertiesProvider; +import com.intellij.ide.fileTemplates.FileTemplate; +import com.intellij.ide.fileTemplates.FileTemplateManager; +import com.intellij.lang.Language; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.command.CommandProcessor; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.Ref; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiDirectory; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiFileFactory; +import com.intellij.psi.codeStyle.CodeStyleManager; +import com.intellij.util.IncorrectOperationException; +import com.magento.idea.magento2plugin.magento.files.ModuleFileInterface; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import java.io.File; +import java.io.IOException; +import java.util.Iterator; +import java.util.List; +import java.util.Properties; + +public class FileFromTemplateGenerator { + private static FileFromTemplateGenerator INSTANCE = null; + private Project project; + + public static FileFromTemplateGenerator getInstance(Project project) { + if (null == INSTANCE) { + INSTANCE = new FileFromTemplateGenerator(); + } + INSTANCE.project = project; + return INSTANCE; + } + + @Nullable + public PsiFile generate(@NotNull ModuleFileInterface moduleFile, @NotNull Properties attributes, @NotNull PsiDirectory baseDir, @NotNull String actionName) { + Ref<PsiFile> fileRef = new Ref(null); + Ref<String> exceptionRef = new Ref(null); + String filePath = baseDir.getText().concat("/").concat(moduleFile.getFileName()); + CommandProcessor.getInstance().executeCommand(project, () -> { + Runnable run = () -> { + try { + PsiFile file = createFile(moduleFile, filePath, baseDir, attributes); + if (file != null) { + fileRef.set(file); + } + } catch (IncorrectOperationException | IOException var9) { + exceptionRef.set(var9.getMessage()); + } + + }; + ApplicationManager.getApplication().runWriteAction(run); + }, actionName, null); + if (!exceptionRef.isNull()) { + Messages.showErrorDialog(exceptionRef.get(), actionName); + return null; + } else { + return fileRef.get(); + } + } + + @Nullable + private PsiFile createFile(@NotNull ModuleFileInterface moduleFile, @NotNull String filePath, @NotNull PsiDirectory baseDir, @NotNull Properties attributes) throws IOException, IncorrectOperationException { + List<String> path = StringUtil.split(filePath.replace(File.separator, "/"), "/"); + String fileName = path.get(path.size() - 1); + PsiFile fileTemplate = createFileFromTemplate(getTestTemplateManager(), baseDir, moduleFile.getTemplate(), attributes, fileName, moduleFile.getLanguage()); + if (fileTemplate == null) { + throw new IncorrectOperationException("Template not found!"); + } else { + PsiElement file; + + file = baseDir.add(fileTemplate); + if (file instanceof PsiFile) { + return (PsiFile)file; + } else { + return null; + } + } + } + + public PsiFile createFileFromTemplate(@NotNull FileTemplateManager templateManager, @NotNull PsiDirectory directory, @NotNull String templateName, @NotNull Properties properties, @NotNull String fileName, @NotNull Language language) throws IOException { + FileTemplate fileTemplate = templateManager.getInternalTemplate(templateName); + fillDefaultProperties(templateManager, properties, directory); + String fileTemplateText = fileTemplate.getText(properties); + PsiFile file = PsiFileFactory.getInstance(project).createFileFromText(fileName, language, fileTemplateText, true, false); + if (fileTemplate.isReformatCode()) { + CodeStyleManager.getInstance(project).reformat(file); + } + + return file; + } + + public void fillDefaultProperties(@NotNull FileTemplateManager templateManager, @NotNull Properties props, @NotNull PsiDirectory directory) { + Properties hardCodedProperties = templateManager.getDefaultProperties(); + Iterator iterator = hardCodedProperties.keySet().iterator(); + + while(iterator.hasNext()) { + Object propertyKey = iterator.next(); + props.setProperty((String)propertyKey, hardCodedProperties.getProperty((String)propertyKey)); + } + + iterator = DefaultTemplatePropertiesProvider.EP_NAME.getExtensionList().iterator(); + + while(iterator.hasNext()) { + DefaultTemplatePropertiesProvider provider = (DefaultTemplatePropertiesProvider)iterator.next(); + provider.fillProperties(directory, props); + } + } + + public FileTemplateManager getTestTemplateManager() { + return FileTemplateManager.getInstance(project); + } +} diff --git a/src/com/magento/idea/magento2plugin/actions/generation/generator/data/ModuleDirectoriesData.java b/src/com/magento/idea/magento2plugin/actions/generation/generator/data/ModuleDirectoriesData.java new file mode 100644 index 000000000..1b02cdef5 --- /dev/null +++ b/src/com/magento/idea/magento2plugin/actions/generation/generator/data/ModuleDirectoriesData.java @@ -0,0 +1,30 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +package com.magento.idea.magento2plugin.actions.generation.generator.data; + +import com.intellij.psi.PsiDirectory; +import org.jetbrains.annotations.NotNull; + +public class ModuleDirectoriesData { + @NotNull + private final PsiDirectory moduleDirectory; + @NotNull + private final PsiDirectory moduleEtc; + + public ModuleDirectoriesData(@NotNull PsiDirectory moduleDirectory, @NotNull PsiDirectory moduleEtc) { + this.moduleDirectory = moduleDirectory; + this.moduleEtc = moduleEtc; + } + + @NotNull + public PsiDirectory getModuleDirectory() { + return moduleDirectory; + } + + @NotNull + public PsiDirectory getModuleEtcDirectory() { + return moduleEtc; + } +} diff --git a/src/com/magento/idea/magento2plugin/magento/files/ComposerJson.java b/src/com/magento/idea/magento2plugin/magento/files/ComposerJson.java new file mode 100644 index 000000000..98b05a265 --- /dev/null +++ b/src/com/magento/idea/magento2plugin/magento/files/ComposerJson.java @@ -0,0 +1,36 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +package com.magento.idea.magento2plugin.magento.files; + +import com.intellij.json.JsonLanguage; +import com.intellij.lang.Language; + +public class ComposerJson implements ModuleFileInterface { + public static String FILE_NAME = "composer.json"; + public static String TEMPLATE = "Magento Module Composer"; + private static ComposerJson INSTANCE = null; + + public static ComposerJson getInstance() { + if (null == INSTANCE) { + INSTANCE = new ComposerJson(); + } + return INSTANCE; + } + + @Override + public String getFileName() { + return FILE_NAME; + } + + @Override + public String getTemplate() { + return TEMPLATE; + } + + @Override + public Language getLanguage() { + return JsonLanguage.INSTANCE; + } +} diff --git a/src/com/magento/idea/magento2plugin/magento/files/ModuleFileInterface.java b/src/com/magento/idea/magento2plugin/magento/files/ModuleFileInterface.java new file mode 100644 index 000000000..918e3b0f7 --- /dev/null +++ b/src/com/magento/idea/magento2plugin/magento/files/ModuleFileInterface.java @@ -0,0 +1,13 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +package com.magento.idea.magento2plugin.magento.files; + +import com.intellij.lang.Language; + +public interface ModuleFileInterface { + public String getFileName(); + public String getTemplate(); + public Language getLanguage(); +} diff --git a/src/com/magento/idea/magento2plugin/magento/files/ModuleXml.java b/src/com/magento/idea/magento2plugin/magento/files/ModuleXml.java new file mode 100644 index 000000000..8140ec15d --- /dev/null +++ b/src/com/magento/idea/magento2plugin/magento/files/ModuleXml.java @@ -0,0 +1,36 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +package com.magento.idea.magento2plugin.magento.files; + +import com.intellij.lang.Language; +import com.intellij.lang.xml.XMLLanguage; + +public class ModuleXml implements ModuleFileInterface { + public static String FILE_NAME = "module.xml"; + public static String TEMPLATE = "Magento Module XML"; + private static ModuleXml INSTANCE = null; + + public static ModuleXml getInstance() { + if (null == INSTANCE) { + INSTANCE = new ModuleXml(); + } + return INSTANCE; + } + + @Override + public String getFileName() { + return FILE_NAME; + } + + @Override + public String getTemplate() { + return TEMPLATE; + } + + @Override + public Language getLanguage() { + return XMLLanguage.INSTANCE; + } +} diff --git a/src/com/magento/idea/magento2plugin/magento/files/RegistrationPhp.java b/src/com/magento/idea/magento2plugin/magento/files/RegistrationPhp.java new file mode 100644 index 000000000..715599dc5 --- /dev/null +++ b/src/com/magento/idea/magento2plugin/magento/files/RegistrationPhp.java @@ -0,0 +1,36 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +package com.magento.idea.magento2plugin.magento.files; + +import com.intellij.lang.Language; +import com.jetbrains.php.lang.PhpLanguage; + +public class RegistrationPhp implements ModuleFileInterface { + public static String FILE_NAME = "registration.php"; + public static String TEMPLATE = "Magento Module Registration Php"; + private static RegistrationPhp INSTANCE = null; + + public static RegistrationPhp getInstance() { + if (null == INSTANCE) { + INSTANCE = new RegistrationPhp(); + } + return INSTANCE; + } + + @Override + public String getFileName() { + return FILE_NAME; + } + + @Override + public String getTemplate() { + return TEMPLATE; + } + + @Override + public Language getLanguage() { + return PhpLanguage.INSTANCE; + } +} diff --git a/src/com/magento/idea/magento2plugin/magento/packages/MagentoPackages.java b/src/com/magento/idea/magento2plugin/magento/packages/MagentoPackages.java new file mode 100644 index 000000000..4df54a8f3 --- /dev/null +++ b/src/com/magento/idea/magento2plugin/magento/packages/MagentoPackages.java @@ -0,0 +1,9 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +package com.magento.idea.magento2plugin.magento.packages; + +public class MagentoPackages { + public static String PACKAGES_ROOT = "app/code"; +} diff --git a/src/com/magento/idea/magento2plugin/util/CamelCaseToHyphen.java b/src/com/magento/idea/magento2plugin/util/CamelCaseToHyphen.java new file mode 100644 index 000000000..7ee209d2a --- /dev/null +++ b/src/com/magento/idea/magento2plugin/util/CamelCaseToHyphen.java @@ -0,0 +1,31 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +package com.magento.idea.magento2plugin.util; + +import java.lang.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class CamelCaseToHyphen { + private static CamelCaseToHyphen INSTANCE = null; + public static CamelCaseToHyphen getInstance() { + if (null == INSTANCE) { + INSTANCE = new CamelCaseToHyphen(); + } + return INSTANCE; + } + + public String convert(String string) { + String regex = "(?=[A-Z][a-z])"; + String subst = "-"; + + Pattern pattern = Pattern.compile(regex); + Matcher matcher = pattern.matcher(string); + + String result = matcher.replaceAll(subst); + + return result.toLowerCase().substring(1); + } +} diff --git a/src/com/magento/idea/magento2plugin/util/Regex.java b/src/com/magento/idea/magento2plugin/util/Regex.java new file mode 100644 index 000000000..5fe10d817 --- /dev/null +++ b/src/com/magento/idea/magento2plugin/util/Regex.java @@ -0,0 +1,11 @@ +/** + * Copyright © Dmytro Kvashnin. All rights reserved. + * See COPYING.txt for license details. + */ +package com.magento.idea.magento2plugin.util; + +public class Regex { + + public static final String ALPHANUMERIC + = "[a-zA-Z0-9]*"; +} From 3c81e2503d609fbf23986770a45abb55de1d0a9b Mon Sep 17 00:00:00 2001 From: Vitaliy Boyko <v.boyko@atwix.com> Date: Tue, 24 Mar 2020 19:55:38 +0200 Subject: [PATCH 2/3] Static fixes --- resources/META-INF/plugin.xml | 2 -- .../dialog/validator/NewMagentoModuleDialogValidator.java | 4 ++++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/resources/META-INF/plugin.xml b/resources/META-INF/plugin.xml index 77c70843e..6780db8c7 100644 --- a/resources/META-INF/plugin.xml +++ b/resources/META-INF/plugin.xml @@ -108,7 +108,6 @@ groupName="Magento" enabledByDefault="true" level="ERROR" implementationClass="com.magento.idea.magento2plugin.inspections.php.PluginInspection"/> <libraryRoot id=".phpstorm.meta.php" path=".phpstorm.meta.php/" runtime="false"/> - </extensions> <application-components> @@ -123,5 +122,4 @@ <!-- Add your actions here --> </actions> - </idea-plugin> diff --git a/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/NewMagentoModuleDialogValidator.java b/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/NewMagentoModuleDialogValidator.java index 9c6c05fe3..16d64a9da 100644 --- a/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/NewMagentoModuleDialogValidator.java +++ b/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/NewMagentoModuleDialogValidator.java @@ -1,3 +1,7 @@ +/* + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ package com.magento.idea.magento2plugin.actions.generation.dialog.validator; import com.magento.idea.magento2plugin.actions.generation.dialog.NewMagentoModuleDialog; From c3a1c7a3b9c68e988d709370fb8782dee43ab9de Mon Sep 17 00:00:00 2001 From: Vitaliy Boyko <v.boyko@atwix.com> Date: Tue, 24 Mar 2020 20:13:37 +0200 Subject: [PATCH 3/3] Fixed templates --- resources/META-INF/plugin.xml | 4 ++++ resources/fileTemplates/internal/Magento Module Composer.html | 4 ---- .../internal/Magento Module Registration Php.html | 4 ---- resources/fileTemplates/internal/Magento Module XML.html | 4 ---- .../{Magento Module XML.xml.ft => Magento Module Xml.xml.ft} | 0 .../magento/idea/magento2plugin/magento/files/ModuleXml.java | 2 +- 6 files changed, 5 insertions(+), 13 deletions(-) delete mode 100644 resources/fileTemplates/internal/Magento Module Composer.html delete mode 100644 resources/fileTemplates/internal/Magento Module Registration Php.html delete mode 100644 resources/fileTemplates/internal/Magento Module XML.html rename resources/fileTemplates/internal/{Magento Module XML.xml.ft => Magento Module Xml.xml.ft} (100%) diff --git a/resources/META-INF/plugin.xml b/resources/META-INF/plugin.xml index 6780db8c7..d89d27dbd 100644 --- a/resources/META-INF/plugin.xml +++ b/resources/META-INF/plugin.xml @@ -108,6 +108,10 @@ groupName="Magento" enabledByDefault="true" level="ERROR" implementationClass="com.magento.idea.magento2plugin.inspections.php.PluginInspection"/> <libraryRoot id=".phpstorm.meta.php" path=".phpstorm.meta.php/" runtime="false"/> + + <internalFileTemplate name="Magento Module Composer"/> + <internalFileTemplate name="Magento Module Registration Php"/> + <internalFileTemplate name="Magento Module Xml"/> </extensions> <application-components> diff --git a/resources/fileTemplates/internal/Magento Module Composer.html b/resources/fileTemplates/internal/Magento Module Composer.html deleted file mode 100644 index 6bfc7988e..000000000 --- a/resources/fileTemplates/internal/Magento Module Composer.html +++ /dev/null @@ -1,4 +0,0 @@ -<html> -<body> -</body> -</html> \ No newline at end of file diff --git a/resources/fileTemplates/internal/Magento Module Registration Php.html b/resources/fileTemplates/internal/Magento Module Registration Php.html deleted file mode 100644 index 6bfc7988e..000000000 --- a/resources/fileTemplates/internal/Magento Module Registration Php.html +++ /dev/null @@ -1,4 +0,0 @@ -<html> -<body> -</body> -</html> \ No newline at end of file diff --git a/resources/fileTemplates/internal/Magento Module XML.html b/resources/fileTemplates/internal/Magento Module XML.html deleted file mode 100644 index 6bfc7988e..000000000 --- a/resources/fileTemplates/internal/Magento Module XML.html +++ /dev/null @@ -1,4 +0,0 @@ -<html> -<body> -</body> -</html> \ No newline at end of file diff --git a/resources/fileTemplates/internal/Magento Module XML.xml.ft b/resources/fileTemplates/internal/Magento Module Xml.xml.ft similarity index 100% rename from resources/fileTemplates/internal/Magento Module XML.xml.ft rename to resources/fileTemplates/internal/Magento Module Xml.xml.ft diff --git a/src/com/magento/idea/magento2plugin/magento/files/ModuleXml.java b/src/com/magento/idea/magento2plugin/magento/files/ModuleXml.java index 8140ec15d..9da3070d6 100644 --- a/src/com/magento/idea/magento2plugin/magento/files/ModuleXml.java +++ b/src/com/magento/idea/magento2plugin/magento/files/ModuleXml.java @@ -9,7 +9,7 @@ public class ModuleXml implements ModuleFileInterface { public static String FILE_NAME = "module.xml"; - public static String TEMPLATE = "Magento Module XML"; + public static String TEMPLATE = "Magento Module Xml"; private static ModuleXml INSTANCE = null; public static ModuleXml getInstance() {