You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ofbiz.apache.org by ad...@apache.org on 2015/01/18 22:03:42 UTC

svn commit: r1652852 [9/22] - in /ofbiz/trunk: applications/content/src/org/ofbiz/content/cms/ applications/content/src/org/ofbiz/content/content/ applications/content/src/org/ofbiz/content/data/ applications/content/src/org/ofbiz/content/output/ appli...

Added: ofbiz/trunk/framework/widget/src/org/ofbiz/widget/model/ModelMenuItem.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/widget/src/org/ofbiz/widget/model/ModelMenuItem.java?rev=1652852&view=auto
==============================================================================
--- ofbiz/trunk/framework/widget/src/org/ofbiz/widget/model/ModelMenuItem.java (added)
+++ ofbiz/trunk/framework/widget/src/org/ofbiz/widget/model/ModelMenuItem.java Sun Jan 18 21:03:40 2015
@@ -0,0 +1,669 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.ofbiz.widget.model;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import org.ofbiz.base.util.Debug;
+import org.ofbiz.base.util.UtilValidate;
+import org.ofbiz.base.util.UtilXml;
+import org.ofbiz.base.util.string.FlexibleStringExpander;
+import org.ofbiz.entity.GenericValue;
+import org.ofbiz.widget.model.CommonWidgetModels.AutoEntityParameters;
+import org.ofbiz.widget.model.CommonWidgetModels.AutoServiceParameters;
+import org.ofbiz.widget.model.CommonWidgetModels.Image;
+import org.ofbiz.widget.model.CommonWidgetModels.Link;
+import org.ofbiz.widget.model.CommonWidgetModels.Parameter;
+import org.ofbiz.widget.portal.PortalPageWorker;
+import org.ofbiz.widget.renderer.MenuStringRenderer;
+import org.w3c.dom.Element;
+
+/**
+ * Models the <menu-item> element.
+ * 
+ * @see <code>widget-menu.xsd</code>
+ */
+@SuppressWarnings("serial")
+public class ModelMenuItem extends ModelWidget {
+
+    /*
+     * ----------------------------------------------------------------------- *
+     *                     DEVELOPERS PLEASE READ
+     * ----------------------------------------------------------------------- *
+     * 
+     * This model is intended to be a read-only data structure that represents
+     * an XML element. Outside of object construction, the class should not
+     * have any behaviors.
+     * 
+     * Instances of this class will be shared by multiple threads - therefore
+     * it is immutable. DO NOT CHANGE THE OBJECT'S STATE AT RUN TIME!
+     * 
+     */
+
+    public static final String module = ModelMenuItem.class.getName();
+
+    private final List<ModelAction> actions;
+    private final String align;
+    private final String alignStyle;
+    private final FlexibleStringExpander associatedContentId;
+    private final String cellWidth;
+    private final ModelMenuCondition condition;
+    private final String disabledTitleStyle;
+    private final String disableIfEmpty;
+    private final String entityName;
+    private final Boolean hideIfSelected;
+    private final MenuLink link;
+    private final List<ModelMenuItem> menuItemList;
+    private final ModelMenu modelMenu;
+    private final String overrideName;
+    private final ModelMenuItem parentMenuItem;
+    private final FlexibleStringExpander parentPortalPageId;
+    private final Integer position;
+    private final String selectedStyle;
+    private final String subMenu;
+    private final FlexibleStringExpander title;
+    private final String titleStyle;
+    private final FlexibleStringExpander tooltip;
+    private final String tooltipStyle;
+    private final String widgetStyle;
+
+    // ===== CONSTRUCTORS =====
+
+    public ModelMenuItem(Element menuItemElement, ModelMenu modelMenu) {
+        this(menuItemElement, modelMenu, null);
+    }
+
+    private ModelMenuItem(Element menuItemElement, ModelMenu modelMenu, ModelMenuItem parentMenuItem) {
+        super(menuItemElement);
+        this.modelMenu = modelMenu;
+        this.parentMenuItem = parentMenuItem;
+        this.entityName = menuItemElement.getAttribute("entity-name");
+        this.title = FlexibleStringExpander.getInstance(menuItemElement.getAttribute("title"));
+        this.tooltip = FlexibleStringExpander.getInstance(menuItemElement.getAttribute("tooltip"));
+        this.parentPortalPageId = FlexibleStringExpander.getInstance(menuItemElement.getAttribute("parent-portal-page-value"));
+        this.titleStyle = menuItemElement.getAttribute("title-style");
+        this.disabledTitleStyle = menuItemElement.getAttribute("disabled-title-style");
+        this.widgetStyle = menuItemElement.getAttribute("widget-style");
+        this.tooltipStyle = menuItemElement.getAttribute("tooltip-style");
+        this.selectedStyle = menuItemElement.getAttribute("selected-style");
+        String hideIfSelected = menuItemElement.getAttribute("hide-if-selected");
+        if (!hideIfSelected.isEmpty())
+            if (hideIfSelected.equalsIgnoreCase("true"))
+                this.hideIfSelected = Boolean.TRUE;
+            else
+                this.hideIfSelected = Boolean.FALSE;
+        else
+            this.hideIfSelected = null;
+        this.disableIfEmpty = menuItemElement.getAttribute("disable-if-empty");
+        this.align = menuItemElement.getAttribute("align");
+        this.alignStyle = menuItemElement.getAttribute("align-style");
+        Integer position = null;
+        String positionStr = menuItemElement.getAttribute("position");
+        if (!positionStr.isEmpty()) {
+            try {
+                position = Integer.valueOf(positionStr);
+            } catch (Exception e) {
+                Debug.logError(e, "Could not convert position attribute of the field element to an integer: [" + positionStr
+                        + "], using the default of the menu renderer", module);
+                position = null;
+            }
+        }
+        this.position = position;
+        this.associatedContentId = FlexibleStringExpander.getInstance(menuItemElement.getAttribute("associated-content-id"));
+        this.cellWidth = menuItemElement.getAttribute("cell-width");
+        this.subMenu = menuItemElement.getAttribute("sub-menu");
+        Element linkElement = UtilXml.firstChildElement(menuItemElement, "link");
+        if (linkElement != null) {
+            this.link = new MenuLink(linkElement, this);
+        } else {
+            this.link = null;
+        }
+        // read in add item defs, add/override one by one using the menuItemList and menuItemMap
+        List<? extends Element> itemElements = UtilXml.childElementList(menuItemElement, "menu-item");
+        if (!itemElements.isEmpty()) {
+            ArrayList<ModelMenuItem> menuItemList = new ArrayList<ModelMenuItem>();
+            Map<String, ModelMenuItem> menuItemMap = new HashMap<String, ModelMenuItem>();
+            for (Element itemElement : itemElements) {
+                ModelMenuItem modelMenuItem = new ModelMenuItem(itemElement, modelMenu, this);
+                addUpdateMenuItem(modelMenuItem, menuItemList, menuItemMap);
+            }
+            menuItemList.trimToSize();
+            this.menuItemList = Collections.unmodifiableList(menuItemList);
+        } else {
+            this.menuItemList = Collections.emptyList();
+        }
+        // read condition under the "condition" element
+        Element conditionElement = UtilXml.firstChildElement(menuItemElement, "condition");
+        if (conditionElement != null) {
+            conditionElement = UtilXml.firstChildElement(conditionElement);
+            this.condition = new ModelMenuCondition(this, conditionElement);
+        } else {
+            this.condition = null;
+        }
+        // read all actions under the "actions" element
+        Element actionsElement = UtilXml.firstChildElement(conditionElement, "actions");
+        if (actionsElement != null) {
+            this.actions = AbstractModelAction.readSubActions(this, actionsElement);
+        } else {
+            this.actions = Collections.emptyList();
+        }
+        this.overrideName = "";
+    }
+
+    // Portal constructor
+    private ModelMenuItem(GenericValue portalPage, ModelMenuItem parentMenuItem, Locale locale) {
+        super(portalPage.getString("portalPageId"));
+        this.actions = Collections.emptyList();
+        this.align = "";
+        this.alignStyle = "";
+        this.associatedContentId = FlexibleStringExpander.getInstance("");
+        this.cellWidth = "";
+        this.condition = null;
+        this.disabledTitleStyle = "";
+        this.disableIfEmpty = "";
+        this.entityName = "";
+        this.hideIfSelected = null;
+        this.menuItemList = Collections.emptyList();
+        this.overrideName = "";
+        this.parentMenuItem = null;
+        this.parentPortalPageId = FlexibleStringExpander.getInstance(portalPage.getString("parentPortalPageId"));
+        this.position = null;
+        this.selectedStyle = "";
+        this.subMenu = "";
+        this.title = FlexibleStringExpander.getInstance((String) portalPage.get("portalPageName", locale));
+        this.titleStyle = "";
+        this.tooltip = FlexibleStringExpander.getInstance("");
+        this.tooltipStyle = "";
+        this.widgetStyle = "";
+        this.link = new MenuLink(portalPage, parentMenuItem, locale);
+        this.modelMenu = parentMenuItem.modelMenu;
+    }
+
+    // Merge constructor
+    private ModelMenuItem(ModelMenuItem existingMenuItem, ModelMenuItem overrideMenuItem) {
+        super(existingMenuItem.getName());
+        this.modelMenu = existingMenuItem.modelMenu;
+        if (UtilValidate.isNotEmpty(overrideMenuItem.getName())) {
+            this.overrideName = overrideMenuItem.getName();
+        } else {
+            this.overrideName = existingMenuItem.getName();
+        }
+        if (UtilValidate.isNotEmpty(overrideMenuItem.entityName)) {
+            this.entityName = overrideMenuItem.entityName;
+        } else {
+            this.entityName = existingMenuItem.entityName;
+        }
+        if (UtilValidate.isNotEmpty(overrideMenuItem.parentPortalPageId)) {
+            this.parentPortalPageId = overrideMenuItem.parentPortalPageId;
+        } else {
+            this.parentPortalPageId = existingMenuItem.parentPortalPageId;
+        }
+        if (UtilValidate.isNotEmpty(overrideMenuItem.title)) {
+            this.title = overrideMenuItem.title;
+        } else {
+            this.title = existingMenuItem.title;
+        }
+        if (UtilValidate.isNotEmpty(overrideMenuItem.tooltip)) {
+            this.tooltip = overrideMenuItem.tooltip;
+        } else {
+            this.tooltip = existingMenuItem.tooltip;
+        }
+        if (UtilValidate.isNotEmpty(overrideMenuItem.titleStyle)) {
+            this.titleStyle = overrideMenuItem.titleStyle;
+        } else {
+            this.titleStyle = existingMenuItem.titleStyle;
+        }
+        if (UtilValidate.isNotEmpty(overrideMenuItem.selectedStyle)) {
+            this.selectedStyle = overrideMenuItem.selectedStyle;
+        } else {
+            this.selectedStyle = existingMenuItem.selectedStyle;
+        }
+        if (UtilValidate.isNotEmpty(overrideMenuItem.widgetStyle)) {
+            this.widgetStyle = overrideMenuItem.widgetStyle;
+        } else {
+            this.widgetStyle = existingMenuItem.widgetStyle;
+        }
+        if (overrideMenuItem.position != null) {
+            this.position = overrideMenuItem.position;
+        } else {
+            this.position = existingMenuItem.position;
+        }
+        this.actions = existingMenuItem.actions;
+        this.align = existingMenuItem.align;
+        this.alignStyle = existingMenuItem.alignStyle;
+        this.associatedContentId = existingMenuItem.associatedContentId;
+        this.cellWidth = existingMenuItem.cellWidth;
+        this.condition = existingMenuItem.condition;
+        this.disabledTitleStyle = existingMenuItem.disabledTitleStyle;
+        this.disableIfEmpty = existingMenuItem.disableIfEmpty;
+        this.hideIfSelected = existingMenuItem.hideIfSelected;
+        this.menuItemList = existingMenuItem.menuItemList;
+        this.parentMenuItem = existingMenuItem.parentMenuItem;
+        this.subMenu = existingMenuItem.subMenu;
+        this.tooltipStyle = existingMenuItem.tooltipStyle;
+        this.link = existingMenuItem.link;
+    }
+
+    @Override
+    public void accept(ModelWidgetVisitor visitor) throws Exception {
+        visitor.visit(this);
+    }
+
+    private void addUpdateMenuItem(ModelMenuItem modelMenuItem, List<ModelMenuItem> menuItemList,
+            Map<String, ModelMenuItem> menuItemMap) {
+        ModelMenuItem existingMenuItem = menuItemMap.get(modelMenuItem.getName());
+        if (existingMenuItem != null) {
+            // does exist, update the item by doing a merge/override
+            ModelMenuItem mergedMenuItem = existingMenuItem.mergeOverrideModelMenuItem(modelMenuItem);
+            int existingItemIndex = menuItemList.indexOf(existingMenuItem);
+            menuItemList.set(existingItemIndex, mergedMenuItem);
+            menuItemMap.put(modelMenuItem.getName(), mergedMenuItem);
+        } else {
+            // does not exist, add to List and Map
+            menuItemList.add(modelMenuItem);
+            menuItemMap.put(modelMenuItem.getName(), modelMenuItem);
+        }
+    }
+
+    public List<ModelAction> getActions() {
+        return actions;
+    }
+
+    public String getAlign() {
+        if (!this.align.isEmpty()) {
+            return this.align;
+        } else if (parentMenuItem != null) {
+            return parentMenuItem.getAlign();
+        } else {
+            return this.modelMenu.getDefaultAlign();
+        }
+    }
+
+    public String getAlignStyle() {
+        if (!this.alignStyle.isEmpty()) {
+            return this.alignStyle;
+        } else if (parentMenuItem != null) {
+            return parentMenuItem.getAlignStyle();
+        } else {
+            return this.modelMenu.getDefaultAlignStyle();
+        }
+    }
+
+    public FlexibleStringExpander getAssociatedContentId() {
+        return associatedContentId;
+    }
+
+    public String getAssociatedContentId(Map<String, Object> context) {
+        String retStr = null;
+        if (this.associatedContentId != null) {
+            retStr = associatedContentId.expandString(context);
+        }
+        if (retStr.isEmpty()) {
+            retStr = this.modelMenu.getDefaultAssociatedContentId(context);
+        }
+        return retStr;
+    }
+
+    public String getCellWidth() {
+        if (!this.cellWidth.isEmpty()) {
+            return this.cellWidth;
+        } else {
+            return this.modelMenu.getDefaultCellWidth();
+        }
+    }
+
+    public ModelMenuCondition getCondition() {
+        return condition;
+    }
+
+    public String getDisabledTitleStyle() {
+        if (!this.disabledTitleStyle.isEmpty()) {
+            return this.disabledTitleStyle;
+        } else if (parentMenuItem != null) {
+            return parentMenuItem.getDisabledTitleStyle();
+        } else {
+            return this.modelMenu.getDefaultDisabledTitleStyle();
+        }
+    }
+
+    public String getDisableIfEmpty() {
+        return this.disableIfEmpty;
+    }
+
+    public String getEntityName() {
+        if (!this.entityName.isEmpty()) {
+            return this.entityName;
+        } else if (parentMenuItem != null) {
+            return parentMenuItem.getEntityName();
+        } else {
+            return this.modelMenu.getDefaultEntityName();
+        }
+    }
+
+    public Boolean getHideIfSelected() {
+        if (hideIfSelected != null) {
+            return this.hideIfSelected;
+        } else {
+            return this.modelMenu.getDefaultHideIfSelected();
+        }
+    }
+
+    public MenuLink getLink() {
+        return this.link;
+    }
+
+    public List<ModelMenuItem> getMenuItemList() {
+        return menuItemList;
+    }
+
+    public ModelMenu getModelMenu() {
+        return modelMenu;
+    }
+
+    @Override
+    public String getName() {
+        if (!this.overrideName.isEmpty()) {
+            return this.overrideName;
+        }
+        return super.getName();
+    }
+
+    public String getOverrideName() {
+        return overrideName;
+    }
+
+    public ModelMenuItem getParentMenuItem() {
+        return parentMenuItem;
+    }
+
+    public FlexibleStringExpander getParentPortalPageId() {
+        return parentPortalPageId;
+    }
+
+    public String getParentPortalPageId(Map<String, Object> context) {
+        return this.parentPortalPageId.expandString(context);
+    }
+
+    public int getPosition() {
+        if (this.position == null) {
+            return 1;
+        } else {
+            return position.intValue();
+        }
+    }
+
+    public String getSelectedStyle() {
+        if (!this.selectedStyle.isEmpty()) {
+            return this.selectedStyle;
+        } else if (parentMenuItem != null) {
+            return parentMenuItem.getSelectedStyle();
+        } else {
+            return this.modelMenu.getDefaultSelectedStyle();
+        }
+    }
+
+    public String getSubMenu() {
+        return subMenu;
+    }
+
+    public FlexibleStringExpander getTitle() {
+        return title;
+    }
+
+    public String getTitle(Map<String, Object> context) {
+        return title.expandString(context);
+    }
+
+    public String getTitleStyle() {
+        if (!this.titleStyle.isEmpty()) {
+            return this.titleStyle;
+        } else if (parentMenuItem != null) {
+            return parentMenuItem.getTitleStyle();
+        } else {
+            return this.modelMenu.getDefaultTitleStyle();
+        }
+    }
+
+    public FlexibleStringExpander getTooltip() {
+        return tooltip;
+    }
+
+    public String getTooltip(Map<String, Object> context) {
+        if (UtilValidate.isNotEmpty(tooltip)) {
+            return tooltip.expandString(context);
+        } else {
+            return "";
+        }
+    }
+
+    public String getTooltipStyle() {
+        if (!this.tooltipStyle.isEmpty()) {
+            return this.tooltipStyle;
+        } else if (parentMenuItem != null) {
+            return parentMenuItem.getTooltipStyle();
+        } else {
+            return this.modelMenu.getDefaultTooltipStyle();
+        }
+    }
+
+    public String getWidgetStyle() {
+        if (!this.widgetStyle.isEmpty()) {
+            return this.widgetStyle;
+        } else if (parentMenuItem != null) {
+            return parentMenuItem.getWidgetStyle();
+        } else {
+            return this.modelMenu.getDefaultWidgetStyle();
+        }
+    }
+
+    public boolean isSelected(Map<String, Object> context) {
+        return getName().equals(modelMenu.getSelectedMenuItemContextFieldName(context));
+    }
+
+    public ModelMenuItem mergeOverrideModelMenuItem(ModelMenuItem overrideMenuItem) {
+        return new ModelMenuItem(this, overrideMenuItem);
+    }
+
+    public void renderMenuItemString(Appendable writer, Map<String, Object> context, MenuStringRenderer menuStringRenderer)
+            throws IOException {
+        if (shouldBeRendered(context)) {
+            AbstractModelAction.runSubActions(actions, context);
+            String parentPortalPageId = getParentPortalPageId(context);
+            if (UtilValidate.isNotEmpty(parentPortalPageId)) {
+                List<GenericValue> portalPages = PortalPageWorker.getPortalPages(parentPortalPageId, context);
+                if (UtilValidate.isNotEmpty(portalPages)) {
+                    Locale locale = (Locale) context.get("locale");
+                    for (GenericValue portalPage : portalPages) {
+                        if (UtilValidate.isNotEmpty(portalPage.getString("portalPageName"))) {
+                            ModelMenuItem localItem = new ModelMenuItem(portalPage, this, locale);
+                            menuStringRenderer.renderMenuItem(writer, context, localItem);
+                        }
+                    }
+                }
+            } else {
+                menuStringRenderer.renderMenuItem(writer, context, this);
+            }
+        }
+    }
+
+    public boolean shouldBeRendered(Map<String, Object> context) {
+        if (this.condition != null) {
+            return this.condition.getCondition().eval(context);
+        }
+        return true;
+    }
+
+    public static class MenuLink {
+        private final ModelMenuItem linkMenuItem;
+        private final Link link;
+
+        public MenuLink(Element linkElement, ModelMenuItem parentMenuItem) {
+            this.linkMenuItem = parentMenuItem;
+            if (linkElement.getAttribute("text").isEmpty()) {
+                linkElement.setAttribute("text", parentMenuItem.getTitle().getOriginal());
+            }
+            if (linkElement.getAttribute("style").isEmpty()) {
+                linkElement.setAttribute("style", parentMenuItem.getWidgetStyle());
+            }
+            this.link = new Link(linkElement);
+        }
+
+        public MenuLink(GenericValue portalPage, ModelMenuItem parentMenuItem, Locale locale) {
+            this.linkMenuItem = parentMenuItem;
+            ArrayList<Parameter> parameterList = new ArrayList<Parameter>();
+            if (parentMenuItem.link != null) {
+                parameterList.addAll(parentMenuItem.link.getParameterList());
+            }
+            parameterList.add(new Parameter("portalPageId", portalPage.getString("portalPageId"), false));
+            parameterList.add(new Parameter("parentPortalPageId", portalPage.getString("parentPortalPageId"), false));
+            String target = "showPortalPage";
+            if (parentMenuItem.link != null) {
+                target= "";
+            }
+            this.link = new Link(portalPage, parameterList, target, locale);
+        }
+
+        public AutoEntityParameters getAutoEntityParameters() {
+            return link.getAutoEntityParameters();
+        }
+
+        public AutoServiceParameters getAutoServiceParameters() {
+            return link.getAutoServiceParameters();
+        }
+
+        public boolean getEncode() {
+            return link.getEncode();
+        }
+
+        public boolean getFullPath() {
+            return link.getFullPath();
+        }
+
+        public String getHeight() {
+            return link.getHeight();
+        }
+
+        public String getId(Map<String, Object> context) {
+            return link.getId(context);
+        }
+
+        public FlexibleStringExpander getIdExdr() {
+            return link.getIdExdr();
+        }
+
+        public Image getImage() {
+            return link.getImage();
+        }
+
+        public String getLinkType() {
+            return link.getLinkType();
+        }
+
+        public String getName() {
+            return link.getName();
+        }
+
+        public String getName(Map<String, Object> context) {
+            return link.getName(context);
+        }
+
+        public FlexibleStringExpander getNameExdr() {
+            return link.getNameExdr();
+        }
+
+        public List<Parameter> getParameterList() {
+            return link.getParameterList();
+        }
+
+        public Map<String, String> getParameterMap(Map<String, Object> context) {
+            return link.getParameterMap(context);
+        }
+
+        public String getPrefix(Map<String, Object> context) {
+            return link.getPrefix(context);
+        }
+
+        public FlexibleStringExpander getPrefixExdr() {
+            return link.getPrefixExdr();
+        }
+
+        public boolean getSecure() {
+            return link.getSecure();
+        }
+
+        public String getStyle(Map<String, Object> context) {
+            return link.getStyle(context);
+        }
+
+        public FlexibleStringExpander getStyleExdr() {
+            return link.getStyleExdr();
+        }
+
+        public String getTarget(Map<String, Object> context) {
+            return link.getTarget(context);
+        }
+
+        public FlexibleStringExpander getTargetExdr() {
+            return link.getTargetExdr();
+        }
+
+        public String getTargetWindow(Map<String, Object> context) {
+            return link.getTargetWindow(context);
+        }
+
+        public FlexibleStringExpander getTargetWindowExdr() {
+            return link.getTargetWindowExdr();
+        }
+
+        public String getText(Map<String, Object> context) {
+            return link.getText(context);
+        }
+
+        public FlexibleStringExpander getTextExdr() {
+            return link.getTextExdr();
+        }
+
+        public String getUrlMode() {
+            return link.getUrlMode();
+        }
+
+        public String getWidth() {
+            return link.getWidth();
+        }
+
+        public ModelMenuItem getLinkMenuItem() {
+            return linkMenuItem;
+        }
+
+        public Link getLink() {
+            return link;
+        }
+
+        public void renderLinkString(Appendable writer, Map<String, Object> context, MenuStringRenderer menuStringRenderer)
+                throws IOException {
+            menuStringRenderer.renderLink(writer, context, this);
+        }
+    }
+}

Added: ofbiz/trunk/framework/widget/src/org/ofbiz/widget/model/ModelScreen.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/widget/src/org/ofbiz/widget/model/ModelScreen.java?rev=1652852&view=auto
==============================================================================
--- ofbiz/trunk/framework/widget/src/org/ofbiz/widget/model/ModelScreen.java (added)
+++ ofbiz/trunk/framework/widget/src/org/ofbiz/widget/model/ModelScreen.java Sun Jan 18 21:03:40 2015
@@ -0,0 +1,194 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.ofbiz.widget.model;
+
+import java.util.Map;
+
+import org.ofbiz.base.util.Debug;
+import org.ofbiz.base.util.UtilGenerics;
+import org.ofbiz.base.util.UtilValidate;
+import org.ofbiz.base.util.UtilXml;
+import org.ofbiz.base.util.string.FlexibleStringExpander;
+import org.ofbiz.entity.Delegator;
+import org.ofbiz.entity.GenericEntity;
+import org.ofbiz.entity.GenericEntityException;
+import org.ofbiz.entity.transaction.TransactionUtil;
+import org.ofbiz.service.LocalDispatcher;
+import org.ofbiz.widget.renderer.ScreenRenderException;
+import org.ofbiz.widget.renderer.ScreenStringRenderer;
+import org.w3c.dom.Element;
+
+/**
+ * Widget Library - Screen model class
+ */
+@SuppressWarnings("serial")
+public class ModelScreen extends ModelWidget {
+
+    public static final String module = ModelScreen.class.getName();
+
+    private final String sourceLocation;
+    private final FlexibleStringExpander transactionTimeoutExdr;
+    private final Map<String, ModelScreen> modelScreenMap;
+    private final boolean useTransaction;
+    private final boolean useCache;
+    private final ModelScreenWidget.Section section;
+
+    /** XML Constructor */
+    public ModelScreen(Element screenElement, Map<String, ModelScreen> modelScreenMap, String sourceLocation) {
+        super(screenElement);
+        this.sourceLocation = sourceLocation;
+        this.transactionTimeoutExdr = FlexibleStringExpander.getInstance(screenElement.getAttribute("transaction-timeout"));
+        this.modelScreenMap = modelScreenMap;
+        this.useTransaction = "true".equals(screenElement.getAttribute("use-transaction"));
+        this.useCache = "true".equals(screenElement.getAttribute("use-cache"));
+
+        // read in the section, which will read all sub-widgets too
+        Element sectionElement = UtilXml.firstChildElement(screenElement, "section");
+        if (sectionElement == null) {
+            throw new IllegalArgumentException("No section found for the screen definition with name: " + getName());
+        }
+        this.section = new ModelScreenWidget.Section(this, sectionElement, true);
+    }
+
+    @Override
+    public void accept(ModelWidgetVisitor visitor) throws Exception {
+        visitor.visit(this);
+    }
+
+    public String getTransactionTimeout() {
+        return transactionTimeoutExdr.getOriginal();
+    }
+
+    public Map<String, ModelScreen> getModelScreenMap() {
+        return modelScreenMap;
+    }
+
+    public boolean getUseTransaction() {
+        return useTransaction;
+    }
+
+    public boolean getUseCache() {
+        return useCache;
+    }
+
+    public ModelScreenWidget.Section getSection() {
+        return section;
+    }
+
+    public String getSourceLocation() {
+        return sourceLocation;
+    }
+
+    /**
+     * Renders this screen to a String, i.e. in a text format, as defined with the
+     * ScreenStringRenderer implementation.
+     *
+     * @param writer The Writer that the screen text will be written to
+     * @param context Map containing the screen context; the following are
+     *   reserved words in this context:
+     *    - parameters (contains any special initial parameters coming in)
+     *    - userLogin (if a user is logged in)
+     *    - autoUserLogin (if a user is automatically logged in, ie no password has been entered)
+     *    - formStringRenderer
+     *    - request, response, session, application (special case, only in HTML contexts, etc)
+     *    - delegator, dispatcher, security
+     *    - null (represents a null field value for entity operations)
+     *    - sections (used for decorators to reference the sections to be decorated and render them)
+     * @param screenStringRenderer An implementation of the ScreenStringRenderer
+     *   interface that is responsible for the actual text generation for
+     *   different screen elements; implementing your own makes it possible to
+     *   use the same screen definitions for many types of screen UIs
+     */
+    public void renderScreenString(Appendable writer, Map<String, Object> context, ScreenStringRenderer screenStringRenderer) throws ScreenRenderException {
+        // make sure the "nullField" object is in there for entity ops
+        context.put("nullField", GenericEntity.NULL_FIELD);
+
+        // wrap the whole screen rendering in a transaction, should improve performance in querying and such
+        Map<String, String> parameters = UtilGenerics.cast(context.get("parameters"));
+        boolean beganTransaction = false;
+        int transactionTimeout = -1;
+        if (parameters != null) {
+            String transactionTimeoutPar = parameters.get("TRANSACTION_TIMEOUT");
+            if (transactionTimeoutPar != null) {
+                try {
+                    transactionTimeout = Integer.parseInt(transactionTimeoutPar);
+                } catch (NumberFormatException nfe) {
+                    String msg = "TRANSACTION_TIMEOUT parameter for screen [" + this.sourceLocation + "#" + getName() + "] is invalid and it will be ignored: " + nfe.toString();
+                    Debug.logWarning(msg, module);
+                }
+            }
+        }
+
+        if (transactionTimeout < 0 && !transactionTimeoutExdr.isEmpty()) {
+            // no TRANSACTION_TIMEOUT parameter, check screen attribute
+            String transactionTimeoutStr = transactionTimeoutExdr.expandString(context);
+            if (UtilValidate.isNotEmpty(transactionTimeoutStr)) {
+                try {
+                    transactionTimeout = Integer.parseInt(transactionTimeoutStr);
+                } catch (NumberFormatException e) {
+                    Debug.logWarning(e, "Could not parse transaction-timeout value, original=[" + transactionTimeoutExdr + "], expanded=[" + transactionTimeoutStr + "]", module);
+                }
+            }
+        }
+
+        try {
+            // If transaction timeout is not present (i.e. is equal to -1), the default transaction timeout is used
+            // If transaction timeout is present, use it to start the transaction
+            // If transaction timeout is set to zero, no transaction is started
+            if (useTransaction) {
+                if (transactionTimeout < 0) {
+                    beganTransaction = TransactionUtil.begin();
+                }
+                if (transactionTimeout > 0) {
+                    beganTransaction = TransactionUtil.begin(transactionTimeout);
+                }
+            }
+
+            // render the screen, starting with the top-level section
+            this.section.renderWidgetString(writer, context, screenStringRenderer);
+            TransactionUtil.commit(beganTransaction);
+        } catch (Exception e) {
+            String errMsg = "Error rendering screen [" + this.sourceLocation + "#" + getName() + "]: " + e.toString();
+            Debug.logError(errMsg + ". Rolling back transaction.", module);
+            try {
+                // only rollback the transaction if we started one...
+                TransactionUtil.rollback(beganTransaction, errMsg, e);
+            } catch (GenericEntityException e2) {
+                Debug.logError(e2, "Could not rollback transaction: " + e2.toString(), module);
+            }
+
+            // throw nested exception, don't need to log details here: Debug.logError(e, errMsg, module);
+
+            // after rolling back, rethrow the exception
+            throw new ScreenRenderException(errMsg, e);
+        }
+    }
+
+    public LocalDispatcher getDispatcher(Map<String, Object> context) {
+        LocalDispatcher dispatcher = (LocalDispatcher) context.get("dispatcher");
+        return dispatcher;
+    }
+
+    public Delegator getDelegator(Map<String, Object> context) {
+        Delegator delegator = (Delegator) context.get("delegator");
+        return delegator;
+    }
+}
+
+

Added: ofbiz/trunk/framework/widget/src/org/ofbiz/widget/model/ModelScreenCondition.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/widget/src/org/ofbiz/widget/model/ModelScreenCondition.java?rev=1652852&view=auto
==============================================================================
--- ofbiz/trunk/framework/widget/src/org/ofbiz/widget/model/ModelScreenCondition.java (added)
+++ ofbiz/trunk/framework/widget/src/org/ofbiz/widget/model/ModelScreenCondition.java Sun Jan 18 21:03:40 2015
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.ofbiz.widget.model;
+
+import java.util.Map;
+
+import org.ofbiz.base.util.UtilGenerics;
+import org.ofbiz.base.util.string.FlexibleStringExpander;
+import org.ofbiz.widget.model.AbstractModelCondition;
+import org.ofbiz.widget.model.AbstractModelCondition.DefaultConditionFactory;
+import org.ofbiz.widget.model.ModelCondition;
+import org.ofbiz.widget.model.ModelConditionFactory;
+import org.ofbiz.widget.model.ModelConditionVisitor;
+import org.ofbiz.widget.model.ModelWidget;
+import org.w3c.dom.Element;
+
+/**
+ * Models the &lt;condition&gt; element.
+ * 
+ * @see <code>widget-screen.xsd</code>
+ */
+@SuppressWarnings("serial")
+public final class ModelScreenCondition {
+
+    /*
+     * ----------------------------------------------------------------------- *
+     *                     DEVELOPERS PLEASE READ
+     * ----------------------------------------------------------------------- *
+     * 
+     * This model is intended to be a read-only data structure that represents
+     * an XML element. Outside of object construction, the class should not
+     * have any behaviors.
+     * 
+     * Instances of this class will be shared by multiple threads - therefore
+     * it is immutable. DO NOT CHANGE THE OBJECT'S STATE AT RUN TIME!
+     * 
+     */
+
+    public static final String module = ModelScreenCondition.class.getName();
+    public static final ModelConditionFactory SCREEN_CONDITION_FACTORY = new ScreenConditionFactory();
+
+    public static class IfEmptySection extends AbstractModelCondition {
+        private final FlexibleStringExpander sectionExdr;
+
+        private IfEmptySection(ModelConditionFactory factory, ModelWidget modelWidget, Element condElement) {
+            super (factory, modelWidget, condElement);
+            this.sectionExdr = FlexibleStringExpander.getInstance(condElement.getAttribute("section-name"));
+        }
+
+        @Override
+        public void accept(ModelConditionVisitor visitor) throws Exception {
+            visitor.visit(this);
+        }
+
+        @Override
+        public boolean eval(Map<String, Object> context) {
+            Map<String, Object> sectionsMap = UtilGenerics.toMap(context.get("sections"));
+            return !sectionsMap.containsKey(this.sectionExdr.expandString(context));
+        }
+
+        public FlexibleStringExpander getSectionExdr() {
+            return sectionExdr;
+        }
+    }
+
+    private static class ScreenConditionFactory extends DefaultConditionFactory {
+
+        @Override
+        public ModelCondition newInstance(ModelWidget modelWidget, Element conditionElement) {
+            if (conditionElement == null) {
+                return DefaultConditionFactory.TRUE;
+            }
+            if ("if-empty-section".equals(conditionElement.getNodeName())) {
+                return new IfEmptySection(this, modelWidget, conditionElement);
+            } else {
+                return super.newInstance(this, modelWidget,conditionElement);
+            }
+        }
+    }
+}