001/*
002 * Copyright 2002-2012 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.beans.support;
018
019import java.io.Serializable;
020
021import org.springframework.lang.Nullable;
022import org.springframework.util.StringUtils;
023
024/**
025 * Mutable implementation of the {@link SortDefinition} interface.
026 * Supports toggling the ascending value on setting the same property again.
027 *
028 * @author Juergen Hoeller
029 * @author Jean-Pierre Pawlak
030 * @since 26.05.2003
031 * @see #setToggleAscendingOnProperty
032 */
033@SuppressWarnings("serial")
034public class MutableSortDefinition implements SortDefinition, Serializable {
035
036        private String property = "";
037
038        private boolean ignoreCase = true;
039
040        private boolean ascending = true;
041
042        private boolean toggleAscendingOnProperty = false;
043
044
045        /**
046         * Create an empty MutableSortDefinition,
047         * to be populated via its bean properties.
048         * @see #setProperty
049         * @see #setIgnoreCase
050         * @see #setAscending
051         */
052        public MutableSortDefinition() {
053        }
054
055        /**
056         * Copy constructor: create a new MutableSortDefinition
057         * that mirrors the given sort definition.
058         * @param source the original sort definition
059         */
060        public MutableSortDefinition(SortDefinition source) {
061                this.property = source.getProperty();
062                this.ignoreCase = source.isIgnoreCase();
063                this.ascending = source.isAscending();
064        }
065
066        /**
067         * Create a MutableSortDefinition for the given settings.
068         * @param property the property to compare
069         * @param ignoreCase whether upper and lower case in String values should be ignored
070         * @param ascending whether to sort ascending (true) or descending (false)
071         */
072        public MutableSortDefinition(String property, boolean ignoreCase, boolean ascending) {
073                this.property = property;
074                this.ignoreCase = ignoreCase;
075                this.ascending = ascending;
076        }
077
078        /**
079         * Create a new MutableSortDefinition.
080         * @param toggleAscendingOnSameProperty whether to toggle the ascending flag
081         * if the same property gets set again (that is, {@code setProperty} gets
082         * called with already set property name again).
083         */
084        public MutableSortDefinition(boolean toggleAscendingOnSameProperty) {
085                this.toggleAscendingOnProperty = toggleAscendingOnSameProperty;
086        }
087
088
089        /**
090         * Set the property to compare.
091         * <p>If the property was the same as the current, the sort is reversed if
092         * "toggleAscendingOnProperty" is activated, else simply ignored.
093         * @see #setToggleAscendingOnProperty
094         */
095        public void setProperty(String property) {
096                if (!StringUtils.hasLength(property)) {
097                        this.property = "";
098                }
099                else {
100                        // Implicit toggling of ascending?
101                        if (isToggleAscendingOnProperty()) {
102                                this.ascending = (!property.equals(this.property) || !this.ascending);
103                        }
104                        this.property = property;
105                }
106        }
107
108        @Override
109        public String getProperty() {
110                return this.property;
111        }
112
113        /**
114         * Set whether upper and lower case in String values should be ignored.
115         */
116        public void setIgnoreCase(boolean ignoreCase) {
117                this.ignoreCase = ignoreCase;
118        }
119
120        @Override
121        public boolean isIgnoreCase() {
122                return this.ignoreCase;
123        }
124
125        /**
126         * Set whether to sort ascending (true) or descending (false).
127         */
128        public void setAscending(boolean ascending) {
129                this.ascending = ascending;
130        }
131
132        @Override
133        public boolean isAscending() {
134                return this.ascending;
135        }
136
137        /**
138         * Set whether to toggle the ascending flag if the same property gets set again
139         * (that is, {@link #setProperty} gets called with already set property name again).
140         * <p>This is particularly useful for parameter binding through a web request,
141         * where clicking on the field header again might be supposed to trigger a
142         * resort for the same field but opposite order.
143         */
144        public void setToggleAscendingOnProperty(boolean toggleAscendingOnProperty) {
145                this.toggleAscendingOnProperty = toggleAscendingOnProperty;
146        }
147
148        /**
149         * Return whether to toggle the ascending flag if the same property gets set again
150         * (that is, {@code setProperty} gets called with already set property name again).
151         */
152        public boolean isToggleAscendingOnProperty() {
153                return this.toggleAscendingOnProperty;
154        }
155
156
157        @Override
158        public boolean equals(@Nullable Object other) {
159                if (this == other) {
160                        return true;
161                }
162                if (!(other instanceof SortDefinition)) {
163                        return false;
164                }
165                SortDefinition otherSd = (SortDefinition) other;
166                return (getProperty().equals(otherSd.getProperty()) &&
167                                isAscending() == otherSd.isAscending() &&
168                                isIgnoreCase() == otherSd.isIgnoreCase());
169        }
170
171        @Override
172        public int hashCode() {
173                int hashCode = getProperty().hashCode();
174                hashCode = 29 * hashCode + (isIgnoreCase() ? 1 : 0);
175                hashCode = 29 * hashCode + (isAscending() ? 1 : 0);
176                return hashCode;
177        }
178
179}