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.extensions.breadcrumb.panel;
018
019import org.apache.wicket.Component;
020import org.apache.wicket.extensions.breadcrumb.BreadCrumbLink;
021import org.apache.wicket.extensions.breadcrumb.IBreadCrumbModel;
022import org.apache.wicket.extensions.breadcrumb.IBreadCrumbParticipant;
023import org.apache.wicket.markup.html.panel.Panel;
024import org.apache.wicket.model.IModel;
025
026
027/**
028 * A panel that participates with a {@link IBreadCrumbModel bread crumb model}. The idea is that you
029 * would have a dialog-like component that is much like a wizard, but more decoupled. A typical
030 * setup is that you have a panel, where the content is dynamic but hierarchical in nature, and that
031 * there are links on the panel that <i>take you deeper into the hierarchy<i>
032 * 
033 * <p>
034 * An example of using {@link BreadCrumbPanel bread crumb panels} and {@link BreadCrumbLink bread
035 * crumb links}:
036 * 
037 * <pre>
038 * add(new BreadCrumbLink(&quot;myLink&quot;, breadCrumbModel)
039 * {
040 *      protected IBreadCrumbParticipant getParticipant(String componentId)
041 *      {
042 *              return new MyPanel(componentId, breadCrumbModel);
043 *      }
044 * });
045 * </pre>
046 * 
047 * where <tt>MyPanel</tt> is a {@link BreadCrumbPanel bread crumb panel} and the link is added to
048 * another {@link BreadCrumbPanel bread crumb panel} instance (this). When clicked, MyPanel will
049 * replace the panel that the link is placed on, and it will set (and add) <tt>MyPanel</tt> as the
050 * active bread crumb in the {@link IBreadCrumbModel bread crumb component model}.
051 * </p>
052 * 
053 * @author Eelco Hillenius
054 */
055public abstract class BreadCrumbPanel extends Panel implements IBreadCrumbParticipant
056{
057        private static final long serialVersionUID = 1L;
058
059        /** The bread crumb model. */
060        private IBreadCrumbModel breadCrumbModel;
061
062        /**
063         * Implementation of the participant.
064         */
065        private final IBreadCrumbParticipant decorated = new BreadCrumbParticipantDelegate(this)
066        {
067                private static final long serialVersionUID = 1L;
068
069                @Override
070                public IModel<String> getTitle()
071                {
072                        return BreadCrumbPanel.this.getTitle();
073                }
074        };
075
076        /**
077         * Construct.
078         * 
079         * @param id
080         *            Component id
081         * @param breadCrumbModel
082         *            The bread crumb model
083         */
084        public BreadCrumbPanel(final String id, final IBreadCrumbModel breadCrumbModel)
085        {
086                super(id);
087                this.breadCrumbModel = breadCrumbModel;
088        }
089
090        /**
091         * Construct.
092         * 
093         * @param id
094         *            Component id
095         * @param breadCrumbModel
096         *            The bread crumb model
097         * @param model
098         *            The model
099         */
100        public BreadCrumbPanel(final String id, final IBreadCrumbModel breadCrumbModel,
101                final IModel<?> model)
102        {
103                super(id, model);
104                this.breadCrumbModel = breadCrumbModel;
105        }
106
107        /**
108         * Activates the {@link BreadCrumbPanel bread crumb panel} that is the result of calling
109         * {@link IBreadCrumbPanelFactory#create(String, IBreadCrumbModel) the create method} of the
110         * bread crumb panel factory.
111         * 
112         * @param breadCrumbPanelFactory
113         */
114        public void activate(final IBreadCrumbPanelFactory breadCrumbPanelFactory)
115        {
116                activate(breadCrumbPanelFactory.create(getId(), breadCrumbModel));
117        }
118
119        /**
120         * Activates the provided participant, which typically has the effect of replacing this current
121         * panel with the one provided - as the participant typically would be a {@link BreadCrumbPanel
122         * bread crumb panel} - and updating the bread crumb model of this panel, pushing the bread
123         * crumb for the given participant on top.
124         * 
125         * @param participant
126         *            The participant to set as the active one
127         */
128        public void activate(final IBreadCrumbParticipant participant)
129        {
130                // get the currently active participant
131                final IBreadCrumbParticipant active = breadCrumbModel.getActive();
132                if (active == null)
133                {
134                        throw new IllegalStateException("The model has no active bread crumb. Before using " +
135                                this + ", you have to have at least one bread crumb in the model");
136                }
137
138                // add back button support
139                addStateChange();
140
141                // set the bread crumb panel as the active one
142                breadCrumbModel.setActive(participant);
143        }
144
145        /**
146         * Gets the bread crumb panel.
147         * 
148         * @return The bread crumb panel
149         */
150        public final IBreadCrumbModel getBreadCrumbModel()
151        {
152                return breadCrumbModel;
153        }
154
155        /**
156         * The participating component == this.
157         * 
158         * @see org.apache.wicket.extensions.breadcrumb.IBreadCrumbParticipant#getComponent()
159         */
160        @Override
161        public Component getComponent()
162        {
163                return decorated.getComponent();
164        }
165
166        /**
167         * @see org.apache.wicket.extensions.breadcrumb.IBreadCrumbParticipant#onActivate(org.apache.wicket.extensions.breadcrumb.IBreadCrumbParticipant)
168         */
169        @Override
170        public void onActivate(final IBreadCrumbParticipant previous)
171        {
172                decorated.onActivate(previous);
173        }
174
175        /**
176         * Sets the bread crumb panel.
177         * 
178         * @param breadCrumbModel
179         *            The bread crumb panel
180         */
181        public final void setBreadCrumbModel(final IBreadCrumbModel breadCrumbModel)
182        {
183                this.breadCrumbModel = breadCrumbModel;
184        }
185}