diff --git a/resources/META-INF/plugin.xml b/resources/META-INF/plugin.xml
index 45ba1193a..b0cc5b59f 100644
--- a/resources/META-INF/plugin.xml
+++ b/resources/META-INF/plugin.xml
@@ -75,6 +75,7 @@
+
diff --git a/resources/fileTemplates/internal/Magento Layout XML.xml.ft b/resources/fileTemplates/internal/Magento Layout XML.xml.ft
index 46efc847d..76f98fb5e 100644
--- a/resources/fileTemplates/internal/Magento Layout XML.xml.ft
+++ b/resources/fileTemplates/internal/Magento Layout XML.xml.ft
@@ -1,4 +1,10 @@
#parse("XML File Header.xml")
-
+#if (${IS_ADMIN} == "true")
+ #set ($isAdmin = true)
+#else
+ #set ($isAdmin = false)
+#end
+
diff --git a/resources/magento2/common.properties b/resources/magento2/common.properties
index 7270fbea4..01ad830e0 100644
--- a/resources/magento2/common.properties
+++ b/resources/magento2/common.properties
@@ -72,4 +72,5 @@ common.template.type=Email Type
common.diagnostic.reportButtonText=Report Me
common.diagnostic.reportSubmittedTitle=The report is successfully submitted!
common.diagnostic.reportSubmittedMessage=Thank you for submitting your report! We will check it as soon as possible.
+common.layout.filename=Layout File Name
common.targetMethod=Target Method
diff --git a/resources/magento2/validation.properties b/resources/magento2/validation.properties
index 83170d817..e3e52c9c0 100644
--- a/resources/magento2/validation.properties
+++ b/resources/magento2/validation.properties
@@ -45,3 +45,5 @@ validator.dbSchema.invalidColumnType=Invalid ''{0}'' column type specified
validator.arrayValuesDialog.invalidValueForRowWithName=Invalid value ''{0}'' specified for the row with name ''{1}''
validator.arrayValuesDialog.namesMustBeUnique=Duplicated items names
validator.arrayValuesDialog.nameMustNotBeEmpty=The array name cannot be empty
+validator.layoutNameRuleInvalid=The layout name is invalid
+validator.layoutNameUnderscoreQtyInvalid=Wrong layout name, please check
diff --git a/src/com/magento/idea/magento2plugin/actions/context/xml/NewLayoutXmlAction.java b/src/com/magento/idea/magento2plugin/actions/context/xml/NewLayoutXmlAction.java
new file mode 100644
index 000000000..04e3cc15b
--- /dev/null
+++ b/src/com/magento/idea/magento2plugin/actions/context/xml/NewLayoutXmlAction.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright © Magento, Inc. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+package com.magento.idea.magento2plugin.actions.context.xml;
+
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.actionSystem.LangDataKeys;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiDirectory;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.magento.idea.magento2plugin.MagentoIcons;
+import com.magento.idea.magento2plugin.actions.generation.dialog.NewLayoutTemplateDialog;
+import com.magento.idea.magento2plugin.magento.files.LayoutXml;
+import com.magento.idea.magento2plugin.magento.packages.Areas;
+import com.magento.idea.magento2plugin.magento.packages.ComponentType;
+import com.magento.idea.magento2plugin.magento.packages.Package;
+import com.magento.idea.magento2plugin.project.Settings;
+import com.magento.idea.magento2plugin.util.magento.GetMagentoModuleUtil;
+import java.util.Arrays;
+import java.util.List;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class NewLayoutXmlAction extends AnAction {
+
+ public static final String ACTION_NAME = "Magento 2 Layout File";
+ public static final String ACTION_DESCRIPTION = "Create a new Magento 2 layout.xml file";
+ private PsiDirectory targetDirectory;
+
+ /**
+ * New layout.xml file generation action constructor.
+ */
+ public NewLayoutXmlAction() {
+ super(ACTION_NAME, ACTION_DESCRIPTION, MagentoIcons.MODULE);
+ }
+
+ @Override
+ @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"})
+ public void update(final @NotNull AnActionEvent event) {
+ setIsAvailableForEvent(event, false);
+ final Project project = event.getProject();
+
+ if (project == null || !Settings.isEnabled(project)) {
+ return;
+ }
+ final DataContext context = event.getDataContext();
+ final PsiElement targetElement = LangDataKeys.PSI_ELEMENT.getData(context);
+ final PsiDirectory targetDirectoryCandidate = resolveTargetDirectory(targetElement);
+
+ if (targetDirectoryCandidate == null) {
+ return;
+ }
+ final GetMagentoModuleUtil.MagentoModuleData moduleData = GetMagentoModuleUtil
+ .getByContext(targetDirectoryCandidate, project);
+
+ if (moduleData == null) {
+ return;
+ }
+ final PsiDirectory viewDir = moduleData.getViewDir();
+
+ if (viewDir == null) {
+ return;
+ }
+ final List allowedDirectories = Arrays.asList(
+ Package.moduleViewDir,
+ Areas.adminhtml.toString(),
+ Areas.frontend.toString()
+ );
+ if (!allowedDirectories.contains(targetDirectoryCandidate.getName())
+ || !moduleData.getType().equals(ComponentType.module)) {
+ return;
+ }
+ final PsiDirectory parentDir = targetDirectoryCandidate.getParentDirectory();
+
+ if (parentDir == null
+ || !targetDirectoryCandidate.equals(viewDir) && !parentDir.equals(viewDir)) {
+ return;
+ }
+ targetDirectory = targetDirectoryCandidate;
+ setIsAvailableForEvent(event, true);
+ }
+
+ @Override
+ public void actionPerformed(final @NotNull AnActionEvent event) {
+ if (event.getProject() == null || targetDirectory == null) {
+ return;
+ }
+
+ NewLayoutTemplateDialog.open(event.getProject(), targetDirectory);
+ }
+
+ /**
+ * Set is action available for event.
+ *
+ * @param event AnActionEvent
+ * @param isAvailable boolean
+ */
+ private void setIsAvailableForEvent(
+ final @NotNull AnActionEvent event,
+ final boolean isAvailable
+ ) {
+ event.getPresentation().setVisible(isAvailable);
+ event.getPresentation().setEnabled(isAvailable);
+ }
+
+ /**
+ * Resolve target directory.
+ *
+ * @param targetElement PsiElement
+ *
+ * @return PsiDirectory
+ */
+ private @Nullable PsiDirectory resolveTargetDirectory(final PsiElement targetElement) {
+ PsiDirectory target = null;
+
+ if (targetElement instanceof PsiDirectory) {
+ target = (PsiDirectory) targetElement;
+ } else if (targetElement instanceof PsiFile) {
+ target = ((PsiFile) targetElement).getContainingDirectory();
+ }
+
+ if (target == null) {
+ return null;
+ }
+
+ if (LayoutXml.PARENT_DIR.equals(target.getName())) {
+ target = target.getParentDirectory();
+ }
+
+ return target;
+ }
+}
diff --git a/src/com/magento/idea/magento2plugin/actions/generation/data/LayoutXmlData.java b/src/com/magento/idea/magento2plugin/actions/generation/data/LayoutXmlData.java
index 3be8921b5..c9727dbb1 100644
--- a/src/com/magento/idea/magento2plugin/actions/generation/data/LayoutXmlData.java
+++ b/src/com/magento/idea/magento2plugin/actions/generation/data/LayoutXmlData.java
@@ -39,6 +39,30 @@ public LayoutXmlData(
this.uiComponentName = uiComponentName;
}
+ /**
+ * Layout XML data.
+ *
+ * @param area String
+ * @param route String
+ * @param moduleName String
+ * @param controllerName String
+ * @param actionName String
+ */
+ public LayoutXmlData(
+ final String area,
+ final String route,
+ final String moduleName,
+ final String controllerName,
+ final String actionName
+ ) {
+ this.area = area;
+ this.route = route;
+ this.moduleName = moduleName;
+ this.controllerName = controllerName;
+ this.actionName = actionName;
+ this.uiComponentName = "";
+ }
+
public String getArea() {
return area;
}
diff --git a/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewLayoutTemplateDialog.form b/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewLayoutTemplateDialog.form
new file mode 100644
index 000000000..f5c0221d5
--- /dev/null
+++ b/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewLayoutTemplateDialog.form
@@ -0,0 +1,113 @@
+
+
diff --git a/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewLayoutTemplateDialog.java b/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewLayoutTemplateDialog.java
new file mode 100644
index 000000000..9dc5507af
--- /dev/null
+++ b/src/com/magento/idea/magento2plugin/actions/generation/dialog/NewLayoutTemplateDialog.java
@@ -0,0 +1,246 @@
+/*
+ * Copyright © Magento, Inc. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+package com.magento.idea.magento2plugin.actions.generation.dialog;
+
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.ComboBox;
+import com.intellij.psi.PsiDirectory;
+import com.magento.idea.magento2plugin.actions.context.xml.NewLayoutXmlAction;
+import com.magento.idea.magento2plugin.actions.generation.data.LayoutXmlData;
+import com.magento.idea.magento2plugin.actions.generation.data.ui.ComboBoxItemData;
+import com.magento.idea.magento2plugin.actions.generation.dialog.util.DialogFieldErrorUtil;
+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.IdentifierRule;
+import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.NotEmptyRule;
+import com.magento.idea.magento2plugin.actions.generation.generator.LayoutXmlTemplateGenerator;
+import com.magento.idea.magento2plugin.bundles.ValidatorBundle;
+import com.magento.idea.magento2plugin.magento.packages.Areas;
+import com.magento.idea.magento2plugin.util.magento.GetModuleNameByDirectoryUtil;
+import java.awt.event.KeyEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.util.HashMap;
+import java.util.Map;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.KeyStroke;
+import org.jetbrains.annotations.NotNull;
+
+public class NewLayoutTemplateDialog extends AbstractDialog {
+
+ private static final String LAYOUT_NAME = "Layout Name";
+
+ private final @NotNull Project project;
+ private final String moduleName;
+ private final PsiDirectory directory;
+
+ private JPanel contentPane;
+ private JButton buttonOK;
+ private JButton buttonCancel;
+
+ @FieldValidation(rule = RuleRegistry.NOT_EMPTY, message = {NotEmptyRule.MESSAGE, LAYOUT_NAME})
+ @FieldValidation(rule = RuleRegistry.LAYOUT_NAME,
+ message = {IdentifierRule.MESSAGE, LAYOUT_NAME})
+ private JTextField layoutName;
+
+ private JComboBox area;
+
+ // labels
+ private JLabel layoutNameLabel; // NOPMD
+ private JLabel areaLabel; // NOPMD
+ private JLabel layoutNameErrorMessage; // NOPMD
+
+ /**
+ * NewLayoutTemplateDialog constructor.
+ *
+ * @param project Project
+ * @param directory PsiDirectory
+ */
+ public NewLayoutTemplateDialog(
+ final @NotNull Project project,
+ final @NotNull PsiDirectory directory
+ ) {
+ super();
+
+ this.project = project;
+ this.moduleName = GetModuleNameByDirectoryUtil.execute(directory, project);
+ this.directory = directory;
+
+ setContentPane(contentPane);
+ setModal(true);
+ setTitle(NewLayoutXmlAction.ACTION_DESCRIPTION);
+ getRootPane().setDefaultButton(buttonOK);
+
+ buttonOK.addActionListener(event -> onOK());
+ buttonCancel.addActionListener(event -> onCancel());
+
+ // call onCancel() when cross is clicked
+ setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
+ addWindowListener(new WindowAdapter() {
+ @Override
+ public void windowClosing(final WindowEvent event) {
+ onCancel();
+ }
+ });
+
+ // call onCancel() on ESCAPE
+ contentPane.registerKeyboardAction(
+ event -> onCancel(),
+ KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0),
+ JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT
+ );
+
+ addComponentListener(new FocusOnAFieldListener(() -> area.requestFocusInWindow()));
+ autoSelectCurrentArea();
+ }
+
+ /**
+ * Open a new layout template dialog.
+ *
+ * @param project Project
+ * @param directory Directory
+ */
+ public static void open(
+ final @NotNull Project project,
+ final @NotNull PsiDirectory directory
+ ) {
+ final NewLayoutTemplateDialog dialog = new NewLayoutTemplateDialog(project, directory);
+ dialog.pack();
+ dialog.centerDialog(dialog);
+ dialog.setVisible(true);
+ }
+
+ /**
+ * Fire generation process if all fields are valid.
+ */
+ private void onOK() {
+ if (validateFormFields() && isUnderscoreCorrect()) {
+ final String[] layoutNameParts = getLayoutNameParts();
+ new LayoutXmlTemplateGenerator(
+ new LayoutXmlData(
+ getArea(),
+ layoutNameParts[0],
+ moduleName,
+ layoutNameParts[1],
+ layoutNameParts[2]
+ ),
+ project
+ ).generate(NewLayoutXmlAction.ACTION_NAME, true);
+ exit();
+ }
+ }
+
+ /**
+ * Create custom components and fill their entries.
+ */
+ @SuppressWarnings({"PMD.UnusedPrivateMethod", "PMD.AvoidInstantiatingObjectsInLoops"})
+ private void createUIComponents() {
+ area = new ComboBox<>();
+
+ for (final Areas areaEntry : Areas.values()) {
+ if (!areaEntry.equals(Areas.adminhtml) && !areaEntry.equals(Areas.frontend)) {
+ continue;
+ }
+ area.addItem(new ComboBoxItemData(areaEntry.toString(), areaEntry.toString()));
+ }
+ }
+
+ private void autoSelectCurrentArea() {
+ final String selectedDirName = directory.getName();
+ final Map areaIndexMap = new HashMap<>();
+
+ for (int i = 0; i < area.getItemCount(); i++) {
+ final ComboBoxItemData item = area.getItemAt(i);
+ areaIndexMap.put(item.getKey(), i);
+ }
+
+ if (areaIndexMap.containsKey(selectedDirName)) {
+ area.setSelectedIndex(areaIndexMap.get(selectedDirName));
+ }
+ }
+
+ /**
+ * Get parts of inserted layout name.
+ *
+ * @return String[]
+ */
+ private String[] getLayoutNameParts() {
+
+ final String[] layoutNameParts = layoutName.getText().trim().split("_");
+ String routeName = "";
+ String controllerName = "";
+ String actionName = "";
+
+ if (layoutNameParts.length >= 1) { // NOPMD
+ routeName = layoutNameParts[0];
+ }
+
+ if (layoutNameParts.length == 3) { // NOPMD
+ controllerName = layoutNameParts[1];
+ actionName = layoutNameParts[2];
+ }
+
+ return new String[]{routeName, controllerName, actionName};
+ }
+
+ /**
+ * Check is count of underscore is correct in layout name.
+ *
+ * @return boolean
+ */
+ private boolean isUnderscoreCorrect() {
+ final String name = layoutName.getText().trim();
+
+ if (name.contains("_")) {
+ final int count = countUnderscore(name);
+
+ if (count != 0 && count != 2) {
+ DialogFieldErrorUtil.showErrorMessageForField(
+ layoutName,
+ layoutNameErrorMessage,
+ new ValidatorBundle()
+ .message("validator.layoutNameUnderscoreQtyInvalid")
+ );
+
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Count underscore symbols in string.
+ *
+ * @param name String
+ * @return int
+ */
+ private int countUnderscore(final String name) {
+ int count = 0;
+
+ for (int i = 0; i < name.length(); i++) {
+ if (name.charAt(i) == '_') { //NOPMD
+ count++;
+ }
+ }
+
+ return count;
+ }
+
+ /**
+ * Get area.
+ *
+ * @return String
+ */
+ private String getArea() {
+ return area.getSelectedItem().toString();
+ }
+}
diff --git a/src/com/magento/idea/magento2plugin/actions/generation/dialog/util/DialogFieldErrorUtil.java b/src/com/magento/idea/magento2plugin/actions/generation/dialog/util/DialogFieldErrorUtil.java
index 80c12d54a..385fc1566 100644
--- a/src/com/magento/idea/magento2plugin/actions/generation/dialog/util/DialogFieldErrorUtil.java
+++ b/src/com/magento/idea/magento2plugin/actions/generation/dialog/util/DialogFieldErrorUtil.java
@@ -19,6 +19,7 @@
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.border.Border;
+import javax.swing.text.JTextComponent;
import org.jetbrains.annotations.NotNull;
public final class DialogFieldErrorUtil {
@@ -165,6 +166,40 @@ public void focusLost(final FocusEvent event) {
return true;
}
+ /**
+ * Show error message for field for component.
+ *
+ * @param fieldComponent JTextComponent
+ * @param messageHolder JLabel
+ * @param message String
+ */
+ public static void showErrorMessageForField(
+ final @NotNull JTextComponent fieldComponent,
+ final @NotNull JLabel messageHolder,
+ final @NotNull String message
+ ) {
+ highlightField(fieldComponent);
+
+ messageHolder.setVisible(true);
+ messageHolder.setFont(UIUtil.getLabelFont(UIUtil.FontSize.MINI));
+ messageHolder.setForeground(ERROR_COLOR);
+ messageHolder.setText(message);
+
+ fieldComponent.addFocusListener(new FocusListener() {
+ @Override
+ public void focusGained(final FocusEvent event) {
+ messageHolder.setVisible(false);
+ messageHolder.setText("");
+ }
+
+ @Override
+ public void focusLost(final FocusEvent event) {
+ messageHolder.setVisible(false);
+ messageHolder.setText("");
+ }
+ });
+ }
+
/**
* Get message holder component for field.
*
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 057126732..14a5ee1de 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
@@ -19,6 +19,7 @@
import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.IdentifierRule;
import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.IdentifierWithColonRule;
import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.IdentifierWithForwardSlash;
+import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.LayoutNameRule;
import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.Lowercase;
import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.MenuIdentifierRule;
import com.magento.idea.magento2plugin.actions.generation.dialog.validator.rule.NotEmptyRule;
@@ -57,7 +58,8 @@ public enum RuleRegistry {
NUMERIC(NumericRule.class),
EXTENDED_NUMERIC(ExtendedNumericRule.class),
TABLE_NAME_LENGTH(TableNameLength.class),
- MENU_IDENTIFIER(MenuIdentifierRule.class);
+ MENU_IDENTIFIER(MenuIdentifierRule.class),
+ LAYOUT_NAME(LayoutNameRule.class);
private Class> rule;
diff --git a/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/rule/LayoutNameRule.java b/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/rule/LayoutNameRule.java
new file mode 100644
index 000000000..9af322458
--- /dev/null
+++ b/src/com/magento/idea/magento2plugin/actions/generation/dialog/validator/rule/LayoutNameRule.java
@@ -0,0 +1,24 @@
+/*
+ * 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;
+import org.jetbrains.annotations.NotNull;
+
+public class LayoutNameRule implements ValidationRule {
+
+ public static final String MESSAGE = "validator.layoutNameRuleInvalid";
+ public static final ValidationRule INSTANCE = new LayoutNameRule();
+
+ @Override
+ public boolean check(final @NotNull String value) {
+ return value.matches(RegExUtil.LAYOUT_NAME);
+ }
+
+ public static ValidationRule getInstance() {
+ return INSTANCE;
+ }
+}
diff --git a/src/com/magento/idea/magento2plugin/actions/generation/generator/LayoutXmlTemplateGenerator.java b/src/com/magento/idea/magento2plugin/actions/generation/generator/LayoutXmlTemplateGenerator.java
new file mode 100644
index 000000000..dc95aa570
--- /dev/null
+++ b/src/com/magento/idea/magento2plugin/actions/generation/generator/LayoutXmlTemplateGenerator.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright © Magento, Inc. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+package com.magento.idea.magento2plugin.actions.generation.generator;
+
+import com.intellij.openapi.command.WriteCommandAction;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.xml.XmlFile;
+import com.intellij.psi.xml.XmlTag;
+import com.magento.idea.magento2plugin.actions.generation.data.LayoutXmlData;
+import com.magento.idea.magento2plugin.actions.generation.generator.util.FindOrCreateLayoutXml;
+import java.util.Properties;
+import org.jetbrains.annotations.NotNull;
+
+public class LayoutXmlTemplateGenerator extends FileGenerator {
+
+ private final LayoutXmlData layoutXmlData;
+ private final Project project;
+ private final FindOrCreateLayoutXml findOrCreateLayoutXml;
+
+ /**
+ * Constructor.
+ *
+ * @param layoutXmlData LayoutXmlData
+ * @param project Project
+ */
+ public LayoutXmlTemplateGenerator(
+ final @NotNull LayoutXmlData layoutXmlData,
+ final Project project
+ ) {
+ super(project);
+ this.layoutXmlData = layoutXmlData;
+ this.project = project;
+ this.findOrCreateLayoutXml = new FindOrCreateLayoutXml(project);
+ }
+
+ /**
+ * Creates a module layout file.
+ *
+ * @param actionName String
+ *
+ * @return PsiFile
+ */
+ @Override
+ public PsiFile generate(final @NotNull String actionName) {
+ final XmlFile layoutXml = (XmlFile) findOrCreateLayoutXml.execute(
+ actionName,
+ layoutXmlData.getRoute(),
+ layoutXmlData.getControllerName(),
+ layoutXmlData.getActionName(),
+ layoutXmlData.getModuleName(),
+ layoutXmlData.getArea()
+ );
+
+ if (layoutXml == null) {
+ return null;
+ }
+ final PsiDocumentManager psiDocumentManager =
+ PsiDocumentManager.getInstance(project);
+ final Document document = psiDocumentManager.getDocument(layoutXml);
+
+ if (document == null) {
+ return null;
+ }
+ WriteCommandAction.runWriteCommandAction(project, () -> {
+ final XmlTag rootTag = layoutXml.getRootTag();
+
+ if (rootTag == null) {
+ return;
+ }
+ psiDocumentManager.commitDocument(document);
+ });
+
+ return layoutXml;
+ }
+
+ @Override
+ @SuppressWarnings("PMD.UncommentedEmptyMethodBody")
+ protected void fillAttributes(final Properties attributes) {}
+}
diff --git a/src/com/magento/idea/magento2plugin/actions/generation/generator/util/FindOrCreateLayoutXml.java b/src/com/magento/idea/magento2plugin/actions/generation/generator/util/FindOrCreateLayoutXml.java
index 177059235..d6b2e8055 100644
--- a/src/com/magento/idea/magento2plugin/actions/generation/generator/util/FindOrCreateLayoutXml.java
+++ b/src/com/magento/idea/magento2plugin/actions/generation/generator/util/FindOrCreateLayoutXml.java
@@ -15,12 +15,16 @@
import com.magento.idea.magento2plugin.util.magento.FileBasedIndexUtil;
import java.util.ArrayList;
import java.util.Properties;
+import org.jetbrains.annotations.NotNull;
public final class FindOrCreateLayoutXml {
+
private final Project project;
+ private final Properties properties;
public FindOrCreateLayoutXml(final Project project) {
this.project = project;
+ properties = new Properties();
}
/**
@@ -60,7 +64,12 @@ public PsiFile execute(
parentDirectory = directoryGenerator
.findOrCreateSubdirectory(parentDirectory, fileDirectory);
}
- final LayoutXml layoutXml = new LayoutXml(routeId, controllerName, controllerActionName);
+
+ LayoutXml layoutXml = new LayoutXml(routeId, controllerName, controllerActionName);
+
+ if (controllerName.isEmpty()) {
+ layoutXml = new LayoutXml(routeId);
+ }
PsiFile layoutXmlFile = FileBasedIndexUtil.findModuleViewFile(
layoutXml.getFileName(),
getArea(area),
@@ -69,9 +78,10 @@ public PsiFile execute(
LayoutXml.PARENT_DIR
);
if (layoutXmlFile == null) {
+ fillDefaultAttributes(area, properties);
layoutXmlFile = fileFromTemplateGenerator.generate(
layoutXml,
- new Properties(),
+ properties,
parentDirectory,
actionName
);
@@ -82,4 +92,15 @@ public PsiFile execute(
private Areas getArea(final String area) {
return Areas.getAreaByString(area);
}
+
+ private void fillDefaultAttributes(
+ final @NotNull String area,
+ final @NotNull Properties properties
+ ) {
+ if (Areas.adminhtml.toString().equals(area)) {
+ properties.setProperty("IS_ADMIN", Boolean.TRUE.toString());
+ } else {
+ properties.setProperty("IS_ADMIN", Boolean.FALSE.toString());
+ }
+ }
}
diff --git a/src/com/magento/idea/magento2plugin/magento/files/LayoutXml.java b/src/com/magento/idea/magento2plugin/magento/files/LayoutXml.java
index 37faf3f34..cfe0910a8 100644
--- a/src/com/magento/idea/magento2plugin/magento/files/LayoutXml.java
+++ b/src/com/magento/idea/magento2plugin/magento/files/LayoutXml.java
@@ -11,19 +11,19 @@
@SuppressWarnings({"PMD.FieldNamingConventions", "PMD.ClassNamingConventions"})
public class LayoutXml implements ModuleFileInterface {
- public static String DEFAULT_FILENAME = "default.xml";
- public static String CACHEABLE_ATTRIBUTE_NAME = "cacheable";
- public static String CACHEABLE_ATTRIBUTE_VALUE_FALSE = "false";
- public static String BLOCK_ATTRIBUTE_TAG_NAME = "block";
- public static String REFERENCE_BLOCK_ATTRIBUTE_TAG_NAME = "referenceBlock";
- public static String ROOT_TAG_NAME = "body";
- public static String REFERENCE_CONTAINER_TAG_NAME = "referenceContainer";
- public static String UI_COMPONENT_TAG_NAME = "uiComponent";
- public static String XML_ATTRIBUTE_TEMPLATE = "template";
- public static String ARGUMENTS_TEMPLATE = "Magento Module Class Arguments In Xml";
- public static String PARENT_DIR = "layout";
- public static String NAME_ATTRIBUTE = "name";
- public static String CONTENT_CONTAINER_NAME = "content";
+ public static final String DEFAULT_FILENAME = "default.xml";
+ public static final String CACHEABLE_ATTRIBUTE_NAME = "cacheable";
+ public static final String CACHEABLE_ATTRIBUTE_VALUE_FALSE = "false";
+ public static final String BLOCK_ATTRIBUTE_TAG_NAME = "block";
+ public static final String REFERENCE_BLOCK_ATTRIBUTE_TAG_NAME = "referenceBlock";
+ public static final String ROOT_TAG_NAME = "body";
+ public static final String REFERENCE_CONTAINER_TAG_NAME = "referenceContainer";
+ public static final String UI_COMPONENT_TAG_NAME = "uiComponent";
+ public static final String XML_ATTRIBUTE_TEMPLATE = "template";
+ public static final String ARGUMENTS_TEMPLATE = "Magento Module Class Arguments In Xml";
+ public static final String PARENT_DIR = "layout";
+ public static final String NAME_ATTRIBUTE = "name";
+ public static final String CONTENT_CONTAINER_NAME = "content";
public static String TEMPLATE = "Magento Layout XML";
private String fileName;
@@ -46,6 +46,15 @@ public LayoutXml(final String routeId, final String controllerName, final String
);
}
+ /**
+ * Layout XML file.
+ *
+ * @param routeId String
+ */
+ public LayoutXml(final String routeId) {
+ this.setFileName(routeId + ".xml");
+ }
+
/**
* Get name of file.
*
diff --git a/src/com/magento/idea/magento2plugin/util/RegExUtil.java b/src/com/magento/idea/magento2plugin/util/RegExUtil.java
index 8a8794ba7..2603d8b4b 100644
--- a/src/com/magento/idea/magento2plugin/util/RegExUtil.java
+++ b/src/com/magento/idea/magento2plugin/util/RegExUtil.java
@@ -49,6 +49,9 @@ public class RegExUtil {
public static final String MAGENTO_VERSION
= "(\\d+)\\.(\\d+)\\.(\\d+)[a-zA-Z0-9_\\-]*";
+ public static final String LAYOUT_NAME
+ = "^([a-zA-Z0-9]+){1,}(_[a-zA-Z0-9]+){0,2}";
+
public static class Magento {
public static final String PHP_CLASS
diff --git a/src/com/magento/idea/magento2plugin/util/magento/GetMagentoModuleUtil.java b/src/com/magento/idea/magento2plugin/util/magento/GetMagentoModuleUtil.java
index 207b7eaf4..503844a89 100644
--- a/src/com/magento/idea/magento2plugin/util/magento/GetMagentoModuleUtil.java
+++ b/src/com/magento/idea/magento2plugin/util/magento/GetMagentoModuleUtil.java
@@ -51,6 +51,9 @@ public static MagentoModuleData getByContext(
final PsiDirectory configDir = registrationFile
.getContainingDirectory()
.findSubdirectory(Package.moduleBaseAreaDir);
+ final PsiDirectory viewDir = registrationFile
+ .getContainingDirectory()
+ .findSubdirectory(Package.moduleViewDir);
final Collection methodReferences = PsiTreeUtil.findChildrenOfType(
registrationFile,
MethodReference.class
@@ -76,7 +79,7 @@ public static MagentoModuleData getByContext(
return null;
}
- return new MagentoModuleData(name, resolvedType, configDir);
+ return new MagentoModuleData(name, resolvedType, configDir, viewDir);
}
return null;
@@ -130,6 +133,7 @@ public static class MagentoModuleData {
private final String name;
private final ComponentType type;
private final PsiDirectory configDir;
+ private final PsiDirectory viewDir;
/**
* Default constructor.
@@ -141,7 +145,7 @@ public MagentoModuleData(
final @NotNull String name,
final @NotNull ComponentType type
) {
- this(name, type, null);
+ this(name, type, null, null);
}
/**
@@ -150,15 +154,18 @@ public MagentoModuleData(
* @param name String
* @param type ComponentType
* @param configDir PsiDirectory
+ * @param viewDir PsiDirectory
*/
public MagentoModuleData(
final @NotNull String name,
final @NotNull ComponentType type,
- final @Nullable PsiDirectory configDir
+ final @Nullable PsiDirectory configDir,
+ final @Nullable PsiDirectory viewDir
) {
this.name = name;
this.type = type;
this.configDir = configDir;
+ this.viewDir = viewDir;
}
public String getName() {
@@ -172,5 +179,9 @@ public ComponentType getType() {
public @Nullable PsiDirectory getConfigDir() {
return configDir;
}
+
+ public @Nullable PsiDirectory getViewDir() {
+ return viewDir;
+ }
}
}