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());
}
--- /dev/null
+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();
+ }
+}
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 {
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) {
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(
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;
/// 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;
}
/// 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 {
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;
}
}
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 {
/// 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(
listOption: listOption,
listType: listType,
options: options,
- widgetType: WidgetModelType.column,
+ modelType: ModelTypeBones.column,
logger: logger);
/// Dumps the instance into a [StringBuffer]
/// 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);
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 {
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,
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].
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;
}
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;
}
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);
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 {
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,
: super.direct(
section: section,
page: page,
- widgetType: WidgetModelType.dbReference,
+ modelType: ModelTypeBones.dbReference,
name: column.name,
label: column.label,
toolTip: column.toolTip,
/// 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;
}
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();
}
}
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';
}
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);
'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;
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,
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;
/// 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:
value = row[name];
}
}
-
- @override
- String widgetName() => name;
}
abstract class ValidatorController {}
import 'package:dart_bones/dart_bones.dart';
import 'package:meta/meta.dart';
+
import '../helper/string_helper.dart';
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].
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.
/// 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,
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) {
return rc;
}
- String widgetName();
+ String widgetName() => name;
/// Tests whether an [object] is a list type.
/// Works for JSArray<dynamic>, List
return name.contains('Map');
}
}
+
+enum ModelTypeBones {
+ allDbFields,
+ button,
+ checkbox,
+ column,
+ combobox,
+ dbReference,
+ emptyLine,
+ image,
+ module,
+ page,
+ section,
+ table,
+ text,
+ textField,
+}
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';
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(
/// 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);
orElse: () => null);
return found;
}
-
- @override
- String widgetName() => name;
}
import 'package:dart_bones/dart_bones.dart';
+import '../helper/name_builder.dart';
import 'button_model.dart';
import 'field_model.dart';
import 'model_base.dart';
class PageModel extends ModelBase {
static final regExprOptions = RegExp(r'^(noAutoButton)$');
final ModuleModel module;
- String name;
final List<SectionModel> sections = [];
PageModelType pageModelType;
final fields = <FieldModel>[];
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.
}
}
- /// 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) {
}
}
+ /// 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
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,
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) {
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'
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 {
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) {
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) {
/// 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')) {
.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:
'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 {
'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',
"sectionType": "simpleForm",
"children": [
{
- "widgetType": "allDbFields",
+ 'modelType': "allDbFields",
}
]
}
"sectionType": "simpleForm",
"children": [
{
- "widgetType": "allDbFields",
+ 'modelType': "allDbFields",
}
]
}
{
"name": "configuration_scope",
"label": "Bereich",
- "widgetType": "textField",
+ 'modelType': "textField",
"filterType": "pattern",
//"options": 'undef',
},
{
"name": "configuration_property",
"label": "Eigenschaft",
- "widgetType": "textField",
+ 'modelType': "textField",
"filterType": "pattern",
},
]
'sectionType': 'simpleForm',
'children': [
{
- 'widgetType': 'allDbFields',
+ 'modelType': 'allDbFields',
}
]
}
'sectionType': 'simpleForm',
'children': [
{
- 'widgetType': 'allDbFields',
+ 'modelType': 'allDbFields',
},
]
}
'sectionType': 'filterPanel',
'children': [
{
- 'widgetType': 'dbReference',
+ 'modelType': 'dbReference',
'filterType': 'pattern',
'name': 'menu_name',
'column': 'menu_name',
"sectionType": "simpleForm",
"children": [
{
- "widgetType": "allDbFields",
+ 'modelType': "allDbFields",
}
]
}
"sectionType": "simpleForm",
"children": [
{
- "widgetType": "allDbFields",
+ 'modelType': "allDbFields",
}
]
}
"sectionType": "filterPanel",
"children": [
{
- "widgetType": "textField",
+ 'modelType': "textField",
"filterType": "pattern",
"name": "role_name",
"label": "Name",
"sectionType": "simpleForm",
"children": [
{
- "widgetType": "allDbFields",
+ 'modelType': "allDbFields",
}
]
}
"sectionType": "simpleForm",
"children": [
{
- "widgetType": "allDbFields",
+ 'modelType': "allDbFields",
},
{
- "widgetType": "button",
+ 'modelType': "button",
"name": "set_password",
"label": "Passwort ändern",
"buttonType": "custom",
"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",
"sectionType": "filterPanel",
"children": [
{
- "widgetType": "dbReference",
+ 'modelType': "dbReference",
"filterType": "pattern",
"name": "user_name",
"column": "user_name",
"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",
"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",
import 'package:dart_bones/dart_bones.dart';
+import '../helper/name_builder.dart';
import 'column_model.dart';
import 'model_base.dart';
import 'model_types.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.
/// 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 {
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 {
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,
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) {
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);
value = parseString('value', map);
break;
}
- options = parseOptions('options', map);
checkOptionsByRegExpr(regExprOptions);
parseFinish();
}
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.
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';
}
/// 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].
/// 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,
}
}
}
-class ConfigurationChangePageState extends State<ConfigurationChangePage> implements RedrawPage {
+class ConfigurationChangePageState extends State<ConfigurationChangePage>
+ implements RedrawPage {
final ApplicationData applicationData;
final int primaryId;
final Map initialRow;
_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);
});
}
}
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) {
}
}
-class ConfigurationCreatePageState extends State<ConfigurationCreatePage> implements RedrawPage {
+class ConfigurationCreatePageState extends State<ConfigurationCreatePage>
+ implements RedrawPage {
final ApplicationData applicationData;
final GlobalKey<FormState> _formKey =
_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);
});
}
}
}
}
-class RoleChangePageState extends State<RoleChangePage> implements RedrawPage{
+class RoleChangePageState extends State<RoleChangePage> implements RedrawPage {
final ApplicationData applicationData;
final int primaryId;
final Map initialRow;
initialRow: initialRow,
));
}
+
@override
void initState() {
super.initState();
- controller = RoleController(
- _formKey, this, 'change', context, applicationData);
+ controller =
+ RoleController(_formKey, this, 'change', context, applicationData);
controller.initialize();
}
customString: customString, callback: callback);
});
}
+
void dispose() {
controller.dispose();
super.dispose();
}
}
-class RoleCreatePageState extends State<RoleCreatePage> implements RedrawPage{
+class RoleCreatePageState extends State<RoleCreatePage> implements RedrawPage {
final ApplicationData applicationData;
final GlobalKey<FormState> _formKey =
@override
Widget build(BuildContext context) {
- controller.beginOfBuild(context);
+ controller?.beginOfBuild(context);
return Scaffold(
appBar: applicationData.appBarBuilder('Neue Rolle'),
drawer: applicationData.drawerBuilder(context),
configuration: applicationData.configuration,
));
}
+
@override
void initState() {
super.initState();
- controller = RoleController(
- _formKey, this, 'create', context, applicationData);
+ controller =
+ RoleController(_formKey, this, 'create', context, applicationData);
controller.initialize();
}
}
}
-class RoleListPageState extends State<RoleListPage> implements RedrawPage{
+class RoleListPageState extends State<RoleListPage> implements RedrawPage {
final ApplicationData applicationData;
final GlobalKey<FormState> _formKey =
MaterialPageRoute(
builder: (context) => UserChangePage(id, applicationData, row)));
}
-
}
}
}
-class UserPasswordPageState extends State<UserPasswordPage> implements RedrawPage {
+class UserPasswordPageState extends State<UserPasswordPage>
+ implements RedrawPage {
final ApplicationData applicationData;
final int primaryId;
final String userName;
}) {
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 =
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';
/// 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,
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)),
--- /dev/null
+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();
+ }
+}
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;
/// 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);
/// 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));
}
///
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();
}
/// 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];
}
});
}
/// [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;
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';
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;
}
/// 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);
+++ /dev/null
-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();
- }
-}
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(
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(
--- /dev/null
+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
+'''));
+ });
+ });
+}
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();
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);
expect(data, isNotNull);
});
test('combobase', () {
- WidgetModel.lastId = 0;
+ ModelBase.lastId = 0;
logger.clear();
final map = <String, dynamic>{
'module': 'demo1',
});
group('errors', () {
test('errors-combobase', () {
- WidgetModel.lastId = 0;
+ ModelBase.lastId = 0;
logger.clear();
final map = <String, dynamic>{
'module': 'demo1',
isTrue);
});
test('errors-missing-texts', () {
- WidgetModel.lastId = 0;
+ ModelBase.lastId = 0;
logger.clear();
final map = <String, dynamic>{
'module': 'demo1',
isTrue);
});
test('errors-#texts!=#values', () {
- WidgetModel.lastId = 0;
+ ModelBase.lastId = 0;
logger.clear();
final map = <String, dynamic>{
'module': 'demo1',
'dataType': 'reference',
'label': 'Role',
'foreignKey': 'role.role_id role_name',
- 'widgetType': 'combobox',
+ 'modelType': 'combobox',
},
]
},
'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',
},
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();
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
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);
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();
});
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': [
"sectionType": "filterPanel",
"children": [
{
- "widgetType": "dbReference",
+ 'modelType': "dbReference",
"filterType": "pattern",
"name": "user_name",
"column": "user_name",
page.addField(TextFieldModel.direct(
null,
page,
- 'x',
- 'y',
- 'z',
+ 'n',
+ 'l',
+ 't',
DataType.int,
<String>[],
33,
page.addField(TextFieldModel.direct(
null,
page,
- 'x',
- 'y',
- 'z',
+ 'n',
+ 'l',
+ 't',
DataType.int,
<String>[],
44,
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': [
isTrue);
});
test('wrong-section', () {
- WidgetModel.lastId = 0;
+ ModelBase.lastId = 0;
logger.clear();
final map = <String, dynamic>{
'module': 'demo1',
isTrue);
});
test('tableTitles not in list', () {
- WidgetModel.lastId = 0;
+ ModelBase.lastId = 0;
logger.clear();
final map = <String, dynamic>{
'module': 'demo1',
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',
logger.clear();
final map = cloneOfMap(userModel);
final field = <String, dynamic>{
- 'widgetType': 'textField',
+ 'modelType': 'textField',
'name': 'year',
'label': 'Year',
'options': 'required;blubb',
});
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',
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',
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
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',
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
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);
});
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);
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',
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',
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',
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',
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',
"sectionType": "filterPanel",
"children": [
{
- "widgetType": ""
+ 'modelType': ""
},
]
},
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);
});
});
'dataType': 'reference',
'label': 'Role',
'foreignKey': 'role.role_id role_name',
- 'widgetType': 'combobox',
+ 'modelType': 'combobox',
},
]
},
'sectionType': 'simpleForm',
'children': [
{
- 'widgetType': 'textField',
+ 'modelType': 'textField',
'name': 'user',
'label': 'User',
'options': 'required unique',
},
{
- 'widgetType': 'button',
+ 'modelType': 'button',
'name': 'buttonStore',
'label': 'Save',
},
'sectionType': 'simpleForm',
'children': [
{
- 'widgetType': 'allDbFields',
+ 'modelType': 'allDbFields',
},
],
},
final logger = MemoryLogger(LEVEL_FINE);
group('module', () {
test('role', () {
- WidgetModel.lastId = 0;
+ ModelBase.lastId = 0;
logger.clear();
final module = RoleModel(logger);
module.parse();
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();
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();
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();
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
'''));
});
});
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)
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) {
throw UnimplementedError();
}
- @override
- // TODO: implement debugDoingBuild
- bool get debugDoingBuild => throw UnimplementedError();
-
@override
InheritedWidget dependOnInheritedElement(InheritedElement ancestor,
{Object aspect}) {
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
void visitChildElements(visitor) {
// TODO: implement visitChildElements
}
-
- @override
- // TODO: implement widget
- Widget get widget => throw UnimplementedError();
}
// 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';
});
group('independent', () {
test('int', () {
- WidgetModel.lastId = 0;
+ ModelBase.lastId = 0;
logger.clear();
final map = <String, dynamic>{
'module': 'demo1',
equals('Zahl zu groß: 11 > 10'));
});
test('date', () {
- WidgetModel.lastId = 0;
+ ModelBase.lastId = 0;
logger.clear();
final map = <String, dynamic>{
'module': 'demo1',
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',
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',
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'));
});
});
}