diff --git a/build.gradle.kts b/build.gradle.kts
index 4a3a58e..c449662 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -4,7 +4,7 @@ plugins {
id("org.jetbrains.intellij.platform") version "2.7.0"
}
group = "com.sdk.dynform.tools"
-version = "3.2.5"
+version = "3.2.6"
repositories {
mavenCentral()
@@ -38,19 +38,18 @@ intellijPlatform {
}
changeNotes = """
+
[3.2.6]
+
+ - Structural Validation: Introduced a new Annotator to validate that all fields used in
<LAYOUT> and <FILTERS> are correctly defined in their respective <FIELDS> sections.
+ - Generator Logic Update: Refined the column width calculation for NUMBER and DATE types in the ActionBean generator for better XML compatibility.
+ - Improved File Opening: Switched to
FileEditorManagerEx for opening generated files, ensuring better window focus and management in recent IDE versions.
+
[3.2.5]
- Dataset to Form Mapping: Implemented comprehensive reference and completion support for the
FORM-NAME attribute in DATASET > FIELDS > FIELD.
- Smart Field Resolution:
FORM-NAME now correctly resolves to hidden fields in FORM_ENTRY > FIELDS and any named fields within FORM_ENTRY > LAYOUT.
- Recursive Form Scanning: Enhanced field discovery to scan across all form entries in the current and recursively included
.frml files.
- [3.2.4]
-
- - Persistent Generation Directories: Generator now remembers the last used directory for Action Beans and Dataset XMLs independently per project.
- - Auto-Open Generated Files: Added configuration to automatically open newly created files in the editor, with a customizable limit on the number of files.
- - Strict Project-Relative Paths: I18n and XSD configuration now strictly enforces file selection within the project root and stores paths as relative for maximum portability.
- - Smart File Browser: Improved file picker logic to automatically start at the current configured directory if it's within the project, falling back to the project root otherwise.
-
[3.2.3]
- Advanced Data Referencing: Implemented comprehensive reference and completion support for
<FOREIGN-DATASETS> and <MASTER-DATA> structures.
diff --git a/src/main/java/com/sdk/dynform/tools/actionbean/GeneratorServices.java b/src/main/java/com/sdk/dynform/tools/actionbean/GeneratorServices.java
index f5f6793..1b8d299 100644
--- a/src/main/java/com/sdk/dynform/tools/actionbean/GeneratorServices.java
+++ b/src/main/java/com/sdk/dynform/tools/actionbean/GeneratorServices.java
@@ -5,7 +5,7 @@ import com.intellij.database.model.DasTableKey;
import com.intellij.database.psi.DbTable;
import com.intellij.database.util.DasUtil;
import com.intellij.openapi.application.ApplicationManager;
-import com.intellij.openapi.fileEditor.FileEditorManager;
+import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
@@ -62,7 +62,9 @@ public class GeneratorServices {
private void openInEditor(VirtualFile file) {
if (file != null) {
ApplicationManager.getApplication().invokeLater(() -> {
- FileEditorManager.getInstance(project).openFile(file, true);
+ FileEditorManagerEx manager = FileEditorManagerEx.getInstanceEx(project);
+ // Using 3-parameter openFile from FileEditorManagerEx to ensure it's handled correctly
+ manager.openFile(file, true, true);
});
}
}
@@ -224,16 +226,19 @@ public class GeneratorServices {
colModel.put("isPk", primaryKeys.contains(colName));
colModel.put("customType", dataType);
+ int width = column.getDasType().toDataType().getLength();
+
// XML Specific fields
String xmlType = "TEXT";
if ("NUMBER".equals(dataType)) {
xmlType = "NUMBER";
+ width = String.valueOf(width).length();
} else if ("DATE".equals(dataType)) {
xmlType = "DATE";
+ width = "dd/mm/yyyy hh:mm:ss".length();
}
- colModel.put("xmlType", xmlType);
- int width = column.getDasType().toDataType().getLength();
+ colModel.put("xmlType", xmlType);
colModel.put("width", Math.max(width, 0));
// Label generation: Use field comment if available, otherwise fallback to generated key
@@ -254,4 +259,4 @@ public class GeneratorServices {
return model;
}
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/sdk/dynform/tools/dynform/DynFormAnnotator.java b/src/main/java/com/sdk/dynform/tools/dynform/DynFormAnnotator.java
new file mode 100644
index 0000000..4cbe8d6
--- /dev/null
+++ b/src/main/java/com/sdk/dynform/tools/dynform/DynFormAnnotator.java
@@ -0,0 +1,79 @@
+package com.sdk.dynform.tools.dynform;
+
+import com.intellij.lang.annotation.AnnotationHolder;
+import com.intellij.lang.annotation.Annotator;
+import com.intellij.lang.annotation.HighlightSeverity;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.xml.XmlAttribute;
+import com.intellij.psi.xml.XmlAttributeValue;
+import com.intellij.psi.xml.XmlTag;
+import org.jetbrains.annotations.NotNull;
+
+public class DynFormAnnotator implements Annotator {
+ @Override
+ public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) {
+ if (!(element instanceof XmlAttributeValue attrValue)) return;
+
+ PsiElement parent = attrValue.getParent();
+ if (!(parent instanceof XmlAttribute attr)) return;
+
+ if (!"NAME".equals(attr.getName())) return;
+
+ PsiElement tagElem = attr.getParent();
+ if (!(tagElem instanceof XmlTag tag) || !"FIELD".equals(tag.getName())) return;
+
+ // Check if this FIELD is inside a LAYOUT tag
+ XmlTag layoutTag = tag.getParentTag();
+ while (layoutTag != null && !"LAYOUT".equals(layoutTag.getName())) {
+ layoutTag = layoutTag.getParentTag();
+ }
+
+ if (layoutTag == null) return;
+
+ // The "Owner" of the LAYOUT (e.g., FORM_ENTRY, FILTERS, GRID-EDITOR)
+ XmlTag ownerTag = layoutTag.getParentTag();
+ if (ownerTag == null) return;
+
+ String fieldName = attrValue.getValue();
+ if (fieldName == null || fieldName.isEmpty()) return;
+
+ // Look for the FIELDS tag that is a sibling of the current LAYOUT
+ XmlTag fieldsTag = ownerTag.findFirstSubTag("FIELDS");
+ if (fieldsTag == null) {
+ holder.newAnnotation(HighlightSeverity.ERROR, "No definition found in <" + ownerTag.getName() + ">")
+ .range(attrValue.getTextRange())
+ .create();
+ return;
+ }
+
+ if (!isFieldDefined(fieldsTag, fieldName)) {
+ holder.newAnnotation(HighlightSeverity.ERROR, "Field '" + fieldName + "' is not defined in of <" + ownerTag.getName() + ">")
+ .range(attrValue.getTextRange())
+ .create();
+ }
+ }
+
+ private boolean isFieldDefined(XmlTag fieldsTag, String name) {
+ for (XmlTag field : fieldsTag.findSubTags("FIELD")) {
+ if (name.equals(field.getAttributeValue("NAME"))) {
+ return true;
+ }
+ }
+ // Also check inside SECTIONS or ROWS if any
+ for (XmlTag sub : fieldsTag.getSubTags()) {
+ if ("SECTION".equals(sub.getName()) || "ROW".equals(sub.getName())) {
+ if (isFieldDefined(sub, name)) return true;
+ }
+ }
+ return false;
+ }
+
+ private static boolean hasAncestorWithName(XmlTag tag, String name) {
+ XmlTag current = tag.getParentTag();
+ while (current != null) {
+ if (name.equals(current.getName())) return true;
+ current = current.getParentTag();
+ }
+ return false;
+ }
+}
diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml
index 333f669..00656df 100644
--- a/src/main/resources/META-INF/plugin.xml
+++ b/src/main/resources/META-INF/plugin.xml
@@ -34,6 +34,12 @@
]]>
[3.2.6]
+
+ - Structural Validation: Introduced a new Annotator to validate that all fields used in
<LAYOUT> and <FILTERS> are correctly defined in their respective <FIELDS> sections.
+ - Generator Logic Update: Refined the column width calculation for NUMBER and DATE types in the ActionBean generator for better XML compatibility.
+ - Improved File Opening: Switched to
FileEditorManagerEx for opening generated files, ensuring better window focus and management in recent IDE versions.
+
[3.2.5]
- Dataset to Form Mapping: Implemented comprehensive reference and completion support for the
FORM-NAME attribute in DATASET > FIELDS > FIELD.
@@ -188,5 +194,6 @@
+