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.util.lang.Args;
022import org.apache.wicket.util.visit.IVisit;
023import org.apache.wicket.util.visit.IVisitor;
024import org.apache.wicket.util.visit.Visit;
025
026/**
027 * 
028 * @author Juergen Donnerstag
029 */
030// TODO Wicket 1.6 :
031// - move to o.a.w.util.visit because this is a useful visitor impl
032// - relax its generics, it could be: DeepChildFirstVisitor<R> implements IVisitor<Component, R>
033public abstract class DeepChildFirstVisitor implements IVisitor<Component, Void>
034{
035        /**
036         * Construct.
037         */
038        public DeepChildFirstVisitor()
039        {
040        }
041
042        /**
043         * Render the child hierarchy headers.
044         * 
045         * @param rootComponent
046         * @return The object return by component()
047         */
048        public final Visit<Void> visit(final Component rootComponent)
049        {
050                Visit<Void> visitor = new Visit<Void>();
051                return visit(rootComponent, visitor);
052        }
053
054        /**
055         * Render the child hierarchy headers.
056         * 
057         * @param rootComponent
058         * @param visit
059         * @return The object return by component()
060         */
061        public final Visit<Void> visit(final Component rootComponent, final Visit<Void> visit)
062        {
063                Args.notNull(rootComponent, "rootComponent");
064                Args.notNull(visit, "visit");
065
066                // Component's don't have children; only MarkupContainers do
067                if (!(rootComponent instanceof MarkupContainer))
068                {
069                        // Call the visitor's callback method
070                        component(rootComponent, visit);
071                        return visit;
072                }
073
074                // while walking down, towards the deep child, we validate if the component is visible. If
075                // not, there is no need to go any deeper
076                if (preCheck(rootComponent) == false)
077                {
078                        return visit;
079                }
080
081                if (visit.isContinue())
082                {
083                        // Iterate over all children
084                        for (Component child : (MarkupContainer)rootComponent)
085                        {
086                                // visit the child
087                                visit(child, visit);
088                                if (visit.isStopped())
089                                {
090                                        return visit;
091                                }
092                        }
093                }
094
095                // visit "this"
096                component(rootComponent, visit);
097                return visit;
098        }
099
100        @Override
101        public abstract void component(Component component, IVisit<Void> visit);
102
103        /**
104         * In order to find the deepest component, we traverse downwards starting from the root (e.g.
105         * Page). However, once a component is not disabled (preCheck() returns false), iteration will
106         * stop and traversal continues with the sibling.
107         * 
108         * @param component
109         *            The component to be tested
110         * @return True, if component is enabled
111         */
112        public abstract boolean preCheck(Component component);
113}