📄 markupcontainer.java
字号:
/* * 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.apache.wicket;import java.util.ArrayList;import java.util.Arrays;import java.util.Collections;import java.util.Comparator;import java.util.Iterator;import java.util.List;import org.apache.wicket.markup.ComponentTag;import org.apache.wicket.markup.MarkupElement;import org.apache.wicket.markup.MarkupException;import org.apache.wicket.markup.MarkupNotFoundException;import org.apache.wicket.markup.MarkupStream;import org.apache.wicket.markup.WicketTag;import org.apache.wicket.markup.resolver.IComponentResolver;import org.apache.wicket.model.IComponentInheritedModel;import org.apache.wicket.model.IModel;import org.apache.wicket.model.IWrapModel;import org.apache.wicket.settings.IDebugSettings;import org.apache.wicket.util.resource.IResourceStream;import org.apache.wicket.util.string.Strings;import org.apache.wicket.version.undo.Change;import org.slf4j.Logger;import org.slf4j.LoggerFactory;/** * A MarkupContainer holds a map of child components. * <ul> * <li><b>Children </b>- Children can be added by calling the add() method, and they can be looked * up using a dotted path. For example, if a container called "a" held a nested container "b" which * held a nested component "c", then a.get("b.c") would return the Component with id "c". The number * of children in a MarkupContainer can be determined by calling size(), and the whole hierarchy of * children held by a MarkupContainer can be traversed by calling visitChildren(), passing in an * implementation of Component.IVisitor. * * <li><b>Markup Rendering </b>- A MarkupContainer also holds/references associated markup which is * used to render the container. As the markup stream for a container is rendered, component * references in the markup are resolved by using the container to look up Components in the * container's component map by id. Each component referenced by the markup stream is given an * opportunity to render itself using the markup stream. * <p> * Components may alter their referring tag, replace the tag's body or insert markup after the tag. * But components cannot remove tags from the markup stream. This is an important guarantee because * graphic designers may be setting attributes on component tags that affect visual presentation. * <p> * The type of markup held in a given container subclass can be determined by calling * getMarkupType(). Markup is accessed via a MarkupStream object which allows a component to * traverse ComponentTag and RawMarkup MarkupElements while rendering a response. Markup in the * stream may be HTML or some other kind of markup, such as VXML, as determined by the specific * container subclass. * <p> * A markup stream may be directly associated with a container via setMarkupStream. However, a * container which does not have a markup stream (its getMarkupStream() returns null) may inherit a * markup stream from a container above it in the component hierarchy. The findMarkupStream() method * will locate the first container at or above this container which has a markup stream. * <p> * All Page containers set a markup stream before rendering by calling the method * getAssociatedMarkupStream() to load the markup associated with the page. Since Page is at the top * of the container hierarchy, it is guaranteed that findMarkupStream will always return a valid * markup stream. * * @see MarkupStream * @author Jonathan Locke */public abstract class MarkupContainer extends Component{ private static final long serialVersionUID = 1L; /** Log for reporting. */ private static final Logger log = LoggerFactory.getLogger(MarkupContainer.class); /** List of children or single child */ private Object children; /** * The markup stream for this container. This variable is used only during the render phase to * provide access to the current element within the stream. */ private transient MarkupStream markupStream; /** * @see org.apache.wicket.Component#Component(String) */ public MarkupContainer(final String id) { super(id); } /** * @see org.apache.wicket.Component#Component(String, IModel) */ public MarkupContainer(final String id, IModel model) { super(id, model); } /** * Adds a child component to this container. * * @param child * The child * @throws IllegalArgumentException * Thrown if a child with the same id is replaced by the add operation. * @return This */ public final MarkupContainer add(final Component child) { checkHierarchyChange(child); if (child == null) { throw new IllegalArgumentException("argument child may not be null"); } if (log.isDebugEnabled()) { log.debug("Add " + child.getId() + " to " + this); } // Add to map addedComponent(child); if (put(child) != null) { throw new IllegalArgumentException(exceptionMessage("A child with id '" + child.getId() + "' already exists")); } return this; } /** * Replaces a child component of this container with another or just adds it in case no child * with the same id existed yet. * * @param child * The child * @return This */ public final MarkupContainer addOrReplace(final Component child) { checkHierarchyChange(child); if (child == null) { throw new IllegalArgumentException("argument child must be not null"); } if (get(child.getId()) == null) { add(child); } else { replace(child); } return this; } /** * This method allows a component to be added by an auto-resolver such as AutoComponentResolver * or AutoLinkResolver. While the component is being added, the component's FLAG_AUTO boolean is * set. The isAuto() method of Component returns true if a component or any of its parents has * this bit set. When a component is added via autoAdd(), the logic in Page that normally (a) * checks for modifications during the rendering process, and (b) versions components, is * bypassed if Component.isAuto() returns true. * <p> * The result of all this is that components added with autoAdd() are free from versioning and * can add their own children without the usual exception that would normally be thrown when the * component hierarchy is modified during rendering. * * @param component * The component to add * @param markupStream * Null, if the parent container is able to provide the markup. Else the markup * stream to be used to render the component. * @return True, if component has been added */ public final boolean autoAdd(final Component component, final MarkupStream markupStream) { if (component == null) { throw new IllegalArgumentException("argument component may not be null"); } /* Replace strategy */ component.setAuto(true); int index = children_indexOf(component); if (index >= 0) { children_remove(index); } add(component); component.prepareForRender(); try { if (markupStream == null) { component.render(); } else { component.render(markupStream); } } finally { component.afterRender(); } return true; } /** * * @param component * The component to add * @return True, if component has been added * * @deprecated since 1.3 Please use {@link #autoAdd(Component, MarkupStream)} instead */ public final boolean autoAdd(final Component component) { return autoAdd(component, null); } /** * @param component * The component to check * @param recurse * True if all descendents should be considered * @return True if the component is contained in this container */ public final boolean contains(final Component component, final boolean recurse) { if (component == null) { throw new IllegalArgumentException("argument component may not be null"); } if (recurse) { // Start at component and continue while we're not out of parents for (Component current = component; current != null;) { // Get parent final MarkupContainer parent = current.getParent(); // If this container is the parent, then the component is // recursively contained by this container if (parent == this) { // Found it! return true; } // Move up the chain to the next parent current = parent; } // Failed to find this container in component's ancestry return false; } else { // Is the component contained in this container? return component.getParent() == this; } } /** * Get a child component by looking it up with the given path. * * @param path * Path to component * @return The component at the path */ public final Component get(final String path) { // Reference to this container if (path == null || path.trim().equals("")) { return this; } // Get child's id, if any final String id = Strings.firstPathComponent(path, Component.PATH_SEPARATOR); // Get child by id Component child = children_get(id); // If the container is transparent, than ask its parent. // ParentResolver does something quite similar, but because of <head>, // <body>, <wicket:panel> etc. it is quite common to have transparent // components. Hence, this is little short cut for a tiny performance // optimization. if ((child == null) && isTransparentResolver() && (getParent() != null)) { child = getParent().get(path); } // Found child? if (child != null) { final String path2 = Strings.afterFirstPathComponent(path, Component.PATH_SEPARATOR); // Recurse on latter part of path return child.get(path2); } return child; } /** * Gets a fresh markup stream that contains the (immutable) markup resource for this class. * * @param throwException * If true, throw an exception, if markup could not be found * @return A stream of MarkupElement elements */ public MarkupStream getAssociatedMarkupStream(final boolean throwException) { try { return getApplication().getMarkupSettings().getMarkupCache().getMarkupStream(this, false, throwException); } catch (MarkupException ex) { // re-throw it. The exception contains already all the information // required. throw ex; } catch (WicketRuntimeException ex) { // throw exception since there is no associated markup throw new MarkupNotFoundException( exceptionMessage("Markup of type '" + getMarkupType() + "' for component '" + getClass().getName() + "' not found." + " Enable debug messages for org.apache.wicket.util.resource to get a list of all filenames tried"), ex); } } /** * Get the markup stream set on this container. * * @return Returns the markup stream set on this container. */ public final MarkupStream getMarkupStream() { return markupStream; } /** * Get the type of associated markup for this component. * * @return The type of associated markup for this component (for example, "html", "wml" or * "vxml"). The markup type for a component is independent of whether or not the * component actually has an associated markup resource file (which is determined at * runtime). If there is no markup type for a component, null may be returned, but this * means that no markup can be loaded for the class. */ public String getMarkupType() { throw new IllegalStateException( exceptionMessage("You cannot directly subclass Page or MarkupContainer. Instead, subclass a markup-specific class, such as WebPage or WebMarkupContainer")); } /** * THIS METHOD IS NOT PART OF THE WICKET PUBLIC API. DO NOT USE IT. * * Adds a child component to this container. * * @param child * The child * @throws IllegalArgumentException * Thrown if a child with the same id is replaced by the add operation. */ public void internalAdd(final Component child) { if (log.isDebugEnabled()) { log.debug("internalAdd " + child.getId() + " to " + this); } // Add to map addedComponent(child); put(child); } /** * Some MarkupContainers (e.g. HtmlHeaderContainer) have to be transparent with respect to their * child components. A transparent container gets its children from its parent container. * <p> * * @see org.apache.wicket.markup.resolver.ParentResolver * * @return false. By default a MarkupContainer is not transparent. */ public boolean isTransparentResolver() { return false; } /** * @return Iterator that iterates through children in the order they were added */ public final Iterator iterator() { return new Iterator() { int index = 0; public boolean hasNext() { return index < children_size(); } public Object next() { return children_get(index++); } public void remove() { final Component removed = children_remove(--index); checkHierarchyChange(removed); removedComponent(removed); } }; } /** * @param comparator * The comparator * @return Iterator that iterates over children in the order specified by comparator */ public final Iterator iterator(Comparator comparator) { final List sorted; if (children == null) { sorted = Collections.EMPTY_LIST; } else { if (children instanceof Component) { sorted = new ArrayList(1); sorted.add(children); } else { sorted = Arrays.asList((Component[])children); } } Collections.sort(sorted, comparator); return sorted.iterator(); } /** * NOT USED ANYMORE; it's here for helping people migrate from Wicket 1.2 to Wicket 1.3 * * @param containerClass * @return nothing * @throws IllegalStateException * throws an {@link IllegalStateException} */ // TODO remove after release 1.3.0 public final IResourceStream newMarkupResourceStream(Class containerClass) { throw new IllegalStateException( "this method is not used any more (and shouldn't be called by clients anyway)"); } /** * @param component * Component to remove from this container */ public void remove(final Component component) { checkHierarchyChange(component); if (component == null) { throw new IllegalArgumentException("argument component may not be null"); } children_remove(component); removedComponent(component); } /** * Removes the given component * * @param id * The id of the component to remove */ public final void remove(final String id) { if (id == null) { throw new IllegalArgumentException("argument id may not be null"); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -