diff --git a/entity/Campaign_entity/Campaign_entity.aod b/entity/Campaign_entity/Campaign_entity.aod index d51ee6244bb2873e72c5e62a078332875d1aa70b..e3c07b68ab3028248444d937340ba529df6a549e 100644 --- a/entity/Campaign_entity/Campaign_entity.aod +++ b/entity/Campaign_entity/Campaign_entity.aod @@ -52,8 +52,7 @@ <title>Start</title> <contentType>DATE</contentType> <resolution>DAY</resolution> - <outputFormat></outputFormat> - <inputFormat></inputFormat> + <outputFormat>dd.MM.yyyy</outputFormat> <state>READONLY</state> <valueProcess>%aditoprj%/entity/Campaign_entity/entityfields/date_start/valueProcess.js</valueProcess> </entityField> @@ -522,6 +521,22 @@ <name>CAMPAIGN_OBEJCTTYPE</name> <valueProcess>%aditoprj%/entity/Campaign_entity/entityfields/campaign_obejcttype/valueProcess.js</valueProcess> </entityField> + <entityConsumer> + <name>PersonConsumer</name> + <dependency> + <name>dependency</name> + <entityName>Person_entity</entityName> + <fieldName>#PROVIDER</fieldName> + </dependency> + </entityConsumer> + <entityConsumer> + <name>OrganisationConsumer</name> + <dependency> + <name>dependency</name> + <entityName>Organisation_entity</entityName> + <fieldName>#PROVIDER</fieldName> + </dependency> + </entityConsumer> <entityField> <name>COUNT</name> <title>Count</title> @@ -537,13 +552,14 @@ <dbRecordContainer> <name>db</name> <alias>Data_alias</alias> + <fromClauseProcess>%aditoprj%/entity/Campaign_entity/recordcontainers/db/fromClauseProcess.js</fromClauseProcess> <conditionProcess>%aditoprj%/entity/Campaign_entity/recordcontainers/db/conditionProcess.js</conditionProcess> <onDBInsert>%aditoprj%/entity/Campaign_entity/recordcontainers/db/onDBInsert.js</onDBInsert> <onDBUpdate>%aditoprj%/entity/Campaign_entity/recordcontainers/db/onDBUpdate.js</onDBUpdate> <onDBDelete>%aditoprj%/entity/Campaign_entity/recordcontainers/db/onDBDelete.js</onDBDelete> <linkInformation> <linkInformation> - <name>f3893829-3af2-4e55-ae85-c3a24411a8b8</name> + <name>f95b8870-15cd-4302-99ec-8a104ae2262d</name> <tableName>CAMPAIGN</tableName> <primaryKey>CAMPAIGNID</primaryKey> <isUIDTable v="true" /> @@ -634,6 +650,18 @@ <recordfield>CAMPAIGN.CAMPAIGNID</recordfield> <aggregateType>COUNT</aggregateType> </aggregateFieldDbMapping> + <consumerMapping> + <name>PersonConsumer</name> + <filterConditionProcess>%aditoprj%/entity/Campaign_entity/recordcontainers/db/recordfieldmappings/personconsumer/filterConditionProcess.js</filterConditionProcess> + <isFilterable v="true" /> + <filtertype>BASIC</filtertype> + </consumerMapping> + <consumerMapping> + <name>OrganisationConsumer</name> + <filterConditionProcess>%aditoprj%/entity/Campaign_entity/recordcontainers/db/recordfieldmappings/organisationconsumer/filterConditionProcess.js</filterConditionProcess> + <isFilterable v="true" /> + <filtertype>BASIC</filtertype> + </consumerMapping> </recordFieldMappings> <filterExtensions> <filterExtensionSet> @@ -643,6 +671,44 @@ <filterConditionProcess>%aditoprj%/entity/Campaign_entity/recordcontainers/db/filterextensions/attribute_filter/filterConditionProcess.js</filterConditionProcess> <filtertype>BASIC</filtertype> </filterExtensionSet> + <filterExtension> + <name>DateStart_filter</name> + <title>Startdatum</title> + <contentType>DATE</contentType> + <filterConditionProcess>%aditoprj%/entity/Campaign_entity/recordcontainers/db/filterextensions/datestart_filter/filterConditionProcess.js</filterConditionProcess> + <filtertype>BASIC</filtertype> + </filterExtension> + <filterExtension> + <name>DateEnd_filter</name> + <title>Enddatum</title> + <contentType>DATE</contentType> + <filterConditionProcess>%aditoprj%/entity/Campaign_entity/recordcontainers/db/filterextensions/dateend_filter/filterConditionProcess.js</filterConditionProcess> + <filtertype>BASIC</filtertype> + </filterExtension> + <filterExtension> + <name>Participant_filter</name> + <title>Participants</title> + <contentType>TEXT</contentType> + <filterValuesProcess>%aditoprj%/entity/Campaign_entity/recordcontainers/db/filterextensions/participant_filter/filterValuesProcess.js</filterValuesProcess> + <filterConditionProcess>%aditoprj%/entity/Campaign_entity/recordcontainers/db/filterextensions/participant_filter/filterConditionProcess.js</filterConditionProcess> + <filtertype>BASIC</filtertype> + </filterExtension> + <filterExtension> + <name>CampaignStep_filter</name> + <title>Steps</title> + <contentType>TEXT</contentType> + <filterValuesProcess>%aditoprj%/entity/Campaign_entity/recordcontainers/db/filterextensions/campaignstep_filter/filterValuesProcess.js</filterValuesProcess> + <filterConditionProcess>%aditoprj%/entity/Campaign_entity/recordcontainers/db/filterextensions/campaignstep_filter/filterConditionProcess.js</filterConditionProcess> + <filtertype>BASIC</filtertype> + </filterExtension> + <filterExtension> + <name>Member_filter</name> + <title>Members</title> + <contentType>TEXT</contentType> + <filterValuesProcess>%aditoprj%/entity/Campaign_entity/recordcontainers/db/filterextensions/member_filter/filterValuesProcess.js</filterValuesProcess> + <filterConditionProcess>%aditoprj%/entity/Campaign_entity/recordcontainers/db/filterextensions/member_filter/filterConditionProcess.js</filterConditionProcess> + <filtertype>BASIC</filtertype> + </filterExtension> </filterExtensions> </dbRecordContainer> </recordContainers> diff --git a/entity/Campaign_entity/recordcontainers/db/conditionProcess.js b/entity/Campaign_entity/recordcontainers/db/conditionProcess.js index 5f3455bc5b51c66cf6a7cd0ed14899bc09356fd9..80bfe7f5212f2df2dac845d90873e9f2315c379d 100644 --- a/entity/Campaign_entity/recordcontainers/db/conditionProcess.js +++ b/entity/Campaign_entity/recordcontainers/db/conditionProcess.js @@ -1,11 +1,19 @@ -import("Employee_lib"); import("system.db"); import("system.result"); -import("Sql_lib"); import("system.vars"); +import("Employee_lib"); +import("Sql_lib"); + if(vars.get("$param.ShowOnlyCurrentUsersCampaigns_param") == 'true') { //TODO: use a preparedCondition (.build instead of .translate) when available #1030812 #1034026 result.string(newWhere("CAMPAIGN.EMPLOYEE_CONTACT_ID", EmployeeUtils.getCurrentContactId()).toString()); +} else { + var condition = new SqlBuilder() + .whereIfSet("STEPDATESTART_TABLEALIAS.CAMPAIGN_ID = CAMPAIGN.CAMPAIGNID") + .andIfSet("STEPDATEEND_TABLEALIAS.CAMPAIGN_ID = CAMPAIGN.CAMPAIGNID") + ; + + result.string(condition.toString()); } \ No newline at end of file diff --git a/entity/Campaign_entity/recordcontainers/db/filterextensions/campaignstep_filter/filterConditionProcess.js b/entity/Campaign_entity/recordcontainers/db/filterextensions/campaignstep_filter/filterConditionProcess.js new file mode 100644 index 0000000000000000000000000000000000000000..d0dddcc8b370c4307bd88e167744ee1c2be730ac --- /dev/null +++ b/entity/Campaign_entity/recordcontainers/db/filterextensions/campaignstep_filter/filterConditionProcess.js @@ -0,0 +1,27 @@ +import("system.result"); +import("system.vars"); +import("Sql_lib"); +import("Util_lib"); +import("Campaign_lib"); + + +var valueSubSelect = "(select CAMPAIGNSTEPID from CAMPAIGNSTEP where CAMPAIGN.CAMPAIGNID = CAMPAIGNSTEP.CAMPAIGN_ID)"; +var countSubSelect = "(select count(*) from CAMPAIGNSTEP where CAMPAIGNSTEP.CAMPAIGN_ID = CAMPAIGN.CAMPAIGNID)"; +var condition = ""; + +switch(vars.get("$local.comparison")) { + case "ISNOTNULL": + condition = countSubSelect + " > 0"; + break; + case "ISNULL": + condition = countSubSelect + " = 0"; + break; + case "NOT_EQUAL": + condition = vars.get("$local.value") + " not in " + valueSubSelect; + break; + case "EQUAL": + condition = vars.get("$local.value") + " in " + valueSubSelect; + break; +} + +result.object(condition); diff --git a/entity/Campaign_entity/recordcontainers/db/filterextensions/campaignstep_filter/filterValuesProcess.js b/entity/Campaign_entity/recordcontainers/db/filterextensions/campaignstep_filter/filterValuesProcess.js new file mode 100644 index 0000000000000000000000000000000000000000..13b3ff34c39b81bad62a1a11c9ade92ac14078fc --- /dev/null +++ b/entity/Campaign_entity/recordcontainers/db/filterextensions/campaignstep_filter/filterValuesProcess.js @@ -0,0 +1,11 @@ +import("system.result"); +import("Sql_lib"); + + +var campaignStepValues = new SqlBuilder() + .select("CAMPAIGNSTEPID, NAME") + .from("CAMPAIGNSTEP") + .orderBy("NAME") + .table(); + +result.object(campaignStepValues); \ No newline at end of file diff --git a/entity/Campaign_entity/recordcontainers/db/filterextensions/dateend_filter/filterConditionProcess.js b/entity/Campaign_entity/recordcontainers/db/filterextensions/dateend_filter/filterConditionProcess.js new file mode 100644 index 0000000000000000000000000000000000000000..c5895859892cd384192c63b347d7c054bb6efc3d --- /dev/null +++ b/entity/Campaign_entity/recordcontainers/db/filterextensions/dateend_filter/filterConditionProcess.js @@ -0,0 +1,17 @@ +import("system.result"); +import("system.vars"); +import("Sql_lib"); +import("Util_lib"); + + +var subSelect = new SqlBuilder() + .select("max(CAMPAIGNSTEP.DATE_END)") + .from("CAMPAIGNSTEP") + .where("CAMPAIGNSTEP.CAMPAIGN_ID = CAMPAIGN.CAMPAIGNID") + .toString(); + +subSelect = "(" + subSelect + ")"; + +var condition = StringUtils.replaceAll(vars.get("$local.condition"), vars.get("$local.columnPlaceholder"), subSelect); + +result.object(condition); diff --git a/entity/Campaign_entity/recordcontainers/db/filterextensions/datestart_filter/filterConditionProcess.js b/entity/Campaign_entity/recordcontainers/db/filterextensions/datestart_filter/filterConditionProcess.js new file mode 100644 index 0000000000000000000000000000000000000000..2d15b9e58f29554efe52a565d2033e5ba2f448ab --- /dev/null +++ b/entity/Campaign_entity/recordcontainers/db/filterextensions/datestart_filter/filterConditionProcess.js @@ -0,0 +1,17 @@ +import("system.result"); +import("system.vars"); +import("Sql_lib"); +import("Util_lib"); + + +var subSelect = new SqlBuilder() + .select("min(CAMPAIGNSTEP.DATE_START)") + .from("CAMPAIGNSTEP") + .where("CAMPAIGNSTEP.CAMPAIGN_ID = CAMPAIGN.CAMPAIGNID") + .toString(); + +subSelect = "(" + subSelect + ")"; + +var condition = StringUtils.replaceAll(vars.get("$local.condition"), vars.get("$local.columnPlaceholder"), subSelect); + +result.object(condition); diff --git a/entity/Campaign_entity/recordcontainers/db/filterextensions/member_filter/filterConditionProcess.js b/entity/Campaign_entity/recordcontainers/db/filterextensions/member_filter/filterConditionProcess.js new file mode 100644 index 0000000000000000000000000000000000000000..48c84a8dcbb02d59429f6b681c2186b3c1767b6b --- /dev/null +++ b/entity/Campaign_entity/recordcontainers/db/filterextensions/member_filter/filterConditionProcess.js @@ -0,0 +1,26 @@ +import("system.result"); +import("system.vars"); +import("Sql_lib"); +import("Util_lib"); + + +var valueSubSelect = "(select CONTACT_ID from OBJECTMEMBER where OBJECTMEMBER.OBJECT_ROWID = CAMPAIGN.CAMPAIGNID)"; +var countSubSelect = "(select count(*) from OBJECTMEMBER where OBJECTMEMBER.OBJECT_ROWID = CAMPAIGN.CAMPAIGNID)"; +var condition = ""; + +switch(vars.get("$local.comparison")) { + case "ISNOTNULL": + condition = countSubSelect + " > 0"; + break; + case "ISNULL": + condition = countSubSelect + " = 0"; + break; + case "NOT_EQUAL": + condition = vars.get("$local.value") + " not in " + valueSubSelect; + break; + case "EQUAL": + condition = vars.get("$local.value") + " in " + valueSubSelect; + break; +} + +result.object(condition); diff --git a/entity/Campaign_entity/recordcontainers/db/filterextensions/member_filter/filterValuesProcess.js b/entity/Campaign_entity/recordcontainers/db/filterextensions/member_filter/filterValuesProcess.js new file mode 100644 index 0000000000000000000000000000000000000000..569b13dcd324261da56d6e462a80f7b0a718c1df --- /dev/null +++ b/entity/Campaign_entity/recordcontainers/db/filterextensions/member_filter/filterValuesProcess.js @@ -0,0 +1,13 @@ +import("system.result"); +import("Sql_lib"); +import("Person_lib"); + + +var query = new SqlBuilder() + .select("OBJECTMEMBER.CONTACT_ID, (" + PersUtils.getResolvingDisplaySubSql("OBJECTMEMBER.CONTACT_ID") + ") as C") + .from("OBJECTMEMBER") + .join("CAMPAIGN", "OBJECTMEMBER.OBJECT_ROWID = CAMPAIGN.CAMPAIGNID") + .join("CONTACT", "OBJECTMEMBER.CONTACT_ID = CONTACT.CONTACTID") + ; + +result.object(query.table()); \ No newline at end of file diff --git a/entity/Campaign_entity/recordcontainers/db/filterextensions/participant_filter/filterConditionProcess.js b/entity/Campaign_entity/recordcontainers/db/filterextensions/participant_filter/filterConditionProcess.js new file mode 100644 index 0000000000000000000000000000000000000000..be23e1087b366a1211fadd6672a3ac0a0e9de033 --- /dev/null +++ b/entity/Campaign_entity/recordcontainers/db/filterextensions/participant_filter/filterConditionProcess.js @@ -0,0 +1,26 @@ +import("system.result"); +import("system.vars"); +import("Sql_lib"); +import("Util_lib"); + + +var valueSubSelect = "(select CONTACT_ID from CAMPAIGNPARTICIPANT where CAMPAIGNPARTICIPANT.CAMPAIGN_ID = CAMPAIGN.CAMPAIGNID)"; +var countSubSelect = "(select count(*) from CAMPAIGNPARTICIPANT where CAMPAIGNPARTICIPANT.CAMPAIGN_ID = CAMPAIGN.CAMPAIGNID)"; +var condition = ""; + +switch(vars.get("$local.comparison")) { + case "ISNOTNULL": + condition = countSubSelect + " > 0"; + break; + case "ISNULL": + condition = countSubSelect + " = 0"; + break; + case "NOT_EQUAL": + condition = vars.get("$local.value") + " not in " + valueSubSelect; + break; + case "EQUAL": + condition = vars.get("$local.value") + " in " + valueSubSelect; + break; +} + +result.object(condition); diff --git a/entity/Campaign_entity/recordcontainers/db/filterextensions/participant_filter/filterValuesProcess.js b/entity/Campaign_entity/recordcontainers/db/filterextensions/participant_filter/filterValuesProcess.js new file mode 100644 index 0000000000000000000000000000000000000000..0ff2d9c975bfceec9ad15b02e8b0a921abf3081b --- /dev/null +++ b/entity/Campaign_entity/recordcontainers/db/filterextensions/participant_filter/filterValuesProcess.js @@ -0,0 +1,16 @@ +import("system.result"); +import("Sql_lib"); +import("Person_lib"); + + +var contactDisplaySelect = "case when CONTACT.PERSON_ID is null" + + " then (select ORGANISATION.NAME FROM ORGANISATION join CONTACT on CONTACT.ORGANISATION_ID = ORGANISATION.ORGANISATIONID where CONTACT.CONTACTID = CAMPAIGNPARTICIPANT.CONTACT_ID)" + + " else (" + PersUtils.getResolvingDisplaySubSql("CAMPAIGNPARTICIPANT.CONTACT_ID") + ")" + + " end"; +var query = new SqlBuilder() + .select("distinct CAMPAIGNPARTICIPANT.CONTACT_ID, (" + contactDisplaySelect + ") as C") + .from("CAMPAIGNPARTICIPANT") + .join("CONTACT on CAMPAIGNPARTICIPANT.CONTACT_ID = CONTACT.CONTACTID", "", "", "inner") + ; + +result.object(query.table()); \ No newline at end of file diff --git a/entity/Campaign_entity/recordcontainers/db/fromClauseProcess.js b/entity/Campaign_entity/recordcontainers/db/fromClauseProcess.js new file mode 100644 index 0000000000000000000000000000000000000000..5eec4c678e0303f56f160d22534f7c2fbe2bd302 --- /dev/null +++ b/entity/Campaign_entity/recordcontainers/db/fromClauseProcess.js @@ -0,0 +1,16 @@ +import("system.result"); +import("system.neon"); +import("system.vars"); + + +var recordState = vars.get("$sys.recordstate"); +var res = "CAMPAIGN"; + +if (recordState != neon.OPERATINGSTATE_NEW && recordState != neon.OPERATINGSTATE_EDIT) { + var subSelectDateStart = "(select min(DATE_START) as STEPDATESTART_ALIAS, CAMPAIGN_ID from CAMPAIGNSTEP group by CAMPAIGN_ID) as STEPDATESTART_TABLEALIAS"; + var subSelectDateEnd = "(select max(DATE_END) as STEPDATEEND_ALIAS, CAMPAIGN_ID from CAMPAIGNSTEP group by CAMPAIGN_ID) as STEPDATEEND_TABLEALIAS"; + + res += ", " + subSelectDateStart + ", " + subSelectDateEnd; +} + +result.string(res); diff --git a/entity/Campaign_entity/recordcontainers/db/recordfieldmappings/date_end.value/expression.js b/entity/Campaign_entity/recordcontainers/db/recordfieldmappings/date_end.value/expression.js index ace40927ffdb20b663900cf4e9d2366690e8a66f..11c77729428dc5d1d87aa9a2a1e4a46366a4c9e1 100644 --- a/entity/Campaign_entity/recordcontainers/db/recordfieldmappings/date_end.value/expression.js +++ b/entity/Campaign_entity/recordcontainers/db/recordfieldmappings/date_end.value/expression.js @@ -1,3 +1,4 @@ import("system.result"); -result.string("(select max(DATE_END) from campaignstep where campaign_id = campaignid)"); \ No newline at end of file + +result.string("STEPDATEEND_ALIAS"); \ No newline at end of file diff --git a/entity/Campaign_entity/recordcontainers/db/recordfieldmappings/date_start.value/expression.js b/entity/Campaign_entity/recordcontainers/db/recordfieldmappings/date_start.value/expression.js index bf0fecca3cb5c6eb05471b61c1c89135d7314ffa..ab23a74c472325d5e8bfd26ddf91f1687fbbf718 100644 --- a/entity/Campaign_entity/recordcontainers/db/recordfieldmappings/date_start.value/expression.js +++ b/entity/Campaign_entity/recordcontainers/db/recordfieldmappings/date_start.value/expression.js @@ -1,3 +1,4 @@ import("system.result"); -result.string("(select min(DATE_START) from campaignstep where campaign_id = campaignid)"); \ No newline at end of file + +result.string("STEPDATESTART_ALIAS"); \ No newline at end of file diff --git a/entity/Campaign_entity/recordcontainers/db/recordfieldmappings/organisationconsumer/filterConditionProcess.js b/entity/Campaign_entity/recordcontainers/db/recordfieldmappings/organisationconsumer/filterConditionProcess.js new file mode 100644 index 0000000000000000000000000000000000000000..0d442ba6a67ca572b6d39d5ec3fc18240c514e60 --- /dev/null +++ b/entity/Campaign_entity/recordcontainers/db/recordfieldmappings/organisationconsumer/filterConditionProcess.js @@ -0,0 +1,11 @@ +import("system.vars"); +import("system.result"); + + +//it's necessary to join the organistion-contact since you may want to search for things like status, language, etc. from an organisation +var from = "CAMPAIGNPARTICIPANT" + + " join CONTACT on (CONTACT.CONTACTID = CAMPAIGNPARTICIPANT.CONTACT_ID)" + + " join ORGANISATION on (ORGANISATION.ORGANISATIONID = CONTACT.ORGANISATION_ID)" +; + +result.string("CAMPAIGNID in (select CAMPAIGNPARTICIPANT.CAMPAIGN_ID from " + from + " where " + vars.get("$local.condition")+ ")"); diff --git a/entity/Campaign_entity/recordcontainers/db/recordfieldmappings/personconsumer/filterConditionProcess.js b/entity/Campaign_entity/recordcontainers/db/recordfieldmappings/personconsumer/filterConditionProcess.js new file mode 100644 index 0000000000000000000000000000000000000000..bab6edf775eaa0affc6a192912814173c5e28a2d --- /dev/null +++ b/entity/Campaign_entity/recordcontainers/db/recordfieldmappings/personconsumer/filterConditionProcess.js @@ -0,0 +1,11 @@ +import("system.vars"); +import("system.result"); + + +//it's necessary to join the person-contact since you may want to search for things like status, language, etc. from an organisation +var from = "CAMPAIGNPARTICIPANT" + + " join CONTACT on (CONTACT.CONTACTID = CAMPAIGNPARTICIPANT.CONTACT_ID)" + + " join PERSON on (PERSON.PERSONID = CONTACT.PERSON_ID)" +; + +result.string("CAMPAIGNID in (select CAMPAIGNPARTICIPANT.CAMPAIGN_ID from " + from + " where " + vars.get("$local.condition")+ ")"); diff --git a/entity/Organisation_entity/Organisation_entity.aod b/entity/Organisation_entity/Organisation_entity.aod index 16ee3b7444d9e3dc79e71ca105aadb970bcf6e26..2811c068175b349fc0d2875335414a1a3c12d28b 100644 --- a/entity/Organisation_entity/Organisation_entity.aod +++ b/entity/Organisation_entity/Organisation_entity.aod @@ -273,6 +273,12 @@ <fieldName>Organisations</fieldName> <isConsumer v="false" /> </entityDependency> + <entityDependency> + <name>271c43f9-8807-4439-9ab4-906fbf019475</name> + <entityName>Campaign_entity</entityName> + <fieldName>OrganisationConsumer</fieldName> + <isConsumer v="false" /> + </entityDependency> </dependencies> </entityProvider> <entityConsumer> diff --git a/entity/Person_entity/Person_entity.aod b/entity/Person_entity/Person_entity.aod index 2268ae38d1314e69f2314eec5ae3284bdbd8df35..a0fac3286f5a3467d6bb90191a90d23855c2eb41 100644 --- a/entity/Person_entity/Person_entity.aod +++ b/entity/Person_entity/Person_entity.aod @@ -284,6 +284,12 @@ <fieldName>PersonConsumer</fieldName> <isConsumer v="false" /> </entityDependency> + <entityDependency> + <name>befbfd87-c065-4a4b-9d1e-8de8fba87302</name> + <entityName>Campaign_entity</entityName> + <fieldName>PersonConsumer</fieldName> + <isConsumer v="false" /> + </entityDependency> </dependencies> </entityProvider> <entityField> diff --git a/neonView/CampaignEdit_view/CampaignEdit_view.aod b/neonView/CampaignEdit_view/CampaignEdit_view.aod index e16693943d7e5b050d64c854e6e3a0208cef9dfc..09b485472214afe13ea75e7c74e38728eb6f02de 100644 --- a/neonView/CampaignEdit_view/CampaignEdit_view.aod +++ b/neonView/CampaignEdit_view/CampaignEdit_view.aod @@ -4,7 +4,7 @@ <title>Campaign</title> <majorModelMode>DISTRIBUTED</majorModelMode> <icon>VAADIN:GROUP</icon> - <size>SMALL</size> + <size>NORMAL</size> <overlayOrientation>PORTRAIT</overlayOrientation> <layout> <noneLayout>