From dd70d7219834d07550f26a09a069e5d68960db37 Mon Sep 17 00:00:00 2001 From: Gavin Cornwell Date: Thu, 16 Mar 2006 15:07:25 +0000 Subject: [PATCH] First phase of the dialog & wizard framework (config implementation) git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@2552 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- .../web/config/DialogsConfigElement.java | 202 +++++++++ .../web/config/DialogsElementReader.java | 86 ++++ .../config/PropertySheetConfigElement.java | 100 ++--- .../web/config/WebClientConfigTest.java | 230 +++++++++- .../web/config/WizardsConfigElement.java | 399 ++++++++++++++++++ .../web/config/WizardsElementReader.java | 160 +++++++ .../component/property/UIPropertySheet.java | 12 +- .../test-config-dialogs-wizards.xml | 78 ++++ .../test-resources/test-config-override.xml | 16 + 9 files changed, 1224 insertions(+), 59 deletions(-) create mode 100644 source/java/org/alfresco/web/config/DialogsConfigElement.java create mode 100644 source/java/org/alfresco/web/config/DialogsElementReader.java create mode 100644 source/java/org/alfresco/web/config/WizardsConfigElement.java create mode 100644 source/java/org/alfresco/web/config/WizardsElementReader.java create mode 100644 source/test-resources/test-config-dialogs-wizards.xml diff --git a/source/java/org/alfresco/web/config/DialogsConfigElement.java b/source/java/org/alfresco/web/config/DialogsConfigElement.java new file mode 100644 index 0000000000..d680de604d --- /dev/null +++ b/source/java/org/alfresco/web/config/DialogsConfigElement.java @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.web.config; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import org.alfresco.config.ConfigElement; +import org.alfresco.config.ConfigException; +import org.alfresco.config.element.ConfigElementAdapter; +import org.alfresco.util.ParameterCheck; + +/** + * Custom config element that represents the config data for a property sheet + * + * @author gavinc + */ +public class DialogsConfigElement extends ConfigElementAdapter +{ + public static final String CONFIG_ELEMENT_ID = "dialogs"; + + private Map dialogs = new LinkedHashMap(8, 10f); + + /** + * Default constructor + */ + public DialogsConfigElement() + { + super(CONFIG_ELEMENT_ID); + } + + /** + * Constructor + * + * @param name Name of the element this config element represents + */ + public DialogsConfigElement(String name) + { + super(name); + } + + /** + * @see org.alfresco.config.ConfigElement#getChildren() + */ + public List getChildren() + { + throw new ConfigException("Reading the dialogs config via the generic interfaces is not supported"); + } + + /** + * @see org.alfresco.config.ConfigElement#combine(org.alfresco.config.ConfigElement) + */ + public ConfigElement combine(ConfigElement configElement) + { + DialogsConfigElement combined = new DialogsConfigElement(); + + // add all the dialogs from this element + for (DialogConfig dialog : this.getDialogs().values()) + { + combined.addDialog(dialog); + } + + // add all the dialogs from the given element + for (DialogConfig dialog : ((DialogsConfigElement)configElement).getDialogs().values()) + { + combined.addDialog(dialog); + } + + return combined; + } + + /** + * Adds a dialog + * + * @param dialogConfig A pre-configured dialog config object + */ + /*package*/ void addDialog(DialogConfig dialogConfig) + { + this.dialogs.put(dialogConfig.getName(), dialogConfig); + } + + /** + * Returns the named dialog + * + * @param name The name of the dialog to retrieve + * @return The DialogConfig object for the requested dialog or null if it doesn't exist + */ + public DialogConfig getDialog(String name) + { + return this.dialogs.get(name); + } + + /** + * @return Returns a map of the dialogs. A linked hash map is used internally to + * preserve ordering. + */ + public Map getDialogs() + { + return this.dialogs; + } + + /** + * Inner class representing the configuration of a single dialog + * + * @author gavinc + */ + public static class DialogConfig + { + protected String name; + protected String page; + protected String managedBean; + protected String title; + protected String titleId; + protected String description; + protected String descriptionId; + + public DialogConfig(String name, String page, String bean, + String title, String titleId, + String description, String descriptionId) + { + // check the mandatory parameters are present + ParameterCheck.mandatoryString("name", name); + ParameterCheck.mandatoryString("page", page); + ParameterCheck.mandatoryString("managedBean", bean); + + this.name = name; + this.page = page; + this.managedBean = bean; + this.title = title; + this.titleId = titleId; + this.description = description; + this.descriptionId = descriptionId; + } + + public String getDescription() + { + return this.description; + } + + public String getDescriptionId() + { + return this.descriptionId; + } + + public String getManagedBean() + { + return this.managedBean; + } + + public String getName() + { + return this.name; + } + + public String getPage() + { + return this.page; + } + + public String getTitle() + { + return this.title; + } + + public String getTitleId() + { + return this.titleId; + } + + /** + * @see java.lang.Object#toString() + */ + @Override + public String toString() + { + StringBuilder buffer = new StringBuilder(super.toString()); + buffer.append(" (name=").append(this.name); + buffer.append(" page=").append(this.page); + buffer.append(" managed-bean=").append(this.managedBean); + buffer.append(" title=").append(this.title); + buffer.append(" titleId=").append(this.titleId); + buffer.append(" description=").append(this.description); + buffer.append(" descriptionId=").append(this.descriptionId).append(")"); + return buffer.toString(); + } + } +} diff --git a/source/java/org/alfresco/web/config/DialogsElementReader.java b/source/java/org/alfresco/web/config/DialogsElementReader.java new file mode 100644 index 0000000000..1c44471121 --- /dev/null +++ b/source/java/org/alfresco/web/config/DialogsElementReader.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.web.config; + +import java.util.Iterator; + +import org.alfresco.config.ConfigElement; +import org.alfresco.config.ConfigException; +import org.alfresco.config.xml.elementreader.ConfigElementReader; +import org.dom4j.Element; + +/** + * Custom element reader to parse config for dialogs + * + * @author gavinc + */ +public class DialogsElementReader implements ConfigElementReader +{ + public static final String ELEMENT_DIALOGS = "dialogs"; + public static final String ELEMENT_DIALOG = "dialog"; + public static final String ATTR_NAME = "name"; + public static final String ATTR_PAGE = "page"; + public static final String ATTR_MANAGED_BEAN = "managed-bean"; + public static final String ATTR_TITLE = "title"; + public static final String ATTR_TITLE_ID = "title-id"; + public static final String ATTR_DESCRIPTION = "description"; + public static final String ATTR_DESCRIPTION_ID = "description-id"; + + /** + * @see org.alfresco.config.xml.elementreader.ConfigElementReader#parse(org.dom4j.Element) + */ + public ConfigElement parse(Element element) + { + DialogsConfigElement configElement = null; + + if (element != null) + { + String elementName = element.getName(); + if (elementName.equals(ELEMENT_DIALOGS) == false) + { + throw new ConfigException("DialogsElementReader can only parse " + + ELEMENT_DIALOGS + "elements, the element passed was '" + + elementName + "'"); + } + + configElement = new DialogsConfigElement(); + + // go through the items to show + Iterator items = element.elementIterator(ELEMENT_DIALOG); + while (items.hasNext()) + { + Element item = items.next(); + + String name = item.attributeValue(ATTR_NAME); + String page = item.attributeValue(ATTR_PAGE); + String bean = item.attributeValue(ATTR_MANAGED_BEAN); + String title = item.attributeValue(ATTR_TITLE); + String titleId = item.attributeValue(ATTR_TITLE_ID); + String description = item.attributeValue(ATTR_DESCRIPTION); + String descriptionId = item.attributeValue(ATTR_DESCRIPTION_ID); + + DialogsConfigElement.DialogConfig cfg = new DialogsConfigElement.DialogConfig( + name, page, bean, title, titleId, description, descriptionId); + + configElement.addDialog(cfg); + } + } + + return configElement; + } + +} diff --git a/source/java/org/alfresco/web/config/PropertySheetConfigElement.java b/source/java/org/alfresco/web/config/PropertySheetConfigElement.java index 3ac1350637..d0b4b612c7 100644 --- a/source/java/org/alfresco/web/config/PropertySheetConfigElement.java +++ b/source/java/org/alfresco/web/config/PropertySheetConfigElement.java @@ -17,8 +17,7 @@ package org.alfresco.web.config; import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -36,12 +35,18 @@ public class PropertySheetConfigElement extends ConfigElementAdapter // TODO: Currently this object just deals with properties and associations to show, // in the future it will also deal with properties and associations to hide. - private List items = new ArrayList(); - private List editableItems = new ArrayList(); - private Map itemsMap = new HashMap(); - private Map editableItemsMap = new HashMap(); - private List itemNames = new ArrayList(); - private List editableItemNames = new ArrayList(); + public static final String CONFIG_ELEMENT_ID = "property-sheet"; + + protected Map items = new LinkedHashMap(8, 10f); + protected Map editableItems = new LinkedHashMap(8, 10f); + + + //private List items = new ArrayList(); + //private List editableItems = new ArrayList(); + //private Map itemsMap = new HashMap(); + //private Map editableItemsMap = new HashMap(); + //private List itemNames = new ArrayList(); + //private List editableItemNames = new ArrayList(); private boolean kidsPopulated = false; /** @@ -49,7 +54,7 @@ public class PropertySheetConfigElement extends ConfigElementAdapter */ public PropertySheetConfigElement() { - super("property-sheet"); + super(CONFIG_ELEMENT_ID); } /** @@ -76,10 +81,8 @@ public class PropertySheetConfigElement extends ConfigElementAdapter { if (this.kidsPopulated == false) { - Iterator items = this.items.iterator(); - while (items.hasNext()) + for (ItemConfig pc : this.items.values()) { - ItemConfig pc = items.next(); GenericConfigElement ce = null; if (pc instanceof PropertyConfig) { @@ -120,17 +123,15 @@ public class PropertySheetConfigElement extends ConfigElementAdapter PropertySheetConfigElement combined = new PropertySheetConfigElement(); // add all the existing properties - Iterator items = this.getItemsToShow().iterator(); - while (items.hasNext()) + for (ItemConfig item : this.getItemsToShow().values()) { - combined.addItem(items.next()); + combined.addItem(item); } // add all the properties from the given element - items = ((PropertySheetConfigElement)configElement).getItemsToShow().iterator(); - while (items.hasNext()) + for (ItemConfig item : ((PropertySheetConfigElement)configElement).getItemsToShow().values()) { - combined.addItem(items.next()); + combined.addItem(item); } return combined; @@ -143,18 +144,19 @@ public class PropertySheetConfigElement extends ConfigElementAdapter */ /*package*/ void addItem(ItemConfig itemConfig) { - if (this.itemsMap.containsKey(itemConfig.getName()) == false) + this.items.put(itemConfig.getName(), itemConfig); + + // remove the item from the map if it is no longer editable + if (itemConfig.isShownInEditMode()) { - this.items.add(itemConfig); - this.itemsMap.put(itemConfig.getName(), itemConfig); - this.itemNames.add(itemConfig.getName()); - - // also add to the edit items collections if necessary - if (itemConfig.isShownInEditMode()) + this.editableItems.put(itemConfig.getName(), itemConfig); + } + else + { + // if the item was added previously as editable it should be removed + if (editableItems.containsKey(itemConfig.getName())) { - this.editableItems.add(itemConfig); - this.editableItemsMap.put(itemConfig.getName(), itemConfig); - this.editableItemNames.add(itemConfig.getName()); + this.editableItems.remove(itemConfig.getName()); } } } @@ -216,23 +218,22 @@ public class PropertySheetConfigElement extends ConfigElementAdapter */ public List getItemNamesToShow() { - return this.itemNames; - } - - /** - * @return Returns the list of item config objects that represent those to display - */ - public List getItemsToShow() - { - return this.items; + List propNames = new ArrayList(this.items.size()); + + for (String name : this.items.keySet()) + { + propNames.add(name); + } + + return propNames; } /** * @return Returns a map of the item names to show */ - public Map getItemsMapToShow() + public Map getItemsToShow() { - return this.itemsMap; + return this.items; } /** @@ -240,23 +241,22 @@ public class PropertySheetConfigElement extends ConfigElementAdapter */ public List getEditableItemNamesToShow() { - return this.editableItemNames; - } - - /** - * @return Returns the list of item config objects that represent those to display - */ - public List getEditableItemsToShow() - { - return this.editableItems; + List propNames = new ArrayList(this.editableItems.size()); + + for (String name : this.editableItems.keySet()) + { + propNames.add(name); + } + + return propNames; } /** * @return Returns a map of the item names to show */ - public Map getEditableItemsMapToShow() + public Map getEditableItemsToShow() { - return this.editableItemsMap; + return this.editableItems; } /** diff --git a/source/java/org/alfresco/web/config/WebClientConfigTest.java b/source/java/org/alfresco/web/config/WebClientConfigTest.java index e4b86a5d18..f3beaf3e01 100644 --- a/source/java/org/alfresco/web/config/WebClientConfigTest.java +++ b/source/java/org/alfresco/web/config/WebClientConfigTest.java @@ -17,6 +17,7 @@ package org.alfresco.web.config; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.Map; @@ -27,7 +28,12 @@ import org.alfresco.config.source.FileConfigSource; import org.alfresco.config.xml.XMLConfigService; import org.alfresco.util.BaseTest; import org.alfresco.web.config.AdvancedSearchConfigElement.CustomProperty; +import org.alfresco.web.config.DialogsConfigElement.DialogConfig; import org.alfresco.web.config.PropertySheetConfigElement.ItemConfig; +import org.alfresco.web.config.WizardsConfigElement.ConditionalPageConfig; +import org.alfresco.web.config.WizardsConfigElement.PageConfig; +import org.alfresco.web.config.WizardsConfigElement.StepConfig; +import org.alfresco.web.config.WizardsConfigElement.WizardConfig; /** * JUnit tests to exercise the capabilities added to the web client config @@ -79,7 +85,7 @@ public class WebClientConfigTest extends BaseTest assertTrue("There should be 6 properties in the list", propNames.size() == 6); // make sure the property sheet config has come back with the correct data - Map props = spacePropConfig.getItemsMapToShow(); + Map props = spacePropConfig.getItemsToShow(); ItemConfig descProp = props.get("description"); assertNotNull("description property config should not be null", descProp); assertEquals("display label for description should be 'Description'", descProp.getDisplayLabel(), @@ -186,7 +192,7 @@ public class WebClientConfigTest extends BaseTest assertEquals("third property name", "icon", itemNamesToEdit.get(2)); // make sure the map has the correct number of items - Map itemsToEditMap = propSheet.getEditableItemsMapToShow(); + Map itemsToEditMap = propSheet.getEditableItemsToShow(); assertNotNull("itemsToEditMap should not be null", itemsToEditMap); assertEquals("Number of properties", 3, itemsToEditMap.size()); @@ -200,11 +206,45 @@ public class WebClientConfigTest extends BaseTest assertNull("size should be null", item); // make sure the list has the correct numbe of items - List itemsToEdit = propSheet.getEditableItemsToShow(); + Collection itemsToEdit = propSheet.getEditableItemsToShow().values(); assertNotNull("itemsToEdit should not be null", itemsToEdit); assertEquals("Number of properties", 3, itemsToEdit.size()); } + public void testPropertyOverride() + { + // setup the config service + List configFiles = new ArrayList(2); + configFiles.add(getResourcesDir() + "test-config.xml"); + configFiles.add(getResourcesDir() + "test-config-override.xml"); + XMLConfigService svc = new XMLConfigService(new FileConfigSource(configFiles)); + svc.init(); + + // get the config for the size property in the space-aspect property sheet + PropertySheetConfigElement propSheet = ((PropertySheetConfigElement)svc.getConfig("space-aspect"). + getConfigElement(PropertySheetConfigElement.CONFIG_ELEMENT_ID)); + assertNotNull("propSheet should not be null", propSheet); + + // make sure the list and map numbers are correct + assertEquals("prop names to show size", 6, propSheet.getItemNamesToShow().size()); + assertEquals("props to show size", 6, propSheet.getItemsToShow().size()); + assertEquals("edit prop names to show size", 5, propSheet.getEditableItemNamesToShow().size()); + assertEquals("edit props to show size", 5, propSheet.getEditableItemsToShow().size()); + + PropertySheetConfigElement.PropertyConfig propConfig = + (PropertySheetConfigElement.PropertyConfig)propSheet.getItemsToShow().get("size"); + assertNotNull("propConfig should not be null", propConfig); + + // make sure config has been overridden + assertTrue("size should be shown in edit mode", propConfig.isShownInEditMode()); + assertTrue("size property should be read only", propConfig.isReadOnly()); + assertNotNull("size property should be in edit map", propSheet.getEditableItemsToShow().get("size")); + + // get the icon + propConfig = (PropertySheetConfigElement.PropertyConfig)propSheet.getItemsToShow().get("icon"); + assertNotNull("propConfig should not be null", propConfig); + } + /** * Tests the custom client configuration objects */ @@ -542,4 +582,188 @@ public class WebClientConfigTest extends BaseTest // expected } } + + public void testDialogs() + { + // setup the config service + String configFiles = getResourcesDir() + "test-config-dialogs-wizards.xml"; + XMLConfigService svc = new XMLConfigService(new FileConfigSource(configFiles)); + svc.init(); + + // get Dialogs config section + Config dialogsConfig = svc.getConfig("Dialogs"); + assertNotNull("dialogsConfig should not be null", dialogsConfig); + + // make sure the dialog-container is correct + assertEquals("dialog container", "/jsp/dialog/container.jsp", + dialogsConfig.getConfigElement("dialog-container").getValue()); + + // make sure a non existent dialog returns null + assertNull("non existent dialog test should return null", + dialogsConfig.getConfigElement("Non Existent Dialog")); + + // get the dialogs element + DialogsConfigElement dialogsElement = (DialogsConfigElement)dialogsConfig. + getConfigElement(DialogsConfigElement.CONFIG_ELEMENT_ID); + assertNotNull("dialogsElement should not be null", dialogsElement); + + // make sure there are 2 items in the list and map + assertEquals("map size", 2, dialogsElement.getDialogs().size()); + + // get the 'createSpace' dialog + DialogConfig dialog = dialogsElement.getDialog("createSpace"); + assertNotNull("createSpace dialog config should not be null", dialog); + + // make sure the info on the dialog is correct + assertEquals("name", "createSpace", dialog.getName()); + assertEquals("page", "/jsp/dialog/create-space.jsp", dialog.getPage()); + assertEquals("managed-bean", "NewSpaceDialog", dialog.getManagedBean()); + assertEquals("title-id", "create_space_title", dialog.getTitleId()); + assertEquals("description-id", "create_space_description", dialog.getDescriptionId()); + assertNull("title should be null", dialog.getTitle()); + assertNull("description should be null", dialog.getDescription()); + + // get the 'spaceDetails' dialog + dialog = dialogsElement.getDialog("spaceDetails"); + assertNotNull("spaceDetails dialog config should not be null", dialog); + + // make sure the info on the dialog is correct + assertEquals("name", "spaceDetails", dialog.getName()); + assertEquals("page", "/jsp/dialog/space-details.jsp", dialog.getPage()); + assertEquals("managed-bean", "SpaceDetailsDialog", dialog.getManagedBean()); + assertEquals("title", "Space Details Dialog", dialog.getTitle()); + assertEquals("description", "Space Details Dialog Decsription", dialog.getDescription()); + assertNull("title-id should be null", dialog.getTitleId()); + assertNull("description-id should be null", dialog.getDescriptionId()); + } + + public void testDialogOverride() + { + // setup the config service + List configFiles = new ArrayList(2); + configFiles.add(getResourcesDir() + "test-config-dialogs-wizards.xml"); + configFiles.add(getResourcesDir() + "test-config-override.xml"); + XMLConfigService svc = new XMLConfigService(new FileConfigSource(configFiles)); + svc.init(); + + // get the 'dialogs' element + DialogsConfigElement dialogsElement = ((DialogsConfigElement)svc.getConfig("Dialogs"). + getConfigElement(DialogsConfigElement.CONFIG_ELEMENT_ID)); + + // make sure there are 2 items in the list and map + assertEquals("map size", 2, dialogsElement.getDialogs().size()); + + // get the 'createSpace' dialog + DialogConfig dialog = dialogsElement.getDialog("createSpace"); + assertNotNull("createSpace dialog should not be null", dialog); + + // make sure the page and managed bean attributes have been overridden + assertEquals("page", "/custom/my-create-space.jsp", dialog.getPage()); + assertEquals("managed-bean", "MyNewSpaceDialog", dialog.getManagedBean()); + assertEquals("title-id", "create_space_title", dialog.getTitleId()); + assertEquals("description-id", "create_space_description", dialog.getDescriptionId()); + } + + public void testWizards() + { + // setup the config service + String configFiles = getResourcesDir() + "test-config-dialogs-wizards.xml"; + XMLConfigService svc = new XMLConfigService(new FileConfigSource(configFiles)); + svc.init(); + + // get Dialogs config section + Config wizardsConfig = svc.getConfig("Wizards"); + assertNotNull("wizardsConfig should not be null", wizardsConfig); + + // make sure the wizard-container is correct + assertEquals("wizard container", "/jsp/wizard/container.jsp", + wizardsConfig.getConfigElement("wizard-container").getValue()); + + // make sure a non existent wizard returns null + assertNull("non existent wizard should not be null", + wizardsConfig.getConfigElement("Non Existent Wizard")); + + // get the wizards element + WizardsConfigElement wizardsElement = (WizardsConfigElement)wizardsConfig. + getConfigElement(WizardsConfigElement.CONFIG_ELEMENT_ID); + assertNotNull("wizardsElement should not be null", wizardsElement); + + // make sure there are 2 items in the map + assertEquals("map size", 2, wizardsElement.getWizards().size()); + + // get the 'exampleWizard' wizard + WizardConfig wizard = wizardsElement.getWizard("exampleWizard"); + assertNotNull("exampleWizard wizard should not be null", wizard); + + // make sure data is correct + assertEquals("name", "exampleWizard", wizard.getName()); + assertEquals("exampleWizard steps", 2, wizard.getNumberSteps()); + assertEquals("managed-bean", "ExampleWizard", wizard.getManagedBean()); + assertEquals("title", "Example Wizard Title", wizard.getTitle()); + assertEquals("description", "Example Wizard Description", wizard.getDescription()); + assertNull("title-id should be null", wizard.getTitleId()); + assertNull("description-id should be null", wizard.getDescriptionId()); + + // get the 'createSpace' wizard and ensure all the data is correct + wizard = wizardsElement.getWizard("createSpace"); + assertEquals("name", "createSpace", wizard.getName()); + assertEquals("createSpace steps", 3, wizard.getNumberSteps()); + assertEquals("managed-bean", "AdvancedSpaceWizard", wizard.getManagedBean()); + assertEquals("title-id", "advanced_space_details_title", wizard.getTitleId()); + assertEquals("description-id", "advanced_space_details_description", wizard.getDescriptionId()); + assertNull("title should be null", wizard.getTitle()); + assertNull("description should be null", wizard.getDescription()); + List steps = wizard.getSteps(); + assertNotNull("steps should not be null", steps); + + // retrieve step1 information and check it is correct + StepConfig step1 = steps.get(0); + assertEquals("step 1 name", "details", step1.getName()); + assertFalse("step 1 should not have conditional pages", step1.hasConditionalPages()); + PageConfig step1Page = step1.getDefaultPage(); + assertNotNull("step1Page should not be null", step1Page); + assertEquals("step 1 page", "/jsp/wizard/new-space/create-from.jsp", step1Page.getPath()); + assertEquals("step 1 title-id", "create_space_details_title", step1Page.getTitleId()); + assertEquals("step 1 description-id", "create_space_details_desc", step1Page.getDescriptionId()); + assertEquals("step 1 instruction-id", "create_space_details_instruction", step1Page.getInstructionId()); + assertNull("step 1 title should be null", step1Page.getTitle()); + assertNull("step 1 description should be null", step1Page.getDescription()); + + // check the conditional step2 data + StepConfig step2 = steps.get(1); + assertEquals("step 2 name", "properties", step2.getName()); + assertTrue("step 2 should have conditional pages", step2.hasConditionalPages()); + PageConfig step2DefaultPage = step2.getDefaultPage(); + assertNotNull("step 2 default page should not be null", step2DefaultPage); + assertEquals("step 2 default page", "/jsp/wizard/new-space/from-scratch.jsp", step2DefaultPage.getPath()); + assertEquals("step 2 default title-id", "create_space_scratch_title", step2DefaultPage.getTitleId()); + assertEquals("step 2 default description-id", "create_space_scratch_desc", step2DefaultPage.getDescriptionId()); + assertEquals("step 2 default instruction-id", "create_space_scratch_instruction", step2DefaultPage.getInstructionId()); + assertNull("step 2 default title should be null", step2DefaultPage.getTitle()); + assertNull("step 2 default description should be null", step2DefaultPage.getDescription()); + List conditionalPages = step2.getConditionalPages(); + assertEquals("number of conditional pages for step 2", 1, conditionalPages.size()); + ConditionalPageConfig step2CondPage = conditionalPages.get(0); + assertNotNull("step 2 cond page should not be null", step2CondPage); + assertEquals("step 2 conditon", "#{AdvancedSpaceWizard.createFrom == 'template'}", step2CondPage.getCondition()); + assertEquals("step 2 cond page", "/jsp/wizard/new-space/from-template.jsp", step2CondPage.getPath()); + assertEquals("step 2 cond title-id", "create_space_template_title", step2CondPage.getTitleId()); + assertEquals("step 2 cond description-id", "create_space_template_desc", step2CondPage.getDescriptionId()); + assertEquals("step 2 cond instruction-id", "create_space_template_instruction", step2CondPage.getInstructionId()); + assertNull("step 2 cond title should be null", step2CondPage.getTitle()); + assertNull("step 2 cond description should be null", step2CondPage.getDescription()); + + // check step 3 data + StepConfig step3 = steps.get(2); + assertEquals("step 3 name", "summary", step3.getName()); + assertFalse("step 3 should not have conditional pages", step3.hasConditionalPages()); + PageConfig step3Page = step3.getDefaultPage(); + assertNotNull("step3Page should not be null", step3Page); + assertEquals("step 3 page", "/jsp/wizard/new-space/summary.jsp", step3Page.getPath()); + assertEquals("step 3 title-id", "create_space_summary_title", step3Page.getTitleId()); + assertEquals("step 3 description-id", "create_space_summary_desc", step3Page.getDescriptionId()); + assertEquals("step 3 instruction-id", "create_space_summary_instruction", step3Page.getInstructionId()); + assertNull("step 3 title should be null", step3Page.getTitle()); + assertNull("step 3 description should be null", step3Page.getDescription()); + } } diff --git a/source/java/org/alfresco/web/config/WizardsConfigElement.java b/source/java/org/alfresco/web/config/WizardsConfigElement.java new file mode 100644 index 0000000000..bf7fb4fb70 --- /dev/null +++ b/source/java/org/alfresco/web/config/WizardsConfigElement.java @@ -0,0 +1,399 @@ +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.web.config; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import org.alfresco.config.ConfigElement; +import org.alfresco.config.ConfigException; +import org.alfresco.config.element.ConfigElementAdapter; +import org.alfresco.util.ParameterCheck; + +/** + * Custom config element that represents the config data for a property sheet + * + * @author gavinc + */ +public class WizardsConfigElement extends ConfigElementAdapter +{ + public static final String CONFIG_ELEMENT_ID = "wizards"; + + private Map wizards = new LinkedHashMap(8, 10f); + + /** + * Default constructor + */ + public WizardsConfigElement() + { + super(CONFIG_ELEMENT_ID); + } + + /** + * Constructor + * + * @param name Name of the element this config element represents + */ + public WizardsConfigElement(String name) + { + super(name); + } + + /** + * @see org.alfresco.config.ConfigElement#getChildren() + */ + public List getChildren() + { + throw new ConfigException("Reading the wizards config via the generic interfaces is not supported"); + } + + /** + * @see org.alfresco.config.ConfigElement#combine(org.alfresco.config.ConfigElement) + */ + public ConfigElement combine(ConfigElement configElement) + { + WizardsConfigElement combined = new WizardsConfigElement(); + + // add all the wizards from this element + for (WizardConfig wizard : this.getWizards().values()) + { + combined.addWizard(wizard); + } + + // add all the wizards from the given element + for (WizardConfig wizard : ((WizardsConfigElement)configElement).getWizards().values()) + { + combined.addWizard(wizard); + } + + return combined; + } + + /** + * Adds a wizard + * + * @param wizardConfig A pre-configured wizard config object + */ + /*package*/ void addWizard(WizardConfig wizardConfig) + { + this.wizards.put(wizardConfig.getName(), wizardConfig); + } + + /** + * Returns the named wizard + * + * @param name The name of the wizard to retrieve + * @return The WizardConfig object for the requested wizard or null if it doesn't exist + */ + public WizardConfig getWizard(String name) + { + return this.wizards.get(name); + } + + /** + * @return Returns a map of the wizards + */ + public Map getWizards() + { + return this.wizards; + } + + public abstract static class AbstractConfig + { + protected String title; + protected String titleId; + protected String description; + protected String descriptionId; + + public AbstractConfig(String title, String titleId, + String description, String descriptionId) + { + this.title = title; + this.titleId = titleId; + this.description = description; + this.descriptionId = descriptionId; + } + + public String getDescription() + { + return this.description; + } + + public String getDescriptionId() + { + return this.descriptionId; + } + + public String getTitle() + { + return this.title; + } + + public String getTitleId() + { + return this.titleId; + } + } + + /** + * Represents the configuration of a single wizard i.e. the <wizard> element + */ + public static class WizardConfig extends AbstractConfig + { + protected String name; + protected String managedBean; + protected List steps = new ArrayList(4); + + public WizardConfig(String name, String bean, + String title, String titleId, + String description, String descriptionId) + { + super(title, titleId, description, descriptionId); + + // check we have a name + ParameterCheck.mandatoryString("name", name); + + this.name = name; + this.managedBean = bean; + } + + public String getName() + { + return this.name; + } + + public String getManagedBean() + { + return this.managedBean; + } + + public void addStep(StepConfig step) + { + this.steps.add(step); + } + + public int getNumberSteps() + { + return this.steps.size(); + } + + public List getSteps() + { + return this.steps; + } + + public StepConfig getStepByName(String name) + { + StepConfig step = null; + + for (StepConfig currentStep : this.steps) + { + if (currentStep.getName().equals(name)) + { + step = currentStep; + break; + } + } + + return step; + } + + /** + * @see java.lang.Object#toString() + */ + @Override + public String toString() + { + StringBuilder buffer = new StringBuilder(super.toString()); + buffer.append(" (name=").append(this.name); + buffer.append(" managed-bean=").append(this.managedBean); + buffer.append(" title=").append(this.title); + buffer.append(" titleId=").append(this.titleId); + buffer.append(" description=").append(this.description); + buffer.append(" descriptionId=").append(this.descriptionId).append(")"); + return buffer.toString(); + } + } + + /** + * Represents the configuration of a page in a wizard i.e. the <page> element + */ + public static class PageConfig extends AbstractConfig + { + protected String path; + protected String instruction; + protected String instructionId; + + public PageConfig(String path, + String title, String titleId, + String description, String descriptionId, + String instruction, String instructionId) + { + super(title, titleId, description, descriptionId); + + // check we have a path + ParameterCheck.mandatoryString("path", path); + + this.path = path; + this.instruction = instruction; + this.instructionId = instructionId; + } + + public String getPath() + { + return this.path; + } + + public String getInstruction() + { + return this.instruction; + } + + public String getInstructionId() + { + return this.instructionId; + } + + /** + * @see java.lang.Object#toString() + */ + @Override + public String toString() + { + StringBuilder buffer = new StringBuilder(super.toString()); + buffer.append(" (path=").append(this.path); + buffer.append(" title=").append(this.title); + buffer.append(" titleId=").append(this.titleId); + buffer.append(" description=").append(this.description); + buffer.append(" descriptionId=").append(this.descriptionId); + buffer.append(" instruction=").append(this.instruction); + buffer.append(" instructionId=").append(this.instructionId).append(")"); + return buffer.toString(); + } + } + + /** + * Represents the configuration of a conditional page in a wizard + * i.e. a <page> element that is placed within a <condition> + * element. + */ + public static class ConditionalPageConfig extends PageConfig + { + protected String condition; + + public ConditionalPageConfig(String path, String condition, + String title, String titleId, + String description, String descriptionId, + String instruction, String instructionId) + { + super(path, title, titleId, description, descriptionId, instruction, instructionId); + + // check we have a path + ParameterCheck.mandatoryString("condition", condition); + + this.condition = condition; + } + + public String getCondition() + { + return this.condition; + } + + /** + * @see java.lang.Object#toString() + */ + @Override + public String toString() + { + StringBuilder buffer = new StringBuilder(super.toString()); + buffer.append(" (path=").append(this.path); + buffer.append(" condition=").append(this.condition); + buffer.append(" title=").append(this.title); + buffer.append(" titleId=").append(this.titleId); + buffer.append(" description=").append(this.description); + buffer.append(" descriptionId=").append(this.descriptionId); + buffer.append(" instruction=").append(this.instruction); + buffer.append(" instructionId=").append(this.instructionId).append(")"); + return buffer.toString(); + } + } + + /** + * Represents the configuration of a step in a wizard + * i.e. the <step> element. + */ + public static class StepConfig + { + protected String name; + protected PageConfig defaultPage; + protected List conditionalPages = + new ArrayList(3); + + public StepConfig(String name) + { + // check we have a name + ParameterCheck.mandatoryString("name", name); + + this.name = name; + } + + public String getName() + { + return this.name; + } + + public void setDefaultPage(PageConfig page) + { + this.defaultPage = page; + } + + public PageConfig getDefaultPage() + { + return this.defaultPage; + } + + public boolean hasConditionalPages() + { + return (this.conditionalPages.size() > 0); + } + + public void addConditionalPage(ConditionalPageConfig conditionalPage) + { + this.conditionalPages.add(conditionalPage); + } + + public List getConditionalPages() + { + return this.conditionalPages; + } + + /** + * @see java.lang.Object#toString() + */ + @Override + public String toString() + { + StringBuilder buffer = new StringBuilder(super.toString()); + buffer.append(" (name=").append(this.name); + buffer.append(" defaultPage=").append(this.defaultPage); + buffer.append(" conditionalPages=").append(this.conditionalPages).append(")"); + return buffer.toString(); + } + } +} diff --git a/source/java/org/alfresco/web/config/WizardsElementReader.java b/source/java/org/alfresco/web/config/WizardsElementReader.java new file mode 100644 index 0000000000..48316f2dfa --- /dev/null +++ b/source/java/org/alfresco/web/config/WizardsElementReader.java @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2005 Alfresco, Inc. + * + * Licensed under the Mozilla Public License version 1.1 + * with a permitted attribution clause. You may obtain a + * copy of the License at + * + * http://www.alfresco.org/legal/license.txt + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific + * language governing permissions and limitations under the + * License. + */ +package org.alfresco.web.config; + +import java.util.Iterator; + +import org.alfresco.config.ConfigElement; +import org.alfresco.config.ConfigException; +import org.alfresco.config.xml.elementreader.ConfigElementReader; +import org.alfresco.web.config.WizardsConfigElement.ConditionalPageConfig; +import org.alfresco.web.config.WizardsConfigElement.PageConfig; +import org.alfresco.web.config.WizardsConfigElement.StepConfig; +import org.dom4j.Element; + +/** + * Custom element reader to parse config for wizards + * + * @author gavinc + */ +public class WizardsElementReader implements ConfigElementReader +{ + public static final String ELEMENT_WIZARDS = "wizards"; + public static final String ELEMENT_WIZARD = "wizard"; + public static final String ELEMENT_STEP = "step"; + public static final String ELEMENT_PAGE = "page"; + public static final String ELEMENT_CONDITION = "condition"; + + public static final String ATTR_NAME = "name"; + public static final String ATTR_MANAGED_BEAN = "managed-bean"; + public static final String ATTR_TITLE = "title"; + public static final String ATTR_TITLE_ID = "title-id"; + public static final String ATTR_DESCRIPTION = "description"; + public static final String ATTR_DESCRIPTION_ID = "description-id"; + public static final String ATTR_INSTRUCTION = "instruction"; + public static final String ATTR_INSTRUCTION_ID = "instruction-id"; + public static final String ATTR_IF = "if"; + public static final String ATTR_PATH = "path"; + + /** + * @see org.alfresco.config.xml.elementreader.ConfigElementReader#parse(org.dom4j.Element) + */ + public ConfigElement parse(Element element) + { + WizardsConfigElement configElement = null; + + if (element != null) + { + String elementName = element.getName(); + if (elementName.equals(ELEMENT_WIZARDS) == false) + { + throw new ConfigException("WizardsElementReader can only parse " + + ELEMENT_WIZARDS + "elements, the element passed was '" + + elementName + "'"); + } + + configElement = new WizardsConfigElement(); + + // go through the items to show + Iterator items = element.elementIterator(ELEMENT_WIZARD); + while (items.hasNext()) + { + Element wizard = items.next(); + + String name = wizard.attributeValue(ATTR_NAME); + String bean = wizard.attributeValue(ATTR_MANAGED_BEAN); + String title = wizard.attributeValue(ATTR_TITLE); + String titleId = wizard.attributeValue(ATTR_TITLE_ID); + String description = wizard.attributeValue(ATTR_DESCRIPTION); + String descriptionId = wizard.attributeValue(ATTR_DESCRIPTION_ID); + + // create the wizard config object + WizardsConfigElement.WizardConfig wizardCfg = new WizardsConfigElement.WizardConfig( + name, bean, title, titleId, description, descriptionId); + + Iterator steps = wizard.elementIterator(ELEMENT_STEP); + while (steps.hasNext()) + { + StepConfig stepCfg = parseStep(steps.next()); + wizardCfg.addStep(stepCfg); + } + + configElement.addWizard(wizardCfg); + } + } + + return configElement; + } + + /** + * Parses the given element which represents a step in a wizard + * + * @param step The Element representing the step + * @return A StepConfig object + */ + protected StepConfig parseStep(Element step) + { + // get the name of the step and create the config object + StepConfig stepCfg = new StepConfig(step.attributeValue(ATTR_NAME)); + + // find and parse the default page + Element defaultPageElem = step.element(ELEMENT_PAGE); + if (defaultPageElem != null) + { + String path = defaultPageElem.attributeValue(ATTR_PATH); + String title = defaultPageElem.attributeValue(ATTR_TITLE); + String titleId = defaultPageElem.attributeValue(ATTR_TITLE_ID); + String description = defaultPageElem.attributeValue(ATTR_DESCRIPTION); + String descriptionId = defaultPageElem.attributeValue(ATTR_DESCRIPTION_ID); + String instruction = defaultPageElem.attributeValue(ATTR_INSTRUCTION); + String instructionId = defaultPageElem.attributeValue(ATTR_INSTRUCTION_ID); + + // create and set the page config on the step + stepCfg.setDefaultPage(new PageConfig(path, title, titleId, description, + descriptionId, instruction, instructionId)); + } + + // find and parse any conditions that are present + Iterator conditions = step.elementIterator(ELEMENT_CONDITION); + while (conditions.hasNext()) + { + Element conditionElem = conditions.next(); + + String ifAttr = conditionElem.attributeValue(ATTR_IF); + Element conditionalPageElem = conditionElem.element(ELEMENT_PAGE); + if (conditionalPageElem == null) + { + throw new ConfigException("A condition in step '" + stepCfg.getName() + + "' does not have a containing element"); + } + + String path = conditionalPageElem.attributeValue(ATTR_PATH); + String title = conditionalPageElem.attributeValue(ATTR_TITLE); + String titleId = conditionalPageElem.attributeValue(ATTR_TITLE_ID); + String description = conditionalPageElem.attributeValue(ATTR_DESCRIPTION); + String descriptionId = conditionalPageElem.attributeValue(ATTR_DESCRIPTION_ID); + String instruction = conditionalPageElem.attributeValue(ATTR_INSTRUCTION); + String instructionId = conditionalPageElem.attributeValue(ATTR_INSTRUCTION_ID); + + // create and add the page to the step + stepCfg.addConditionalPage(new ConditionalPageConfig(path, ifAttr, title, + titleId, description, descriptionId, instruction, instructionId)); + } + + return stepCfg; + } +} diff --git a/source/java/org/alfresco/web/ui/repo/component/property/UIPropertySheet.java b/source/java/org/alfresco/web/ui/repo/component/property/UIPropertySheet.java index b4c92dfcb4..a2c2381195 100644 --- a/source/java/org/alfresco/web/ui/repo/component/property/UIPropertySheet.java +++ b/source/java/org/alfresco/web/ui/repo/component/property/UIPropertySheet.java @@ -17,8 +17,8 @@ package org.alfresco.web.ui.repo.component.property; import java.io.IOException; +import java.util.Collection; import java.util.Iterator; -import java.util.List; import java.util.Map; import javax.faces.component.NamingContainer; @@ -120,18 +120,18 @@ public class UIPropertySheet extends UIPanel implements NamingContainer if (itemsToDisplay != null) { - List itemsToRender = null; + Collection itemsToRender = null; if (this.getMode().equalsIgnoreCase(EDIT_MODE)) { - itemsToRender = itemsToDisplay.getEditableItemsToShow(); + itemsToRender = itemsToDisplay.getEditableItemsToShow().values(); if (logger.isDebugEnabled()) logger.debug("Items to render: " + itemsToDisplay.getEditableItemNamesToShow()); } else { - itemsToRender = itemsToDisplay.getItemsToShow(); + itemsToRender = itemsToDisplay.getItemsToShow().values(); if (logger.isDebugEnabled()) logger.debug("Items to render: " + itemsToDisplay.getItemNamesToShow()); @@ -439,10 +439,10 @@ public class UIPropertySheet extends UIPanel implements NamingContainer * in an external config file. * * @param context JSF context - * @param properties List of properties to render (driven from configuration) + * @param properties Collection of properties to render (driven from configuration) * @throws IOException */ - private void createComponentsFromConfig(FacesContext context, List items) + private void createComponentsFromConfig(FacesContext context, Collection items) throws IOException { // ********************************** diff --git a/source/test-resources/test-config-dialogs-wizards.xml b/source/test-resources/test-config-dialogs-wizards.xml new file mode 100644 index 0000000000..dc181401e7 --- /dev/null +++ b/source/test-resources/test-config-dialogs-wizards.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + /jsp/dialog/container.jsp + + + + + + + + + + + /jsp/wizard/container.jsp + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/source/test-resources/test-config-override.xml b/source/test-resources/test-config-override.xml index b7b438e528..740619d92d 100644 --- a/source/test-resources/test-config-override.xml +++ b/source/test-resources/test-config-override.xml @@ -76,4 +76,20 @@ + + + + + + + + + /custom/my-container.jsp + + + + + + \ No newline at end of file