From afac9682ae7aa015585618e5a5ba5a717753fd0b Mon Sep 17 00:00:00 2001 From: quasi Date: Wed, 1 Jul 2009 17:31:31 +0000 Subject: [PATCH] BaseAddress MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Erste Version fertig. Scheint soweit alles zu funktionieren. Die Auswahlbox für die Landesauswahl ist nun auch endlich alphabetisch sortiert nach den Ländernamen und nicht nach ISO-Code. Bitte testen. git-svn-id: https://svn.libreccm.org/ccm/trunk@205 8810af33-2d31-482b-a856-94f89814c4df --- .../arsdigita/content-types/BaseAddress.pdl | 4 +- .../src/ccm-cms-types-baseAddress.config | 2 +- .../cms/contenttypes/BaseAddress.java | 31 ++- .../cms/contenttypes/BaseAddressConfig.java | 4 +- .../BaseAddressConfig_parameter.properties | 16 +- .../BaseAddressResources.properties | 7 + .../BaseAddressResources_de.properties | 7 + .../ui/BaseAddressPropertiesStep.java | 103 ++++++++++ .../ui/BaseAddressPropertyForm.java | 178 ++++++++++++++++++ .../cms/contenttypes/BaseAddress.xsl | 71 +++++++ 10 files changed, 392 insertions(+), 31 deletions(-) create mode 100644 ccm-cms-types-baseAddress/src/com/arsdigita/cms/contenttypes/BaseAddressResources_de.properties create mode 100644 ccm-cms-types-baseAddress/src/com/arsdigita/cms/contenttypes/ui/BaseAddressPropertiesStep.java create mode 100644 ccm-cms-types-baseAddress/src/com/arsdigita/cms/contenttypes/ui/BaseAddressPropertyForm.java create mode 100644 ccm-cms-types-baseAddress/web/static/content-types/com/arsdigita/cms/contenttypes/BaseAddress.xsl diff --git a/ccm-cms-types-baseAddress/pdl/com/arsdigita/content-types/BaseAddress.pdl b/ccm-cms-types-baseAddress/pdl/com/arsdigita/content-types/BaseAddress.pdl index fd70eff04..20b7475fe 100644 --- a/ccm-cms-types-baseAddress/pdl/com/arsdigita/content-types/BaseAddress.pdl +++ b/ccm-cms-types-baseAddress/pdl/com/arsdigita/content-types/BaseAddress.pdl @@ -1,9 +1,9 @@ model com.arsdigita.cms.contenttypes; -import com.arsdigita.cms.ContentItem; +import com.arsdigita.cms.ContentPage; // Address object -object type BaseAddress extends ContentItem { +object type BaseAddress extends ContentPage { String [0..1] address = ct_baseAddresses.address VARCHAR(1000); String [0..1] postalCode = ct_baseAddresses.postalCode VARCHAR(20); diff --git a/ccm-cms-types-baseAddress/src/ccm-cms-types-baseAddress.config b/ccm-cms-types-baseAddress/src/ccm-cms-types-baseAddress.config index adfdba100..610be6c7f 100755 --- a/ccm-cms-types-baseAddress/src/ccm-cms-types-baseAddress.config +++ b/ccm-cms-types-baseAddress/src/ccm-cms-types-baseAddress.config @@ -1,4 +1,4 @@ - + diff --git a/ccm-cms-types-baseAddress/src/com/arsdigita/cms/contenttypes/BaseAddress.java b/ccm-cms-types-baseAddress/src/com/arsdigita/cms/contenttypes/BaseAddress.java index f36d0e560..33b6d0b69 100755 --- a/ccm-cms-types-baseAddress/src/com/arsdigita/cms/contenttypes/BaseAddress.java +++ b/ccm-cms-types-baseAddress/src/com/arsdigita/cms/contenttypes/BaseAddress.java @@ -27,9 +27,8 @@ import com.arsdigita.persistence.DataObject; import com.arsdigita.persistence.OID; import com.arsdigita.util.Assert; import java.math.BigDecimal; -import java.util.ArrayList; -import java.util.Collections; import java.util.Locale; +import java.util.TreeMap; /** *

DomainObject class to represent address ContentType @@ -175,33 +174,29 @@ public class BaseAddress extends ContentPage { } // Convert the iso country code to country names using the current locale - public String getCountryNameFromIsoCode(String isoCountryCode) { + public static String getCountryNameFromIsoCode(String isoCountryCode) { LocaleNegotiator negotiatedLocale = new LocaleNegotiator("", "", "", null); - java.util.Locale locale = new java.util.Locale("", isoCountryCode); - return locale.getDisplayCountry(negotiatedLocale.getLocale()); } // Get a sorted list auf all countries - public ArrayList getSortedListOfCountries(Locale inLang) { + public static TreeMap getSortedListOfCountries(Locale inLang) { - Locale[] locales = Locale.getAvailableLocales(); - ArrayList countryNames = new ArrayList(); - - for(Locale locale : locales) { - - if(locale.getDisplayCountry(inLang) != null) { - - countryNames.add(locale.getDisplayCountry(inLang)); - + LocaleNegotiator negotiatedLocale = new LocaleNegotiator("", "", "", null); + String[] countries = Locale.getISOCountries(); + TreeMap countryNames = new TreeMap(); + + for(String country : countries) { + if(inLang != null) { + countryNames.put(new java.util.Locale("", country).getDisplayCountry(inLang), country); + } else { + countryNames.put(new java.util.Locale("", country).getDisplayCountry(negotiatedLocale.getLocale()), country); } } - - Collections.sort(countryNames); - + return countryNames; } } diff --git a/ccm-cms-types-baseAddress/src/com/arsdigita/cms/contenttypes/BaseAddressConfig.java b/ccm-cms-types-baseAddress/src/com/arsdigita/cms/contenttypes/BaseAddressConfig.java index e24e56c55..2fd2b871b 100644 --- a/ccm-cms-types-baseAddress/src/com/arsdigita/cms/contenttypes/BaseAddressConfig.java +++ b/ccm-cms-types-baseAddress/src/com/arsdigita/cms/contenttypes/BaseAddressConfig.java @@ -29,12 +29,12 @@ public class BaseAddressConfig extends AbstractConfig { public BaseAddressConfig() { m_hideCountryCodeSelection = new BooleanParameter( - "com.arsdigita.cms.contenttypes.address.hide_country_code_selection", + "com.arsdigita.cms.contenttypes.baseaddress.hide_country_code_selection", Parameter.REQUIRED, new Boolean(false)); m_hidePostalCode = new BooleanParameter( - "com.arsdigita.cms.contenttypes.address.hide_postal_code", + "com.arsdigita.cms.contenttypes.baseaddress.hide_postal_code", Parameter.REQUIRED, new Boolean(false)); diff --git a/ccm-cms-types-baseAddress/src/com/arsdigita/cms/contenttypes/BaseAddressConfig_parameter.properties b/ccm-cms-types-baseAddress/src/com/arsdigita/cms/contenttypes/BaseAddressConfig_parameter.properties index 62d3e7fdf..c0522251c 100644 --- a/ccm-cms-types-baseAddress/src/com/arsdigita/cms/contenttypes/BaseAddressConfig_parameter.properties +++ b/ccm-cms-types-baseAddress/src/com/arsdigita/cms/contenttypes/BaseAddressConfig_parameter.properties @@ -1,9 +1,9 @@ -com.arsdigita.cms.contenttypes.address.hide_country_code_selection.title=Hide ISO Country Code -com.arsdigita.cms.contenttypes.address.hide_country_code_selection.purpose=Hide the ISO country code selection box -com.arsdigita.cms.contenttypes.address.hide_country_code_selection.example=false -com.arsdigita.cms.contenttypes.address.hide_country_code_selection.format=[boolean] +com.arsdigita.cms.contenttypes.baseaddress.hide_country_code_selection.title=Hide ISO Country Code +com.arsdigita.cms.contenttypes.baseaddress.hide_country_code_selection.purpose=Hide the ISO country code selection box +com.arsdigita.cms.contenttypes.baseaddress.hide_country_code_selection.example=false +com.arsdigita.cms.contenttypes.baseaddress.hide_country_code_selection.format=[boolean] -com.arsdigita.cms.contenttypes.address.hide_postal_code.title=Hide Postal Code -com.arsdigita.cms.contenttypes.address.hide_postal_code.purpose=Hide the the postal code entry field -com.arsdigita.cms.contenttypes.address.hide_postal_code.example=false -com.arsdigita.cms.contenttypes.address.hide_postal_code.format=[boolean] +com.arsdigita.cms.contenttypes.baseaddress.hide_postal_code.title=Hide Postal Code +com.arsdigita.cms.contenttypes.baseaddress.hide_postal_code.purpose=Hide the the postal code entry field +com.arsdigita.cms.contenttypes.baseaddress.hide_postal_code.example=false +com.arsdigita.cms.contenttypes.baseaddress.hide_postal_code.format=[boolean] diff --git a/ccm-cms-types-baseAddress/src/com/arsdigita/cms/contenttypes/BaseAddressResources.properties b/ccm-cms-types-baseAddress/src/com/arsdigita/cms/contenttypes/BaseAddressResources.properties index e69de29bb..b38a1563b 100755 --- a/ccm-cms-types-baseAddress/src/com/arsdigita/cms/contenttypes/BaseAddressResources.properties +++ b/ccm-cms-types-baseAddress/src/com/arsdigita/cms/contenttypes/BaseAddressResources.properties @@ -0,0 +1,7 @@ +cms.contenttypes.ui.baseAddress.address=Address +cms.contenttypes.ui.baseAddress.postal_code=Postal Code +cms.contenttypes.ui.baseAddress.city=City +cms.contenttypes.ui.baseAddress.state=State +cms.contenttypes.ui.baseAddress.iso_country_code=Country +cms.contenttypes.ui.baseAddress.error_iso_country=You must select a country +baseAddress.authoring.basic_properties.title=Basic Properties \ No newline at end of file diff --git a/ccm-cms-types-baseAddress/src/com/arsdigita/cms/contenttypes/BaseAddressResources_de.properties b/ccm-cms-types-baseAddress/src/com/arsdigita/cms/contenttypes/BaseAddressResources_de.properties new file mode 100644 index 000000000..2df4ae775 --- /dev/null +++ b/ccm-cms-types-baseAddress/src/com/arsdigita/cms/contenttypes/BaseAddressResources_de.properties @@ -0,0 +1,7 @@ +cms.contenttypes.ui.baseAddress.address=Adresse +cms.contenttypes.ui.baseAddress.postal_code=Postleitzahl +cms.contenttypes.ui.baseAddress.city=Stadt +cms.contenttypes.ui.baseAddress.state=Bundesland +cms.contenttypes.ui.baseAddress.iso_country_code=Land +cms.contenttypes.ui.baseAddress.error_iso_country=Bitte wählen Sie ein Land aus +baseAddress.authoring.basic_properties.title=Eigenschaften \ No newline at end of file diff --git a/ccm-cms-types-baseAddress/src/com/arsdigita/cms/contenttypes/ui/BaseAddressPropertiesStep.java b/ccm-cms-types-baseAddress/src/com/arsdigita/cms/contenttypes/ui/BaseAddressPropertiesStep.java new file mode 100644 index 000000000..0b8cc25f4 --- /dev/null +++ b/ccm-cms-types-baseAddress/src/com/arsdigita/cms/contenttypes/ui/BaseAddressPropertiesStep.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2009 Jens Pelzetter, for the Center of Social Politics of the University of Bremen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +package com.arsdigita.cms.contenttypes.ui; + +import com.arsdigita.bebop.Component; +import com.arsdigita.bebop.PageState; +import com.arsdigita.cms.ContentPage; +import com.arsdigita.cms.ContentSection; +import com.arsdigita.cms.ItemSelectionModel; +import com.arsdigita.cms.contenttypes.BaseAddress; +import com.arsdigita.domain.DomainObject; +import com.arsdigita.toolbox.ui.DomainObjectPropertySheet; +import com.arsdigita.cms.ui.authoring.AuthoringKitWizard; +import com.arsdigita.cms.ui.authoring.BasicPageForm; +import com.arsdigita.cms.ui.authoring.SimpleEditStep; +import com.arsdigita.cms.ui.workflow.WorkflowLockedComponentAccess; +import com.arsdigita.cms.contenttypes.util.BaseAddressGlobalizationUtil; + +import java.text.DateFormat; + +public class BaseAddressPropertiesStep extends SimpleEditStep { + public static final String EDIT_SHEET_NAME = "edit"; + + public BaseAddressPropertiesStep(ItemSelectionModel itemModel, + AuthoringKitWizard parent) { + super(itemModel, parent); + + setDefaultEditKey(EDIT_SHEET_NAME); + BasicPageForm editSheet; + + editSheet = new BaseAddressPropertyForm(itemModel, this); + add(EDIT_SHEET_NAME, "Edit", + new WorkflowLockedComponentAccess(editSheet, itemModel), + editSheet.getSaveCancelSection().getCancelButton()); + + setDisplayComponent(getBaseAddressPropertySheet(itemModel)); + } + + public static Component getBaseAddressPropertySheet(ItemSelectionModel itemModel) { + DomainObjectPropertySheet sheet = new DomainObjectPropertySheet(itemModel); + + sheet.add((String)BaseAddressGlobalizationUtil.globalize("cms.contenttypes.ui.name").localize(), BaseAddress.NAME); + sheet.add((String)BaseAddressGlobalizationUtil.globalize("cms.contenttypes.ui.title").localize(), BaseAddress.TITLE); + sheet.add((String)BaseAddressGlobalizationUtil.globalize("cms.contenttypes.ui.baseAddress.address").localize(), BaseAddress.ADDRESS); + sheet.add((String)BaseAddressGlobalizationUtil.globalize("cms.contenttypes.ui.baseAddress.postal_code").localize(), BaseAddress.POSTAL_CODE); + sheet.add((String)BaseAddressGlobalizationUtil.globalize("cms.contenttypes.ui.baseAddress.city").localize(), BaseAddress.CITY); + sheet.add((String)BaseAddressGlobalizationUtil.globalize("cms.contenttypes.ui.baseAddress.state").localize(), BaseAddress.STATE); + + sheet.add((String)BaseAddressGlobalizationUtil.globalize("cms.contenttypes.ui.baseAddress.country").localize(), + BaseAddress.ISO_COUNTRY_CODE, + new DomainObjectPropertySheet.AttributeFormatter() { + public String format(DomainObject item, + String attribute, + PageState state) { + BaseAddress baseAddress = (BaseAddress)item; + if(baseAddress.getIsoCountryCode() != null) { + return BaseAddress.getCountryNameFromIsoCode(baseAddress.getIsoCountryCode()); + } else { + return (String)BaseAddressGlobalizationUtil.globalize + ("cms.ui.unknown").localize(); + } + } + } + ); + + if(!ContentSection.getConfig().getHideLaunchDate()) { + sheet.add((String)BaseAddressGlobalizationUtil.globalize("cms.ui.authoring.page_launch_date").localize(), + ContentPage.LAUNCH_DATE, + new DomainObjectPropertySheet.AttributeFormatter() { + public String format(DomainObject item, + String attribute, + PageState state) { + ContentPage page = (ContentPage)item; + if (page.getLaunchDate() != null) { + return DateFormat.getDateInstance(DateFormat.LONG).format(page.getLaunchDate()); + } + else { + return (String)BaseAddressGlobalizationUtil.globalize("cms.ui.unknown").localize(); + } + } + }); + } + + return sheet; + } +} \ No newline at end of file diff --git a/ccm-cms-types-baseAddress/src/com/arsdigita/cms/contenttypes/ui/BaseAddressPropertyForm.java b/ccm-cms-types-baseAddress/src/com/arsdigita/cms/contenttypes/ui/BaseAddressPropertyForm.java new file mode 100644 index 000000000..745fe1728 --- /dev/null +++ b/ccm-cms-types-baseAddress/src/com/arsdigita/cms/contenttypes/ui/BaseAddressPropertyForm.java @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2009 Jens Pelzetter, for the Center of Social Politics of the University of Bremen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +package com.arsdigita.cms.contenttypes.ui; + +import com.arsdigita.bebop.FormData; +import com.arsdigita.bebop.FormProcessException; +import com.arsdigita.bebop.Label; +import com.arsdigita.bebop.event.FormInitListener; +import com.arsdigita.bebop.event.FormProcessListener; +import com.arsdigita.bebop.event.FormSectionEvent; +import com.arsdigita.bebop.event.FormSubmissionListener; +import com.arsdigita.bebop.event.ParameterEvent; +import com.arsdigita.bebop.event.ParameterListener; +import com.arsdigita.bebop.form.Option; +import com.arsdigita.bebop.form.SingleSelect; +import com.arsdigita.bebop.form.TextArea; +import com.arsdigita.bebop.form.TextField; +import com.arsdigita.bebop.parameters.NotNullValidationListener; +import com.arsdigita.bebop.parameters.StringInRangeValidationListener; +import com.arsdigita.bebop.parameters.ParameterModel; +import com.arsdigita.bebop.parameters.StringParameter; +import com.arsdigita.bebop.parameters.ParameterData; +import com.arsdigita.cms.ItemSelectionModel; +import com.arsdigita.cms.contenttypes.BaseAddress; +import com.arsdigita.cms.contenttypes.util.BaseAddressGlobalizationUtil; +import com.arsdigita.cms.ui.authoring.BasicPageForm; +import java.util.Iterator; +import java.util.Map; +import org.apache.log4j.Logger; + +/** + * Form to edit the properties of a baseAddress. + * + * @author: Jens Pelzetter + * @author: Sören Bernstein + */ +public class BaseAddressPropertyForm extends BasicPageForm implements FormProcessListener, FormInitListener, FormSubmissionListener { + private static final Logger s_log = Logger.getLogger(BaseAddressPropertyForm.class); + + private BaseAddressPropertiesStep m_step; + + public static final String ADDRESS = BaseAddress.ADDRESS; + public static final String POSTAL_CODE = BaseAddress.POSTAL_CODE; + public static final String CITY = BaseAddress.CITY; + public static final String STATE = BaseAddress.STATE; + public static final String ISO_COUNTRY_CODE = BaseAddress.ISO_COUNTRY_CODE; + + public static final String ID = "BaseAddress_edit"; + + public BaseAddressPropertyForm(ItemSelectionModel itemModel) { + this(itemModel,null); + } + + public BaseAddressPropertyForm(ItemSelectionModel itemModel, BaseAddressPropertiesStep step) { + super(ID, itemModel); + m_step = step; + addSubmissionListener (this); + } + + protected void addWidgets() { + super.addWidgets (); + + add(new Label((String)BaseAddressGlobalizationUtil.globalize("cms.contenttypes.ui.baseAddress.address").localize())); + ParameterModel addressParam = new StringParameter(ADDRESS); + addressParam.addParameterListener( new NotNullValidationListener( ) ); + addressParam.addParameterListener( new StringInRangeValidationListener(0, 1000) ); + TextArea address = new TextArea(addressParam); + address.setRows(5); + address.setCols(30); + add(address); + + add(new Label((String)BaseAddressGlobalizationUtil.globalize("cms.contenttypes.ui.baseAddress.postal_code").localize())); + ParameterModel postalCodeParam = new StringParameter(POSTAL_CODE); + TextField postalCode = new TextField(postalCodeParam); + /* XXX NumberListener ?*/ + add(postalCode); + + add(new Label((String)BaseAddressGlobalizationUtil.globalize("cms.contenttypes.ui.baseAddress.city").localize())); + ParameterModel cityParam = new StringParameter(CITY); + TextField city = new TextField(cityParam); + add(city); + + add(new Label((String)BaseAddressGlobalizationUtil.globalize("cms.contenttypes.ui.baseAddress.state").localize())); + ParameterModel stateParam = new StringParameter(STATE); + TextField state = new TextField(stateParam); + add(state); + + if (!BaseAddress.getConfig().getHideCountryCodeSelection()) { + add(new Label((String)BaseAddressGlobalizationUtil.globalize("cms.contenttypes.ui.baseAddress.country").localize())); + ParameterModel countryParam = new StringParameter(ISO_COUNTRY_CODE); + countryParam.addParameterListener(new StringInRangeValidationListener(0, 2)); + + SingleSelect country = new SingleSelect(countryParam); + + country.addOption(new Option("", new Label((String)BaseAddressGlobalizationUtil.globalize("cms.ui.select_one" ).localize()))); + + Iterator countries = BaseAddress.getSortedListOfCountries(null).entrySet().iterator(); + while(countries.hasNext()) { + Map.Entry elem = (Map.Entry)countries.next(); + country.addOption(new Option(elem.getValue().toString(), elem.getKey().toString())); + } + + country.addValidationListener( + new ParameterListener() { + public void validate(ParameterEvent e) throws FormProcessException { + ParameterData data = e.getParameterData(); + String isoCode = (String) data.getValue() ; + s_log.debug("ISO code is : " + isoCode); + if (isoCode == null || isoCode.length() == 0) { + data.addError((String)BaseAddressGlobalizationUtil.globalize("cms.contenttypes.ui.address.error_iso_country").localize()); + } + } + } + ); + + add(country); + } + + } + + public void init(FormSectionEvent fse) { + FormData data = fse.getFormData(); + BaseAddress baseAddress = (BaseAddress)super.initBasicWidgets(fse); + + data.put(ADDRESS, baseAddress.getAddress()); + data.put(POSTAL_CODE, baseAddress.getPostalCode()); + data.put(CITY, baseAddress.getCity()); + data.put(STATE, baseAddress.getState()); + if(!BaseAddress.getConfig().getHideCountryCodeSelection()) { + data.put(ISO_COUNTRY_CODE, baseAddress.getIsoCountryCode()); + } + } + + public void submitted(FormSectionEvent fse) { + if (m_step != null && + getSaveCancelSection().getCancelButton().isSelected(fse.getPageState())) { + m_step.cancelStreamlinedCreation(fse.getPageState()); + } + } + + public void process(FormSectionEvent fse) { + FormData data = fse.getFormData(); + + BaseAddress baseAddress = (BaseAddress)super.processBasicWidgets(fse); + + if (baseAddress != null && + getSaveCancelSection().getSaveButton().isSelected(fse.getPageState())) { + baseAddress.setAddress((String)data.get(ADDRESS)); + baseAddress.setPostalCode((String)data.get(POSTAL_CODE)); + baseAddress.setCity((String)data.get(CITY)); + baseAddress.setState((String)data.get(STATE)); + baseAddress.setIsoCountryCode((String)data.get(ISO_COUNTRY_CODE)); + + baseAddress.save(); + } + + if (m_step != null) { + m_step.maybeForwardToNextStep(fse.getPageState()); + } + } +} \ No newline at end of file diff --git a/ccm-cms-types-baseAddress/web/static/content-types/com/arsdigita/cms/contenttypes/BaseAddress.xsl b/ccm-cms-types-baseAddress/web/static/content-types/com/arsdigita/cms/contenttypes/BaseAddress.xsl new file mode 100644 index 000000000..d4fe25a8b --- /dev/null +++ b/ccm-cms-types-baseAddress/web/static/content-types/com/arsdigita/cms/contenttypes/BaseAddress.xsl @@ -0,0 +1,71 @@ + +]> + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Address:
Postal Code:
City:
Country:
+
+
+ + +

+ + Address +
+
+ + Postal Code +
+
+ + City +
+
+ + Country +
+
+ + + \ No newline at end of file