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.markup.html.repeater.data.sort;
018
019import org.apache.wicket.markup.html.link.Link;
020import org.apache.wicket.util.lang.Args;
021
022/**
023 * A component that represents a sort header. When the link is clicked it will toggle the state of a
024 * sortable property within the sort state object.
025 * 
026 * @param <S>
027 *            the type of the sorting parameter
028 * @author Phil Kulak
029 * @author Igor Vaynberg (ivaynberg)
030 */
031public class OrderByLink<S> extends Link<Void>
032{
033        private static final long serialVersionUID = 1L;
034
035        /** sortable property */
036        private final S property;
037
038        /** locator for sort state object */
039        private final ISortStateLocator<S> stateLocator;
040
041        /**
042         * Constructor.
043         * 
044         * @param id
045         *            the component id of the link
046         * @param property
047         *            the name of the sortable property this link represents. this value will be used as
048         *            parameter for sort state object methods. sort state object will be located via the
049         *            stateLocator argument.
050         * @param stateLocator
051         *            locator used to locate sort state object that this will use to read/write state of
052         *            sorted properties
053         *
054         */
055        public OrderByLink(final String id, final S property, final ISortStateLocator<S> stateLocator)
056        {
057                super(id);
058
059                Args.notNull(property, "property");
060
061                this.property = property;
062                this.stateLocator = stateLocator;
063        }
064
065        /**
066         * @see org.apache.wicket.markup.html.link.Link
067         */
068        @Override
069        public final void onClick()
070        {
071                sort();
072                onSortChanged();
073        }
074
075        /**
076         * This method is a hook for subclasses to perform an action after sort has changed
077         */
078        protected void onSortChanged()
079        {
080                // noop
081        }
082
083        /**
084         * Re-sort data provider according to this link
085         * 
086         * @return this
087         */
088        public final OrderByLink<S> sort()
089        {
090                if (isVersioned())
091                {
092                        // version the old state
093                        addStateChange();
094                }
095
096                ISortState<S> state = stateLocator.getSortState();
097
098                // get current sort order
099                SortOrder order = state.getPropertySortOrder(property);
100
101                // set next sort order
102                state.setPropertySortOrder(property, nextSortOrder(order));
103
104                return this;
105        }
106
107        /**
108         * returns the next sort order when changing it
109         * 
110         * @param order
111         *            previous sort order
112         * @return next sort order
113         */
114        protected SortOrder nextSortOrder(final SortOrder order)
115        {
116                // init / flip order
117                if (order == SortOrder.NONE)
118                {
119                        return SortOrder.ASCENDING;
120                }
121                else
122                {
123                        return order == SortOrder.ASCENDING ? SortOrder.DESCENDING : SortOrder.ASCENDING;
124                }
125        }
126}