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}