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.util.StringUtils;
022
023/**
024 * Mutable implementation of the {@link SortDefinition} interface.
025 * Supports toggling the ascending value on setting the same property again.
026 *
027 * @author Juergen Hoeller
028 * @author Jean-Pierre Pawlak
029 * @since 26.05.2003
030 * @see #setToggleAscendingOnProperty
031 */
032@SuppressWarnings("serial")
033public class MutableSortDefinition implements SortDefinition, Serializable {
034
035        private String property = "";
036
037        private boolean ignoreCase = true;
038
039        private boolean ascending = true;
040
041        private boolean toggleAscendingOnProperty = false;
042
043
044        /**
045         * Create an empty MutableSortDefinition,
046         * to be populated via its bean properties.
047         * @see #setProperty
048         * @see #setIgnoreCase
049         * @see #setAscending
050         */
051        public MutableSortDefinition() {
052        }
053
054        /**
055         * Copy constructor: create a new MutableSortDefinition
056         * that mirrors the given sort definition.
057         * @param source the original sort definition
058         */
059        public MutableSortDefinition(SortDefinition source) {
060                this.property = source.getProperty();
061                this.ignoreCase = source.isIgnoreCase();
062                this.ascending = source.isAscending();
063        }
064
065        /**
066         * Create a MutableSortDefinition for the given settings.
067         * @param property the property to compare
068         * @param ignoreCase whether upper and lower case in String values should be ignored
069         * @param ascending whether to sort ascending (true) or descending (false)
070         */
071        public MutableSortDefinition(String property, boolean ignoreCase, boolean ascending) {
072                this.property = property;
073                this.ignoreCase = ignoreCase;
074                this.ascending = ascending;
075        }
076
077        /**
078         * Create a new MutableSortDefinition.
079         * @param toggleAscendingOnSameProperty whether to toggle the ascending flag
080         * if the same property gets set again (that is, {@code setProperty} gets
081         * called with already set property name again).
082         */
083        public MutableSortDefinition(boolean toggleAscendingOnSameProperty) {
084                this.toggleAscendingOnProperty = toggleAscendingOnSameProperty;
085        }
086
087
088        /**
089         * Set the property to compare.
090         * <p>If the property was the same as the current, the sort is reversed if
091         * "toggleAscendingOnProperty" is activated, else simply ignored.
092         * @see #setToggleAscendingOnProperty
093         */
094        public void setProperty(String property) {
095                if (!StringUtils.hasLength(property)) {
096                        this.property = "";
097                }
098                else {
099                        // Implicit toggling of ascending?
100                        if (isToggleAscendingOnProperty()) {
101                                this.ascending = (!property.equals(this.property) || !this.ascending);
102                        }
103                        this.property = property;
104                }
105        }
106
107        @Override
108        public String getProperty() {
109                return this.property;
110        }
111
112        /**
113         * Set whether upper and lower case in String values should be ignored.
114         */
115        public void setIgnoreCase(boolean ignoreCase) {
116                this.ignoreCase = ignoreCase;
117        }
118
119        @Override
120        public boolean isIgnoreCase() {
121                return this.ignoreCase;
122        }
123
124        /**
125         * Set whether to sort ascending (true) or descending (false).
126         */
127        public void setAscending(boolean ascending) {
128                this.ascending = ascending;
129        }
130
131        @Override
132        public boolean isAscending() {
133                return this.ascending;
134        }
135
136        /**
137         * Set whether to toggle the ascending flag if the same property gets set again
138         * (that is, {@link #setProperty} gets called with already set property name again).
139         * <p>This is particularly useful for parameter binding through a web request,
140         * where clicking on the field header again might be supposed to trigger a
141         * resort for the same field but opposite order.
142         */
143        public void setToggleAscendingOnProperty(boolean toggleAscendingOnProperty) {
144                this.toggleAscendingOnProperty = toggleAscendingOnProperty;
145        }
146
147        /**
148         * Return whether to toggle the ascending flag if the same property gets set again
149         * (that is, {@code setProperty} gets called with already set property name again).
150         */
151        public boolean isToggleAscendingOnProperty() {
152                return this.toggleAscendingOnProperty;
153        }
154
155
156        @Override
157        public boolean equals(Object other) {
158                if (this == other) {
159                        return true;
160                }
161                if (!(other instanceof SortDefinition)) {
162                        return false;
163                }
164                SortDefinition otherSd = (SortDefinition) other;
165                return (getProperty().equals(otherSd.getProperty()) &&
166                                isAscending() == otherSd.isAscending() &&
167                                isIgnoreCase() == otherSd.isIgnoreCase());
168        }
169
170        @Override
171        public int hashCode() {
172                int hashCode = getProperty().hashCode();
173                hashCode = 29 * hashCode + (isIgnoreCase() ? 1 : 0);
174                hashCode = 29 * hashCode + (isAscending() ? 1 : 0);
175                return hashCode;
176        }
177
178}