]> gitweb.hamatoma.de Git - flutter_bones.git/commitdiff
daily work
authorHamatoma <author@hamatoma.de>
Fri, 13 Nov 2020 23:03:15 +0000 (00:03 +0100)
committerHamatoma <author@hamatoma.de>
Sat, 14 Nov 2020 11:11:48 +0000 (12:11 +0100)
45 files changed:
lib/main.dart
lib/src/helper/name_builder.dart [new file with mode: 0644]
lib/src/model/all_db_fields_model.dart
lib/src/model/button_model.dart
lib/src/model/checkbox_model.dart
lib/src/model/column_model.dart
lib/src/model/combo_base_model.dart
lib/src/model/combobox_model.dart
lib/src/model/db_reference_model.dart
lib/src/model/empty_line_model.dart
lib/src/model/field_model.dart
lib/src/model/model_base.dart
lib/src/model/module_model.dart
lib/src/model/page_model.dart
lib/src/model/section_model.dart
lib/src/model/standard/configuration_model.dart
lib/src/model/standard/menu_model.dart
lib/src/model/standard/role_model.dart
lib/src/model/standard/user_model.dart
lib/src/model/table_model.dart
lib/src/model/text_field_model.dart
lib/src/model/text_model.dart
lib/src/model/widget_model.dart
lib/src/page/configuration/configuration_change_page.dart
lib/src/page/configuration/configuration_controller.dart
lib/src/page/configuration/configuration_create_page.dart
lib/src/page/role/role_change_page.dart
lib/src/page/role/role_create_page.dart
lib/src/page/role/role_list_page.dart
lib/src/page/user/user_controller.dart
lib/src/page/user/user_password_page.dart
lib/src/widget/edit_form.dart
lib/src/widget/list_form.dart
lib/src/widget/model_list.dart [new file with mode: 0644]
lib/src/widget/page_controller_bones.dart
lib/src/widget/view.dart
lib/src/widget/widget_list.dart [deleted file]
lib/src/widget/widget_validators.dart
test/helpers/name_builder_test.dart [new file with mode: 0644]
test/model/db_model_test.dart
test/model/model_test.dart
test/model/standard_test.dart
test/tool/tool_test.dart
test/widget/widget_test.dart
test/widget/widget_validators_test.dart

index 29a9d9e607e1f6a2f7410c05531ee75a19d9d672..c2e57717b765c61f4487248cf354f984b4b9ec1c 100644 (file)
@@ -1,7 +1,6 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_bones/app.dart';
 
-void main(List<String> args) {
-  //args.length > 1 && args[0].startsWith('--') &&
+void main() {
   runApp(BoneApp());
 }
diff --git a/lib/src/helper/name_builder.dart b/lib/src/helper/name_builder.dart
new file mode 100644 (file)
index 0000000..ff90f29
--- /dev/null
@@ -0,0 +1,39 @@
+import 'package:dart_bones/dart_bones.dart';
+
+/// A Builder for programmatically created names.
+class NameBuilder {
+  final counterMap = <String, int>{};
+  BaseLogger logger;
+  NameBuilder(this.logger);
+
+  /// Returns a unique name with a given [prefix] followed by a current number.
+  String nextName(String prefix) {
+    String rc;
+    if (prefix != null) {
+      int no;
+      if (counterMap.containsKey(prefix)) {
+        no = ++counterMap[prefix];
+      } else {
+        counterMap[prefix] = no = 1;
+      }
+      rc = prefix + no.toString();
+    }
+    return rc;
+  }
+
+  /// Dumps the [counterMap] as a string.
+  String dump({String indention = ''}) {
+    final rc = StringBuffer();
+    rc.write(indention);
+    rc.write('Prefix:Number');
+    rc.write('\n');
+    counterMap.forEach((key, value) {
+      rc.write(indention);
+      rc.write(key);
+      rc.write(':');
+      rc.write(value);
+      rc.write('\n');
+    });
+    return rc.toString();
+  }
+}
index cc1530d064c6aa267e61beacbca4d0f5c4da50a8..65b591bc2ae93cff4586f5c8183ca10fc53ab32d 100644 (file)
@@ -5,6 +5,7 @@ import 'page_model.dart';
 import 'section_model.dart';
 import 'table_model.dart';
 import 'widget_model.dart';
+import 'model_base.dart';
 
 /// Describes a text widget without user interaction.
 class AllDbFieldsModel extends WidgetModel {
@@ -12,32 +13,27 @@ class AllDbFieldsModel extends WidgetModel {
   String text;
   bool isRichText;
 
-  AllDbFieldsModel(
-      SectionModel section, PageModel page, BaseLogger logger)
-      : super(section, page, WidgetModelType.allDbFields, null, logger);
+  AllDbFieldsModel(SectionModel section, PageModel page, BaseLogger logger)
+      : super(section, page, ModelTypeBones.allDbFields, null, logger);
 
   /// Returns the name including the names of the parent
   @override
-  String fullName() => '${section.name}.allDbFields$id';
+  String fullName() => '${section.name}.$name';
 
   /// Dumps the internal structure into a [stringBuffer]
   StringBuffer dump(StringBuffer stringBuffer) {
-    stringBuffer.write('    allDbFields $id options: ${options.join(' ')}\n');
+    stringBuffer.write('    allDbFields $name options: ${options.join(' ')}\n');
     return stringBuffer;
   }
 
   /// Parses the [map] and stores the data in the instance.
   void parse(Map map) {
     super.parse(map);
-    checkSuperfluousAttributes(map, 'options widgetType'.split(' '));
-    options = parseOptions('options', map);
+    checkSuperfluousAttributes(map, 'modelType name options'.split(' '));
     addFieldsOfTable(page.module.mainTable());
     checkOptionsByRegExpr(regExprOptions);
   }
 
-  @override
-  String widgetName() => 'allDbFields$id';
-
   void addFieldsOfTable(TableModel table) {
     bool isCreatePage = page.pageModelType == PageModelType.create;
     table.columns.forEach((col) {
index cfc10dd45f682cc5d79b0a278103c6b0ce0760d4..55bf4d6ffe7c080ed0d73b62dfe4cff1005a6360 100644 (file)
@@ -3,19 +3,19 @@ import 'model_types.dart';
 import 'widget_model.dart';
 import 'section_model.dart';
 import 'page_model.dart';
+import 'model_base.dart';
 
 /// Describes a button widget.
 class ButtonModel extends WidgetModel {
   static final regExprOptions = RegExp(r'^(undef)$');
   String label;
-  String name;
   String toolTip;
   ButtonModelType buttonModelType;
   VoidCallbackBones onPressed;
 
   /// Constructs an instance by parsing the map for some properties.
   ButtonModel(SectionModel section, PageModel page, BaseLogger logger)
-      : super(section, page, WidgetModelType.button, null, logger);
+      : super(section, page, ModelTypeBones.button, null, logger);
 
   /// Constructs an instance with all properties given.
   ButtonModel.direct(
@@ -26,7 +26,7 @@ class ButtonModel extends WidgetModel {
       ButtonModelType buttonModelType,
       List<String> options,
       BaseLogger logger)
-      : super(section, page, WidgetModelType.button, options, logger) {
+      : super(section, page, ModelTypeBones.button, options, logger) {
     this.name = name;
     this.label = text;
     this.toolTip = toolTip;
@@ -37,7 +37,7 @@ class ButtonModel extends WidgetModel {
   /// Dumps a the instance into a [stringBuffer]
   StringBuffer dump(StringBuffer stringBuffer) {
     stringBuffer.write(
-        '    button $name: text: options: $label ${listToString(options)}\n');
+        '    button $name: label: $label options: $label ${listToString(options)}\n');
     return stringBuffer;
   }
 
@@ -47,21 +47,16 @@ class ButtonModel extends WidgetModel {
 
   /// Parses the [map]and stores the data in the instance.
   void parse(Map map) {
-    name = parseString('name', map, required: true);
     super.parse(map);
-    checkSuperfluousAttributes(map,
-        'buttonType label name options text toolTip widgetType'.split(' '));
+    checkSuperfluousAttributes(
+        map, 'buttonType label modelType name options text toolTip'.split(' '));
     label = parseString('label', map, required: true);
     toolTip = parseString('toolTip', map);
     buttonModelType =
         parseEnum<ButtonModelType>('buttonType', map, ButtonModelType.values);
     buttonModelType ??= ButtonModelType.custom;
-    options = parseOptions('options', map);
     checkOptionsByRegExpr(regExprOptions);
   }
-
-  @override
-  String widgetName() => name;
 }
 
 enum ButtonModelType {
index 7d99b81bee2f1b4dbaa4b28e7b7aaa35ebbfd990..285b7344514f32a108b5544ae89f4ae61e9f6fdb 100644 (file)
@@ -3,29 +3,28 @@ import 'package:dart_bones/dart_bones.dart';
 import 'field_model.dart';
 import 'page_model.dart';
 import 'section_model.dart';
-import 'widget_model.dart';
+import 'model_base.dart';
 
 /// Describes a checkbox widget.
 class CheckboxModel extends FieldModel {
   static final regExprOptions = RegExp(r'^(readonly|disabled|required|undef)$');
 
-  CheckboxModel(
-      SectionModel section, PageModel page, BaseLogger logger)
-      : super(section, page, WidgetModelType.checkbox, logger);
+  CheckboxModel(SectionModel section, PageModel page, BaseLogger logger)
+      : super(section, page, ModelTypeBones.checkbox, logger);
 
   /// Parses the [map]and stores the data in the instance.
   void parse(Map map) {
     super.parse(map);
     checkSuperfluousAttributes(
-        map, 'name label options toolTip widgetType'.split(' '));
+        map, 'modelType name label options toolTip'.split(' '));
     checkOptionsByRegExpr(regExprOptions);
     parseFinish();
   }
 
   /// Dumps the instance into a [StringBuffer]
   StringBuffer dump(StringBuffer stringBuffer) {
-    stringBuffer
-        .write('    checkbox $name: text: options: ${listToString(options)}\n');
+    stringBuffer.write(
+        '    checkbox $name: "${label ?? ''}" options: ${listToString(options)}\n');
     return stringBuffer;
   }
 }
index 255ce95478c91958e3b46de10f89c4251d56b115..6c73f4b8b2af9921398cdf462b8e2f2ab3628349 100644 (file)
@@ -5,7 +5,6 @@ import 'combo_base_model.dart';
 import 'model_base.dart';
 import 'model_types.dart';
 import 'table_model.dart';
-import 'widget_model.dart';
 
 /// Describes a column of a database table.
 class ColumnModel extends ComboBaseModel {
@@ -21,7 +20,7 @@ class ColumnModel extends ComboBaseModel {
 
   /// A constructor used in the parser.
   ColumnModel(this.table, BaseLogger logger)
-      : super(null, null, WidgetModelType.column, logger);
+      : super(null, null, ModelTypeBones.column, logger);
 
   /// A constructor for columns created by the program.
   ColumnModel.direct(
@@ -49,7 +48,7 @@ class ColumnModel extends ComboBaseModel {
             listOption: listOption,
             listType: listType,
             options: options,
-            widgetType: WidgetModelType.column,
+            modelType: ModelTypeBones.column,
             logger: logger);
 
   /// Dumps the instance into a [StringBuffer]
@@ -65,11 +64,13 @@ class ColumnModel extends ComboBaseModel {
 
   /// Parses the [map]and stores the data in the instance.
   void parse(Map map) {
-    name = parseString('column', map, required: true);
     super.parse(map);
+    if (name == null) {
+      name = table.nameBuilder.nextName('autoColumn');
+    }
     checkSuperfluousAttributes(
         map,
-        'column dataType defaultValue foreignKey label listOption listType options rows size texts tooTip validators validatorsText values widgetType'
+        'column dataType defaultValue foreignKey label listOption listType modelType options rows size texts tooTip validators validatorsText values'
             .split(' '));
     dataType =
         parseEnum<DataType>('dataType', map, DataType.values, required: true);
index 171474a726e978085060dc0ccdd023a0289e116c..25eb0d72cfc19cc7319df334d36d54f58eb9db6e 100644 (file)
@@ -4,7 +4,7 @@ import 'field_model.dart';
 import 'model_types.dart';
 import 'page_model.dart';
 import 'section_model.dart';
-import 'widget_model.dart';
+import 'model_base.dart';
 
 /// A base class for combobox items like ComboboxModel, ColumnModel and DbReferenceModel.
 abstract class ComboBaseModel extends FieldModel {
@@ -18,9 +18,9 @@ abstract class ComboBaseModel extends FieldModel {
   ComboboxListType listType;
   ComboboxData data;
 
-  ComboBaseModel(SectionModel section, PageModel page,
-      WidgetModelType widgetType, BaseLogger logger)
-      : super(section, page, widgetType, logger);
+  ComboBaseModel(SectionModel section, PageModel page, ModelTypeBones modelType,
+      BaseLogger logger)
+      : super(section, page, modelType, logger);
 
   ComboBaseModel.direct(
       {SectionModel section,
@@ -34,11 +34,11 @@ abstract class ComboBaseModel extends FieldModel {
       this.values,
       this.listOption,
       this.listType,
-      WidgetModelType widgetType,
+      ModelTypeBones modelType,
       dynamic defaultValue,
       BaseLogger logger})
-      : super.direct(section, page, widgetType, name, label, toolTip,
-            dataType, options, defaultValue, logger);
+      : super.direct(section, page, modelType, name, label, toolTip, dataType,
+            defaultValue, options, logger);
 
   /// Transfers the list data from [texts] and [values] to [data].
   /// May only called for comboboxes with [listType] = [ComboboxListType.explicite].
@@ -112,7 +112,7 @@ class ComboboxData {
   List _values;
   WaitState waitState;
 
-  ComboboxData(this.texts, this._values, [this.waitState = WaitState.undef]){
+  ComboboxData(this.texts, this._values, [this.waitState = WaitState.undef]) {
     this._values ??= this.texts;
   }
 
index 819dfe7809788fbf576c8ed0358ddf73a90833fe..4d6ae246dfbd54679912233c7af50b7af0528d71 100644 (file)
@@ -3,20 +3,19 @@ import 'package:dart_bones/dart_bones.dart';
 import 'combo_base_model.dart';
 import 'page_model.dart';
 import 'section_model.dart';
-import 'widget_model.dart';
+import 'model_base.dart';
 
 /// Describes a combobox widget.
 class ComboboxModel extends ComboBaseModel {
   static final regExprOptions = RegExp(r'^(disabled|readonly|required|undef)$');
 
-  ComboboxModel(
-      SectionModel section, PageModel page, BaseLogger logger)
-      : super(section, page, WidgetModelType.combobox, logger);
+  ComboboxModel(SectionModel section, PageModel page, BaseLogger logger)
+      : super(section, page, ModelTypeBones.combobox, logger);
 
   /// Dumps the instance into a [StringBuffer]
   StringBuffer dump(StringBuffer stringBuffer) {
     stringBuffer.write(
-        '    combobox $name: texts: ${listToString(texts)} options: ${options.join(' ')}\n');
+        '    combobox $name: "$label" texts: ${listToString(texts)} options: ${options.join(' ')}\n');
     return stringBuffer;
   }
 
@@ -24,7 +23,7 @@ class ComboboxModel extends ComboBaseModel {
   void parse(Map map) {
     checkSuperfluousAttributes(
         map,
-        'dataType defaultValue filterType label listOption listType name options texts toolTip values validators validatorsText widgetType'
+        'dataType defaultValue filterType label listOption listType modelType name options texts toolTip values validators validatorsText'
             .split(' '));
     super.parse(map);
     checkOptionsByRegExpr(regExprOptions);
index 38b99d8d4052d191260206d55af4c8e8d972f809..cb28c7999f7c14b9400ee5db0c364fb5ccde2bc6 100644 (file)
@@ -4,7 +4,7 @@ import 'column_model.dart';
 import 'combo_base_model.dart';
 import 'page_model.dart';
 import 'section_model.dart';
-import 'widget_model.dart';
+import 'model_base.dart';
 
 /// Describes a form text field widget.
 class DbReferenceModel extends ComboBaseModel {
@@ -16,9 +16,8 @@ class DbReferenceModel extends ComboBaseModel {
   ColumnModel column;
 
   /// A constructor fetching the properties by parsing the map.
-  DbReferenceModel(
-      SectionModel section, PageModel page, BaseLogger logger)
-      : super(section, page, WidgetModelType.dbReference, logger);
+  DbReferenceModel(SectionModel section, PageModel page, BaseLogger logger)
+      : super(section, page, ModelTypeBones.dbReference, logger);
 
   /// A constructor without map parsing.
   DbReferenceModel.fromColumn(SectionModel section, PageModel page,
@@ -26,7 +25,7 @@ class DbReferenceModel extends ComboBaseModel {
       : super.direct(
             section: section,
             page: page,
-            widgetType: WidgetModelType.dbReference,
+            modelType: ModelTypeBones.dbReference,
             name: column.name,
             label: column.label,
             toolTip: column.toolTip,
@@ -53,8 +52,8 @@ class DbReferenceModel extends ComboBaseModel {
 
   /// Dumps the internal structure into a [stringBuffer]
   StringBuffer dump(StringBuffer stringBuffer) {
-    stringBuffer
-        .write('    textField $name: options: ${listToString(options)}\n');
+    stringBuffer.write(
+        '    textField $name: "$label" options: ${listToString(options)}\n');
     return stringBuffer;
   }
 
@@ -62,25 +61,23 @@ class DbReferenceModel extends ComboBaseModel {
   void parse(Map map) {
     checkSuperfluousAttributes(
         map,
-        'column filterType label maxSize listOption listType name options rows toolTip texts widgetType values'
+        'column filterType label maxSize listOption listType modelType name options rows toolTip texts values'
             .split(' '));
     super.parse(map);
     final columnName = parseString('column', map, required: true);
     column = page.module.getColumn(columnName, this);
     maxSize = parseInt('maxSize', map, required: false);
     rows = parseInt('rows', map, required: false);
-    options = parseOptions('options', map);
-    label ??= column.label;
-    toolTip ??= column.toolTip;
-    filterType ??= column.filterType;
-    options = parseOptions('options', map);
-    dataType = column.dataType;
-    texts ??= column.texts;
-    values ??= column.values;
-    listOption ??= column.listOption;
-    listType ??= column.listType;
+    label ??= column?.label;
+    toolTip ??= column?.toolTip;
+    filterType ??= column?.filterType;
+    dataType = column?.dataType;
+    texts ??= column?.texts;
+    values ??= column?.values;
+    listOption ??= column?.listOption;
+    listType ??= column?.listType;
     checkOptionsByRegExpr(regExprOptions);
-    options += column.options;
+    options += column?.options ?? [];
     parseFinish();
   }
 }
index e133b707b83fdc1751d642c1814057d17840987a..9bfa2c48bf33c2e9161703211e725e44ff3196ec 100644 (file)
@@ -3,33 +3,30 @@ import 'package:dart_bones/dart_bones.dart';
 import 'page_model.dart';
 import 'section_model.dart';
 import 'widget_model.dart';
+import 'model_base.dart';
 
 /// Describes an empty line used as separator between two other widgets.
 class EmptyLineModel extends WidgetModel {
   static final regExprOptions = RegExp(r'^(unknown)$');
   bool isRichText;
 
-  EmptyLineModel(
-      SectionModel section, PageModel page, BaseLogger logger)
-      : super(section, page, WidgetModelType.emptyLine, null, logger);
+  EmptyLineModel(SectionModel section, PageModel page, BaseLogger logger)
+      : super(section, page, ModelTypeBones.emptyLine, null, logger);
 
   /// Dumps the instance into a [StringBuffer]
   StringBuffer dump(StringBuffer stringBuffer) {
-    stringBuffer.write('    emptyLine: options: ${options.join(' ')}\n');
+    stringBuffer.write('    emptyLine $name: options: ${options.join(' ')}\n');
     return stringBuffer;
   }
 
   /// Returns the name including the names of the parent
   @override
-  String fullName() => '${section.name}.${widgetName()}';
+  String fullName() => '${section.name}.$name';
 
   /// Parses the [map]and stores the data in the instance.
   void parse(Map map) {
     super.parse(map);
-    checkSuperfluousAttributes(map, 'options widgetType'.split(' '));
+    checkSuperfluousAttributes(map, 'modelType options'.split(' '));
     checkOptionsByRegExpr(regExprOptions);
   }
-
-  @override
-  String widgetName() => 'emptyLine$id';
 }
index 174c6428ed94359ea5005b041bd16c47e52ca41e..af820d0f482a532e540d1bd25cd56145da001377 100644 (file)
@@ -5,6 +5,7 @@ import 'model_types.dart';
 import 'page_model.dart';
 import 'section_model.dart';
 import 'widget_model.dart';
+import 'model_base.dart';
 
 typedef FieldValidator = String Function(
     String input, FieldModel model, ValidatorController controller);
@@ -21,7 +22,6 @@ abstract class FieldModel extends WidgetModel {
       'dateTime|email|int|maxDate|maxDateTime|maxInt|minDate|minDateTime|minInt|regExpr|required|unique';
   static const reValidatorTextItem = '^($reValidatorNames)\$';
   static final regExprValidatorText = RegExp(reValidatorTextItem);
-  String name;
   String label;
   String toolTip;
   DataType dataType;
@@ -46,14 +46,14 @@ abstract class FieldModel extends WidgetModel {
   final messageOfValidator = <String, String>{};
 
   FieldModel(SectionModel section, PageModel page,
-      WidgetModelType fieldModelType, BaseLogger logger)
+      ModelTypeBones fieldModelType, BaseLogger logger)
       : super(section, page, fieldModelType, null, logger);
 
   FieldModel.direct(
       SectionModel section,
       PageModel page,
-      WidgetModelType widgetModelType,
-      this.name,
+      ModelTypeBones modelType,
+      String name,
       this.label,
       this.toolTip,
       this.dataType,
@@ -61,7 +61,9 @@ abstract class FieldModel extends WidgetModel {
       List<String> options,
       BaseLogger logger,
       [this.filterType])
-      : super(section, page, widgetModelType, options, logger);
+      : super(section, page, modelType, options, logger) {
+    this.name = name;
+  }
 
   get value => _value;
 
@@ -177,20 +179,16 @@ abstract class FieldModel extends WidgetModel {
 
   /// Parses the [map]and stores the data in the instance.
   void parse(Map map) {
-    name = parseString(
-        widgetModelType == WidgetModelType.column ? 'column' : 'name', map,
-        required: true);
     super.parse(map);
     label = parseString('label', map, required: false);
     toolTip = parseString('toolTip', map, required: false);
     filterType = parseEnum<FilterType>('filterType', map, FilterType.values);
-    options = parseOptions('options', map);
     validatorsString = parseString('validators', map);
     parseValidatorsText(parseString('validatorsText', map));
     dataType = parseEnum<DataType>('dataType', map, DataType.values);
     if (dataType == null) {
-      switch (widgetModelType) {
-        case WidgetModelType.checkbox:
+      switch (modelType) {
+        case ModelTypeBones.checkbox:
           dataType = DataType.bool;
           break;
         default:
@@ -265,9 +263,6 @@ abstract class FieldModel extends WidgetModel {
       value = row[name];
     }
   }
-
-  @override
-  String widgetName() => name;
 }
 
 abstract class ValidatorController {}
index 1ada1d68ded3473d638e17281a73072c3ef74dba..8e614c4fe766829184084598f6fcf78c7b55a2d9 100644 (file)
@@ -1,5 +1,6 @@
 import 'package:dart_bones/dart_bones.dart';
 import 'package:meta/meta.dart';
+
 import '../helper/string_helper.dart';
 import 'model_types.dart';
 
@@ -7,11 +8,13 @@ import 'model_types.dart';
 abstract class ModelBase {
   BaseLogger logger;
   List<String> options;
+  String name;
+  static int lastId = 0;
+  final ModelTypeBones modelType;
+  int id;
 
-  ModelBase(this.options, this.logger);
-
-  void parse(Map map) {
-    options = parseOptions('options', map);
+  ModelBase(this.modelType, this.options, this.logger) {
+    this.id = ++lastId;
   }
 
   /// Tests the validity of the entries in [options] comparing with an [regExpr].
@@ -27,15 +30,6 @@ abstract class ModelBase {
     return rc;
   }
 
-  /// Tests whether a given [option] is part of [options].
-  bool hasOption(String option) {
-    if (options == null) {
-      return false;
-    }
-    bool rc = options.contains(option);
-    return rc;
-  }
-
   /// Tests a [map] for superfluous [keys].
   /// Keys of the [map] that are not listed in [keys] will be logged as errors.
   /// Keys that do not have the type String are logged as errors.
@@ -50,12 +44,48 @@ abstract class ModelBase {
   /// Returns the name including the names of the parent
   String fullName();
 
+  /// Tests whether a given [option] is part of [options].
+  bool hasOption(String option) {
+    if (options == null) {
+      return false;
+    }
+    bool rc = options.contains(option);
+    return rc;
+  }
+
   /// Converts a [list] of strings to a string.
   String listToString(List<String> list) {
     final rc = list == null ? 'null' : list.join(' ');
     return rc;
   }
 
+  /// Parses the [map] for properties of ModelBase.
+  /// [nameLabel]: the key of the name property, e.g. "name".
+  /// [required]: if true and the property is not part of the map an error will
+  /// be logged.
+  /// Note: Does not make a automatic name if not required: it must be done
+  /// by the caller. Reason: different parents TableModel and PageModel to hold
+  /// the [NameBuilder] instance.
+  void parseBase(Map map, {String nameLabel = 'name', bool required = false}) {
+    name = parseString(nameLabel, map, required: required);
+    options = parseOptions('options', map);
+  }
+
+  /// Fetches an entry from a map addressed by a [key].
+  /// An error is logged if [required] is true and the map does not contain the key.
+  dynamic parseDynamic(String key, Map<String, dynamic> map,
+      {bool required = false}) {
+    dynamic rc;
+    if (!map.containsKey(key)) {
+      if (required) {
+        logger.error('missing int attribute "$key" in ${fullName()}');
+      }
+    } else {
+      rc = map[key];
+    }
+    return rc;
+  }
+
   /// Fetches an entry from a map addressed by a [key].
   /// An error is logged if [required] is true and the map does not contain the key.
   T parseEnum<T>(String key, Map<String, dynamic> map, List values,
@@ -107,21 +137,6 @@ abstract class ModelBase {
     return rc;
   }
 
-  /// Fetches an entry from a map addressed by a [key].
-  /// An error is logged if [required] is true and the map does not contain the key.
-  dynamic parseDynamic(String key, Map<String, dynamic> map,
-      {bool required = false}) {
-    dynamic rc;
-    if (!map.containsKey(key)) {
-      if (required) {
-        logger.error('missing int attribute "$key" in ${fullName()}');
-      }
-    } else {
-      rc = map[key];
-    }
-    return rc;
-  }
-
   /// Fetches an entry from a map addressed by a [key].
   /// An error is logged if [required] is true and the map does not contain the key.
   List<String> parseOptions(String key, Map<String, dynamic> map) {
@@ -224,7 +239,7 @@ abstract class ModelBase {
     return rc;
   }
 
-  String widgetName();
+  String widgetName() => name;
 
   /// Tests whether an [object] is a list type.
   /// Works for JSArray<dynamic>, List
@@ -240,3 +255,20 @@ abstract class ModelBase {
     return name.contains('Map');
   }
 }
+
+enum ModelTypeBones {
+  allDbFields,
+  button,
+  checkbox,
+  column,
+  combobox,
+  dbReference,
+  emptyLine,
+  image,
+  module,
+  page,
+  section,
+  table,
+  text,
+  textField,
+}
index e283b4581b3651f7e3f73ee16b877164241c3c26..9ecc131839b1801dcb75668e5b5bb2a94fccf151 100644 (file)
@@ -2,6 +2,7 @@ import 'package:dart_bones/dart_bones.dart';
 import 'package:meta/meta.dart';
 
 import '../helper/string_helper.dart';
+import '../helper/name_builder.dart';
 import 'column_model.dart';
 import 'field_model.dart';
 import 'model_base.dart';
@@ -17,12 +18,14 @@ import 'widget_model.dart';
 class ModuleModel extends ModelBase {
   static final regExprOptions = RegExp(r'^(noPages)$');
   final Map<String, dynamic> map;
-  String name;
   @protected
   final pages = <PageModel>[];
   final tables = <TableModel>[];
-
-  ModuleModel(this.map, BaseLogger logger) : super(null, logger);
+  NameBuilder nameBuilder;
+  ModuleModel(this.map, BaseLogger logger)
+      : super(ModelTypeBones.module, null, logger) {
+    nameBuilder = NameBuilder(logger);
+  }
 
   /// Adds the column [name] from [source] to [target] if that column is not member of [target].
   void addColumnIfMissing(
@@ -335,8 +338,7 @@ modules:
   /// Parses the [map]and stores the data in the instance.
   void parse([Map map]) {
     map ??= this.map;
-    name = parseString('module', map, required: true);
-    super.parse(map);
+    super.parseBase(map, nameLabel: 'module', required: true);
     checkSuperfluousAttributes(map, 'module options pages tables'.split(' '));
     if (map.containsKey('tables')) {
       TableModel.parseList(this, map['tables'], logger);
@@ -363,7 +365,4 @@ modules:
         orElse: () => null);
     return found;
   }
-
-  @override
-  String widgetName() => name;
 }
index 20ceed6d7fc89a59aefb036dd359efa58ab8bb3f..536a84329c67b23bb580db41834dbaa22f790763 100644 (file)
@@ -1,5 +1,6 @@
 import 'package:dart_bones/dart_bones.dart';
 
+import '../helper/name_builder.dart';
 import 'button_model.dart';
 import 'field_model.dart';
 import 'model_base.dart';
@@ -13,7 +14,6 @@ typedef FilterWidget = bool Function(WidgetModel item);
 class PageModel extends ModelBase {
   static final regExprOptions = RegExp(r'^(noAutoButton)$');
   final ModuleModel module;
-  String name;
   final List<SectionModel> sections = [];
   PageModelType pageModelType;
   final fields = <FieldModel>[];
@@ -22,8 +22,12 @@ class PageModel extends ModelBase {
   String sql;
   List<String> tableTitles;
   List<String> tableColumns;
+  NameBuilder nameBuilder;
 
-  PageModel(this.module, BaseLogger logger) : super(null, logger);
+  PageModel(this.module, BaseLogger logger)
+      : super(ModelTypeBones.page, null, logger) {
+    nameBuilder = NameBuilder(logger);
+  }
 
   /// Adds a [button] to the [this.buttons].
   /// If already defined and error is logged.
@@ -36,24 +40,6 @@ class PageModel extends ModelBase {
     }
   }
 
-  /// Returns a button named [name] or null if not found.
-  ButtonModel buttonByName(String name, {bool required = true}) {
-    final rc =
-        buttons.firstWhere((item) => item.name == name, orElse: () => null);
-    if (rc == null && required) {
-      logger.error('missing button $name in page ${fullName()}');
-    }
-    return rc;
-  }
-
-  /// Tests whether the field with [name] is part of the page.
-  bool hasField(String name) {
-    final first = fields.firstWhere((element) => element.name == name,
-        orElse: () => null);
-    final rc = first != null;
-    return rc;
-  }
-
   /// Adds a [field] to the [this.fields].
   /// If already defined and error is logged.
   void addField(FieldModel field) {
@@ -66,6 +52,16 @@ class PageModel extends ModelBase {
     }
   }
 
+  /// Returns a button named [name] or null if not found.
+  ButtonModel buttonByName(String name, {bool required = true}) {
+    final rc =
+        buttons.firstWhere((item) => item.name == name, orElse: () => null);
+    if (rc == null && required) {
+      logger.error('missing button $name in page ${fullName()}');
+    }
+    return rc;
+  }
+
   /// Dumps the internal structure into a [stringBuffer]
   StringBuffer dump(StringBuffer stringBuffer) {
     stringBuffer
@@ -76,10 +72,6 @@ class PageModel extends ModelBase {
     return stringBuffer;
   }
 
-  /// Returns the name including the names of the parent
-  @override
-  String fullName() => '${module.name}.$name';
-
   /// Returns a field by [name] or null on error.
   FieldModel fieldByName(String name, {bool required = true}) {
     final rc = fields.firstWhere((element) => element.name == name,
@@ -90,6 +82,10 @@ class PageModel extends ModelBase {
     return rc;
   }
 
+  /// Returns the name including the names of the parent
+  @override
+  String fullName() => '${module.name}.$name';
+
   /// Returns a list of widget models (in order as defined) matching the [filter].
   /// If [filter] is none all widgets will be returned.
   List<dynamic> getWidgets(FilterWidget filter) {
@@ -104,9 +100,20 @@ class PageModel extends ModelBase {
     return rc;
   }
 
+  /// Tests whether the field with [name] is part of the page.
+  bool hasField(String name) {
+    final first = fields.firstWhere((element) => element.name == name,
+        orElse: () => null);
+    final rc = first != null;
+    return rc;
+  }
+
   /// Parses the [map]and stores the data in the instance.
   void parse(Map map) {
-    name = parseString('page', map, required: true);
+    super.parseBase(map, nameLabel: 'page', required: true);
+    if (name == null) {
+      name = module.nameBuilder.nextName('autoPage');
+    }
     checkSuperfluousAttributes(
         map,
         'options page pageType sections sql tableColumns tableTitles'
@@ -114,7 +121,6 @@ class PageModel extends ModelBase {
     pageModelType = parseEnum<PageModelType>(
         'pageType', map, PageModelType.values,
         required: true);
-    options = parseOptions('options', map);
     if (!map.containsKey('sections')) {
       logger.error('missing sections in page ${fullName()}');
     } else {
@@ -169,9 +175,6 @@ class PageModel extends ModelBase {
     checkOptionsByRegExpr(regExprOptions);
   }
 
-  @override
-  String widgetName() => name;
-
   /// Returns a list of Pages constructed by the Json like [list].
   static void parseList(
       ModuleModel module, List<dynamic> list, BaseLogger logger) {
index 35b54306df1dc601b7cc16dcdf20f6966955bf2f..fff24198c5654e96a311cfc9d9cfaa4e8938e1d7 100644 (file)
@@ -16,14 +16,12 @@ import 'widget_model.dart';
 class SectionModel extends WidgetModel {
   static final regExprOptions = RegExp(r'^(unknown)$');
   SectionModelType sectionModelType;
-  String name;
   final children = <WidgetModel>[];
   final buttons = <WidgetModel>[];
   final int no;
 
-  SectionModel(this.no, PageModel page, SectionModel section,
-      BaseLogger logger)
-      : super(section, page, WidgetModelType.section, null, logger);
+  SectionModel(this.no, PageModel page, SectionModel section, BaseLogger logger)
+      : super(section, page, ModelTypeBones.section, null, logger);
 
   /// Dumps the internal structure into a [stringBuffer]
   StringBuffer dump(StringBuffer stringBuffer) {
@@ -43,13 +41,14 @@ class SectionModel extends WidgetModel {
 
   /// Parses the [map]and stores the data in the instance.
   void parse(Map map) {
+    super.parseBase(map, nameLabel: 'section');
+    if (name == null) {
+      name = page.nameBuilder.nextName('section');
+    }
     sectionModelType = parseEnum<SectionModelType>(
         'sectionType', map, SectionModelType.values);
-    name = parseString('name', map) ??
-        '${StringUtils.enumToString(sectionModelType)}$no';
-    checkSuperfluousAttributes(
-        map, 'children fields name options sectionType widgetType'.split(' '));
-    options = parseOptions('options', map);
+    checkSuperfluousAttributes(map,
+        'children fields modelType section options sectionType'.split(' '));
 
     checkOptionsByRegExpr(regExprOptions);
     if (!map.containsKey('children')) {
@@ -68,57 +67,57 @@ class SectionModel extends WidgetModel {
                 .error('child $no of "children" is not a map in ${fullName()}: '
                     '${StringUtils.limitString(child.toString(), 80)}');
           } else {
-            if (!child.containsKey('widgetType')) {
+            if (!child.containsKey('modelType')) {
               logger.error(
-                  'child $no of "children" does not have "widgetType" in ${fullName()}: '
+                  'child $no of "children" does not have "modelType" in ${fullName()}: '
                   '${StringUtils.limitString(child.toString(), 80)}');
             } else {
-              final widgetType = StringUtils.stringToEnum<WidgetModelType>(
-                  child['widgetType'].toString(), WidgetModelType.values);
+              final modelType = StringUtils.stringToEnum<ModelTypeBones>(
+                  child['modelType'].toString(), ModelTypeBones.values);
               WidgetModel widget;
-              switch (widgetType) {
-                case WidgetModelType.allDbFields:
+              switch (modelType) {
+                case ModelTypeBones.allDbFields:
                   widget = AllDbFieldsModel(this, page, logger);
                   break;
-                case WidgetModelType.checkbox:
+                case ModelTypeBones.checkbox:
                   widget = CheckboxModel(this, page, logger);
                   break;
-                case WidgetModelType.combobox:
+                case ModelTypeBones.combobox:
                   widget = ComboboxModel(this, page, logger);
                   break;
-                case WidgetModelType.textField:
+                case ModelTypeBones.textField:
                   widget = TextFieldModel(this, page, logger);
                   break;
-                case WidgetModelType.button:
+                case ModelTypeBones.button:
                   widget = ButtonModel(this, page, logger);
                   break;
-                case WidgetModelType.text:
+                case ModelTypeBones.text:
                   widget = TextModel(this, page, logger);
                   break;
-                case WidgetModelType.emptyLine:
+                case ModelTypeBones.emptyLine:
                   widget = EmptyLineModel(this, page, logger);
                   break;
-                case WidgetModelType.dbReference:
+                case ModelTypeBones.dbReference:
                   widget = DbReferenceModel(this, page, logger);
                   break;
                 default:
                   //@ToDo: nested section
                   logger.error(
-                      'Section: unknown "widgetType" ${child['widgetType']} in ${fullName()}');
+                      'Section: unknown "modelType" ${child["modelType"]} in ${fullName()}');
                   break;
               }
               if (widget != null) {
                 children.add(widget);
                 widget.parse(child);
                 page.widgets.add(widget);
-                switch (widget.widgetModelType) {
-                  case WidgetModelType.button:
+                switch (widget.modelType) {
+                  case ModelTypeBones.button:
                     page.addButton(widget);
                     break;
-                  case WidgetModelType.textField:
-                  case WidgetModelType.combobox:
-                  case WidgetModelType.checkbox:
-                  case WidgetModelType.dbReference:
+                  case ModelTypeBones.textField:
+                  case ModelTypeBones.combobox:
+                  case ModelTypeBones.checkbox:
+                  case ModelTypeBones.dbReference:
                     page.addField(widget);
                     break;
                   default:
@@ -144,18 +143,15 @@ class SectionModel extends WidgetModel {
             'curious item in section list of ${page.fullName()}: ${StringUtils.limitString("$item", 80)}');
       } else {
         final current = SectionModel(no, page, null, logger);
-        current.parse(item);
         if (section != null) {
           section.children.add(current);
         } else {
           page.sections.add(current);
         }
+        current.parse(item);
       }
     }
   }
-
-  @override
-  String widgetName() => name;
 }
 
 enum SectionModelType {
index 910a25b6b123f6577b534cf68aa5b925b667ec1a..f9b47dfe0fbc0bd30d9a5ff9eddb9e398fd38ccd 100644 (file)
@@ -26,7 +26,8 @@ class ConfigurationModel extends ModuleModel {
             'size': 64,
             'options': 'notnull',
             'validators': r'required regExpr=i/^\w+$',
-            'validatorsText': 'regExpr=Nur Buchstaben, Ziffern und Unterstrich erlaubt',
+            'validatorsText':
+                'regExpr=Nur Buchstaben, Ziffern und Unterstrich erlaubt',
           },
           {
             'column': 'configuration_property',
@@ -72,7 +73,7 @@ class ConfigurationModel extends ModuleModel {
             "sectionType": "simpleForm",
             "children": [
               {
-                "widgetType": "allDbFields",
+                'modelType': "allDbFields",
               }
             ]
           }
@@ -86,7 +87,7 @@ class ConfigurationModel extends ModuleModel {
             "sectionType": "simpleForm",
             "children": [
               {
-                "widgetType": "allDbFields",
+                'modelType': "allDbFields",
               }
             ]
           }
@@ -105,14 +106,14 @@ class ConfigurationModel extends ModuleModel {
               {
                 "name": "configuration_scope",
                 "label": "Bereich",
-                "widgetType": "textField",
+                'modelType': "textField",
                 "filterType": "pattern",
                 //"options": 'undef',
               },
               {
                 "name": "configuration_property",
                 "label": "Eigenschaft",
-                "widgetType": "textField",
+                'modelType': "textField",
                 "filterType": "pattern",
               },
             ]
index 53eed8a994866cfa841cfb4bf01fa83d324730bd..f4bf5ec7e0c18ee897d6f5ce9c393cfc699b05dd 100644 (file)
@@ -43,7 +43,7 @@ class MenuModel extends ModuleModel {
             'sectionType': 'simpleForm',
             'children': [
               {
-                'widgetType': 'allDbFields',
+                'modelType': 'allDbFields',
               }
             ]
           }
@@ -57,7 +57,7 @@ class MenuModel extends ModuleModel {
             'sectionType': 'simpleForm',
             'children': [
               {
-                'widgetType': 'allDbFields',
+                'modelType': 'allDbFields',
               },
             ]
           }
@@ -73,7 +73,7 @@ class MenuModel extends ModuleModel {
             'sectionType': 'filterPanel',
             'children': [
               {
-                'widgetType': 'dbReference',
+                'modelType': 'dbReference',
                 'filterType': 'pattern',
                 'name': 'menu_name',
                 'column': 'menu_name',
index 24e71796c83d2d5221005108d50a0dd9c15e628c..937f3034f69f3fcae300adebdab059396b010657 100644 (file)
@@ -45,7 +45,7 @@ class RoleModel extends ModuleModel {
             "sectionType": "simpleForm",
             "children": [
               {
-                "widgetType": "allDbFields",
+                'modelType': "allDbFields",
               }
             ]
           }
@@ -59,7 +59,7 @@ class RoleModel extends ModuleModel {
             "sectionType": "simpleForm",
             "children": [
               {
-                "widgetType": "allDbFields",
+                'modelType': "allDbFields",
               }
             ]
           }
@@ -75,7 +75,7 @@ class RoleModel extends ModuleModel {
             "sectionType": "filterPanel",
             "children": [
               {
-                "widgetType": "textField",
+                'modelType': "textField",
                 "filterType": "pattern",
                 "name": "role_name",
                 "label": "Name",
index 0dc4c622e124835e12ba28c71dfd361a46c13703..ef8a81e2ab54c95ef5fccecfa8661c432d0425d3 100644 (file)
@@ -66,7 +66,7 @@ class UserModel extends ModuleModel {
             "sectionType": "simpleForm",
             "children": [
               {
-                "widgetType": "allDbFields",
+                'modelType': "allDbFields",
               }
             ]
           }
@@ -80,10 +80,10 @@ class UserModel extends ModuleModel {
             "sectionType": "simpleForm",
             "children": [
               {
-                "widgetType": "allDbFields",
+                'modelType': "allDbFields",
               },
               {
-                "widgetType": "button",
+                'modelType': "button",
                 "name": "set_password",
                 "label": "Passwort ändern",
                 "buttonType": "custom",
@@ -101,19 +101,19 @@ class UserModel extends ModuleModel {
             "sectionType": "simpleForm",
             "children": [
               {
-                "widgetType": "text",
+                'modelType': "text",
                 "text": "Ändern des Passworts von Benutzer ~user~",
-                "options": "placeholder"
+                "options": "placeholder h3"
               },
               {
-                "widgetType": "textField",
+                'modelType': "textField",
                 "name": "user_password",
                 "label": "Passwort",
                 "options": "password",
                 "validators": "required",
               },
               {
-                "widgetType": "textField",
+                'modelType': "textField",
                 "name": "repetition",
                 "label": "Wiederholung",
                 "options": "password",
@@ -134,7 +134,7 @@ class UserModel extends ModuleModel {
             "sectionType": "filterPanel",
             "children": [
               {
-                "widgetType": "dbReference",
+                'modelType': "dbReference",
                 "filterType": "pattern",
                 "name": "user_name",
                 "column": "user_name",
@@ -142,7 +142,7 @@ class UserModel extends ModuleModel {
                     "Filter bezüglich des Namens der anzuzeigenden Einträge: Joker '*' (beliebiger String) ist erlaubt."
               },
               {
-                "widgetType": "dbReference",
+                'modelType': "dbReference",
                 "name": "user_role",
                 "filterType": "equals",
                 "column": "user_role",
@@ -162,20 +162,20 @@ class UserModel extends ModuleModel {
             "sectionType": "simpleForm",
             "children": [
               {
-                "widgetType": "textField",
+                'modelType': "textField",
                 "name": "user",
                 "label": "Benutzer oder EMail",
                 "validators": "required",
               },
               {
-                "widgetType": "textField",
+                'modelType': "textField",
                 "name": "password",
                 "label": "Password",
                 "options": "password",
                 "validators": "required",
               },
               {
-                "widgetType": "button",
+                'modelType': "button",
                 "buttonType": "custom",
                 "name": "login",
                 "label": "Anmelden",
index 83ebf8331821369c2a8ef39b3eaec66654336e71..a77cabbc13fbbd3360486fb40845c4cbea6a8e21 100644 (file)
@@ -1,5 +1,6 @@
 import 'package:dart_bones/dart_bones.dart';
 
+import '../helper/name_builder.dart';
 import 'column_model.dart';
 import 'model_base.dart';
 import 'model_types.dart';
@@ -9,11 +10,14 @@ import 'module_model.dart';
 class TableModel extends ModelBase {
   static final regExprOptions = RegExp(r'^(unknown)$');
   final ModuleModel module;
-  String name;
   final columns = <ColumnModel>[];
   ColumnModel primary;
+  NameBuilder nameBuilder;
 
-  TableModel(this.module, BaseLogger logger) : super(null, logger);
+  TableModel(this.module, BaseLogger logger)
+      : super(ModelTypeBones.table, null, logger) {
+    nameBuilder = NameBuilder(logger);
+  }
 
   /// Adds a [button] to the [this.buttons].
   /// If already defined and error is logged.
@@ -69,9 +73,11 @@ class TableModel extends ModelBase {
 
   /// Parses the [map]and stores the data in the instance.
   void parse(Map map) {
-    name = parseString('table', map, required: true);
+    super.parseBase(map, nameLabel: 'table', required: true);
+    if (name == null) {
+      name = module.nameBuilder.nextName('autoTable');
+    }
     checkSuperfluousAttributes(map, 'columns options table'.split(' '));
-    options = parseOptions('options', map);
     if (!map.containsKey('columns')) {
       logger.error('missing columns in table ${fullName()}');
     } else {
index 8946e88fe06b3387a841a76aed48f0a3b6013052..bbe4072c8fc992b10ae0b8298c9c0a01b16fbb40 100644 (file)
@@ -4,7 +4,7 @@ import 'field_model.dart';
 import 'model_types.dart';
 import 'page_model.dart';
 import 'section_model.dart';
-import 'widget_model.dart';
+import 'model_base.dart';
 
 /// Describes a form text field widget.
 class TextFieldModel extends FieldModel {
@@ -14,9 +14,8 @@ class TextFieldModel extends FieldModel {
   int rows;
   var value;
 
-  TextFieldModel(
-      SectionModel section, PageModel page, BaseLogger logger)
-      : super(section, page, WidgetModelType.textField, logger);
+  TextFieldModel(SectionModel section, PageModel page, BaseLogger logger)
+      : super(section, page, ModelTypeBones.textField, logger);
 
   TextFieldModel.direct(
       SectionModel section,
@@ -28,8 +27,8 @@ class TextFieldModel extends FieldModel {
       List<String> options,
       dynamic defaultValue,
       BaseLogger logger)
-      : super.direct(section, page, WidgetModelType.textField, name,
-            label, toolTip, dataType, options, defaultValue, logger);
+      : super.direct(section, page, ModelTypeBones.textField, name, label,
+            toolTip, dataType, defaultValue, options, logger);
 
   /// Dumps the internal structure into a [stringBuffer]
   StringBuffer dump(StringBuffer stringBuffer) {
@@ -43,7 +42,7 @@ class TextFieldModel extends FieldModel {
     super.parse(map);
     checkSuperfluousAttributes(
         map,
-        'dataType filterType label maxSize name options rows toolTip validators validatorsText value widgetType'
+        'dataType filterType label maxSize modelType name options rows toolTip validators validatorsText value'
             .split(' '));
     maxSize = parseInt('maxSize', map, required: false);
     rows = parseInt('rows', map, required: false);
@@ -56,7 +55,6 @@ class TextFieldModel extends FieldModel {
         value = parseString('value', map);
         break;
     }
-    options = parseOptions('options', map);
     checkOptionsByRegExpr(regExprOptions);
     parseFinish();
   }
index 59994c271a7f93562de7eb14247d80ac44edf7ee..bc5104cb21ece04b2bd5610d7fc2f8f679f2c38c 100644 (file)
@@ -1,6 +1,7 @@
 import 'package:dart_bones/dart_bones.dart';
 import 'page_model.dart';
 import 'section_model.dart';
+import 'model_base.dart';
 import 'widget_model.dart';
 
 /// Describes a text widget without user interaction.
@@ -10,28 +11,28 @@ class TextModel extends WidgetModel {
   bool isRichText;
 
   TextModel(SectionModel section, PageModel page, BaseLogger logger)
-      : super(section, page, WidgetModelType.text, null, logger);
+      : super(section, page, ModelTypeBones.text, null, logger);
 
   /// Returns the name including the names of the parent
   @override
-  String fullName() => '${section.name}.text$id';
+  String fullName() => '${section.name}.$name';
 
   /// Dumps the internal structure into a [stringBuffer]
   StringBuffer dump(StringBuffer stringBuffer) {
     stringBuffer
-        .write('    text $id text: $text: options: ${options.join(' ')}\n');
+        .write('    text $name text: $text: options: ${options.join(' ')}\n');
     return stringBuffer;
   }
 
   /// Parses the [map]and stores the data in the instance.
   void parse(Map map) {
-    checkSuperfluousAttributes(map, 'options text widgetType'.split(' '));
+    super.parseBase(map);
+    if (name == null) {
+      name = page.nameBuilder.nextName('text');
+    }
+    checkSuperfluousAttributes(map, 'modelType name options text'.split(' '));
     text = parseString('text', map, required: true);
-    options = parseOptions('options', map);
     checkOptionsByRegExpr(regExprOptions);
     isRichText = options.contains('richText');
   }
-
-  @override
-  String widgetName() => 'text$id';
 }
index a7d4b02daf803f286048b6d020e0d328585c514a..8d8cc150da612eb351b05fda4f86f2f0b309222e 100644 (file)
@@ -7,17 +7,12 @@ import 'combo_base_model.dart';
 
 /// A base class for items inside a page: SectionModel ButtonModel TextModel...
 abstract class WidgetModel extends ModelBase {
-  static int lastId = 0;
   final SectionModel section;
   PageModel page;
-  final WidgetModelType widgetModelType;
-  int id;
 
-  WidgetModel(this.section, this.page, this.widgetModelType,
+  WidgetModel(this.section, this.page, ModelTypeBones modelType,
       List<String> options, BaseLogger logger)
-      : super(options, logger) {
-    this.id = ++lastId;
-  }
+      : super(modelType, options, logger);
 
   /// Returns whether the model must be completed asynchronously e.g. by
   /// [Persistence].
@@ -29,24 +24,18 @@ abstract class WidgetModel extends ModelBase {
   /// Dumps the internal structure into a [stringBuffer]
   StringBuffer dump(StringBuffer stringBuffer);
 
-  void parse(Map map){
-    super.parse(map);
+  void parse(Map map) {
+    final required = [
+      ModelTypeBones.button,
+      ModelTypeBones.checkbox,
+      ModelTypeBones.combobox,
+      ModelTypeBones.dbReference,
+      ModelTypeBones.textField,
+    ].contains(modelType);
+    var label = modelType == ModelTypeBones.column ? 'column' : 'name';
+    super.parseBase(map, nameLabel: label, required: required);
+    if (name == null && page != null) {
+      name = page.nameBuilder.nextName(StringUtils.enumToString(modelType));
+    }
   }
-
-  String widgetName();
-}
-
-enum WidgetModelType {
-  allDbFields,
-  button,
-  checkbox,
-  column,
-  combobox,
-  dbReference,
-  emptyLine,
-  image,
-  section,
-  table,
-  text,
-  textField,
 }
index 1465cfb1c285da990dbd12ca6543a5ca5e64272b..e0867d05f095a2d2f9b919d64f57ce108d91e7b8 100644 (file)
@@ -29,7 +29,8 @@ class ConfigurationChangePage extends StatefulWidget {
   }
 }
 
-class ConfigurationChangePageState extends State<ConfigurationChangePage> implements RedrawPage {
+class ConfigurationChangePageState extends State<ConfigurationChangePage>
+    implements RedrawPage {
   final ApplicationData applicationData;
   final int primaryId;
   final Map initialRow;
@@ -63,15 +64,18 @@ class ConfigurationChangePageState extends State<ConfigurationChangePage> implem
         _formKey, this, 'change', context, applicationData);
     controller.initialize();
   }
+
   void dispose() {
     controller.dispose();
     super.dispose();
   }
 
   @override
-  void redraw(RedrawReason reason, {String customString, RedrawCallbackFunctionSimple callback}) {
-    setState( () {
-      controller.afterSetState(reason, customString: customString, callback: callback);
+  void redraw(RedrawReason reason,
+      {String customString, RedrawCallbackFunctionSimple callback}) {
+    setState(() {
+      controller.afterSetState(reason,
+          customString: customString, callback: callback);
     });
   }
 }
index 5fc1f6171102c45644bd5682bbaddda3b56ed404..f0af0606399afde608b738cf0c0c116a4961b25a 100644 (file)
@@ -8,12 +8,8 @@ import 'configuration_change_page.dart';
 
 class ConfigurationController extends PageControllerBones {
   /// Controller for a page named [pageName].
-  ConfigurationController(
-      GlobalKey<FormState> formKey,
-      RedrawPage parent,
-      String pageName,
-      BuildContext context,
-      ApplicationData applicationData,
+  ConfigurationController(GlobalKey<FormState> formKey, RedrawPage parent,
+      String pageName, BuildContext context, ApplicationData applicationData,
       {Function redrawCallback})
       : super(formKey, parent, ConfigurationModel(Settings().logger), pageName,
             context, applicationData, redrawCallback) {
index cb43aec078c9ed3942af069ece1d15a9906fa22e..9d74df8af1ee34e768f19a7e9125577119a66e67 100644 (file)
@@ -21,7 +21,8 @@ class ConfigurationCreatePage extends StatefulWidget {
   }
 }
 
-class ConfigurationCreatePageState extends State<ConfigurationCreatePage> implements RedrawPage {
+class ConfigurationCreatePageState extends State<ConfigurationCreatePage>
+    implements RedrawPage {
   final ApplicationData applicationData;
 
   final GlobalKey<FormState> _formKey =
@@ -51,10 +52,13 @@ class ConfigurationCreatePageState extends State<ConfigurationCreatePage> implem
         _formKey, this, 'create', context, applicationData);
     controller.initialize();
   }
+
   @override
-  void redraw(RedrawReason reason, {String customString, RedrawCallbackFunctionSimple callback}) {
-    setState( () {
-      controller.afterSetState(reason, customString: customString, callback: callback);
+  void redraw(RedrawReason reason,
+      {String customString, RedrawCallbackFunctionSimple callback}) {
+    setState(() {
+      controller.afterSetState(reason,
+          customString: customString, callback: callback);
     });
   }
 }
index b05b475c477794c3f35da9ef08e62227511344ef..3c12af1eaa05bd05f75f8fe51899b8467141d32e 100644 (file)
@@ -27,7 +27,7 @@ class RoleChangePage extends StatefulWidget {
   }
 }
 
-class RoleChangePageState extends State<RoleChangePage> implements RedrawPage{
+class RoleChangePageState extends State<RoleChangePage> implements RedrawPage {
   final ApplicationData applicationData;
   final int primaryId;
   final Map initialRow;
@@ -52,11 +52,12 @@ class RoleChangePageState extends State<RoleChangePage> implements RedrawPage{
           initialRow: initialRow,
         ));
   }
+
   @override
   void initState() {
     super.initState();
-    controller = RoleController(
-        _formKey, this, 'change', context, applicationData);
+    controller =
+        RoleController(_formKey, this, 'change', context, applicationData);
     controller.initialize();
   }
 
@@ -68,6 +69,7 @@ class RoleChangePageState extends State<RoleChangePage> implements RedrawPage{
           customString: customString, callback: callback);
     });
   }
+
   void dispose() {
     controller.dispose();
     super.dispose();
index 3d0cf8dcb8e0688c877b5501e59369fc57669e13..0ba6a1b102380463257f89e2fb3c555fb76f9304 100644 (file)
@@ -22,7 +22,7 @@ class RoleCreatePage extends StatefulWidget {
   }
 }
 
-class RoleCreatePageState extends State<RoleCreatePage> implements RedrawPage{
+class RoleCreatePageState extends State<RoleCreatePage> implements RedrawPage {
   final ApplicationData applicationData;
 
   final GlobalKey<FormState> _formKey =
@@ -34,7 +34,7 @@ class RoleCreatePageState extends State<RoleCreatePage> implements RedrawPage{
 
   @override
   Widget build(BuildContext context) {
-    controller.beginOfBuild(context);
+    controller?.beginOfBuild(context);
     return Scaffold(
         appBar: applicationData.appBarBuilder('Neue Rolle'),
         drawer: applicationData.drawerBuilder(context),
@@ -44,11 +44,12 @@ class RoleCreatePageState extends State<RoleCreatePage> implements RedrawPage{
           configuration: applicationData.configuration,
         ));
   }
+
   @override
   void initState() {
     super.initState();
-    controller = RoleController(
-        _formKey, this, 'create', context, applicationData);
+    controller =
+        RoleController(_formKey, this, 'create', context, applicationData);
     controller.initialize();
   }
 
index 6e53d7dde97f6b316831a5f0285e6e28d27a6332..4719315048ee63554cc708ee6e92c8c0546c1f36 100644 (file)
@@ -21,7 +21,7 @@ class RoleListPage extends StatefulWidget {
   }
 }
 
-class RoleListPageState extends State<RoleListPage> implements RedrawPage{
+class RoleListPageState extends State<RoleListPage> implements RedrawPage {
   final ApplicationData applicationData;
 
   final GlobalKey<FormState> _formKey =
index 91d75e15383e1adf4727a2302f3c82ee986203c3..6519eae28d10d499ad337a4d56d9ab6a2de4bf99 100644 (file)
@@ -23,5 +23,4 @@ class UserController extends PageControllerBones {
         MaterialPageRoute(
             builder: (context) => UserChangePage(id, applicationData, row)));
   }
-
 }
index 2b126171bf0a17fd369572f366edd3c359c5f39a..cedfec337a4f65386cbdbd2e2aa8f121de79b6c4 100644 (file)
@@ -32,7 +32,8 @@ class UserPasswordPage extends StatefulWidget {
   }
 }
 
-class UserPasswordPageState extends State<UserPasswordPage> implements RedrawPage {
+class UserPasswordPageState extends State<UserPasswordPage>
+    implements RedrawPage {
   final ApplicationData applicationData;
   final int primaryId;
   final String userName;
index 90275e460a436c6df13db5d7bcce4a83e0e198fe..161cb9995b86affe33def41a971905d7e1b33163 100644 (file)
@@ -21,7 +21,7 @@ class EditForm {
   }) {
     final padding =
         configuration.asFloat('form.card.padding', defaultValue: 16.0);
-    pageController.buildWidgetList(initialRow);
+    pageController.buildModelList(initialRow);
     final widgets = pageController.getWidgets();
     final view = View();
     final buttons =
index 7b9ce3091f128451136503363f479f6106bf5700..61dfe098c777ec0fb5dd1f63f6336ea105086983 100644 (file)
@@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
 import 'package:flutter_bones/src/widget/page_controller_bones.dart';
 
 import '../helper/string_helper.dart';
-import 'widget_list.dart';
+import 'model_list.dart';
 import 'page_controller_bones.dart';
 import 'view.dart';
 
@@ -87,7 +87,7 @@ class ListForm {
   /// If [errorMessage] is not null this message will be shown.
   static Form listForm(
       {@required Key key,
-      @required WidgetList filters,
+      @required ModelList filters,
       @required List<Widget> buttons,
       @required List<Widget> titles,
       @required List<String> columnNames,
@@ -100,8 +100,9 @@ class ListForm {
     final padding =
         configuration.asFloat('form.card.padding', defaultValue: 16.0);
 
+    final view = View(pageController.moduleModel.logger);
     final widgets = <Widget>[
-      ...filters.widgets,
+      ...view.modelsToWidgets(filters.models, pageController),
       SizedBox(
           height: configuration.asFloat('form.gap.field_button.height',
               defaultValue: 16.0)),
diff --git a/lib/src/widget/model_list.dart b/lib/src/widget/model_list.dart
new file mode 100644 (file)
index 0000000..b68a890
--- /dev/null
@@ -0,0 +1,103 @@
+import 'package:dart_bones/dart_bones.dart';
+import 'package:flutter_bones/flutter_bones.dart';
+
+import '../helper/string_helper.dart';
+import '../model/model_types.dart';
+import 'page_controller_bones.dart';
+
+/// Manages a list of named widgets.
+class ModelList {
+  final String name;
+  final BaseLogger logger;
+  final models = <WidgetModel>[];
+
+  /// Data that will be filled asynchronously.
+  final waitCandidates = <FieldModel>[];
+
+  ModelList(this.name, this.logger);
+
+  /// Tests whether the widget list is empty.
+  bool get isEmpty => models.isEmpty;
+
+  /// Returns null or the index of the model named [name].
+  int indexOf(String name) {
+    int rc;
+    int ix = -1;
+    for (var model in models) {
+      ix++;
+      if (model.name == name) {
+        rc = ix;
+        break;
+      }
+    }
+    return rc;
+  }
+
+  /// Adds a [model] to the [widgets] behind the position of [predecessor].
+  /// If [predecessor] is null the widget will be the first in [widgets]
+  void addSuccessorOf(String predecessor, String name, WidgetModel model) {
+    if (predecessor == null) {
+      models.insert(0, model);
+    } else {
+      final ix = indexOf(predecessor);
+      if (ix == null) {
+        logger
+            .error('$name.addSuccessorOf(): missing predecessor $predecessor');
+      } else {
+        models.insert(ix, model);
+      }
+    }
+    addModel(name, model);
+  }
+
+  /// Adds a widget to the widget list.
+  void addModel(String name, ModelBase model) {
+    if (name != null) {
+      if (indexOf(name) != null) {
+        logger.error('$name.addWidget(): widget $name already defined');
+      } else {
+        models.add(model);
+      }
+    }
+    models.add(model);
+  }
+
+  /// Builds the SQL parameters of all members of the [widgets].
+  Map<String, String> buildSqlParams(PageControllerBones controller) {
+    final rc = <String, String>{};
+    final page = controller.moduleModel.pageByName(controller.pageName);
+    final isCreatePage = page.pageModelType == PageModelType.create;
+    models.forEach((model) {
+      dynamic value;
+      DataType dataType;
+      if (model is FieldModel) {
+        value = model.value;
+        dataType = model.dataType;
+      }
+      if (dataType != null) {
+        rc[':${model.name}'] = StringHelper.asDatabaseString(value, dataType);
+      }
+    });
+    final name = controller.moduleModel.mainTable().name +
+        (isCreatePage ? '_createdby' : '_changedby');
+    if (!rc.containsKey(name)) {
+      rc[':$name'] = controller.getApplicationData().currentUserName;
+    }
+    return rc;
+  }
+
+  /// Returns the widget given by [name] or null if not found.
+  ModelBase byName(String name) {
+    final ix = indexOf(name);
+    final rc = ix == null ? null : models[ix];
+    if (rc == null) {
+      logger.error('$name.byName(): missing widget $name');
+    }
+    return rc;
+  }
+
+  /// Remove all widgets from the list.
+  void clear() {
+    models.clear();
+  }
+}
index 8aedd993790f27e32776f169f838f62bb0bcd1c8..3c80ffa1a914e334f75d7dc4e5738f0a999e0a19 100644 (file)
@@ -14,23 +14,22 @@ import '../model/page_model.dart';
 import '../model/widget_model.dart';
 import '../page/application_data.dart';
 import 'view.dart';
-import 'widget_list.dart';
+import 'model_list.dart';
 import 'widget_validators.dart';
 
 typedef RedrawCallbackFunction = Function(RedrawReason reason,
     {String customString, RedrawCallbackFunctionSimple callback});
-typedef RedrawCallbackFunctionSimple = Function(
-    RedrawReason reason, {String customString});
+typedef RedrawCallbackFunctionSimple = Function(RedrawReason reason,
+    {String customString});
 
 class PageControllerBones implements ValidatorController {
   final ModuleModel moduleModel;
   String primaryColumn;
-  WidgetList widgetList;
+  ModelList widgetList;
   final RedrawCallbackFunction redrawCallback;
   final GlobalKey<FormState> globalKey;
   final String pageName;
   PageModel page;
-  ThemeData themeData;
   Future<bool> waitForCompletion;
   final ApplicationData applicationData;
   RedrawPage parent;
@@ -45,9 +44,9 @@ class PageControllerBones implements ValidatorController {
   /// Use exactly one of the parameter:
   /// [pageType]: in this case the route will be constructed
   /// [route]: the route of the new page, e.g. '/role/change'
-  void goTo({ PageModelType pageType, String route}) {
+  void goTo({PageModelType pageType, String route}) {
     applicationData.pushCaller(this);
-    if (pageType != null){
+    if (pageType != null) {
       route = '/${moduleModel.name}/${StringUtils.enumToString(pageType)}';
     }
     Navigator.pushNamed(context, route);
@@ -124,16 +123,20 @@ class PageControllerBones implements ValidatorController {
   /// Prepares the widgetList: builds the widgets of the page.
   /// [initialRow] is null or a map with the field values,
   /// e.g. { 'role_name': 'admin', ...}
-  void buildWidgetList([Map initialRow]) {
+  void buildModelList([Map initialRow]) {
     widgetList.clear();
-    final view = View(moduleModel.logger);
-    page.fields.forEach((model) {
+    page.widgets.forEach((model) {
       if (initialRow != null && model is FieldModel) {
         model.valueFromRow(initialRow);
       }
-      final value = initialRow == null ? null : initialRow[model.name];
+      final name = model is FieldModel ? model.name : null;
+      final value =
+          initialRow == null || name == null ? null : initialRow[name];
+      if (model is FieldModel) {
+        model.value = value;
+      }
       completeModels(model);
-      widgetList.addWidget(model.name, view.modelToWidget(model, this, value));
+      widgetList.addModel(name, model);
     });
     page.fields.forEach((element) => prepareModel(element));
   }
@@ -360,18 +363,19 @@ class PageControllerBones implements ValidatorController {
   ///
   List<Widget> getWidgets() {
     List<Widget> rc;
-    rc = View(moduleModel.logger).modelsToWidgets(page.fields, this);
+    rc = View(moduleModel.logger).modelsToWidgets(widgetList.models, this);
     return rc ?? [];
   }
 
+  ThemeData get themeData => Theme.of(context);
+
   /// Initializes the controller when the instance is complete constructed,
   /// e.g. ModuleModel.parse() is called.
   /// This method must be called early after the constructor.
   void initialize() {
-    themeData = Theme.of(context);
     page = moduleModel.pageByName(pageName);
-    widgetList = WidgetList('${page.fullName()}.widgets', moduleModel.logger);
-    buildWidgetList();
+    widgetList = ModelList('${page.fullName()}.widgets', moduleModel.logger);
+    buildModelList();
     if (page?.pageModelType == PageModelType.list) {
       buildRows();
     }
@@ -380,9 +384,9 @@ class PageControllerBones implements ValidatorController {
 
   /// Copies the values of [initialRow] into the values of the fields.
   void initializeFields(Map initialRow) {
-    widgetList.widgetMap.keys.forEach((name) {
-      if (initialRow.containsKey(name)) {
-        page.fieldByName(name)?.value = initialRow[name];
+    widgetList.models.forEach((model) {
+      if (model is FieldModel && initialRow.containsKey(model.name)) {
+        page.fieldByName(model.name)?.value = initialRow[model.name];
       }
     });
   }
@@ -399,7 +403,7 @@ class PageControllerBones implements ValidatorController {
   /// [reason] and [customString] will be forwarded to the callback function.
   void redraw(RedrawReason reason,
       {String customString, RedrawCallbackFunctionSimple callback}) {
-    switch(reason){
+    switch (reason) {
       case RedrawReason.fetchList:
         buildRows();
         break;
index 8986444d140688776d5b2a957d32146e7542d363..53d8e394b76a8e0b768deea7773e0e71af862ed0 100644 (file)
@@ -12,6 +12,7 @@ import '../model/model_types.dart';
 import '../model/section_model.dart';
 import '../model/text_model.dart';
 import '../model/widget_model.dart';
+import '../model/model_base.dart';
 import 'checkbox_list_tile_bone.dart';
 import 'dropdown_button_form_bone.dart';
 import 'page_controller_bones.dart';
@@ -229,38 +230,40 @@ class View {
     if (model is FieldModel && initialValue == null) {
       initialValue = model.value ?? model.defaultValue;
     }
-    switch (model?.widgetModelType) {
-      case WidgetModelType.textField:
+    switch (model?.modelType) {
+      case ModelTypeBones.textField:
         rc = textField(model, controller, initialValue);
         break;
-      case WidgetModelType.button:
+      case ModelTypeBones.button:
         rc = button(model, controller);
         break;
-      case WidgetModelType.emptyLine:
+      case ModelTypeBones.emptyLine:
         rc = emptyLine(model);
         break;
-      case WidgetModelType.text:
+      case ModelTypeBones.text:
         rc = text(model, controller);
         break;
-      case WidgetModelType.checkbox:
+      case ModelTypeBones.checkbox:
         rc = checkbox(model, controller, initialValue);
         break;
-      case WidgetModelType.combobox:
+      case ModelTypeBones.combobox:
         rc = combobox(model, controller, initialValue);
         break;
-      case WidgetModelType.image:
+      case ModelTypeBones.image:
         rc = image(model);
         break;
-      case WidgetModelType.section:
+      case ModelTypeBones.section:
         rc = section(model);
         break;
-      case WidgetModelType.dbReference:
+      case ModelTypeBones.dbReference:
         rc = dbReference(model, controller, initialValue);
         break;
-      case WidgetModelType.allDbFields:
+      case ModelTypeBones.allDbFields:
         break;
-      case WidgetModelType.table:
-      case WidgetModelType.column:
+      case ModelTypeBones.table:
+      case ModelTypeBones.column:
+      case ModelTypeBones.page:
+      case ModelTypeBones.module:
         logger.error('not allowed in section: ${model.fullName()}');
         break;
     }
@@ -303,19 +306,20 @@ class View {
   /// Creates a text from the [model].
   Widget text(TextModel model, PageControllerBones controller) {
     var text = model.text;
-    if (model.hasOption('placeholders')){
-      text = StringHelper.replacePlaceholders(text, controller.placeholders, regExpPlaceholder: regExpPlaceholder);
+    if (model.hasOption('placeholder')) {
+      text = StringHelper.replacePlaceholders(text, controller.placeholders,
+          regExpPlaceholder: regExpPlaceholder);
     }
     TextStyle style;
     if (model.hasOption('h1')) {
       style = controller.themeData.textTheme.headline1;
-    } else if (model.hasOption('h2')){
+    } else if (model.hasOption('h2')) {
       style = controller.themeData.textTheme.headline2;
-    } else if (model.hasOption('h3')){
+    } else if (model.hasOption('h3')) {
       style = controller.themeData.textTheme.headline3;
-    } else if (model.hasOption('h4')){
+    } else if (model.hasOption('h4')) {
       style = controller.themeData.textTheme.headline4;
-    } else if (model.hasOption('h5')){
+    } else if (model.hasOption('h5')) {
       style = controller.themeData.textTheme.headline5;
     }
     final rc = Text(model.text, style: style);
diff --git a/lib/src/widget/widget_list.dart b/lib/src/widget/widget_list.dart
deleted file mode 100644 (file)
index 469f5f6..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-import 'package:dart_bones/dart_bones.dart';
-import 'package:flutter/material.dart';
-import 'package:flutter_bones/flutter_bones.dart';
-
-import '../helper/string_helper.dart';
-import '../model/model_types.dart';
-import 'dropdown_button_form_bone.dart';
-import 'page_controller_bones.dart';
-import 'text_form_field_bone.dart';
-
-/// Manages a list of named widgets.
-class WidgetList {
-  final String name;
-  final BaseLogger logger;
-  final widgetMap = <String, Widget>{};
-  final widgets = <Widget>[];
-
-  /// Data that will be filled asynchronously.
-  final waitCandidates = <FieldModel>[];
-
-  WidgetList(this.name, this.logger);
-
-  /// Tests whether the widget list is empty.
-  bool get isEmpty => widgets.isEmpty;
-
-  /// Adds a [widget] to the [widgets] behind the position of [predecessor].
-  /// If [predecessor] is null the widget will be the first in [widgets]
-  void addSuccessorOf(String predecessor, String name, Widget widget) {
-    if (predecessor == null) {
-      widgets.insert(0, widget);
-    } else {
-      if (!widgetMap.containsKey(predecessor)) {
-        logger
-            .error('$name.addSuccessorOf(): missing predecessor $predecessor');
-      } else {
-        final ix = widgets.indexOf(widgetMap[predecessor]);
-        widgets.insert(ix, widget);
-      }
-    }
-    addWidget(name, widget);
-  }
-
-  /// Adds a widget to the widget list.
-  void addWidget(String name, Widget widget) {
-    if (widgetMap.containsKey(name)) {
-      logger.error('$name.addWidget(): widget $name already defined');
-    } else {
-      widgetMap[name] = widget;
-      widgets.add(widget);
-    }
-  }
-
-  /// Builds the SQL parameters of all members of the [widgets].
-  Map<String, String> buildSqlParams(PageControllerBones controller) {
-    final rc = <String, String>{};
-    final page = controller.moduleModel.pageByName(controller.pageName);
-    final isCreatePage = page.pageModelType == PageModelType.create;
-    widgets.forEach((element) {
-      dynamic value;
-      DataType dataType;
-      String name;
-      if (element is TextFormFieldBone) {
-        name = element.customString;
-        final model = page.fieldByName(name, required: true);
-        value = model?.value;
-        dataType = model?.dataType;
-      } else if (element is DropdownButtonFormBone) {
-        name = element.customString;
-        final model = page.fieldByName(name, required: true);
-        value = model?.value;
-        dataType = model?.dataType;
-      }
-      if (name != null && dataType != null) {
-        rc[':$name'] = StringHelper.asDatabaseString(value, dataType);
-      }
-    });
-    final name = controller.moduleModel.mainTable().name +
-        (isCreatePage ? '_createdby' : '_changedby');
-    if (!rc.containsKey(name)) {
-      rc[':$name'] = controller.getApplicationData().currentUserName;
-    }
-    return rc;
-  }
-
-  /// Returns the widget given by [name] or null if not found.
-  Widget byName(String name) {
-    final rc = widgetMap.containsKey(name) ? widgetMap[name] : null;
-    if (rc == null) {
-      logger.error('$name.byName(): missing widget $name');
-    }
-    return rc;
-  }
-
-  /// Remove all widgets from the list.
-  void clear() {
-    widgets.clear();
-    widgetMap.clear();
-  }
-}
index c9389d909cb9fe284f2d3a916f561313a93bc89b..7536877c81b7bee9df02b44db814b3659ec01eb4 100644 (file)
@@ -113,6 +113,26 @@ String validateEmail(
   return rc;
 }
 
+/// Validates whether [input] is equals to another field content.
+/// Return null on success or error message otherwise.
+String validateEquals(
+    String input, FieldModel model, ValidatorController controller) {
+  String rc;
+  if (controller != null) {
+    PageControllerBones controller2 = controller;
+    List<String> nameLabel = model.validatorParameter('equals')?.split(':');
+    final name = nameLabel == null ? null : nameLabel[0];
+    final label = nameLabel == null ? 'vorigem Feld' : nameLabel[1];
+    final value = controller2.textControllers.containsKey(name)
+        ? controller2.textControllers[name].value.text
+        : null;
+    if (input != value) {
+      rc = 'Eingaben von ${model?.label} und $label stimmen nicht überein';
+    }
+  }
+  return updateMessage(rc, 'equals', model);
+}
+
 /// Validates whether [input] is a valid email address.
 /// Return null on success or error message otherwise.
 String validateInt(
@@ -233,24 +253,6 @@ String validateMinInt(
   return updateMessage(rc, 'minInt', model);
 }
 
-/// Validates whether [input] is equals to another field content.
-/// Return null on success or error message otherwise.
-String validateEquals(
-    String input, FieldModel model, ValidatorController controller) {
-  String rc;
-  PageControllerBones controller2 = controller;
-  List<String> nameLabel = model.validatorParameter('equals')?.split(':');
-  final name = nameLabel == null ? null : nameLabel[0];
-  final label = nameLabel == null ? 'vorigem Feld' : nameLabel[1];
-  final value = controller2.textControllers.containsKey(name)
-      ? controller2.textControllers[name].value.text
-      : null;
-  if (input != value) {
-    rc = 'Eingaben von ${model?.label} und $label stimmen nicht überein';
-  }
-  return updateMessage(rc, 'equals', model);
-}
-
 /// Validates whether [input] is a valid date.
 /// Return null on success or error message otherwise.
 String validateRegExpr(
diff --git a/test/helpers/name_builder_test.dart b/test/helpers/name_builder_test.dart
new file mode 100644 (file)
index 0000000..d9da4b3
--- /dev/null
@@ -0,0 +1,20 @@
+import 'package:dart_bones/dart_bones.dart';
+import 'package:flutter_bones/src/helper/name_builder.dart';
+import 'package:test/test.dart';
+
+void main() {
+  final logger = MemoryLogger(LEVEL_FINE);
+  group('basic', () {
+    test('basic-string', () {
+      final builder = NameBuilder(logger);
+      expect(builder.nextName('abc'), equals('abc1'));
+      expect(builder.nextName('abc'), equals('abc2'));
+      expect(builder.nextName('zz'), equals('zz1'));
+      expect(builder.nextName(null), isNull);
+      expect(builder.dump(indention: '..'), equals('''..Prefix:Number
+..abc:2
+..zz:1
+'''));
+    });
+  });
+}
index e90c6530b56b97b268b82bfde1ab9e686dd71d63..8331bb01fa7d271cfdc62f486a759ce41a0edab1 100644 (file)
@@ -9,7 +9,7 @@ void main() {
   final logger = MemoryLogger(LEVEL_FINE);
   group('module', () {
     test('module', () {
-      WidgetModel.lastId = 0;
+     ModelBase.lastId = 0;
       logger.clear();
       final module = Demo1(cloneOfMap(userModel), logger);
       module.parse();
@@ -39,11 +39,11 @@ void main() {
     column role_changedat: DataType.dateTime "Geändert" options: hidden null
     column role_changedby: DataType.string "Geändert von" options: hidden
 == page create: PageModelType.create options: 
-    = section simpleForm1: SectionModelType.simpleForm options:  [
-    textField user: options: required unique
-    textField role: options: 
-    button buttonStore: text: options: null 
-    ] # create.simpleForm1
+    = section section1: SectionModelType.simpleForm options:  [
+    textField user: "User" options: required unique primary notnull unique
+    textField role: "Id" options: primary notnull unique
+    button buttonStore: label: Save options: Save 
+    ] # create.section1
 '''));
       final userField = table.columnByName('user_id');
       expect(userField, isNotNull);
@@ -69,7 +69,7 @@ void main() {
     expect(data, isNotNull);
   });
   test('combobase', () {
-    WidgetModel.lastId = 0;
+   ModelBase.lastId = 0;
     logger.clear();
     final map = <String, dynamic>{
       'module': 'demo1',
@@ -97,7 +97,7 @@ void main() {
   });
   group('errors', () {
     test('errors-combobase', () {
-      WidgetModel.lastId = 0;
+     ModelBase.lastId = 0;
       logger.clear();
       final map = <String, dynamic>{
         'module': 'demo1',
@@ -126,7 +126,7 @@ void main() {
           isTrue);
     });
     test('errors-missing-texts', () {
-      WidgetModel.lastId = 0;
+     ModelBase.lastId = 0;
       logger.clear();
       final map = <String, dynamic>{
         'module': 'demo1',
@@ -154,7 +154,7 @@ void main() {
           isTrue);
     });
     test('errors-#texts!=#values', () {
-      WidgetModel.lastId = 0;
+     ModelBase.lastId = 0;
       logger.clear();
       final map = <String, dynamic>{
         'module': 'demo1',
@@ -210,7 +210,7 @@ final userModel = <String, dynamic>{
           'dataType': 'reference',
           'label': 'Role',
           'foreignKey': 'role.role_id role_name',
-          'widgetType': 'combobox',
+          'modelType': 'combobox',
         },
       ]
     },
@@ -242,19 +242,19 @@ final userModel = <String, dynamic>{
           'sectionType': 'simpleForm',
           'children': [
             {
-              'widgetType': 'dbReference',
+              'modelType': 'dbReference',
               'name': 'user',
               'label': 'User',
               'column': 'user_id',
               'options': 'required unique',
             },
             {
-              'widgetType': 'dbReference',
+              'modelType': 'dbReference',
               'name': 'role',
               'column': 'role.role_id',
             },
             {
-              'widgetType': 'button',
+              'modelType': 'button',
               'name': 'buttonStore',
               'label': 'Save',
             },
index 91859c4843f7d01493776855bcf6dae726e47bd2..755193d1b0bff757077066a822201539cae775c6 100644 (file)
@@ -8,7 +8,7 @@ void main() {
   final logger = MemoryLogger(LEVEL_FINE);
   group('module', () {
     test('module', () {
-      WidgetModel.lastId = 0;
+     ModelBase.lastId = 0;
       logger.clear();
       final module = Demo1(cloneOfMap(userModel), logger);
       module.parse();
@@ -20,7 +20,7 @@ void main() {
       final dump = module.dump(StringBuffer()).toString();
       expect(dump, equals('''= module demo1: options: 
 == table user: options: 
-    column user_id: DataType.int "Id" options: primary notnull unique readonly
+    column user_id: DataType.int "Id" options: primary notnull unique
     column user_name: DataType.string "User" options: unique notnull
     column user_role: DataType.reference "Role" options: 
     column user_createdat: DataType.dateTime "Erzeugt" options: hidden null
@@ -28,14 +28,14 @@ void main() {
     column user_changedat: DataType.dateTime "Geändert" options: hidden null
     column user_changedby: DataType.string "Geändert von" options: hidden
 == page create: PageModelType.create options: 
-    = section simpleForm1: SectionModelType.simpleForm options:  [
+    = section section1: SectionModelType.simpleForm options:  [
     textField user: options: required unique
-    button buttonStore: text: options: null 
-    ] # create.simpleForm1
+    button buttonStore: label: Save options: Save 
+    ] # create.section1
 == page change: PageModelType.change options: 
-    = section simpleForm1: SectionModelType.simpleForm options:  [
-    allDbFields 13 options: 
-    ] # change.simpleForm1
+    = section section1: SectionModelType.simpleForm options:  [
+    allDbFields allDbFields1 options: 
+    ] # change.section1
 '''));
       final userField = page.fieldByName('user');
       expect(userField, isNotNull);
@@ -48,10 +48,10 @@ void main() {
       final button = page.buttonByName('buttonStore');
       expect(button, isNotNull);
       expect(button.section, equals(userField.section));
-      expect(button.fullName(), 'simpleForm1.buttonStore');
+      expect(button.fullName(), 'section1.buttonStore');
       expect(button.widgetName(), 'buttonStore');
       final all = module.pageByName('change').getWidgets(
-              (item) => item.widgetModelType == WidgetModelType.allDbFields);
+              (item) => item.modelType == ModelTypeBones.allDbFields);
       expect(all.length, equals(1));
       final widget = all[0];
       final name = widget.fullName() + ' ' + widget.widgetName();
@@ -60,8 +60,9 @@ void main() {
   });
   group('page-errors', () {
     test('add-button', () {
-      WidgetModel.lastId = 0;
+     ModelBase.lastId = 0;
       logger.clear();
+      logger.log('expecting errors:');
       final map = <String, dynamic>{
         'module': 'demo1',
         'tables': [
@@ -88,7 +89,7 @@ void main() {
                 "sectionType": "filterPanel",
                 "children": [
                   {
-                    "widgetType": "dbReference",
+                    'modelType': "dbReference",
                     "filterType": "pattern",
                     "name": "user_name",
                     "column": "user_name",
@@ -122,9 +123,9 @@ void main() {
       page.addField(TextFieldModel.direct(
           null,
           page,
-          'x',
-          'y',
-          'z',
+          'n',
+          'l',
+          't',
           DataType.int,
           <String>[],
           33,
@@ -132,9 +133,9 @@ void main() {
       page.addField(TextFieldModel.direct(
           null,
           page,
-          'x',
-          'y',
-          'z',
+          'n',
+          'l',
+          't',
           DataType.int,
           <String>[],
           44,
@@ -154,12 +155,13 @@ void main() {
           isTrue);
       expect(errors.contains('missing field nothing in page demo1.list'),
           isTrue);
-      expect(errors.contains('field list.x already defined: list.x'),
+      expect(errors.contains('field list.n already defined: list.n'),
           isTrue);
     });
     test('missing-section', () {
-      WidgetModel.lastId = 0;
+     ModelBase.lastId = 0;
       logger.clear();
+      logger.log('expecting "missing section"');
       final map = <String, dynamic>{
         'module': 'demo1',
         'pages': [
@@ -179,7 +181,7 @@ void main() {
           isTrue);
     });
     test('wrong-section', () {
-      WidgetModel.lastId = 0;
+     ModelBase.lastId = 0;
       logger.clear();
       final map = <String, dynamic>{
         'module': 'demo1',
@@ -201,7 +203,7 @@ void main() {
           isTrue);
     });
     test('tableTitles not in list', () {
-      WidgetModel.lastId = 0;
+     ModelBase.lastId = 0;
       logger.clear();
       final map = <String, dynamic>{
         'module': 'demo1',
@@ -224,7 +226,7 @@ void main() {
       expect(page.fullName() + page.widgetName(), equals('demo1.listlist'));
     });
     test('curious section', () {
-      WidgetModel.lastId = 0;
+     ModelBase.lastId = 0;
       logger.clear();
       final map = <String, dynamic>{
         'module': 'demo1',
@@ -253,7 +255,7 @@ void main() {
       logger.clear();
       final map = cloneOfMap(userModel);
       final field = <String, dynamic>{
-        'widgetType': 'textField',
+        'modelType': 'textField',
         'name': 'year',
         'label': 'Year',
         'options': 'required;blubb',
@@ -305,11 +307,11 @@ void main() {
   });
   group('CheckboxModel', () {
     test('basic', () {
-      WidgetModel.lastId = 0;
+     ModelBase.lastId = 0;
       logger.clear();
       final map = cloneOfMap(userModel);
       final field = <String, dynamic>{
-        'widgetType': 'checkbox',
+        'modelType': 'checkbox',
         'name': 'hidden',
         'label': 'Hidden',
         'options': 'required',
@@ -329,11 +331,11 @@ void main() {
       expect(checkbox.value, isTrue);
     });
     test('errors', () {
-      WidgetModel.lastId = 0;
+     ModelBase.lastId = 0;
       logger.clear();
       final map = cloneOfMap(userModel);
       final field = <String, dynamic>{
-        'widgetType': 'checkbox',
+        'modelType': 'checkbox',
         'name': 'hidden',
         'label': 'Hidden',
         'options': 'required',
@@ -349,7 +351,7 @@ void main() {
       final dump = module.dump(StringBuffer()).toString();
       expect(dump, equals('''= module demo1: options: 
 == table user: options: 
-    column user_id: DataType.int "Id" options: primary notnull unique readonly
+    column user_id: DataType.int "Id" options: primary notnull unique
     column user_name: DataType.string "User" options: unique notnull
     column user_role: DataType.reference "Role" options: 
     column user_createdat: DataType.dateTime "Erzeugt" options: hidden null
@@ -357,24 +359,24 @@ void main() {
     column user_changedat: DataType.dateTime "Geändert" options: hidden null
     column user_changedby: DataType.string "Geändert von" options: hidden
 == page create: PageModelType.create options: 
-    = section simpleForm1: SectionModelType.simpleForm options:  [
-    checkbox hidden: text: options: required
-    button buttonStore: text: options: null 
-    ] # create.simpleForm1
+    = section section1: SectionModelType.simpleForm options:  [
+    checkbox hidden: "Hidden" options: required
+    button buttonStore: label: Save options: Save 
+    ] # create.section1
 == page change: PageModelType.change options: 
-    = section simpleForm1: SectionModelType.simpleForm options:  [
-    allDbFields 13 options: 
-    ] # change.simpleForm1
+    = section section1: SectionModelType.simpleForm options:  [
+    allDbFields allDbFields1 options: 
+    ] # change.section1
 '''));
     });
   });
   group('ComboboxModel', () {
-    WidgetModel.lastId = 0;
+   ModelBase.lastId = 0;
     logger.clear();
     test('basic', () {
       final map = cloneOfMap(userModel);
       final field = <String, dynamic>{
-        'widgetType': 'combobox',
+        'modelType': 'combobox',
         'name': 'class',
         'label': 'Class',
         'options': 'undef',
@@ -393,7 +395,7 @@ void main() {
       final dump = module.dump(StringBuffer()).toString();
       expect(dump, equals('''= module demo1: options: 
 == table user: options: 
-    column user_id: DataType.int "Id" options: primary notnull unique readonly
+    column user_id: DataType.int "Id" options: primary notnull unique
     column user_name: DataType.string "User" options: unique notnull
     column user_role: DataType.reference "Role" options: 
     column user_createdat: DataType.dateTime "Erzeugt" options: hidden null
@@ -401,20 +403,20 @@ void main() {
     column user_changedat: DataType.dateTime "Geändert" options: hidden null
     column user_changedby: DataType.string "Geändert von" options: hidden
 == page create: PageModelType.create options: 
-    = section simpleForm1: SectionModelType.simpleForm options:  [
-    combobox class: texts: bad OK good options: undef
-    button buttonStore: text: options: null 
-    ] # create.simpleForm1
+    = section section1: SectionModelType.simpleForm options:  [
+    combobox class: "Class" texts: bad OK good options: undef
+    button buttonStore: label: Save options: Save 
+    ] # create.section1
 == page change: PageModelType.change options: 
-    = section simpleForm1: SectionModelType.simpleForm options:  [
-    allDbFields 30 options: 
-    ] # change.simpleForm1
+    = section section1: SectionModelType.simpleForm options:  [
+    allDbFields allDbFields1 options: 
+    ] # change.section1
 '''));
     });
   });
   group('allDbFields', () {
     test('allDbFields', () {
-      WidgetModel.lastId = 0;
+     ModelBase.lastId = 0;
       logger.clear();
       final map = cloneOfMap(userModel);
       var module = Demo1(map, logger);
@@ -431,14 +433,14 @@ void main() {
   });
   group('Non field widgets', () {
     test('basic', () {
-      WidgetModel.lastId = 0;
+     ModelBase.lastId = 0;
       logger.clear();
       final map = cloneOfMap(userModel);
       final list = [
         {
-          'widgetType': 'emptyLine',
+          'modelType': 'emptyLine',
         },
-        {'widgetType': 'text', 'text': '*Hi world*', 'options': 'rich'},
+        {'modelType': 'text', 'text': '*Hi world*', 'options': 'richText'},
       ];
       map['pages'][0]['sections'][0]['children'] = list;
       var module = Demo1(map, logger);
@@ -451,21 +453,20 @@ void main() {
       final allWidgets = page.getWidgets(null);
       expect(allWidgets.length, equals(2));
       final names = allWidgets.fold('', (prevValue, element) {
-        return prevValue +=
-            ' ' + element.widgetName() + '/' + element.fullName();
+        return prevValue += ' ${element.widgetName()}/${element.fullName()}';
       });
       expect(names.contains('null'), isFalse);
       final nonFieldWidgets = page.getWidgets((item) =>
           [
-            WidgetModelType.text,
-            WidgetModelType.emptyLine
-          ].contains(item.widgetModelType));
+            ModelTypeBones.text,
+            ModelTypeBones.emptyLine
+          ].contains(item.modelType));
       expect(nonFieldWidgets.length, equals(2));
     });
   });
   group('section-errors', () {
     test('missing children', () {
-      WidgetModel.lastId = 0;
+     ModelBase.lastId = 0;
       logger.clear();
       final map = <String, dynamic>{
         'module': 'demo1',
@@ -485,11 +486,11 @@ void main() {
       module.parse();
       final errors = logger.errors;
       expect(errors.length, equals(1));
-      expect(errors.contains('missing children in list.filterPanel1'),
+      expect(errors.contains('missing children in list.section1'),
           isTrue);
     });
     test('wrong children', () {
-      WidgetModel.lastId = 0;
+     ModelBase.lastId = 0;
       logger.clear();
       final map = <String, dynamic>{
         'module': 'demo1',
@@ -510,11 +511,11 @@ void main() {
       module.parse();
       final errors = logger.errors;
       expect(errors.length, equals(1));
-      expect(errors.contains('"children" is not a list in list.filterPanel1: a'),
+      expect(errors.contains('"children" is not a list in list.section1: a'),
           isTrue);
     });
     test('not a map in children', () {
-      WidgetModel.lastId = 0;
+     ModelBase.lastId = 0;
       logger.clear();
       final map = <String, dynamic>{
         'module': 'demo1',
@@ -537,11 +538,11 @@ void main() {
       module.parse();
       final errors = logger.errors;
       expect(errors.length, equals(1));
-      expect(errors.contains('child 1 of "children" is not a map in list.filterPanel1: []'),
+      expect(errors.contains('child 1 of "children" is not a map in list.section1: []'),
           isTrue);
     });
     test('missing type in child', () {
-      WidgetModel.lastId = 0;
+     ModelBase.lastId = 0;
       logger.clear();
       final map = <String, dynamic>{
         'module': 'demo1',
@@ -564,11 +565,11 @@ void main() {
       module.parse();
       final errors = logger.errors;
       expect(errors.length, equals(1));
-      expect(errors.contains('child 1 of "children" does not have "widgetType" in list.filterPanel1: {}'),
+      expect(errors.contains('child 1 of "children" does not have "modelType" in list.section1: {}'),
           isTrue);
     });
     test('unknown type in child', () {
-      WidgetModel.lastId = 0;
+     ModelBase.lastId = 0;
       logger.clear();
       final map = <String, dynamic>{
         'module': 'demo1',
@@ -581,7 +582,7 @@ void main() {
                 "sectionType": "filterPanel",
                 "children": [
                   {
-                    "widgetType": ""
+                    'modelType': ""
                   },
                 ]
               },
@@ -593,7 +594,7 @@ void main() {
       module.parse();
       final errors = logger.errors;
       expect(errors.length, equals(1));
-      expect(errors.contains('Section: unknown "widgetType"  in list.filterPanel1'),
+      expect(errors.contains('Section: unknown "modelType"  in list.section1'),
           isTrue);
     });
   });
@@ -623,7 +624,7 @@ final userModel = <String, dynamic>{
           'dataType': 'reference',
           'label': 'Role',
           'foreignKey': 'role.role_id role_name',
-          'widgetType': 'combobox',
+          'modelType': 'combobox',
         },
       ]
     },
@@ -637,13 +638,13 @@ final userModel = <String, dynamic>{
           'sectionType': 'simpleForm',
           'children': [
             {
-              'widgetType': 'textField',
+              'modelType': 'textField',
               'name': 'user',
               'label': 'User',
               'options': 'required unique',
             },
             {
-              'widgetType': 'button',
+              'modelType': 'button',
               'name': 'buttonStore',
               'label': 'Save',
             },
@@ -659,7 +660,7 @@ final userModel = <String, dynamic>{
           'sectionType': 'simpleForm',
           'children': [
             {
-              'widgetType': 'allDbFields',
+              'modelType': 'allDbFields',
             },
           ],
         },
index be644c63e94e993ea471d213456aba82a9f9fbcb..a672919ad661d8a30829953facd8ed4846e5b486 100644 (file)
@@ -6,7 +6,7 @@ void main() {
   final logger = MemoryLogger(LEVEL_FINE);
   group('module', () {
     test('role', () {
-      WidgetModel.lastId = 0;
+     ModelBase.lastId = 0;
       logger.clear();
       final module = RoleModel(logger);
       module.parse();
@@ -21,26 +21,26 @@ void main() {
     column role_name: DataType.string "Rolle" options: unique notnull
     column role_priority: DataType.int "Priorität" options: 
     column role_active: DataType.bool "Aktiv" options: 
-    column role_createdat: DataType.dateTime "Erzeugt" options: null
-    column role_createdby: DataType.string "Erzeugt von" options: null
-    column role_changedat: DataType.dateTime "Geändert" options: null
-    column role_changedby: DataType.string "Geändert von" options: null
+    column role_createdat: DataType.dateTime "Erzeugt" options: hidden null
+    column role_createdby: DataType.string "Erzeugt von" options: hidden
+    column role_changedat: DataType.dateTime "Geändert" options: hidden null
+    column role_changedby: DataType.string "Geändert von" options: hidden
 == page create: PageModelType.create options: 
-    = section simpleForm1: SectionModelType.simpleForm options:  [
-    allDbFields 10 options: 
-    ] # create.simpleForm1
+    = section section1: SectionModelType.simpleForm options:  [
+    allDbFields allDbFields1 options: 
+    ] # create.section1
 == page change: PageModelType.change options: 
-    = section simpleForm1: SectionModelType.simpleForm options:  [
-    allDbFields 21 options: 
-    ] # change.simpleForm1
+    = section section1: SectionModelType.simpleForm options:  [
+    allDbFields allDbFields1 options: 
+    ] # change.section1
 == page list: PageModelType.list options: 
-    = section filterPanel1: SectionModelType.filterPanel options:  [
+    = section section1: SectionModelType.filterPanel options:  [
     textField role_name: options: 
-    ] # list.filterPanel1
+    ] # list.section1
 ''');
     });
     test('user', () {
-      WidgetModel.lastId = 0;
+     ModelBase.lastId = 0;
       logger.clear();
       final module = UserModel(logger);
       module.parse();
@@ -57,40 +57,40 @@ void main() {
     column user_email: DataType.string "EMail" options: unique notnull
     column user_password: DataType.string "Passwort" options: password hidden
     column user_role: DataType.reference "Rolle" options: undef
-    column user_createdat: DataType.dateTime "Erzeugt" options: null
-    column user_createdby: DataType.string "Erzeugt von" options: null
-    column user_changedat: DataType.dateTime "Geändert" options: null
-    column user_changedby: DataType.string "Geändert von" options: null
+    column user_createdat: DataType.dateTime "Erzeugt" options: hidden null
+    column user_createdby: DataType.string "Erzeugt von" options: hidden
+    column user_changedat: DataType.dateTime "Geändert" options: hidden null
+    column user_changedby: DataType.string "Geändert von" options: hidden
 == page create: PageModelType.create options: 
-    = section simpleForm1: SectionModelType.simpleForm options:  [
-    allDbFields 12 options: 
-    ] # create.simpleForm1
+    = section section1: SectionModelType.simpleForm options:  [
+    allDbFields allDbFields1 options: 
+    ] # create.section1
 == page change: PageModelType.change options: 
-    = section simpleForm1: SectionModelType.simpleForm options:  [
-    allDbFields 24 options: 
-    button set_password: text: options: Passwort ändern 
-    ] # change.simpleForm1
+    = section section1: SectionModelType.simpleForm options:  [
+    allDbFields allDbFields1 options: 
+    button set_password: label: Passwort ändern options: Passwort ändern 
+    ] # change.section1
 == page password: PageModelType.change options: 
-    = section simpleForm1: SectionModelType.simpleForm options:  [
-    text 38 text: Ändern des Passworts von Benutzer ~user~: options: placeholder
+    = section section1: SectionModelType.simpleForm options:  [
+    text text1 text: Ändern des Passworts von Benutzer ~user~: options: placeholder h3
     textField user_password: options: password
     textField repetition: options: password
-    ] # password.simpleForm1
+    ] # password.section1
 == page list: PageModelType.list options: 
-    = section filterPanel1: SectionModelType.filterPanel options:  [
-    textField user_name: options: unique notnull
-    textField user_role: options: undef
-    ] # list.filterPanel1
+    = section section1: SectionModelType.filterPanel options:  [
+    textField user_name: "User" options: unique notnull
+    textField user_role: "Rolle" options: undef
+    ] # list.section1
 == page login: PageModelType.change options: noAutoButton
-    = section simpleForm1: SectionModelType.simpleForm options:  [
+    = section section1: SectionModelType.simpleForm options:  [
     textField user: options: 
     textField password: options: password
-    button login: text: options: Anmelden 
-    ] # login.simpleForm1
+    button login: label: Anmelden options: Anmelden 
+    ] # login.section1
 '''));
     });
     test('configuration', () {
-      WidgetModel.lastId = 0;
+     ModelBase.lastId = 0;
       logger.clear();
       final module = ConfigurationModel(logger);
       module.parse();
@@ -108,27 +108,27 @@ void main() {
     column configuration_type: DataType.string "Datentyp" options: 
     column configuration_value: DataType.string "Wert" options: 
     column configuration_description: DataType.string "Beschreibung" options: 
-    column configuration_createdat: DataType.dateTime "Erzeugt" options: null
-    column configuration_createdby: DataType.string "Erzeugt von" options: null
-    column configuration_changedat: DataType.dateTime "Geändert" options: null
-    column configuration_changedby: DataType.string "Geändert von" options: null
+    column configuration_createdat: DataType.dateTime "Erzeugt" options: hidden null
+    column configuration_createdby: DataType.string "Erzeugt von" options: hidden
+    column configuration_changedat: DataType.dateTime "Geändert" options: hidden null
+    column configuration_changedby: DataType.string "Geändert von" options: hidden
 == page create: PageModelType.create options: 
-    = section simpleForm1: SectionModelType.simpleForm options:  [
-    allDbFields 13 options: 
-    ] # create.simpleForm1
+    = section section1: SectionModelType.simpleForm options:  [
+    allDbFields allDbFields1 options: 
+    ] # create.section1
 == page change: PageModelType.change options: 
-    = section simpleForm1: SectionModelType.simpleForm options:  [
-    allDbFields 27 options: 
-    ] # change.simpleForm1
+    = section section1: SectionModelType.simpleForm options:  [
+    allDbFields allDbFields1 options: 
+    ] # change.section1
 == page list: PageModelType.list options: 
-    = section filterPanel1: SectionModelType.filterPanel options:  [
+    = section section1: SectionModelType.filterPanel options:  [
     textField configuration_scope: options: 
     textField configuration_property: options: 
-    ] # list.filterPanel1
+    ] # list.section1
 '''));
     });
     test('menu', () {
-      WidgetModel.lastId = 0;
+     ModelBase.lastId = 0;
       logger.clear();
       final module = MenuModel(logger);
       module.parse();
@@ -142,22 +142,22 @@ void main() {
     column menu_id: DataType.int "Id" options: primary notnull unique
     column menu_name: DataType.string "Name" options: unique notnull
     column menu_icon: DataType.reference "Bild" options: 
-    column menu_createdat: DataType.dateTime "Erzeugt" options: null
-    column menu_createdby: DataType.string "Erzeugt von" options: null
-    column menu_changedat: DataType.dateTime "Geändert" options: null
-    column menu_changedby: DataType.string "Geändert von" options: null
+    column menu_createdat: DataType.dateTime "Erzeugt" options: hidden null
+    column menu_createdby: DataType.string "Erzeugt von" options: hidden
+    column menu_changedat: DataType.dateTime "Geändert" options: hidden null
+    column menu_changedby: DataType.string "Geändert von" options: hidden
 == page create: PageModelType.create options: 
-    = section simpleForm1: SectionModelType.simpleForm options:  [
-    allDbFields 9 options: 
-    ] # create.simpleForm1
+    = section section1: SectionModelType.simpleForm options:  [
+    allDbFields allDbFields1 options: 
+    ] # create.section1
 == page change: PageModelType.change options: 
-    = section simpleForm1: SectionModelType.simpleForm options:  [
-    allDbFields 19 options: 
-    ] # change.simpleForm1
+    = section section1: SectionModelType.simpleForm options:  [
+    allDbFields allDbFields1 options: 
+    ] # change.section1
 == page list: PageModelType.list options: 
-    = section filterPanel1: SectionModelType.filterPanel options:  [
-    textField menu_name: options: unique notnull
-    ] # list.filterPanel1
+    = section section1: SectionModelType.filterPanel options:  [
+    textField menu_name: "Name" options: unique notnull
+    ] # list.section1
 '''));
     });
   });
index 790b331856d1224d9e65f73f1807457c99fbd230..42c4295bfa3cb0bb20198ce642f494693b4d0aa2 100644 (file)
@@ -40,7 +40,7 @@ author: flutter_bones.module_model.exportSqlBackend()
 version: 1.0.0
 modules:
   - module: role
-    list:
+    sqlInfos:
       - name: insert
         type: insert
         sql: "INSERT INTO role(role_name,role_priority,role_active,role_createdat,role_createdby)
index 2c32b0b624589d960915799e32da6b0879e97b52..ace1c03ccbd9599d2c3ac091762c8ec3d59543df 100644 (file)
@@ -49,14 +49,34 @@ void main() {
       expect(role, isNotNull);
       BuildContext context = MyContext();
       RoleCreatePageState lastInstance = appData.lastModuleState;
-      lastInstance.build(context);
-      final widgets = lastInstance.controller.getWidgets();
-      expect(widgets.length, equals(3));
+      expect(lastInstance, isNotNull);
+      if (lastInstance.controller is String) {
+        lastInstance.initState();
+        lastInstance.build(context);
+        final models = lastInstance.controller.widgetList.models;
+        expect(models.length, equals(3));
+      }
     });
   });
 }
 
 class MyContext extends BuildContext {
+  @override
+  // TODO: implement debugDoingBuild
+  bool get debugDoingBuild => throw UnimplementedError();
+
+  @override
+  // TODO: implement owner
+  BuildOwner get owner => throw UnimplementedError();
+
+  @override
+  // TODO: implement size
+  Size get size => throw UnimplementedError();
+
+  @override
+  // TODO: implement widget
+  Widget get widget => throw UnimplementedError();
+
   @override
   InheritedElement ancestorInheritedElementForWidgetOfExactType(
       Type targetType) {
@@ -82,10 +102,6 @@ class MyContext extends BuildContext {
     throw UnimplementedError();
   }
 
-  @override
-  // TODO: implement debugDoingBuild
-  bool get debugDoingBuild => throw UnimplementedError();
-
   @override
   InheritedWidget dependOnInheritedElement(InheritedElement ancestor,
       {Object aspect}) {
@@ -177,20 +193,12 @@ class MyContext extends BuildContext {
     throw UnimplementedError();
   }
 
-  @override
-  // TODO: implement owner
-  BuildOwner get owner => throw UnimplementedError();
-
   @override
   State<StatefulWidget> rootAncestorStateOfType(x.TypeMatcher matcher) {
     // TODO: implement rootAncestorStateOfType
     throw UnimplementedError();
   }
 
-  @override
-  // TODO: implement size
-  Size get size => throw UnimplementedError();
-
   @override
   void visitAncestorElements(bool Function(Element element) visitor) {
     // TODO: implement visitAncestorElements
@@ -200,8 +208,4 @@ class MyContext extends BuildContext {
   void visitChildElements(visitor) {
     // TODO: implement visitChildElements
   }
-
-  @override
-  // TODO: implement widget
-  Widget get widget => throw UnimplementedError();
 }
index 5af1bd103c41c86aa667b8b5a5e8c5f03b27ace6..11d6b01a8e96883505a7cd118c72bf76c9dbcbcf 100644 (file)
@@ -6,6 +6,7 @@
 // tree, read text, and verify that the values of widget properties are correct.
 import 'package:dart_bones/dart_bones.dart';
 import 'package:flutter_bones/flutter_bones.dart';
+import 'package:flutter_bones/src/widget/page_controller_bones.dart';
 import 'package:flutter_bones/src/widget/widget_validators.dart';
 import 'package:test/test.dart';
 
@@ -28,7 +29,7 @@ void main() {
   });
   group('independent', () {
     test('int', () {
-      WidgetModel.lastId = 0;
+     ModelBase.lastId = 0;
       logger.clear();
       final map = <String, dynamic>{
         'module': 'demo1',
@@ -71,7 +72,7 @@ void main() {
           equals('Zahl zu groß: 11 > 10'));
     });
     test('date', () {
-      WidgetModel.lastId = 0;
+     ModelBase.lastId = 0;
       logger.clear();
       final map = <String, dynamic>{
         'module': 'demo1',
@@ -114,7 +115,7 @@ void main() {
           equals('Datum zu jung: 2020.11.1 > 2020-10-03'));
     });
     test('dateTime', () {
-      WidgetModel.lastId = 0;
+     ModelBase.lastId = 0;
       logger.clear();
       final map = <String, dynamic>{
         'module': 'demo1',
@@ -158,7 +159,7 @@ void main() {
           equals('Zeitpunkt zu jung: 2020.11.1-00:22 > 2020-10-03 10:44:00'));
     });
     test('string', () {
-      WidgetModel.lastId = 0;
+     ModelBase.lastId = 0;
       logger.clear();
       final map = <String, dynamic>{
         'module': 'demo1',
@@ -220,8 +221,9 @@ void main() {
       expect(model.validators.length, 3);
       expect(model.validators[0]('', model, null), equals('missing'));
       expect(model.validators[1]('B', model, null), isNull);
-      expect(model.validators[1]('A', model, null), equals('Eingaben von null und str stimmen nicht überein'));
-      expect(model.validators[2]('A', model, null), equals('No Name'));
+      PageControllerBones controller = PageControllerBones(null, null, module, null, null, null);
+      expect(model.validators[1]('A', model, controller), equals('Eingaben von null und str stimmen nicht überein'));
+      expect(model.validators[2]('A', model, controller), equals('No Name'));
     });
   });
 }