From 56488feb4cc0271cdef73aff6a734e45c20b410f Mon Sep 17 00:00:00 2001
From: "ankostis@host:STUW025" <ankostis@gmail.com>
Date: Thu, 29 May 2014 08:37:02 +0200
Subject: [PATCH] Link JSON to GUI controls (labels & toolstips)

* json: Read defaults from schemas.
* prefs:  Make all props non-required.
---
 CHANGES.md                        |  34 ++++--
 CSE/Classes/cJsonFile.vb          |  65 +++++++---
 CSE/Classes/cPreferences.vb       | 132 +++++++++++---------
 CSE/GUI/FB_Dialog.vb              |   2 +-
 CSE/GUI/F_Main.vb                 |  26 ++--
 CSE/GUI/F_Preferences.designer.vb | 195 +++++++++++++++++++++---------
 CSE/GUI/F_Preferences.vb          |  88 ++++++++------
 CSE/GUI/minor_routines_GUI.vb     |  99 ++++++++++++++-
 8 files changed, 448 insertions(+), 193 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index ced75e1..31ae967 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,12 +1,30 @@
             VECTO-CSE's Changes
             ===================
+ 
+#### 2014-05-29: 2.0.1-pre1 ####
+JRC contributions:
+  * Read/write Vehicle-file as JSON.
+  * prefsUI: Add Reload button.
+  * Remember window-location (use .net Settings for that).
+  * Start logging stack-traces in the file-log.
+##### Internal:
+  * Start saving stack-traces into the log-file.
+  * Enhance JSON-files with standard header/body behavior.
+  * Link JSON to GUI controls (labels & toolstips)
+  * json: Read defaults from schemas.
 
-### 2014-05-23: CSE-2.0.1-pre0
 
-* Remove the versioning infos from app-name (manual, project-name, folders).
-* Possible to use any editor (not only notepad.exe).
-* Separate config/ from Declaration/ folders.
-* Added README.md, CHANGES.md, COPYING.txt files.
-#### Internal:
-* Auto create config/ on the 1st run, convert it to JSON with transparent error-handling.
-* FIX leaking of file-descriptors by using VB's 'Using' statement (class 'cFile_v3' now implements IDisposeable).
+#### 2014-05-23: 2.0.1-pre0 ####
+JRC contributions:
+  * Remove the versioning infos from app-name (manual, project-name, folders).
+  * Use SemanticVersioning 2.0.0 (see http://semver.org/).
+  * Possible to use any editor (not only notepad.exe).
+  * Separate config/ from Declaration/ folders.
+  * Added README.md, CHANGES.md, COPYING.txt files.
+##### Internal:
+  * Auto create config/ on the 1st run, converted to JSON with transparent error-handling.
+  * FIX leaking of file-descriptors by using VB's 'Using' statement (class 'cFile_v3' now implements IDisposeable).
+
+
+#### 2014-05-14: CSE2.01 ####
+1st delivery from TU-Graz under Lot-3.
diff --git a/CSE/Classes/cJsonFile.vb b/CSE/Classes/cJsonFile.vb
index 8db3849..13a2b94 100644
--- a/CSE/Classes/cJsonFile.vb
+++ b/CSE/Classes/cJsonFile.vb
@@ -69,9 +69,12 @@ Public MustInherit Class cJsonFile
                         },
                         "BodySchema": {
                             "title": "Body schema",
-                            "type": ["boolean", "object"],
-                            "description": "When set to True, it is replaced by the Body's schema on the next save, so as to provide users with documentation on the file.",
-                            "default": false,
+                            "type": ["boolean", "object", "null"],
+                            "description": "Body schema is included HERE, for documenting file. \n _
+                              When null/property missing, application decides what to do. \n _
+                              When True, it is always replaced by the Body's schema on the next save.\n _
+                              When False, it overrides Application's choice and is not replaced ever.", 
+                            "default": null,
                         },
                     }
                 },
@@ -90,7 +93,7 @@ Public MustInherit Class cJsonFile
 
     ''' <summary>When a instance_with_defauls is Created, it gets its /Body from this method</summary>
     ''' <remarks>The result json must be valid after replacing with this body.</remarks>
-    Protected MustOverride Function BodySchema() As JObject
+    Public MustOverride Function BodySchema() As JObject
 
     ''' <summary>Invoked by this class for subclasses to validate file</summary>
     ''' <remarks>To signify validation-failure it can throw an exception or add err-messages into the supplied list</remarks>
@@ -135,7 +138,7 @@ Public MustInherit Class cJsonFile
         WriteJsonFile(fpath, Json_Contents)
     End Sub
 
-
+    ''' <summary>Maintains header's standard props and overlays any props from subclass.</summary>
     Sub UpdateHeader()
         Dim h As JObject = Me.Header
 
@@ -145,16 +148,22 @@ Public MustInherit Class cJsonFile
             h("StrictBody") = False
         End If
 
-        '' Add schema for documenting file according to its boolean(/Header/BodySchema) if any or failback to global prefs:/Body/IncludeSchemas.
-        ''
+        '' Decide whether to include body-schema in header (for documenting file),
+        ''   by checking the folllowing, ordered by priority:
+        ''      1.   jsonfile:/Header/BodySchema
+        ''      2.   prefs:/Body/IncludeSchemas
+        ''      2.b. prefschema:/properties/Body/properties/IncludeSchemas/default   (implict by cPreferences.IncludeSchemas property)
+        ''      3.   false
+        Dim isIncludeSchema As Boolean
         Dim bodySchema = h("BodySchema")
-        Dim includeSchema = False
-        If bodySchema Is Nothing AndAlso AppPreferences IsNot Nothing Then
-            includeSchema = AppPreferences.IncludeSchemas
-        ElseIf bodySchema IsNot Nothing AndAlso bodySchema.Type = JTokenType.Boolean Then
-            includeSchema = bodySchema
+        If bodySchema IsNot Nothing AndAlso bodySchema.Type = JTokenType.Boolean Then
+            isIncludeSchema = bodySchema
+        ElseIf AppPreferences IsNot Nothing Then
+            isIncludeSchema = AppPreferences.IncludeSchemas
+        Else
+            isIncludeSchema = False
         End If
-        If includeSchema Then
+        If isIncludeSchema Then
             h("BodySchema") = Me.BodySchema
         End If
 
@@ -207,6 +216,26 @@ Public MustInherit Class cJsonFile
         End If
     End Function
 
+    ''' <summary>Used by sublasses to implement Propety-Get with defaults when non-existent</summary>
+    ''' <param name="propPath">The JSON.net's XPath for a Body property, including the starting dot('.').
+    ''' 
+    ''' Examples:
+    '''   PROP REQUESTED                     'propPath' ARGUMENT
+    '''   --------------                     -------------------
+    '''   /Body/SomeProp'                --> .SomeProp
+    '''   /Body/someGroup/somePropName   --> .someGroup.somePropName'.  
+    ''' </param>
+    Protected Function BodyGetter(ByVal propPath As String) As JToken
+        Dim value As JToken = Me.Body.SelectToken(propPath)
+        If value Is Nothing Then  '' No prop existed
+            '' Return a default from schema (if any).
+            ''
+            Dim schemaPath = propPath.Replace(".", ".properties.")
+            Return Me.BodySchema.SelectToken(schemaPath & ".default")
+        Else
+            Return value
+        End If
+    End Function
 
 #Region "json props"
     Protected ReadOnly Property Header() As JObject
@@ -245,10 +274,18 @@ Public MustInherit Class cJsonFile
     Public ReadOnly Property StrictBody As Boolean
         Get
             Dim value = Me.Body("StrictBody")
-            Return IIf(value Is Nothing, False, value)
+            Return IIf(value Is Nothing OrElse value.Type = JTokenType.Null, False, value)
         End Get
     End Property
 
+    '' NO, logic behind it more complex, see UpdateHeader() instead.
+    'Public ReadOnly Property BodySchema As Boolean
+    '    Get
+    '        Dim value = Me.Body("BodySchema")
+    '        Return IIf(value Is Nothing OrElse value.Type = JTokenType.Null, False, value)
+    '    End Get
+    'End Property
+
 #End Region ' "json props"
 
 End Class
diff --git a/CSE/Classes/cPreferences.vb b/CSE/Classes/cPreferences.vb
index 78d0c77..ac80749 100644
--- a/CSE/Classes/cPreferences.vb
+++ b/CSE/Classes/cPreferences.vb
@@ -13,64 +13,84 @@ Public Class cPreferences
            }</json>.Value)
     End Function
 
-    ' Default-prefs specified here.
+    ' Defaults specified here.
     Protected Overrides Function BodyContent() As JObject
-        Return JObject.Parse(<json>{
-                "WorkingDir":   null,
-                "WriteLog":     true,
-                "LogSize":      2,
-                "LogLevel":     5,
-                "Editor":       "notepad.exe",
-            }</json>.Value)
+        '' Return empty body since all proprs are optional.
+        '' They will become concrete on the 1st store.
+        Return New JObject()
+        'Return JObject.Parse(<json>{
+        '        "workingDir":   null,
+        '        "writeLog":     true,
+        '        "logSize":      10,
+        '        "logLevel":     5,
+        '        "editor":       "notepad.exe",
+        '    }</json>.Value)
     End Function
 
-    Protected Overrides Function BodySchema() As JObject
+    Public Overrides Function BodySchema() As JObject
         Return JObject.Parse(JSchemaStr())
     End Function
 
     ''' <param name="allowAdditionalProps">when false, more strict validation</param>
-    Protected Function JSchemaStr(Optional ByVal allowAdditionalProps As Boolean = True) As String
+    Public Shared Function JSchemaStr(Optional ByVal allowAdditionalProps As Boolean = True) As String
         Dim allowAdditionalProps_str As String = IIf(allowAdditionalProps, "true", "false")
         Return <json>{
             "title": "Schema for vecto-cse PREFERENCES",
             "type": "object", "additionalProperties": <%= allowAdditionalProps_str %>, 
             "required": true,
             "properties": {
-                "WorkingDir": {
+                "workingDir": {
+                    "title": "Working Directory",
                     "type": ["string", "null"], 
-                    "required": false,
                     "default": null,
-                    "description": "Last used Working Directory Path for input/output files, when null/empty,  uses app's dir",
+                    "description": "The path of the Working Directory for input/output files. \nWhen null/empty, app's dir implied.",
                 }, 
-                "WriteLog": {
+                "writeLog": {
+                    "title": "Log to file",
                     "type": "boolean",
-                    "required": true,
-                    "description": "Whether to write messages to log file (default: true)",
+                    "default": true,
+                    "description": "Whether to write messages to log file.",
                 }, 
-                "LogSize": {
+                "logSize": {
+                    "title": "Log-file's limit",
                     "type": "integer",
-                    "required": true,
-                    "description": "Allowed Log-file size limit [MiB] (default: 2)",
+                    "minimum": 0,
+                    "default": 10,
+                    "description": "Allowed Log-file size limit [MiB].",
                 }, 
-                "LogLevel": {
+                "logLevel": {
+                    "title": "Log-window's Level",
                     "type": "integer",
-                    "required": true,
-                    "description": "Message Output Level (default: 5 - 'info')",
+                    "minimum": 0,
+                    "maximum": 10, "exclusiveMaximum": true,
+                    "default": 5,
+                    "description": "Sets the threshold(Level) above from which log-messages to appear in the log-window.
+    0     : All
+    3-7   : No infos
+    8     : No warnings
+    9     : Not even errors!
+    other : Nothing at all",
                 }, 
-                "Editor": {
+                "editor": {
                     "type": "string",
-                    "required": true,
-                    "description": "Path (or filename if in PATH) of some (text or JSON) editor (default: 'notepad.exe')",
+                    "default": "notepad.exe",
+                    "description": "Path (or just the filename, if in PATH) of a text editor.",
                 }, 
-                "StrictBodies": {
+                "strictBodies": {
+                    "title": "Strict Bodies",
                     "type": "boolean",
                     "default": false,
-                    "description": "The global-default to use when reading JSON-files without a /Header/StrictBody property.",
+                    "description": "Controls whether unknown body-properties are accepted when reading JSON-files. 
+It is useful for debugging malformed input-files, ie to detect 
+accidentally renamed properties.
+Each file can override it by setting its /Header/StrictBody property.",
                 }, 
-                "IncludeSchemas": {
+                "includeSchemas": {
+                    "title": "Include Schemas",
                     "type": "boolean",
-                    "default": true,
-                    "description": "When true, provides documentation to json-files by populating their Header/BodySchema element when storing them, unless it is already set to false.",
+                    "default": false,
+                    "description": "Controls whether to self-document JSON-files by populating their '/Header/BodySchema' property.
+Each file can override it by setting its '/Header/BodySchema' property to false/true.",
                 }, 
             }
         }</json>.Value
@@ -109,10 +129,10 @@ Public Class cPreferences
 
 
 #Region "json props"
-    Public Property WorkingDir As String
+    Public Property workingDir As String
         Get
-            Dim value As String = Me.Body("WorkingDir")
-            If value Is Nothing OrElse value.Trim().Length = 0 Then
+            Dim value As String = Me.Body("workingDir")
+            If value Is Nothing OrElse String.IsNullOrWhiteSpace(value) Then
                 Return MyPath
             ElseIf IO.Path.IsPathRooted(value) Then
                 Return value
@@ -157,70 +177,64 @@ Public Class cPreferences
             '' NOTE: Early-binding makes Nulls end-up as 'string' schema-type.
             ''
             If value Is Nothing Then
-                Me.Json_Contents("Body")("WorkingDir") = Nothing
+                Me.Json_Contents("Body")("workingDir") = Nothing
             Else
-                Me.Json_Contents("Body")("WorkingDir") = value
+                Me.Json_Contents("Body")("workingDir") = value
             End If
         End Set
     End Property
 
-    Public Property WriteLog As Boolean
+    Public Property writeLog As Boolean
         Get
-            Return Me.Body("WriteLog")
+            Return BodyGetter(".writeLog")
         End Get
         Set(ByVal value As Boolean)
-            Me.Body("WriteLog") = value
+            Me.Body("writeLog") = value
         End Set
     End Property
 
-    Public Property LogSize As Integer
+    Public Property logSize As Integer
         Get
-            Return Me.Body("LogSize")
+            Return BodyGetter(".logSize")
         End Get
         Set(ByVal value As Integer)
-            Me.Body("LogSize") = value
+            Me.Body("logSize") = value
         End Set
     End Property
 
-    Public Property LogLevel As Integer
+    Public Property logLevel As Integer
         Get
-            Return Me.Body("LogLevel")
+            Return BodyGetter(".logLevel")
         End Get
         Set(ByVal value As Integer)
-            Me.Body("LogLevel") = value
+            Me.Body("logLevel") = value
         End Set
     End Property
 
-    Public Property Editor As String
+    Public Property editor As String
         Get
-            Return Me.Body("Editor")
+            Return BodyGetter(".editor")
         End Get
         Set(ByVal value As String)
-            If value Is Nothing OrElse value.Trim().Length = 0 Then
-                value = "notepad.exe"
-            End If
-
-            Me.Body("Editor") = value
+            Me.Body("editor") = value
         End Set
     End Property
 
-    Public Property StrictBodies As Boolean
+    Public Property strictBodies As Boolean
         Get
-            Dim value = Me.Body("StrictBodies")
-            Return IIf(value Is Nothing, False, value)
+            Return BodyGetter(".strictBodies")
         End Get
         Set(ByVal value As Boolean)
-            Me.Body("StrictBodies") = value
+            Me.Body("strictBodies") = value
         End Set
     End Property
 
-    Public Property IncludeSchemas As Boolean
+    Public Property includeSchemas As Boolean
         Get
-            Dim value = Me.Body("IncludeSchemas")
-            Return IIf(value Is Nothing, False, value)
+            Return BodyGetter(".includeSchemas")
         End Get
         Set(ByVal value As Boolean)
-            Me.Body("IncludeSchemas") = value
+            Me.Body("includeSchemas") = value
         End Set
     End Property
 
diff --git a/CSE/GUI/FB_Dialog.vb b/CSE/GUI/FB_Dialog.vb
index 01aaf6a..3609793 100644
--- a/CSE/GUI/FB_Dialog.vb
+++ b/CSE/GUI/FB_Dialog.vb
@@ -687,7 +687,7 @@ Public Class FB_Dialog
 
     'ButtonWorkDir_Click
     Private Sub ButtonWorkDir_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonWorkDir.Click
-        SetFolder(AppPreferences.WorkingDir)
+        SetFolder(AppPreferences.workingDir)
     End Sub
 
     'ButtonDesktop_Click
diff --git a/CSE/GUI/F_Main.vb b/CSE/GUI/F_Main.vb
index ed2d345..d76731c 100644
--- a/CSE/GUI/F_Main.vb
+++ b/CSE/GUI/F_Main.vb
@@ -42,8 +42,8 @@ Public Class F_Main
 
         ' Polling if the working dir exist (If not then generate the folder)
         '
-        If Not IO.Directory.Exists(AppPreferences.WorkingDir) Then
-            IO.Directory.CreateDirectory(AppPreferences.WorkingDir)
+        If Not IO.Directory.Exists(AppPreferences.workingDir) Then
+            IO.Directory.CreateDirectory(AppPreferences.workingDir)
         End If
 
         ' Write the beginning in the Log
@@ -56,7 +56,7 @@ Public Class F_Main
             Me.Close()
         End If
 
-        ' Write a defailt config file if failed to read one.
+        ' Write a defult config file if failed to read one.
         If Not configL Then
             Try
                 AppPreferences.Store(PreferencesPath)
@@ -78,7 +78,7 @@ Public Class F_Main
     ' Open the filebrowser for the selection of the vehiclefile
     Private Sub ButtonSelectVeh_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonSelectVeh.Click
         ' Open the filebrowser with the *.csveh parameter
-        If fbVEH.OpenDialog(AppPreferences.WorkingDir, False) Then
+        If fbVEH.OpenDialog(AppPreferences.workingDir, False) Then
             If (fbVEH.Files(0) <> Nothing) Then
                 Me.TextBoxVeh1.Text = fbVEH.Files(0)
             End If
@@ -97,7 +97,7 @@ Public Class F_Main
     ' Open the filebrowser for the selection of the weatherfile
     Private Sub ButtonSelectWeather_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonSelectWeather.Click
         ' Open the filebrowser with the *.cswea parameter
-        If fbAMB.OpenDialog(AppPreferences.WorkingDir, False) Then
+        If fbAMB.OpenDialog(AppPreferences.workingDir, False) Then
             If (fbAMB.Files(0) <> Nothing) Then
                 Me.TextBoxWeather.Text = fbAMB.Files(0)
             End If
@@ -129,7 +129,7 @@ Public Class F_Main
     ' Open the filebrowser for the selection of the datafile from the calibration run
     Private Sub ButtonSelectDataC_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonSelectDataC.Click
         ' Open the filebrowser with the *.csdat parameter
-        If fbVEL.OpenDialog(AppPreferences.WorkingDir, False) Then
+        If fbVEL.OpenDialog(AppPreferences.workingDir, False) Then
             If (fbVEL.Files(0) <> Nothing) Then
                 Me.TextBoxDataC.Text = fbVEL.Files(0)
             End If
@@ -153,7 +153,7 @@ Public Class F_Main
     ' Open the filebrowser for the selection of the measure section config file (MSC)
     Private Sub ButtonSelectMSCC_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonSelectMSCC.Click
         ' Open the filebrowser with the *.csmsc parameter
-        If fbMSC.OpenDialog(AppPreferences.WorkingDir, False) Then
+        If fbMSC.OpenDialog(AppPreferences.workingDir, False) Then
             If (fbMSC.Files(0) <> Nothing) Then
                 Me.TextBoxMSCC.Text = fbMSC.Files(0)
             End If
@@ -235,7 +235,7 @@ Public Class F_Main
     ' Open the filebrowser for the selection of the measure section file from the test run
     Private Sub ButtonSelectMSCT_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonSelectMSCT.Click
         ' Open the filebrowser with the *.csmsc parameter
-        If fbMSC.OpenDialog(AppPreferences.WorkingDir, False) Then
+        If fbMSC.OpenDialog(AppPreferences.workingDir, False) Then
             If (fbMSC.Files(0) <> Nothing) Then
                 Me.TextBoxMSCT.Text = fbMSC.Files(0)
             End If
@@ -259,7 +259,7 @@ Public Class F_Main
     ' Open the filebrowser for the selection of the first low speed data file from the test run
     Private Sub ButtonSelectDataLS1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonSelectDataLS1.Click
         ' Open the filebrowser with the *.csdat parameter
-        If fbVEL.OpenDialog(AppPreferences.WorkingDir, False) Then
+        If fbVEL.OpenDialog(AppPreferences.workingDir, False) Then
             If (fbVEL.Files(0) <> Nothing) Then
                 Me.TextBoxDataLS1.Text = fbVEL.Files(0)
             End If
@@ -283,7 +283,7 @@ Public Class F_Main
     ' Open the filebrowser for the selection of the high speed data file from the test run
     Private Sub ButtonSelectDataHS_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonSelectDataHS.Click
         ' Open the filebrowser with the *.csdat parameter
-        If fbVEL.OpenDialog(AppPreferences.WorkingDir, False) Then
+        If fbVEL.OpenDialog(AppPreferences.workingDir, False) Then
             If (fbVEL.Files(0) <> Nothing) Then
                 Me.TextBoxDataHS.Text = fbVEL.Files(0)
             End If
@@ -307,7 +307,7 @@ Public Class F_Main
     ' Open the filebrowser for the selection of the second low speed data file from the test run
     Private Sub ButtonSelectDataLS2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonSelectDataLS2.Click
         ' Open the filebrowser with the *.csdat parameter
-        If fbVEL.OpenDialog(AppPreferences.WorkingDir, False) Then
+        If fbVEL.OpenDialog(AppPreferences.workingDir, False) Then
             If (fbVEL.Files(0) <> Nothing) Then
                 Me.TextBoxDataLS2.Text = fbVEL.Files(0)
             End If
@@ -393,7 +393,7 @@ Public Class F_Main
     ' Menu open
     Private Sub ToolStripMenuItemOpen_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ToolStripMenuItemOpen.Click
         ' Open the filebrowser with the *.csjob parameter
-        If fbVECTO.OpenDialog(AppPreferences.WorkingDir, False) Then
+        If fbVECTO.OpenDialog(AppPreferences.workingDir, False) Then
             JobFile = fbVECTO.Files(0)
             If (JobFile <> Nothing) Then
                 ' Clear the GUI
@@ -566,7 +566,7 @@ Public Class F_Main
         '##### START THE CALCULATION #####
         '#################################
 
-        calculation(Cali)
+            calculation(Cali)
 
         '#################################
 
diff --git a/CSE/GUI/F_Preferences.designer.vb b/CSE/GUI/F_Preferences.designer.vb
index cf3bb3e..de9bb90 100644
--- a/CSE/GUI/F_Preferences.designer.vb
+++ b/CSE/GUI/F_Preferences.designer.vb
@@ -23,37 +23,44 @@ Partial Class F_Preferences
     <System.Diagnostics.DebuggerStepThrough()> _
     Private Sub InitializeComponent()
         Dim resources As System.ComponentModel.ComponentResourceManager = New System.ComponentModel.ComponentResourceManager(GetType(F_Preferences))
-        Me.TextBoxWorDir = New System.Windows.Forms.TextBox()
+        Me.workingDir = New System.Windows.Forms.TextBox()
         Me.ButtonSelectWorDir = New System.Windows.Forms.Button()
         Me.GroupBoxWorDir = New System.Windows.Forms.GroupBox()
         Me.ButtonOK = New System.Windows.Forms.Button()
         Me.ButtonCancel = New System.Windows.Forms.Button()
-        Me.CheckBoxWriteLog = New System.Windows.Forms.CheckBox()
+        Me.writeLog = New System.Windows.Forms.CheckBox()
         Me.GroupBoxInterface = New System.Windows.Forms.GroupBox()
         Me.LabelInfo = New System.Windows.Forms.Label()
-        Me.TextBoxLogSize = New System.Windows.Forms.TextBox()
+        Me.logSize = New System.Windows.Forms.TextBox()
         Me.Label16 = New System.Windows.Forms.Label()
         Me.Label1 = New System.Windows.Forms.Label()
-        Me.TextBoxMSG = New System.Windows.Forms.TextBox()
+        Me.logLevel = New System.Windows.Forms.TextBox()
         Me.TabControl1 = New System.Windows.Forms.TabControl()
         Me.TabPage2 = New System.Windows.Forms.TabPage()
         Me.GroupBoxNotepad = New System.Windows.Forms.GroupBox()
         Me.ButtonSelectNotepad = New System.Windows.Forms.Button()
-        Me.TextBoxNotepad = New System.Windows.Forms.TextBox()
+        Me.editor = New System.Windows.Forms.TextBox()
+        Me.GroupBox1 = New System.Windows.Forms.GroupBox()
+        Me.strictBodies = New System.Windows.Forms.CheckBox()
+        Me.includeSchemas = New System.Windows.Forms.CheckBox()
+        Me.TextBox1 = New System.Windows.Forms.TextBox()
+        Me.Label3 = New System.Windows.Forms.Label()
+        Me.CheckBox1 = New System.Windows.Forms.CheckBox()
         Me.ButtonReload = New System.Windows.Forms.Button()
         Me.GroupBoxWorDir.SuspendLayout()
         Me.GroupBoxInterface.SuspendLayout()
         Me.TabControl1.SuspendLayout()
         Me.TabPage2.SuspendLayout()
         Me.GroupBoxNotepad.SuspendLayout()
+        Me.GroupBox1.SuspendLayout()
         Me.SuspendLayout()
         '
-        'TextBoxWorDir
+        'workingDir
         '
-        Me.TextBoxWorDir.Location = New System.Drawing.Point(6, 19)
-        Me.TextBoxWorDir.Name = "TextBoxWorDir"
-        Me.TextBoxWorDir.Size = New System.Drawing.Size(444, 20)
-        Me.TextBoxWorDir.TabIndex = 1
+        Me.workingDir.Location = New System.Drawing.Point(6, 19)
+        Me.workingDir.Name = "workingDir"
+        Me.workingDir.Size = New System.Drawing.Size(444, 20)
+        Me.workingDir.TabIndex = 1
         '
         'ButtonSelectWorDir
         '
@@ -68,7 +75,7 @@ Partial Class F_Preferences
         'GroupBoxWorDir
         '
         Me.GroupBoxWorDir.Controls.Add(Me.ButtonSelectWorDir)
-        Me.GroupBoxWorDir.Controls.Add(Me.TextBoxWorDir)
+        Me.GroupBoxWorDir.Controls.Add(Me.workingDir)
         Me.GroupBoxWorDir.Location = New System.Drawing.Point(5, 6)
         Me.GroupBoxWorDir.Name = "GroupBoxWorDir"
         Me.GroupBoxWorDir.Size = New System.Drawing.Size(490, 51)
@@ -79,7 +86,8 @@ Partial Class F_Preferences
         'ButtonOK
         '
         Me.ButtonOK.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
-        Me.ButtonOK.Location = New System.Drawing.Point(436, 235)
+        Me.ButtonOK.DialogResult = System.Windows.Forms.DialogResult.OK
+        Me.ButtonOK.Location = New System.Drawing.Point(436, 242)
         Me.ButtonOK.Name = "ButtonOK"
         Me.ButtonOK.Size = New System.Drawing.Size(75, 23)
         Me.ButtonOK.TabIndex = 0
@@ -90,78 +98,78 @@ Partial Class F_Preferences
         '
         Me.ButtonCancel.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
         Me.ButtonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel
-        Me.ButtonCancel.Location = New System.Drawing.Point(99, 235)
+        Me.ButtonCancel.Location = New System.Drawing.Point(99, 242)
         Me.ButtonCancel.Name = "ButtonCancel"
         Me.ButtonCancel.Size = New System.Drawing.Size(75, 23)
         Me.ButtonCancel.TabIndex = 1
         Me.ButtonCancel.Text = "Cancel"
         Me.ButtonCancel.UseVisualStyleBackColor = True
         '
-        'CheckBoxWriteLog
+        'writeLog
         '
-        Me.CheckBoxWriteLog.AutoSize = True
-        Me.CheckBoxWriteLog.Location = New System.Drawing.Point(353, 15)
-        Me.CheckBoxWriteLog.Name = "CheckBoxWriteLog"
-        Me.CheckBoxWriteLog.Size = New System.Drawing.Size(129, 17)
-        Me.CheckBoxWriteLog.TabIndex = 5
-        Me.CheckBoxWriteLog.Text = "Write log file (LOG.txt)"
-        Me.CheckBoxWriteLog.UseVisualStyleBackColor = True
+        Me.writeLog.AutoSize = True
+        Me.writeLog.Location = New System.Drawing.Point(13, 58)
+        Me.writeLog.Name = "writeLog"
+        Me.writeLog.Size = New System.Drawing.Size(108, 17)
+        Me.writeLog.TabIndex = 2
+        Me.writeLog.Text = "Log-file Enabled?"
+        Me.writeLog.UseVisualStyleBackColor = True
         '
         'GroupBoxInterface
         '
         Me.GroupBoxInterface.Controls.Add(Me.LabelInfo)
-        Me.GroupBoxInterface.Controls.Add(Me.TextBoxLogSize)
+        Me.GroupBoxInterface.Controls.Add(Me.logSize)
         Me.GroupBoxInterface.Controls.Add(Me.Label16)
         Me.GroupBoxInterface.Controls.Add(Me.Label1)
-        Me.GroupBoxInterface.Controls.Add(Me.TextBoxMSG)
-        Me.GroupBoxInterface.Controls.Add(Me.CheckBoxWriteLog)
+        Me.GroupBoxInterface.Controls.Add(Me.logLevel)
+        Me.GroupBoxInterface.Controls.Add(Me.writeLog)
         Me.GroupBoxInterface.Location = New System.Drawing.Point(5, 120)
         Me.GroupBoxInterface.Name = "GroupBoxInterface"
-        Me.GroupBoxInterface.Size = New System.Drawing.Size(490, 75)
+        Me.GroupBoxInterface.Size = New System.Drawing.Size(341, 84)
         Me.GroupBoxInterface.TabIndex = 11
         Me.GroupBoxInterface.TabStop = False
-        Me.GroupBoxInterface.Text = "Interface"
+        Me.GroupBoxInterface.Text = "Logging && Messages"
         '
         'LabelInfo
         '
         Me.LabelInfo.AutoSize = True
-        Me.LabelInfo.Location = New System.Drawing.Point(185, 22)
+        Me.LabelInfo.Location = New System.Drawing.Point(154, 22)
         Me.LabelInfo.Name = "LabelInfo"
         Me.LabelInfo.Size = New System.Drawing.Size(39, 13)
         Me.LabelInfo.TabIndex = 12
         Me.LabelInfo.Text = "Label2"
         '
-        'TextBoxLogSize
+        'logSize
         '
-        Me.TextBoxLogSize.Location = New System.Drawing.Point(440, 38)
-        Me.TextBoxLogSize.Name = "TextBoxLogSize"
-        Me.TextBoxLogSize.Size = New System.Drawing.Size(36, 20)
-        Me.TextBoxLogSize.TabIndex = 11
+        Me.logSize.Location = New System.Drawing.Point(299, 55)
+        Me.logSize.Name = "logSize"
+        Me.logSize.Size = New System.Drawing.Size(36, 20)
+        Me.logSize.TabIndex = 3
         '
         'Label16
         '
         Me.Label16.AutoSize = True
-        Me.Label16.Location = New System.Drawing.Point(356, 41)
+        Me.Label16.Location = New System.Drawing.Point(181, 59)
         Me.Label16.Name = "Label16"
-        Me.Label16.Size = New System.Drawing.Size(78, 13)
+        Me.Label16.Size = New System.Drawing.Size(112, 13)
         Me.Label16.TabIndex = 10
-        Me.Label16.Text = "Size Limit [MiB]"
+        Me.Label16.Text = "Log-file size limit [MiB]:"
         '
         'Label1
         '
         Me.Label1.AutoSize = True
-        Me.Label1.Location = New System.Drawing.Point(27, 22)
+        Me.Label1.Location = New System.Drawing.Point(10, 22)
         Me.Label1.Name = "Label1"
-        Me.Label1.Size = New System.Drawing.Size(110, 13)
+        Me.Label1.Size = New System.Drawing.Size(96, 13)
         Me.Label1.TabIndex = 7
-        Me.Label1.Text = "Output Window Level"
+        Me.Label1.Text = "Log-window Level:"
         '
-        'TextBoxMSG
+        'logLevel
         '
-        Me.TextBoxMSG.Location = New System.Drawing.Point(143, 19)
-        Me.TextBoxMSG.Name = "TextBoxMSG"
-        Me.TextBoxMSG.Size = New System.Drawing.Size(36, 20)
-        Me.TextBoxMSG.TabIndex = 6
+        Me.logLevel.Location = New System.Drawing.Point(112, 19)
+        Me.logLevel.Name = "logLevel"
+        Me.logLevel.Size = New System.Drawing.Size(36, 20)
+        Me.logLevel.TabIndex = 1
         '
         'TabControl1
         '
@@ -172,18 +180,19 @@ Partial Class F_Preferences
         Me.TabControl1.Location = New System.Drawing.Point(3, 3)
         Me.TabControl1.Name = "TabControl1"
         Me.TabControl1.SelectedIndex = 0
-        Me.TabControl1.Size = New System.Drawing.Size(508, 226)
+        Me.TabControl1.Size = New System.Drawing.Size(508, 233)
         Me.TabControl1.TabIndex = 12
         '
         'TabPage2
         '
         Me.TabPage2.Controls.Add(Me.GroupBoxNotepad)
         Me.TabPage2.Controls.Add(Me.GroupBoxWorDir)
+        Me.TabPage2.Controls.Add(Me.GroupBox1)
         Me.TabPage2.Controls.Add(Me.GroupBoxInterface)
         Me.TabPage2.Location = New System.Drawing.Point(4, 22)
         Me.TabPage2.Name = "TabPage2"
         Me.TabPage2.Padding = New System.Windows.Forms.Padding(3)
-        Me.TabPage2.Size = New System.Drawing.Size(500, 200)
+        Me.TabPage2.Size = New System.Drawing.Size(500, 207)
         Me.TabPage2.TabIndex = 0
         Me.TabPage2.Text = "General"
         Me.TabPage2.UseVisualStyleBackColor = True
@@ -191,7 +200,7 @@ Partial Class F_Preferences
         'GroupBoxNotepad
         '
         Me.GroupBoxNotepad.Controls.Add(Me.ButtonSelectNotepad)
-        Me.GroupBoxNotepad.Controls.Add(Me.TextBoxNotepad)
+        Me.GroupBoxNotepad.Controls.Add(Me.editor)
         Me.GroupBoxNotepad.Location = New System.Drawing.Point(5, 63)
         Me.GroupBoxNotepad.Name = "GroupBoxNotepad"
         Me.GroupBoxNotepad.Size = New System.Drawing.Size(490, 51)
@@ -209,17 +218,77 @@ Partial Class F_Preferences
         Me.ButtonSelectNotepad.Text = "..."
         Me.ButtonSelectNotepad.UseVisualStyleBackColor = True
         '
-        'TextBoxNotepad
-        '
-        Me.TextBoxNotepad.Location = New System.Drawing.Point(6, 19)
-        Me.TextBoxNotepad.Name = "TextBoxNotepad"
-        Me.TextBoxNotepad.Size = New System.Drawing.Size(444, 20)
-        Me.TextBoxNotepad.TabIndex = 1
+        'editor
+        '
+        Me.editor.Location = New System.Drawing.Point(6, 19)
+        Me.editor.Name = "editor"
+        Me.editor.Size = New System.Drawing.Size(444, 20)
+        Me.editor.TabIndex = 1
+        '
+        'GroupBox1
+        '
+        Me.GroupBox1.Controls.Add(Me.strictBodies)
+        Me.GroupBox1.Controls.Add(Me.includeSchemas)
+        Me.GroupBox1.Controls.Add(Me.TextBox1)
+        Me.GroupBox1.Controls.Add(Me.Label3)
+        Me.GroupBox1.Controls.Add(Me.CheckBox1)
+        Me.GroupBox1.Location = New System.Drawing.Point(352, 120)
+        Me.GroupBox1.Name = "GroupBox1"
+        Me.GroupBox1.Size = New System.Drawing.Size(152, 84)
+        Me.GroupBox1.TabIndex = 11
+        Me.GroupBox1.TabStop = False
+        Me.GroupBox1.Text = "JSON"
+        '
+        'strictBodies
+        '
+        Me.strictBodies.AutoSize = True
+        Me.strictBodies.Location = New System.Drawing.Point(6, 57)
+        Me.strictBodies.Name = "strictBodies"
+        Me.strictBodies.Size = New System.Drawing.Size(91, 17)
+        Me.strictBodies.TabIndex = 12
+        Me.strictBodies.Text = "Strict Bodies?"
+        Me.strictBodies.UseVisualStyleBackColor = True
+        '
+        'includeSchemas
+        '
+        Me.includeSchemas.AutoSize = True
+        Me.includeSchemas.Location = New System.Drawing.Point(6, 21)
+        Me.includeSchemas.Name = "includeSchemas"
+        Me.includeSchemas.Size = New System.Drawing.Size(114, 17)
+        Me.includeSchemas.TabIndex = 12
+        Me.includeSchemas.Text = "Include Schemas?"
+        Me.includeSchemas.UseVisualStyleBackColor = True
+        '
+        'TextBox1
+        '
+        Me.TextBox1.Location = New System.Drawing.Point(440, 38)
+        Me.TextBox1.Name = "TextBox1"
+        Me.TextBox1.Size = New System.Drawing.Size(36, 20)
+        Me.TextBox1.TabIndex = 11
+        '
+        'Label3
+        '
+        Me.Label3.AutoSize = True
+        Me.Label3.Location = New System.Drawing.Point(356, 41)
+        Me.Label3.Name = "Label3"
+        Me.Label3.Size = New System.Drawing.Size(78, 13)
+        Me.Label3.TabIndex = 10
+        Me.Label3.Text = "Size Limit [MiB]"
+        '
+        'CheckBox1
+        '
+        Me.CheckBox1.AutoSize = True
+        Me.CheckBox1.Location = New System.Drawing.Point(353, 15)
+        Me.CheckBox1.Name = "CheckBox1"
+        Me.CheckBox1.Size = New System.Drawing.Size(129, 17)
+        Me.CheckBox1.TabIndex = 5
+        Me.CheckBox1.Text = "Write log file (LOG.txt)"
+        Me.CheckBox1.UseVisualStyleBackColor = True
         '
         'ButtonReload
         '
         Me.ButtonReload.Anchor = CType((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
-        Me.ButtonReload.Location = New System.Drawing.Point(18, 235)
+        Me.ButtonReload.Location = New System.Drawing.Point(18, 242)
         Me.ButtonReload.Name = "ButtonReload"
         Me.ButtonReload.Size = New System.Drawing.Size(75, 23)
         Me.ButtonReload.TabIndex = 0
@@ -232,7 +301,7 @@ Partial Class F_Preferences
         Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
         Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
         Me.CancelButton = Me.ButtonCancel
-        Me.ClientSize = New System.Drawing.Size(515, 270)
+        Me.ClientSize = New System.Drawing.Size(515, 277)
         Me.Controls.Add(Me.TabControl1)
         Me.Controls.Add(Me.ButtonCancel)
         Me.Controls.Add(Me.ButtonReload)
@@ -252,25 +321,33 @@ Partial Class F_Preferences
         Me.TabPage2.ResumeLayout(False)
         Me.GroupBoxNotepad.ResumeLayout(False)
         Me.GroupBoxNotepad.PerformLayout()
+        Me.GroupBox1.ResumeLayout(False)
+        Me.GroupBox1.PerformLayout()
         Me.ResumeLayout(False)
 
     End Sub
-    Friend WithEvents TextBoxWorDir As System.Windows.Forms.TextBox
+    Friend WithEvents workingDir As System.Windows.Forms.TextBox
     Friend WithEvents ButtonSelectWorDir As System.Windows.Forms.Button
     Friend WithEvents GroupBoxWorDir As System.Windows.Forms.GroupBox
     Friend WithEvents ButtonOK As System.Windows.Forms.Button
     Friend WithEvents ButtonCancel As System.Windows.Forms.Button
-    Friend WithEvents CheckBoxWriteLog As System.Windows.Forms.CheckBox
+    Friend WithEvents writeLog As System.Windows.Forms.CheckBox
     Friend WithEvents GroupBoxInterface As System.Windows.Forms.GroupBox
     Friend WithEvents TabControl1 As System.Windows.Forms.TabControl
     Friend WithEvents TabPage2 As System.Windows.Forms.TabPage
     Friend WithEvents Label1 As System.Windows.Forms.Label
-    Friend WithEvents TextBoxMSG As System.Windows.Forms.TextBox
-    Friend WithEvents TextBoxLogSize As System.Windows.Forms.TextBox
+    Friend WithEvents logLevel As System.Windows.Forms.TextBox
+    Friend WithEvents logSize As System.Windows.Forms.TextBox
     Friend WithEvents Label16 As System.Windows.Forms.Label
     Friend WithEvents GroupBoxNotepad As System.Windows.Forms.GroupBox
     Friend WithEvents ButtonSelectNotepad As System.Windows.Forms.Button
-    Friend WithEvents TextBoxNotepad As System.Windows.Forms.TextBox
+    Friend WithEvents editor As System.Windows.Forms.TextBox
     Friend WithEvents LabelInfo As System.Windows.Forms.Label
     Friend WithEvents ButtonReload As System.Windows.Forms.Button
+    Friend WithEvents GroupBox1 As System.Windows.Forms.GroupBox
+    Friend WithEvents TextBox1 As System.Windows.Forms.TextBox
+    Friend WithEvents Label3 As System.Windows.Forms.Label
+    Friend WithEvents CheckBox1 As System.Windows.Forms.CheckBox
+    Friend WithEvents strictBodies As System.Windows.Forms.CheckBox
+    Friend WithEvents includeSchemas As System.Windows.Forms.CheckBox
 End Class
diff --git a/CSE/GUI/F_Preferences.vb b/CSE/GUI/F_Preferences.vb
index c1f7094..3af4a18 100644
--- a/CSE/GUI/F_Preferences.vb
+++ b/CSE/GUI/F_Preferences.vb
@@ -1,36 +1,56 @@
+Imports Newtonsoft.Json.Linq
+
 Public Class F_Preferences
 
     ' Load confic
     Private Sub F03_Options_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
-        ' Allocate the data from the confic file (Only by the start)
-        UI_PopulateFrom(AppPreferences)
+        Dim controlPairs As IList(Of Control()) = New List(Of Control())
+        ''                CONTROL        LABEL
+        controlPairs.Add({Me.workingDir, Me.GroupBoxWorDir})
+        controlPairs.Add({Me.editor, Me.GroupBoxNotepad})
+        controlPairs.Add({Me.writeLog, Nothing})
+        controlPairs.Add({Me.logLevel, Label1})
+        controlPairs.Add({Me.logSize, Label16})
+        controlPairs.Add({Me.includeSchemas, Nothing})
+        controlPairs.Add({Me.strictBodies, Nothing})
+
+        '' Add help-tooltips from Json-Schema.
+        ''
+        Dim schema = JObject.Parse(cPreferences.JSchemaStr)
+        For Each row In controlPairs
+            Dim ctrl = row(0)
+            Dim Label = row(1)
+            updateControlsFromSchema(schema, ctrl, Label)
+        Next
 
-        ' Define the Infolable
-        TextBoxMSG_TextChanged(sender, e)
+        UI_PopulateFrom(AppPreferences)
     End Sub
 
     Private Sub UI_PopulateFrom(ByVal value As cPreferences)
         ' Allocate the data from the confic file (Only by the start)
-        Me.TextBoxWorDir.Text = value.WorkingDir
-        Me.TextBoxNotepad.Text = value.Editor
-        Me.CheckBoxWriteLog.Checked = value.WriteLog
-        Me.TextBoxMSG.Text = value.LogLevel
-        Me.TextBoxLogSize.Text = value.LogSize
+        Me.workingDir.Text = value.workingDir
+        Me.editor.Text = value.Editor
+        Me.writeLog.Checked = value.WriteLog
+        Me.logLevel.Text = value.LogLevel
+        Me.logSize.Text = value.LogSize
+        Me.includeSchemas.Checked = value.IncludeSchemas
+        Me.strictBodies.Checked = value.StrictBodies
     End Sub
 
     Private Sub UI_PopulateTo(ByVal value As cPreferences)
-        value.WorkingDir = Me.TextBoxWorDir.Text
-        value.Editor = Me.TextBoxNotepad.Text
-        value.WriteLog = Me.CheckBoxWriteLog.Checked
-        value.LogLevel = Me.TextBoxMSG.Text
-        value.LogSize = Me.TextBoxLogSize.Text
-
+        value.workingDir = Me.workingDir.Text
+        value.Editor = Me.editor.Text
+        value.WriteLog = Me.writeLog.Checked
+        value.LogLevel = Me.logLevel.Text
+        value.LogSize = Me.logSize.Text
+        value.IncludeSchemas = Me.includeSchemas.Checked
+        value.StrictBodies = Me.strictBodies.Checked
     End Sub
 
     ' Open the filebrowser for selecting the working dir
     Private Sub ButtonWorDir_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonSelectWorDir.Click
-        If fbWorkDir.OpenDialog(Me.TextBoxWorDir.Text) Then
-            Me.TextBoxWorDir.Text = fbWorkDir.Files(0)
+        If fbWorkDir.OpenDialog(Me.workingDir.Text) Then
+            Me.workingDir.Text = fbWorkDir.Files(0)
         End If
     End Sub
 
@@ -46,10 +66,11 @@ Public Class F_Preferences
 
             ' Message for the restart of VECTO
             RestartN = True
-            fInfWarErr(7, False, "Preferences have changed. Ask to restart.")
-            fInfWarErr(7, True, format("Preferences have changed.\nDo you want to restart VECTO now?"))
+            fInfWarErr(7, False, format("Stored Preferences({0}).", PreferencesPath))
+            fInfWarErr(7, True, format("Stored Preferences({0}). \n\nDo you want to restart VECTO now?", PreferencesPath))
         Catch ex As Exception
-            fInfWarErr(9, False, format("Failed storing Preferences({0}) due to: {1} \n  Preferences left unmodified!", PreferencesPath, ex.Message), ex)
+            fInfWarErr(9, False, format("Failed storing Preferences({0}) due to: {1} \n  Preferences left unmodified!", _
+                                        PreferencesPath, ex.Message), ex)
         End Try
 
         ' Close the window
@@ -61,9 +82,6 @@ Public Class F_Preferences
         Try
             AppPreferences = New cPreferences(PreferencesPath)
             UI_PopulateFrom(AppPreferences)
-
-            ' Define the Infolable
-            TextBoxMSG_TextChanged(sender, e)
         Catch ex As Exception
             fInfWarErr(9, False, format("Failed loading Preferences({0}) due to: {1}", _
                                         PreferencesPath, ex.Message), ex)
@@ -77,13 +95,13 @@ Public Class F_Preferences
 
     ' Select the Notepad path
     Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonSelectNotepad.Click
-        If fbExe.OpenDialog(Me.TextBoxWorDir.Text) Then
-            Me.TextBoxNotepad.Text = fbExe.Files(0)
+        If fbExe.OpenDialog(Me.workingDir.Text) Then
+            Me.editor.Text = fbExe.Files(0)
         End If
     End Sub
 
     ' Interception from kyepress events in the MSG box
-    Private Sub TextBoxMSG_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles TextBoxMSG.KeyPress
+    Private Sub TextBoxMSG_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles logLevel.KeyPress
         Select Case Asc(e.KeyChar)
             Case 48 To 56, 8 ' Numbers from 1 till 8 allowed (ASCII)
             Case Else ' Eliminate all other inputs
@@ -92,13 +110,13 @@ Public Class F_Preferences
     End Sub
 
     ' Set the MSG box to default if it is leave without an input
-    Private Sub TextBoxMSG_Leave(ByVal sender As Object, ByVal e As System.EventArgs) Handles TextBoxMSG.Leave
-        If Me.TextBoxMSG.Text = Nothing Then Me.TextBoxMSG.Text = 5
+    Private Sub TextBoxMSG_Leave(ByVal sender As Object, ByVal e As System.EventArgs) Handles logLevel.Leave
+        If Me.logLevel.Text = Nothing Then Me.logLevel.Text = 5
     End Sub
 
     ' Changes in the MSG --> Change the lable
-    Private Sub TextBoxMSG_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBoxMSG.TextChanged
-        Select Case Me.TextBoxMSG.Text
+    Private Sub TextBoxMSG_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles logLevel.TextChanged
+        Select Case Me.logLevel.Text
             Case 0 To 2 ' Show all
                 Me.LabelInfo.Text = "All"
             Case 3 ' No infos with priority 5 (*)
@@ -117,7 +135,7 @@ Public Class F_Preferences
     End Sub
 
     ' Changes in the LogSizeBox
-    Private Sub TextBoxLogSize_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles TextBoxLogSize.KeyPress
+    Private Sub TextBoxLogSize_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles logSize.KeyPress, TextBox1.KeyPress
         Select Case Asc(e.KeyChar)
             Case 48 To 58, 8 ' Numbers allowed (ASCII)
             Case Else ' Eliminate all other input data
@@ -126,12 +144,8 @@ Public Class F_Preferences
     End Sub
 
     ' Set the LogSize to default if it is leave without an input
-    Private Sub TextBoxLogSize_Leave(ByVal sender As Object, ByVal e As System.EventArgs) Handles TextBoxLogSize.Leave
-        If Me.TextBoxLogSize.Text = Nothing Then Me.TextBoxLogSize.Text = 2
-    End Sub
-
-    Private Sub GroupBoxWorDir_Enter(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles GroupBoxWorDir.Enter
-
+    Private Sub TextBoxLogSize_Leave(ByVal sender As Object, ByVal e As System.EventArgs) Handles logSize.Leave, TextBox1.Leave
+        If Me.logSize.Text = Nothing Then Me.logSize.Text = 2
     End Sub
 End Class
 
diff --git a/CSE/GUI/minor_routines_GUI.vb b/CSE/GUI/minor_routines_GUI.vb
index 35fb5bf..608e5e3 100644
--- a/CSE/GUI/minor_routines_GUI.vb
+++ b/CSE/GUI/minor_routines_GUI.vb
@@ -1,4 +1,6 @@
-Module minor_routines_GUI
+Imports Newtonsoft.Json.Linq
+
+Module minor_routines_GUI
 
     ' Clear the GUI
     Public Function fClear_VECTO_Form(ByVal Komplet As Boolean, Optional ByVal Fields As Boolean = True) As Boolean
@@ -579,4 +581,97 @@
 
     End Function
 
-End Module
\ No newline at end of file
+    Sub updateControlsFromSchema(ByVal schema As JObject, ByVal ctrl As Control, ByVal label As Control)
+        Try
+            Dim pschema = schema.SelectToken(".properties." & ctrl.Name)
+            If pschema Is Nothing Then
+                fInfWarErr(8, False, format("Schema2GUI: Could not find schema for Control({0})!\n\iSchema: {1}", ctrl.Name, schema))
+                Return
+            End If
+
+            '' Set title on control/label
+            ''
+            Dim title = pschema("title")
+            If title IsNot Nothing Then
+                If label IsNot Nothing Then
+                    label.Text = title
+                Else
+                    If TypeOf ctrl Is CheckBox Then
+                        title = title.ToString() & "?"
+                    End If
+                End If
+                ctrl.Text = title
+            End If
+
+            '' Build tooltip.
+            ''
+            Dim infos = _
+                From pname In {"title", "description", "type", "enum", "default", _
+                               "minimum", "exclusiveMinimum", "maximum", "exclusiveMaximum"}
+                Select pschema(pname)
+
+            ''TODO: Include other schema-props in tooltips.
+
+            If infos.Any() Then
+                Dim msg = schemaInfos2helpMsg(infos.ToArray())
+                Dim t = New ToolTip()
+                t.SetToolTip(ctrl, msg)
+                t.AutomaticDelay = 300
+                t.AutoPopDelay = 10000
+            End If
+
+
+        Catch ex As Exception
+            fInfWarErr(8, False, format("Schema2GUI: Skipped exception: {0} ", ex.Message), ex)
+        End Try
+    End Sub
+
+    ''' <summary>Builds a human-readable help-string from any non-null schema-properties.</summary>
+    Function schemaInfos2helpMsg(ByVal ParamArray propSchemaInfos() As JToken) As String
+        Dim titl = propSchemaInfos(0)
+        Dim desc = propSchemaInfos(1)
+        Dim type = propSchemaInfos(2)
+        Dim chce = propSchemaInfos(3)
+        Dim dflt = propSchemaInfos(4)
+        Dim mini = propSchemaInfos(5)
+        Dim miex = propSchemaInfos(6) '' exclusiveMin
+        Dim maxi = propSchemaInfos(7)
+        Dim maex = propSchemaInfos(8) '' exclusiveMax
+
+        Dim sdesc As String = ""
+        Dim stype As String = ""
+        Dim senum As String = ""
+        Dim sdflt As String = ""
+        Dim slimt As String = ""
+
+        If desc IsNot Nothing Then
+            sdesc = format(desc.ToString())
+        ElseIf titl IsNot Nothing Then
+            sdesc = format(titl.ToString())
+        End If
+        If type IsNot Nothing Then stype = type.ToString(Newtonsoft.Json.Formatting.None) & ": "
+        If chce IsNot Nothing Then senum = format("\n- choices: {0}", chce.ToString(Newtonsoft.Json.Formatting.None))
+        If dflt IsNot Nothing Then sdflt = format("\n- default: {0}", dflt)
+        If mini IsNot Nothing OrElse maxi IsNot Nothing Then
+            Dim infinitySymbol = "" + ChrW(&H221E)
+            Dim open = "("c
+            Dim smin = infinitySymbol
+            Dim smax = infinitySymbol
+            Dim clos = ")"c
+
+            If mini IsNot Nothing Then
+                smin = mini
+                If (miex Is Nothing OrElse Not CBool(miex)) Then open = "["c
+            End If
+            If maxi IsNot Nothing Then
+                smax = maxi
+                If (maex Is Nothing OrElse Not CBool(maex)) Then clos = "]"c
+            End If
+            slimt = format("\n- limits : {0}{1}, {2}{3}", _
+                           open, smin, smax, clos)
+        End If
+
+        Return String.Join("", stype, sdesc, senum, sdflt, slimt)
+    End Function
+
+End Module
-- 
GitLab