nextapp.echo2.extras.webcontainer.TabPanePeer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ibis-echo2 Show documentation
Show all versions of ibis-echo2 Show documentation
Echo2 bundled with Echo2_Extras, Echo2_FileTransfer and echopointing and various improvements/bugfixes
/*
* This file is part of the Echo2 Extras Project.
* Copyright (C) 2002-2009 NextApp, Inc.
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*/
package nextapp.echo2.extras.webcontainer;
import java.util.HashSet;
import java.util.Set;
import org.w3c.dom.Element;
import nextapp.echo2.app.Border;
import nextapp.echo2.app.Color;
import nextapp.echo2.app.Component;
import nextapp.echo2.app.Extent;
import nextapp.echo2.app.FillImage;
import nextapp.echo2.app.Font;
import nextapp.echo2.app.ImageReference;
import nextapp.echo2.app.Insets;
import nextapp.echo2.app.Pane;
import nextapp.echo2.app.update.ServerComponentUpdate;
import nextapp.echo2.extras.app.TabPane;
import nextapp.echo2.extras.app.layout.TabPaneLayoutData;
import nextapp.echo2.webcontainer.ComponentSynchronizePeer;
import nextapp.echo2.webcontainer.ContainerInstance;
import nextapp.echo2.webcontainer.LazyRenderContainer;
import nextapp.echo2.webcontainer.PartialUpdateManager;
import nextapp.echo2.webcontainer.PartialUpdateParticipant;
import nextapp.echo2.webcontainer.PropertyUpdateProcessor;
import nextapp.echo2.webcontainer.RenderContext;
import nextapp.echo2.webcontainer.RenderState;
import nextapp.echo2.webcontainer.SynchronizePeerFactory;
import nextapp.echo2.webcontainer.image.ImageRenderSupport;
import nextapp.echo2.webcontainer.propertyrender.BorderRender;
import nextapp.echo2.webcontainer.propertyrender.ColorRender;
import nextapp.echo2.webcontainer.propertyrender.ExtentRender;
import nextapp.echo2.webcontainer.propertyrender.FillImageRender;
import nextapp.echo2.webcontainer.propertyrender.FontRender;
import nextapp.echo2.webcontainer.propertyrender.InsetsRender;
import nextapp.echo2.webrender.ServerMessage;
import nextapp.echo2.webrender.Service;
import nextapp.echo2.webrender.WebRenderServlet;
import nextapp.echo2.webrender.output.CssStyle;
import nextapp.echo2.webrender.servermessage.DomUpdate;
import nextapp.echo2.webrender.service.JavaScriptService;
/**
* ComponentSynchronizePeer
implementation for synchronizing
* TabPane
components.
*/
public class TabPanePeer
implements ComponentSynchronizePeer, ImageRenderSupport, LazyRenderContainer, PropertyUpdateProcessor {
private static final String IMAGE_ID_TAB_ACTIVE_BACKGROUND = "tabActiveBackground";
private static final String IMAGE_ID_TAB_INACTIVE_BACKGROUND = "tabInactiveBackground";
private static final String PROPERTY_ACTIVE_TAB = "activeTab";
/**
* Component property to enabled/disable lazy rendering of child tabs.
* Default value is interpreted to be true.
*/
public static final String PROPERTY_LAZY_RENDER_ENABLED = "nextapp.echo2.extras.webcontainer.TabPanePeer.lazyRenderEnabled";
/**
* Service to provide supporting JavaScript library.
*/
public static final Service TAB_PANE_SERVICE = JavaScriptService.forResource("Echo2Extras.TabPane",
"/nextapp/echo2/extras/webcontainer/resource/js/TabPane.js");
static {
WebRenderServlet.getServiceRegistry().add(TAB_PANE_SERVICE);
}
/**
* RenderState
implementation to store data on whether child
* components have been lazily rendered to client.
*/
private static class TabPaneRenderState implements RenderState {
/**
* Render id of currently active tab.
*/
private String activeTabId;
/**
* Set of rendered child components.
*/
private Set renderedChildren = new HashSet();
}
/**
* PartialUpdateParticipant
to update active tab.
*/
private PartialUpdateParticipant activeTabUpdateParticipant = new PartialUpdateParticipant() {
/**
* @see nextapp.echo2.webcontainer.PartialUpdateParticipant#renderProperty(nextapp.echo2.webcontainer.RenderContext,
* nextapp.echo2.app.update.ServerComponentUpdate)
*/
public void renderProperty(RenderContext rc, ServerComponentUpdate update) {
renderSetActiveTab(rc, update, (TabPane) update.getParent());
}
/**
* @see nextapp.echo2.webcontainer.PartialUpdateParticipant#canRenderProperty(nextapp.echo2.webcontainer.RenderContext,
* nextapp.echo2.app.update.ServerComponentUpdate)
*/
public boolean canRenderProperty(RenderContext rc, ServerComponentUpdate update) {
return true;
}
};
/**
* The PartialUpdateManager
for this synchronization peer.
*/
private PartialUpdateManager partialUpdateManager;
/**
* Default constructor.
*/
public TabPanePeer() {
partialUpdateManager = new PartialUpdateManager();
partialUpdateManager.add(TabPane.ACTIVE_TAB_INDEX_CHANGED_PROPERTY, activeTabUpdateParticipant);
}
private String getRenderedActiveTabId(ContainerInstance ci, TabPane tabPane) {
TabPaneRenderState renderState = (TabPaneRenderState) ci.getRenderState(tabPane);
return renderState.activeTabId;
}
/**
* Performs configuration tasks related to the active tab of a TabPane
.
*
* @param ci the relevant ContainerInstance
* @param tabPane the rendering TabPane
* @return true if the active tab requires rendering
*/
private boolean configureActiveTab(ContainerInstance ci, TabPane tabPane) {
TabPaneRenderState renderState = (TabPaneRenderState) ci.getRenderState(tabPane);
int componentCount = tabPane.getVisibleComponentCount();
int activeTabIndex = tabPane.getActiveTabIndex();
// Retrieve currently active component according to TabPane.activeTabIndex.
Component activeTab = (activeTabIndex >= 0 && activeTabIndex < componentCount)
? tabPane.getComponent(activeTabIndex) : null;
// If TabPane component does not specify a valid active tab, query render state.
if (activeTab == null && renderState.activeTabId != null) {
activeTab = getChildByRenderId(tabPane, renderState.activeTabId);
}
// If neither component nor render state have active tab information, pick a tab to be active.
if (activeTab == null) {
if (componentCount == 0) {
// No tabs available, return false indicating that active tab DOES not require rendering.
return false;
}
if (tabPane.getActiveTabIndex() == -1) {
// TabPane component state indicates no tab selected: select first tab.
activeTab = tabPane.getVisibleComponent(0);
} else {
// TabPane component state indicates a now-defunct tab was selected: select last tab.
activeTab = tabPane.getVisibleComponent(componentCount - 1);
}
}
// Store active tab in render state.
renderState.activeTabId = activeTab.getRenderId();
if (isLazyRenderEnabled(tabPane)) {
// Determine if active tab is rendered or not. If it is not rendered, mark its state rendered and
// return true to indicate that it should be rendered.
if (!isRendered(ci, tabPane, activeTab)) {
setRendered(ci, tabPane, activeTab);
return true;
} else {
return false;
}
} else {
return false;
}
}
/**
* @see nextapp.echo2.webcontainer.ComponentSynchronizePeer#getContainerId(nextapp.echo2.app.Component)
*/
public String getContainerId(Component child) {
return ContainerInstance.getElementId(child.getParent()) + "_content_" + child.getRenderId();
}
/**
* Returns the child component with the specified render id.
*
* @param tabPane the TabPane
* @param renderId the render identifier
* @return the child component, or null if no child exists with the
* specified id.
*/
private Component getChildByRenderId(TabPane tabPane, String renderId) {
Component[] children = tabPane.getVisibleComponents();
for (int i = 0; i < children.length; ++i) {
if (children[i].getRenderId().equals(renderId)) {
return children[i];
}
}
return null;
}
/**
* @see nextapp.echo2.webcontainer.image.ImageRenderSupport#getImage(nextapp.echo2.app.Component, java.lang.String)
*/
public ImageReference getImage(Component component, String imageId) {
if (IMAGE_ID_TAB_ACTIVE_BACKGROUND.equals(imageId)) {
FillImage backgroundImage = (FillImage) component.getRenderProperty(TabPane.PROPERTY_TAB_ACTIVE_BACKGROUND_IMAGE);
return backgroundImage == null ? null : backgroundImage.getImage();
} else if (IMAGE_ID_TAB_INACTIVE_BACKGROUND.equals(imageId)) {
FillImage backgroundImage = (FillImage) component.getRenderProperty(TabPane.PROPERTY_TAB_INACTIVE_BACKGROUND_IMAGE);
return backgroundImage == null ? null : backgroundImage.getImage();
} else {
return null;
}
}
/**
* Determines if a TabPane
should be lazy-rendered.
*
* @param tabPane the TabPane
to query
* @return true if lazy-rendering should be enabled
*/
private boolean isLazyRenderEnabled(TabPane tabPane) {
Boolean lazyRenderEnabled = (Boolean) tabPane.getRenderProperty(PROPERTY_LAZY_RENDER_ENABLED);
return lazyRenderEnabled == null ? true : lazyRenderEnabled.booleanValue();
}
/**
* @see nextapp.echo2.webcontainer.LazyRenderContainer#isRendered(nextapp.echo2.webcontainer.ContainerInstance,
* nextapp.echo2.app.Component, nextapp.echo2.app.Component)
*/
public boolean isRendered(ContainerInstance ci, Component parent, Component child) {
if (!isLazyRenderEnabled((TabPane) parent)) {
return true;
}
TabPaneRenderState renderState = (TabPaneRenderState) ci.getRenderState(parent);
if (renderState == null ) {
// Entire component has not been rendered, thus child has not been rendered.
return false;
}
return renderState.renderedChildren.contains(child);
}
/**
* @see nextapp.echo2.webcontainer.PropertyUpdateProcessor#processPropertyUpdate(nextapp.echo2.webcontainer.ContainerInstance,
* nextapp.echo2.app.Component, org.w3c.dom.Element)
*/
public void processPropertyUpdate(ContainerInstance ci, Component component, Element propertyElement) {
String propertyName = propertyElement.getAttribute(PropertyUpdateProcessor.PROPERTY_NAME);
if (PROPERTY_ACTIVE_TAB.equals(propertyName)) {
String propertyValue = propertyElement.getAttribute("value");
Component[] children = component.getVisibleComponents();
for (int i = 0; i < children.length; ++i) {
if (children[i].getRenderId().equals(propertyValue)) {
ci.getUpdateManager().getClientUpdateManager().setComponentProperty(component,
TabPane.INPUT_TAB_INDEX, new Integer(i));
return;
}
}
}
}
/**
* @see nextapp.echo2.webcontainer.ComponentSynchronizePeer#renderAdd(nextapp.echo2.webcontainer.RenderContext,
* nextapp.echo2.app.update.ServerComponentUpdate, java.lang.String, nextapp.echo2.app.Component)
*/
public void renderAdd(RenderContext rc, ServerComponentUpdate update, String targetId, Component component) {
ServerMessage serverMessage = rc.getServerMessage();
serverMessage.addLibrary(TAB_PANE_SERVICE.getId());
serverMessage.addLibrary(ExtrasUtil.JS_EXTRAS_UTIL_SERVICE.getId());
TabPane tabPane = (TabPane) component;
ContainerInstance ci = rc.getContainerInstance();
resetRenderState(ci, tabPane);
configureActiveTab(ci, tabPane);
renderInitDirective(rc, tabPane, targetId);
Component[] children = tabPane.getVisibleComponents();
for (int i = 0; i < children.length; ++i) {
renderAddTabDirective(rc, update, tabPane, children[i]);
}
boolean lazyRenderEnabled = isLazyRenderEnabled(tabPane);
for (int i = 0; i < children.length; ++i) {
if (!lazyRenderEnabled || isRendered(ci, tabPane, children[i])) {
renderChild(rc, update, tabPane, children[i]);
}
}
}
private void renderAddChildren(RenderContext rc, ServerComponentUpdate update, boolean activeTabRenderRequired) {
TabPane tabPane = (TabPane) update.getParent();
ContainerInstance ci = rc.getContainerInstance();
Component activeTab = null;
if (activeTabRenderRequired) {
TabPaneRenderState renderState = (TabPaneRenderState) ci.getRenderState(tabPane);
activeTab = getChildByRenderId(tabPane, renderState.activeTabId);
if (activeTab == null) {
activeTabRenderRequired = false;
}
}
if (update.hasAddedChildren()) {
Component[] addedChildren = update.getAddedChildren();
Component[] children = tabPane.getVisibleComponents();
// Iterating through arrays and checking for reference equality is used here (versus loading daddedChildren
// into a hashtable) because we'll be dealing with very small array lengths, typically less than 10.
for (int i = 0; i < children.length; ++i) {
for (int j = 0; j < addedChildren.length; ++j) {
if (children[i] == addedChildren[j]) {
renderAddTabDirective(rc, update, tabPane, children[i]);
break;
}
}
}
boolean lazyRenderEnabled = isLazyRenderEnabled(tabPane);
// Add children.
for (int i = 0; i < addedChildren.length; ++i) {
if (!lazyRenderEnabled || isRendered(ci, tabPane, addedChildren[i])) {
renderChild(rc, update, tabPane, addedChildren[i]);
if (addedChildren[i] == activeTab) {
activeTabRenderRequired = false;
}
}
}
}
if (activeTabRenderRequired) {
renderChild(rc, update, tabPane, activeTab);
}
}
private void renderAddTabDirective(RenderContext rc, ServerComponentUpdate update, TabPane tabPane, Component child) {
ContainerInstance ci = rc.getContainerInstance();
boolean rendered = !isLazyRenderEnabled(tabPane) || isRendered(ci, tabPane, child);
TabPaneLayoutData layoutData = (TabPaneLayoutData) child.getLayoutData();
String elementId = ContainerInstance.getElementId(tabPane);
Element addPartElement = rc.getServerMessage().appendPartDirective(ServerMessage.GROUP_ID_UPDATE,
"ExtrasTabPane.MessageProcessor", "add-tab");
addPartElement.setAttribute("eid", elementId);
addPartElement.setAttribute("tab-id", child.getRenderId());
addPartElement.setAttribute("tab-index", Integer.toString(tabPane.indexOf(child)));
if (rendered) {
addPartElement.setAttribute("rendered", "true");
}
if (child instanceof Pane) {
addPartElement.setAttribute("pane", "true");
}
if (layoutData != null) {
if (layoutData.getTitle() != null) {
addPartElement.setAttribute("title", layoutData.getTitle());
}
}
}
/**
* Renders an individual child component of the TabPane
.
*
* @param rc the relevant RenderContext
* @param update the ServerComponentUpdate
being performed
* @param child The child Component
to be rendered
*/
private void renderChild(RenderContext rc, ServerComponentUpdate update, TabPane tabPane, Component child) {
ComponentSynchronizePeer syncPeer = SynchronizePeerFactory.getPeerForComponent(child.getClass());
syncPeer.renderAdd(rc, update, getContainerId(child), child);
}
/**
* @see nextapp.echo2.webcontainer.ComponentSynchronizePeer#renderDispose(
* nextapp.echo2.webcontainer.RenderContext, nextapp.echo2.app.update.ServerComponentUpdate, nextapp.echo2.app.Component)
*/
public void renderDispose(RenderContext rc, ServerComponentUpdate update, Component component) {
ServerMessage serverMessage = rc.getServerMessage();
serverMessage.addLibrary(TAB_PANE_SERVICE.getId());
serverMessage.addLibrary(ExtrasUtil.JS_EXTRAS_UTIL_SERVICE.getId());
renderDisposeDirective(rc, (TabPane) component);
}
/**
* Renders a dispose directive.
*
* @param rc the relevant RenderContext
* @param tabPane the TabPane
being rendered
*/
private void renderDisposeDirective(RenderContext rc, TabPane tabPane) {
String elementId = ContainerInstance.getElementId(tabPane);
ServerMessage serverMessage = rc.getServerMessage();
Element initElement = serverMessage.appendPartDirective(ServerMessage.GROUP_ID_PREREMOVE,
"ExtrasTabPane.MessageProcessor", "dispose");
initElement.setAttribute("eid", elementId);
}
/**
* Renders an initialization directive.
*
* @param rc the relevant RenderContext
* @param tabPane the TabPane
being rendered
*/
private void renderInitDirective(RenderContext rc, TabPane tabPane, String targetId) {
String elementId = ContainerInstance.getElementId(tabPane);
ServerMessage serverMessage = rc.getServerMessage();
Element partElement = serverMessage.addPart(ServerMessage.GROUP_ID_UPDATE, "ExtrasTabPane.MessageProcessor");
Element initElement = serverMessage.getDocument().createElement("init");
initElement.setAttribute("container-eid", targetId);
initElement.setAttribute("eid", elementId);
if (!tabPane.isRenderEnabled()) {
initElement.setAttribute("enabled", "false");
}
Color background = (Color) tabPane.getRenderProperty(TabPane.PROPERTY_BACKGROUND);
if (background != null) {
initElement.setAttribute("default-background", ColorRender.renderCssAttributeValue(background));
}
Color foreground = (Color) tabPane.getRenderProperty(TabPane.PROPERTY_FOREGROUND);
if (foreground != null) {
initElement.setAttribute("default-foreground", ColorRender.renderCssAttributeValue(foreground));
}
Insets defaultContentInsets = (Insets) tabPane.getRenderProperty(TabPane.PROPERTY_DEFAULT_CONTENT_INSETS);
if (defaultContentInsets != null) {
initElement.setAttribute("default-content-insets", InsetsRender.renderCssAttributeValue(defaultContentInsets));
}
Insets insets = (Insets) tabPane.getRenderProperty(TabPane.PROPERTY_INSETS);
if (insets != null) {
initElement.setAttribute("insets", InsetsRender.renderCssAttributeValue(insets));
}
Extent tabInset = (Extent) tabPane.getRenderProperty(TabPane.PROPERTY_TAB_INSET);
if (tabInset != null) {
initElement.setAttribute("tab-inset", ExtentRender.renderCssAttributeValue(tabInset));
}
Extent tabSpacing = (Extent) tabPane.getRenderProperty(TabPane.PROPERTY_TAB_SPACING);
if (tabSpacing != null) {
initElement.setAttribute("tab-spacing", ExtentRender.renderCssAttributeValue(tabSpacing));
}
Integer tabPosition = (Integer) tabPane.getRenderProperty(TabPane.PROPERTY_TAB_POSITION);
if (tabPosition != null) {
initElement.setAttribute("tab-position", tabPosition.intValue() == TabPane.TAB_POSITION_BOTTOM ? "bottom" : "top");
}
Integer borderType = (Integer) tabPane.getRenderProperty(TabPane.PROPERTY_BORDER_TYPE);
if (borderType != null) {
switch (borderType.intValue()) {
case TabPane.BORDER_TYPE_ADJACENT_TO_TABS:
initElement.setAttribute("border-type", "adjacent");
break;
case TabPane.BORDER_TYPE_NONE:
initElement.setAttribute("border-type", "none");
break;
case TabPane.BORDER_TYPE_PARALLEL_TO_TABS:
initElement.setAttribute("border-type", "parallel");
break;
case TabPane.BORDER_TYPE_SURROUND:
initElement.setAttribute("border-type", "surround");
break;
}
}
// Render tab active properties.
Color tabActiveBackground = (Color) tabPane.getRenderProperty(TabPane.PROPERTY_TAB_ACTIVE_BACKGROUND);
if (tabActiveBackground != null) {
initElement.setAttribute("tab-active-background", ColorRender.renderCssAttributeValue(tabActiveBackground));
}
FillImage tabActiveBackgroundImage = (FillImage) tabPane.getRenderProperty(TabPane.PROPERTY_TAB_ACTIVE_BACKGROUND_IMAGE);
if (tabActiveBackgroundImage != null) {
CssStyle backgroundImageStyle = new CssStyle();
FillImageRender.renderToStyle(backgroundImageStyle, rc, this, tabPane, IMAGE_ID_TAB_ACTIVE_BACKGROUND,
tabActiveBackgroundImage, 0);
initElement.setAttribute("tab-active-background-image", backgroundImageStyle.renderInline());
}
Border tabActiveBorder = (Border) tabPane.getRenderProperty(TabPane.PROPERTY_TAB_ACTIVE_BORDER);
if (tabActiveBorder != null) {
if (tabActiveBorder.getColor() != null) {
initElement.setAttribute("tab-active-border-color",
ColorRender.renderCssAttributeValue(tabActiveBorder.getColor()));
}
if (tabActiveBorder.getSize() != null && tabActiveBorder.getSize().getUnits() == Extent.PX) {
initElement.setAttribute("tab-active-border-size", Integer.toString(tabActiveBorder.getSize().getValue()));
}
initElement.setAttribute("tab-active-border-style", BorderRender.getStyleValue(tabActiveBorder.getStyle()));
}
Font tabActiveFont = (Font) tabPane.getRenderProperty(TabPane.PROPERTY_TAB_ACTIVE_FONT);
if (tabActiveFont != null) {
CssStyle fontStyle = new CssStyle();
FontRender.renderToStyle(fontStyle, tabActiveFont);
initElement.setAttribute("tab-active-font", fontStyle.renderInline());
}
Color tabActiveForeground = (Color) tabPane.getRenderProperty(TabPane.PROPERTY_TAB_ACTIVE_FOREGROUND);
if (tabActiveForeground != null) {
initElement.setAttribute("tab-active-foreground", ColorRender.renderCssAttributeValue(tabActiveForeground));
}
// Render tab inactive properties.
Color tabInactiveBackground = (Color) tabPane.getRenderProperty(TabPane.PROPERTY_TAB_INACTIVE_BACKGROUND);
if (tabInactiveBackground != null) {
initElement.setAttribute("tab-inactive-background", ColorRender.renderCssAttributeValue(tabInactiveBackground));
}
FillImage tabInactiveBackgroundImage = (FillImage) tabPane.getRenderProperty(
TabPane.PROPERTY_TAB_INACTIVE_BACKGROUND_IMAGE);
if (tabInactiveBackgroundImage != null) {
CssStyle backgroundImageStyle = new CssStyle();
FillImageRender.renderToStyle(backgroundImageStyle, rc, this, tabPane, IMAGE_ID_TAB_INACTIVE_BACKGROUND,
tabInactiveBackgroundImage, 0);
initElement.setAttribute("tab-inactive-background-image", backgroundImageStyle.renderInline());
}
Border tabInactiveBorder = (Border) tabPane.getRenderProperty(TabPane.PROPERTY_TAB_INACTIVE_BORDER);
if (tabInactiveBorder != null) {
if (tabInactiveBorder.getColor() != null) {
initElement.setAttribute("tab-inactive-border-color",
ColorRender.renderCssAttributeValue(tabInactiveBorder.getColor()));
}
if (tabInactiveBorder.getSize() != null && tabInactiveBorder.getSize().getUnits() == Extent.PX) {
initElement.setAttribute("tab-inactive-border-size", Integer.toString(tabInactiveBorder.getSize().getValue()));
}
initElement.setAttribute("tab-inactive-border-style", BorderRender.getStyleValue(tabInactiveBorder.getStyle()));
}
Font tabInactiveFont= (Font) tabPane.getRenderProperty(TabPane.PROPERTY_TAB_INACTIVE_FONT);
if (tabInactiveFont != null) {
CssStyle fontStyle = new CssStyle();
FontRender.renderToStyle(fontStyle, tabInactiveFont);
initElement.setAttribute("tab-inactive-font", fontStyle.renderInline());
}
Color tabInactiveForeground = (Color) tabPane.getRenderProperty(TabPane.PROPERTY_TAB_INACTIVE_FOREGROUND);
if (tabInactiveForeground != null) {
initElement.setAttribute("tab-inactive-foreground", ColorRender.renderCssAttributeValue(tabInactiveForeground));
}
String activeTabId = getRenderedActiveTabId(rc.getContainerInstance(), tabPane);
if (activeTabId != null) {
initElement.setAttribute("active-tab", activeTabId);
}
partElement.appendChild(initElement);
}
/**
* Renders directives to remove any children from the client that were
* removed in the specified ServerComponentUpdate
.
*
* @param rc the relevant RenderContext
* @param update the ServerComponentUpdate
to process
*/
private void renderRemoveChildren(RenderContext rc, ServerComponentUpdate update) {
TabPane tabPane = (TabPane) update.getParent();
Component[] removedChildren = update.getRemovedChildren();
for (int i = 0; i < removedChildren.length; ++i) {
renderRemoveTabDirective(rc, update, tabPane, removedChildren[i]);
}
}
/**
* Renders a directive to the ServerMessage
to remove a tab
* from a TabPane
.
*
* @param rc the relevant RenderContext
* @param update the ServerComponentUpdate
describing the
* change
* @param tabPane the TabPane
being updated
* @param child the child Component
being removed form the
* TabPane
*/
private void renderRemoveTabDirective(RenderContext rc, ServerComponentUpdate update, TabPane tabPane, Component child) {
String elementId = ContainerInstance.getElementId(tabPane);
Element removeTabElement = rc.getServerMessage().appendPartDirective(ServerMessage.GROUP_ID_REMOVE,
"ExtrasTabPane.MessageProcessor", "remove-tab");
removeTabElement.setAttribute("eid", elementId);
removeTabElement.setAttribute("tab-id", child.getRenderId());
}
/**
* Updates the active tab of a pre-existing TabPane
on the
* client. This method will render the tab's component hierarchy to the
* client if it has not yet been loaded, and then render a set-active-tab
* directive to select the tab.
*
* @param rc the relevant RenderContext
* @param update the ServerComponentUpdate
describing the
* change
* @param tabPane the TabPane
being updated
*/
private void renderSetActiveTab(RenderContext rc, ServerComponentUpdate update, TabPane tabPane) {
ContainerInstance ci = rc.getContainerInstance();
boolean activeTabRenderRequired = configureActiveTab(ci, tabPane);
Component activeTab = null;
if (activeTabRenderRequired) {
TabPaneRenderState renderState = (TabPaneRenderState) ci.getRenderState(tabPane);
activeTab = getChildByRenderId(tabPane, renderState.activeTabId);
if (activeTab != null) {
renderChild(rc, update, tabPane, activeTab);
}
}
renderSetActiveTabDirective(rc, update, tabPane);
}
/**
* Renders a directive to the ServerMessage
to set the
* active tab of a pre-exisiting TabPane
*
* @param rc the relevant RenderContext
* @param update the ServerComponentUpdate
describing the
* change
* @param tabPane the TabPane
being updated
*/
private void renderSetActiveTabDirective(RenderContext rc, ServerComponentUpdate update, TabPane tabPane) {
Component activeTab = null;
TabPaneRenderState renderState = (TabPaneRenderState) rc.getContainerInstance().getRenderState(tabPane);
activeTab = getChildByRenderId(tabPane, renderState.activeTabId);
if (activeTab == null) {
return;
}
String elementId = ContainerInstance.getElementId(tabPane);
Element setActiveTabElement = rc.getServerMessage().appendPartDirective(ServerMessage.GROUP_ID_UPDATE,
"ExtrasTabPane.MessageProcessor", "set-active-tab");
setActiveTabElement.setAttribute("eid", elementId);
setActiveTabElement.setAttribute("active-tab", activeTab.getRenderId());
}
/**
* @see nextapp.echo2.webcontainer.ComponentSynchronizePeer#renderUpdate(
* nextapp.echo2.webcontainer.RenderContext, nextapp.echo2.app.update.ServerComponentUpdate, java.lang.String)
*/
public boolean renderUpdate(RenderContext rc, ServerComponentUpdate update, String targetId) {
ContainerInstance ci = rc.getContainerInstance();
TabPane tabPane = (TabPane) update.getParent();
// Determine if fully replacing the component is required.
boolean fullReplace = false;
if (update.hasUpdatedLayoutDataChildren()) {
fullReplace = true;
} else if (update.hasUpdatedProperties()) {
if (!partialUpdateManager.canProcess(rc, update)) {
fullReplace = true;
}
}
if (fullReplace) {
// Perform full update.
DomUpdate.renderElementRemove(rc.getServerMessage(), ContainerInstance.getElementId(update.getParent()));
renderAdd(rc, update, targetId, update.getParent());
} else {
// Perform incremental updates.
if (update.hasRemovedChildren() || update.hasAddedChildren()) {
boolean activeTabRenderRequired = configureActiveTab(ci, tabPane);
if (update.hasRemovedChildren()) {
renderRemoveChildren(rc, update);
}
if (update.hasAddedChildren() || activeTabRenderRequired) {
renderAddChildren(rc, update, activeTabRenderRequired);
}
renderSetActiveTabDirective(rc, update, tabPane);
}
if (update.hasUpdatedProperties()) {
partialUpdateManager.process(rc, update);
}
}
return fullReplace;
}
/**
* Resets the RenderState
of a TabPane
in the
* ContainerInstance
. Invoked when a TabPane
is
* initially rendered to the client.
*
* @param ci the relevant ContainerInstance
* @param tabPane the TabPane
being rendered
*/
private void resetRenderState(ContainerInstance ci, TabPane tabPane) {
TabPaneRenderState renderState = new TabPaneRenderState();
ci.setRenderState(tabPane, renderState);
}
/**
* Sets a flag in the RenderState
to indicate that a particular
* tab of a TabPane
has been/is being rendered to the client.
* This method is used to facilitate lazy-rendering, ensuring each tab of
* a TabPane
is rendered tot he client only once.
*
* @param ci the relevant ContainerInstance
* @param tabPane the TabPane
being rendered
* @param child the child tab component
*/
private void setRendered(ContainerInstance ci, TabPane tabPane, Component child) {
TabPaneRenderState renderState = (TabPaneRenderState) ci.getRenderState(tabPane);
if (renderState == null ) {
renderState = new TabPaneRenderState();
ci.setRenderState(tabPane, renderState);
}
renderState.renderedChildren.add(child);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy