1 /*
2  * Copyright 2002-2007 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package org.springframework.beans.support;
18 
19 import java.io.Serializable;
20 
21 import org.springframework.util.StringUtils;
22 
23 /**
24  * Mutable implementation of the {@link SortDefinition} interface.
25  * Supports toggling the ascending value on setting the same property again.
26  *
27  * @author Juergen Hoeller
28  * @author Jean-Pierre Pawlak
29  * @since 26.05.2003
30  * @see #setToggleAscendingOnProperty
31  */
32 public class MutableSortDefinition implements SortDefinition, Serializable {
33 
34 	private String property = "";
35 
36 	private boolean ignoreCase = true;
37 
38 	private boolean ascending = true;
39 
40 	private boolean toggleAscendingOnProperty = false;
41 
42 
43 	/**
44 	 * Create an empty MutableSortDefinition,
45 	 * to be populated via its bean properties.
46 	 * @see #setProperty
47 	 * @see #setIgnoreCase
48 	 * @see #setAscending
49 	 */
MutableSortDefinition()50 	public MutableSortDefinition() {
51 	}
52 
53 	/**
54 	 * Copy constructor: create a new MutableSortDefinition
55 	 * that mirrors the given sort definition.
56 	 * @param source the original sort definition
57 	 */
MutableSortDefinition(SortDefinition source)58 	public MutableSortDefinition(SortDefinition source) {
59 		this.property = source.getProperty();
60 		this.ignoreCase = source.isIgnoreCase();
61 		this.ascending = source.isAscending();
62 	}
63 
64 	/**
65 	 * Create a MutableSortDefinition for the given settings.
66 	 * @param property the property to compare
67 	 * @param ignoreCase whether upper and lower case in String values should be ignored
68 	 * @param ascending whether to sort ascending (true) or descending (false)
69 	 */
MutableSortDefinition(String property, boolean ignoreCase, boolean ascending)70 	public MutableSortDefinition(String property, boolean ignoreCase, boolean ascending) {
71 		this.property = property;
72 		this.ignoreCase = ignoreCase;
73 		this.ascending = ascending;
74 	}
75 
76 	/**
77 	 * Create a new MutableSortDefinition.
78 	 * @param toggleAscendingOnSameProperty whether to toggle the ascending flag
79 	 * if the same property gets set again (that is, <code>setProperty</code> gets
80 	 * called with already set property name again).
81 	 */
MutableSortDefinition(boolean toggleAscendingOnSameProperty)82 	public MutableSortDefinition(boolean toggleAscendingOnSameProperty) {
83 		this.toggleAscendingOnProperty = toggleAscendingOnSameProperty;
84 	}
85 
86 
87 	/**
88 	 * Set the property to compare.
89 	 * <p>If the property was the same as the current, the sort is reversed if
90 	 * "toggleAscendingOnProperty" is activated, else simply ignored.
91 	 * @see #setToggleAscendingOnProperty
92 	 */
setProperty(String property)93 	public void setProperty(String property) {
94 		if (!StringUtils.hasLength(property)) {
95 			this.property = "";
96 		}
97 		else {
98 			// Implicit toggling of ascending?
99 			if (isToggleAscendingOnProperty()) {
100 				this.ascending = (!property.equals(this.property) || !this.ascending);
101 			}
102 			this.property = property;
103 		}
104 	}
105 
getProperty()106 	public String getProperty() {
107 		return this.property;
108 	}
109 
110 	/**
111 	 * Set whether upper and lower case in String values should be ignored.
112 	 */
setIgnoreCase(boolean ignoreCase)113 	public void setIgnoreCase(boolean ignoreCase) {
114 		this.ignoreCase = ignoreCase;
115 	}
116 
isIgnoreCase()117 	public boolean isIgnoreCase() {
118 		return this.ignoreCase;
119 	}
120 
121 	/**
122 	 * Set whether to sort ascending (true) or descending (false).
123 	 */
setAscending(boolean ascending)124 	public void setAscending(boolean ascending) {
125 		this.ascending = ascending;
126 	}
127 
isAscending()128 	public boolean isAscending() {
129 		return this.ascending;
130 	}
131 
132 	/**
133 	 * Set whether to toggle the ascending flag if the same property gets set again
134 	 * (that is, {@link #setProperty} gets called with already set property name again).
135 	 * <p>This is particularly useful for parameter binding through a web request,
136 	 * where clicking on the field header again might be supposed to trigger a
137 	 * resort for the same field but opposite order.
138 	 */
setToggleAscendingOnProperty(boolean toggleAscendingOnProperty)139 	public void setToggleAscendingOnProperty(boolean toggleAscendingOnProperty) {
140 		this.toggleAscendingOnProperty = toggleAscendingOnProperty;
141 	}
142 
143 	/**
144 	 * Return whether to toggle the ascending flag if the same property gets set again
145 	 * (that is, {@link #setProperty} gets called with already set property name again).
146 	 */
isToggleAscendingOnProperty()147 	public boolean isToggleAscendingOnProperty() {
148 		return this.toggleAscendingOnProperty;
149 	}
150 
151 
152 	@Override
equals(Object other)153 	public boolean equals(Object other) {
154 		if (this == other) {
155 			return true;
156 		}
157 		if (!(other instanceof SortDefinition)) {
158 			return false;
159 		}
160 		SortDefinition otherSd = (SortDefinition) other;
161 		return (getProperty().equals(otherSd.getProperty()) &&
162 		    isAscending() == otherSd.isAscending() && isIgnoreCase() == otherSd.isIgnoreCase());
163 	}
164 
165 	@Override
hashCode()166 	public int hashCode() {
167 		int hashCode = getProperty().hashCode();
168 		hashCode = 29 * hashCode + (isIgnoreCase() ? 1 : 0);
169 		hashCode = 29 * hashCode + (isAscending() ? 1 : 0);
170 		return hashCode;
171 	}
172 
173 }
174