org.carewebframework.shell.layout.UIElementLayout.java Source code

Java tutorial

Introduction

Here is the source code for org.carewebframework.shell.layout.UIElementLayout.java

Source

/**
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
 * If a copy of the MPL was not distributed with this file, You can obtain one at
 * http://mozilla.org/MPL/2.0/.
 * 
 * This Source Code Form is also subject to the terms of the Health-Related Additional
 * Disclaimer of Warranty and Limitation of Liability available at
 * http://www.carewebframework.org/licensing/disclaimer.
 */
package org.carewebframework.shell.layout;

import java.util.Collections;

import org.carewebframework.shell.plugins.PluginDefinition;

import org.springframework.util.StringUtils;

import org.zkoss.zul.Div;

/**
 * Wrapper for a UI layout component.
 */
public class UIElementLayout extends UIElementZKBase {

    static {
        registerAllowedParentClass(UIElementLayout.class, UIElementBase.class);
        registerAllowedChildClass(UIElementLayout.class, UIElementBase.class);
    }

    private String layoutName;

    private boolean shared;

    private boolean linked = true;

    private UILayout layout;

    private final Div div = new Div();

    private PluginDefinition def;

    private boolean loaded;

    private boolean initializing;

    public UIElementLayout() {
        fullSize(div);
        setOuterComponent(div);
    }

    public UIElementLayout(String layoutName, boolean shared) {
        this();
        this.layoutName = layoutName;
        this.shared = shared;
        def = new PluginDefinition(PluginDefinition.getDefinition(getClass()));
        super.setDefinition(def);
        initDefinition();
    }

    private void initDefinition() {
        if (def != null) {
            def.setName(layoutName);
            def.setCategory("Layouts\\" + (shared ? "Shared" : "Private"));
        }
    }

    @Override
    public void setDefinition(PluginDefinition definition) {
        if (definition != null && def == null) {
            def = new PluginDefinition(definition);
            layoutName = def.getName();
            String category = def.getCategory();
            shared = category != null && category.contains("Shared");
            super.setDefinition(def);
        }
    }

    @Override
    public String getDisplayName() {
        return (linked ? "Linked" : "Embedded") + " Layout - " + layoutName;
    }

    public UILayout getLayout() throws Exception {
        if (layout == null) {
            layout = new UILayout();
            String xml = LayoutUtil.getLayoutContent(new LayoutIdentifier(layoutName, shared));

            if (StringUtils.isEmpty(xml)) {
                raise("Unknown layout: " + layoutName);
            }

            layout.loadFromText(xml);
        }

        return layout;
    }

    public String getLayoutName() {
        return layoutName;
    }

    public void setLayoutName(String layoutName) {
        this.layoutName = layoutName;
        initDefinition();
    }

    public boolean getShared() {
        return shared;
    }

    public void setShared(boolean shared) {
        this.shared = shared;
        initDefinition();
    }

    @Override
    public void beforeInitialize(boolean deserializing) throws Exception {
        initializing = true;
        super.beforeInitialize(deserializing);
    }

    /**
     * If this is a linked layout, must deserialize from it.
     */
    @Override
    public void afterInitialize(boolean deserializing) throws Exception {
        super.afterInitialize(deserializing);

        if (linked) {
            internalDeserialize(false);
        }

        initializing = false;
    }

    /**
     * A linked layout has no serializable children.
     */
    @Override
    public Iterable<UIElementBase> getSerializableChildren() {
        return linked ? Collections.<UIElementBase>emptyList() : super.getSerializableChildren();
    }

    /**
     * Deserialize from the associated layout.
     * 
     * @param forced If true, force deserialization regardless of load state.
     */
    private void internalDeserialize(boolean forced) {
        if (!forced && loaded) {
            return;
        }

        lockDescendants(false);
        removeChildren();
        loaded = true;

        try {
            if (linked) {
                checkForCircularReference();
            }

            getLayout().deserialize(this);

            if (linked) {
                lockDescendants(true);
            }
        } catch (Exception e) {
            raise("Error loading layout.", e);
        }
    }

    /**
     * Checks for a circular reference to the same linked layout, throwing an exception if found.
     */
    private void checkForCircularReference() {
        UIElementLayout layout = this;

        while ((layout = layout.getAncestor(UIElementLayout.class)) != null) {
            if (layout.linked && layout.shared == shared && layout.layoutName.equals(layoutName)) {
                raise("Circular reference to layout " + layoutName);
            }
        }
    }

    /**
     * Sets the lock state for all descendants of this layout.
     * 
     * @param lock The lock state.
     */
    private void lockDescendants(boolean lock) {
        lockDescendants(getChildren(), lock);
    }

    /**
     * Sets the lock state for all descendants of this layout.
     * 
     * @param children List of descendants.
     * @param lock The lock state.
     */
    private void lockDescendants(Iterable<UIElementBase> children, boolean lock) {
        for (UIElementBase child : children) {
            child.setLocked(lock);
            lockDescendants(child.getChildren(), lock);
        }
    }

    /**
     * Returns the linked state. If true, the associated layout is linked by reference. Any changes
     * to the layout will be reflected when the containing layout is loaded. If false, the
     * associated layout is embedded. Any changes to the original layout will not be reflected when
     * the containing layout is loaded. Additionally, all child UI elements of a linked layout are
     * locked and may not be modified. Child elements of an embedded layout may be freely edited.
     * 
     * @return The linked state.
     */
    public boolean getLinked() {
        return linked;
    }

    /**
     * Sets the linked state. A change in this state requires reloading of the associated layout.
     * 
     * @param linked The linked state.
     */
    public void setLinked(boolean linked) {
        if (linked != this.linked) {
            this.linked = linked;

            if (!initializing) {
                internalDeserialize(true);
                getRoot().activate(true);
            }
        }
    }
}