001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.wicket.markup.renderStrategy;
018
019import org.apache.wicket.Component;
020import org.apache.wicket.MarkupContainer;
021import org.apache.wicket.markup.html.internal.HtmlHeaderContainer;
022import org.apache.wicket.markup.html.internal.HtmlHeaderContainer.HeaderStreamState;
023import org.apache.wicket.util.lang.Args;
024import org.apache.wicket.util.visit.IVisit;
025
026/**
027 * This a header render strategy implements a child->parent->root sequence, which is inverse to how
028 * it was until Wicket 1.5. It now allows parent containers to replace child contributions, since
029 * their contribution is added to the markup after the child ones (see <a
030 * href="https://issues.apache.org/jira/browse/WICKET-2693">WICKET-2693</a>).
031 * 
032 * Please note that irrespective of the render strategy, if the same header content (e.g. CSS file)
033 * gets added twice to the header, only the first will be rendered and the 2nd will be skipped.
034 * 
035 * @author Juergen Donnerstag
036 */
037public class ChildFirstHeaderRenderStrategy extends AbstractHeaderRenderStrategy
038{
039        /**
040         * Construct.
041         */
042        public ChildFirstHeaderRenderStrategy()
043        {
044        }
045
046        @Override
047        public void renderHeader(final HtmlHeaderContainer headerContainer,
048                HeaderStreamState headerStreamState, final Component rootComponent)
049        {
050                Args.notNull(headerContainer, "headerContainer");
051                Args.notNull(rootComponent, "rootComponent");
052
053                // First the application level headers
054                renderApplicationLevelHeaders(headerContainer);
055
056                // Then its child hierarchy
057                renderChildHeaders(headerContainer, rootComponent);
058
059                // Then the root component's headers
060                renderRootComponent(headerContainer, headerStreamState, rootComponent);
061        }
062
063        /**
064         * Render the child hierarchy headers.
065         * 
066         * @param headerContainer
067         * @param rootComponent
068         */
069        @Override
070        protected void renderChildHeaders(final HtmlHeaderContainer headerContainer,
071                final Component rootComponent)
072        {
073                Args.notNull(headerContainer, "headerContainer");
074                Args.notNull(rootComponent, "rootComponent");
075
076                if (rootComponent instanceof MarkupContainer)
077                {
078                        new DeepChildFirstVisitor()
079                        {
080                                @Override
081                                public void component(final Component component, final IVisit<Void> visit)
082                                {
083                                        if (component != rootComponent)
084                                        {
085                                                component.internalRenderHead(headerContainer);
086                                        }
087                                }
088
089                                @Override
090                                public boolean preCheck(Component component)
091                                {
092                                        return component.isVisibleInHierarchy();
093                                }
094                        }.visit(rootComponent);
095                }
096        }
097}