View Javadoc
1   /*
2    * Copyright 2012 Olivier Godineau
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5    * use this file except in compliance with the License. You may obtain a copy of
6    * the License at http://www.apache.org/licenses/LICENSE-2.0
7    * 
8    * Unless required by applicable law or agreed to in writing, software
9    * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11   * License for the specific language governing permissions and limitations under
12   * the License.
13   */
14  package olg.csv.base;
15  
16  /**
17   * Cell in a spreadsheet. Impoverished model to be conformed with use of CSV.
18   * 
19   * @author Olivier Godineau
20   * @see Row
21   */
22  public class Cell {
23  
24  	/**
25  	 * Reg Exp to validate num Cell format.
26  	 */
27  	private static final String FORMAT_NUM_REGEXP = "(:?[A-Z]+)|(:?\\d+)";
28  
29  	/**
30  	 * NB alpha char.
31  	 */
32  	private static final int NB_CHAR = 26;
33  	/**
34  	 * A char as byte.
35  	 */
36  	private static final byte CHAR_A = 64;
37  
38  	/**
39  	 * the cell num in its row.
40  	 */
41  	private final int num;
42  	/**
43  	 * The value of the cell.
44  	 */
45  	private final String value;
46  
47  	/**
48  	 * Interprets the String in argument as a cell number. Two ways :
49  	 * <ul>
50  	 * <li>This argument is an non negative integer</li>
51  	 * <li>this argument is a string in Sheet cell number format (as C, AB ,...</li>
52  	 * </ul>
53  	 * 
54  	 * @param num
55  	 *            the num cell. Must match one of the two cases see above.
56  	 * @return the cell num as integer.
57  	 * 
58  	 */
59  	public static int fromSheetCellNumber(String num) {
60  		int retour;
61  		if (num == null || !num.matches(FORMAT_NUM_REGEXP)) {
62  			throw new IllegalArgumentException(String.format(
63  					"fromSheetCellNumber argument num[%s] must match ([A-Z]+) regex " + "or be a non negative integer",
64  					num));
65  		}
66  		if (num.matches("(:?\\d+)")) {
67  			retour = Integer.parseInt(num);
68  		} else {
69  			retour = fromSheetFormatNumber(num);
70  		}
71  		return retour;
72  	}
73  
74  	/**
75  	 * Returns a num cell in a spreadsheet cell number format.
76  	 * 
77  	 * @param num
78  	 *            . Must be >=0.
79  	 * @return the num as a spreadsheet cell number
80  	 */
81  	public static String getSheetFormatNumber(int num) {
82  		int curr = num + 1;
83  		StringBuilder retour = new StringBuilder();
84  		do {
85  			int mod = curr % NB_CHAR;
86  			mod = (mod == 0 ? NB_CHAR : mod);
87  
88  			retour.insert(0, ((char) (CHAR_A + mod)));
89  			curr -= mod;
90  
91  		} while ((curr = curr / NB_CHAR) != 0);
92  
93  		return retour.toString();
94  	}
95  
96  	/**
97  	 * Returns the default cell name.
98  	 * 
99  	 * @param num
100 	 *            the num of a cell.
101 	 * @return the default cell name.
102 	 */
103 	public static String defaultCellName(String num) {
104 		if (num == null || !num.matches(FORMAT_NUM_REGEXP)) {
105 			throw new IllegalArgumentException(String.format(
106 					"defaultCellName argument num[%s] must match ([A-Z]+) regex or be a non negative integer", num));
107 		}
108 		String cellNum = num;
109 		if (num.matches("(:?\\d+)")) {
110 			cellNum = getSheetFormatNumber(Integer.parseInt(num));
111 		}
112 		return "column_" + cellNum;
113 	}
114 	/**
115 	 * 
116 	 * @param num
117 	 *            column number. Must be >= 0.
118 	 * @param value
119 	 *            cell value
120 	 */
121 	public Cell(int num, String value) {
122 		super();
123 		if (num < 0) {
124 			throw new IllegalArgumentException(String.format(
125 					"Cell constructor argument num[%s] must be a positive integer", num));
126 		}
127 		this.num = num;
128 		this.value = value;
129 	}
130 
131 	/**
132 	 * 
133 	 * @param num
134 	 *            column number
135 	 * @param value
136 	 *            cell value
137 	 */
138 	public Cell(String num, String value) {
139 		super();
140 		this.num = Cell.fromSheetCellNumber(num);
141 		this.value = value;
142 	}
143 
144 	/**
145 	 * Column number of this cell among parent row cells.
146 	 * 
147 	 * @return the cell num.
148 	 */
149 	public int getNum() {
150 		return num;
151 	}
152 
153 	/**
154 	 * Returns the value of this cell.
155 	 * 
156 	 * @return <code>null</code> if this cell is empty.
157 	 */
158 	public String getValue() {
159 		return value;
160 	}
161 
162 	/**
163 	 * Returns true if this cell represents an empty cell.
164 	 * 
165 	 * @return true if cell is empty.
166 	 */
167 	public boolean isEmpty() {
168 		return value == null;
169 	}
170 
171 	/**
172 	 * Returns the column number of this cell in a spreadsheet format ( A for 0,
173 	 * AA for 26, ...).
174 	 * 
175 	 * @return the column number in a sheet format.
176 	 */
177 	public String getSheetFormatNumber() {
178 		return getSheetFormatNumber(num);
179 	}
180 
181 	/**
182 	 * Returns the couple (num: value) that this cell represents.
183 	 * 
184 	 * @return the cell string representation.
185 	 */
186 	public String toString() {
187 		return "(" + num + ":" + value + ")";
188 	}
189 
190 	@Override
191 	public int hashCode() {
192 		final int prime = 31; // NOPMD by olivier on 27/01/12 00:28
193 		int result = 1;
194 		result = prime * result + num;
195 		return result;
196 	}
197 
198 	@Override
199 	public boolean equals(Object obj) {
200 		boolean retour = true;
201 		if (this != obj) {
202 			if (obj == null || getClass() != obj.getClass()) {
203 				retour = false;
204 			} else {
205 				retour = num != ((Cell) obj).num;
206 			}
207 		}
208 
209 		return retour;
210 	}
211 
212 	/**
213 	 * Returns the column number.
214 	 * 
215 	 * @param num
216 	 *            column number in a spreadsheet format.
217 	 * @return the column number.
218 	 */
219 	private static int fromSheetFormatNumber(final String num) {
220 		int retour = 0;
221 		int multi = 1;
222 
223 		char[] chars = num.toCharArray();
224 		for (int i = chars.length - 1; i >= 0; i--) {
225 			retour += multi * (((byte) chars[i] - CHAR_A));
226 			multi *= NB_CHAR;
227 		}
228 
229 		return retour - 1;
230 	}
231 }