View Javadoc

1   /*
2    * Copyright (c) 2003-2008 by Cosylab d. d.
3    *
4    * This file is part of CosyBeans-Common.
5    *
6    * CosyBeans-Common is free software: you can redistribute it and/or modify
7    * it under the terms of the GNU General Public License as published by
8    * the Free Software Foundation, either version 3 of the License, or
9    * (at your option) any later version.
10   *
11   * CosyBeans-Common is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   * GNU General Public License for more details.
15   *
16   * You should have received a copy of the GNU General Public License
17   * along with CosyBeans-Common.  If not, see <http://www.gnu.org/licenses/>.
18   */
19  
20  package com.cosylab.gui.components.numberfield;
21  
22  import com.cosylab.logging.DebugLogger;
23  
24  import com.cosylab.util.PrintfFormat;
25  import com.cosylab.util.StringUtilities;
26  
27  import java.util.logging.Level;
28  import java.util.logging.Logger;
29  
30  
31  /**
32   * AnglesNumberDescriptor displays double as angle string.
33   *
34   * @author <a href="mailto:igor.kriznar@cosylab.com">Igor Kriznar</a>
35   */
36  public class AngleNumberDescriptor implements NumberDescriptor
37  {
38  	/**
39  	 * @see NumberDescriptor
40  	 */
41  	public final static String NAME = "Angle Visualization";
42  
43  	/**
44  	 * @see NumberDescriptor
45  	 */
46  	public final static String DESCRIPTION = "Displays double value in degree format: XX\u00B0XX'XX\".";
47  	private final Logger logger = DebugLogger.getLogger("AND", Level.OFF);
48  	private char secondSeparator = '"';
49  	private char minuteSeparator = '\'';
50  	private char degreeSeparator = '\u00B0';
51  	private Class numberType;
52  	private String format;
53  	private PrintfFormat formatter;
54  	private boolean useFullFormat = false;
55  	private int decimals=0;
56  
57  	/**
58  	 * Creates a new AngleNumberDescriptor object.
59  	 */
60  	public AngleNumberDescriptor()
61  	{
62  		super();
63  	}
64  
65  	/**
66  	 * Creates a new AngleNumberDescriptor object.
67  	 *
68  	 * @param full if <code>true</code> number is printed in full format
69  	 */
70  	public AngleNumberDescriptor(boolean full)
71  	{
72  		this();
73  		useFullFormat = full;
74  	}
75  
76  	/**
77  	 * Creates a new AngleNumberDescriptor with specified separator characters.
78  	 *
79  	 * @param degreeSeparator separator after degree part of value
80  	 * @param minuteSeparator separator after minutes part of value
81  	 * @param secondSeparator separator after seconds part of value, if 0 it is
82  	 *        not diplayed.
83  	 */
84  	public AngleNumberDescriptor(char degreeSeparator, char minuteSeparator,
85  	    char secondSeparator)
86  	{
87  		this();
88  		setDegreeSeparator(degreeSeparator);
89  		setMinuteSeparator(minuteSeparator);
90  		setSecondSeparator(secondSeparator);
91  	}
92  
93  	/**
94  	 * Creates a new AngleNumberDescriptor with specified separator characters.
95  	 *
96  	 * @param degreeSeparator separator after degree part of value
97  	 * @param minuteSeparator separator after minutes part of value
98  	 * @param secondSeparator separator after seconds part of value, if 0 it is
99  	 *        not diplayed.
100 	 * @param full if <code>true</code> number is printed in full format
101 	 */
102 	public AngleNumberDescriptor(char degreeSeparator, char minuteSeparator,
103 	    char secondSeparator, boolean full)
104 	{
105 		this(degreeSeparator, minuteSeparator, secondSeparator);
106 		useFullFormat = full;
107 	}
108 
109 	/**
110 	 * Test applet
111 	 *
112 	 * @param args cmd
113 	 */
114 	public static void main(String[] args)
115 	{
116 		AngleNumberDescriptor a = new AngleNumberDescriptor();
117 
118 		Double d = new Double(3.4434);
119 		String s = a.printString(d);
120 		System.out.println(d + " -> " + s + " -> " + a.parseNumber(s));
121 	}
122 
123 	/*
124 	 * (non-Javadoc)
125 	 *
126 	 * @see com.cosylab.gui.components.numberfield.NumberDescriptor#parseNumber(java.lang.String)
127 	 */
128 	public Number parseNumber(String number)
129 	{
130 		logger.info("parsing '" + number + "'");
131 
132 		try {
133 			double deg = 0.0;
134 			double min = 0.0;
135 			double sec = 0.0;
136 			int degI = -1;
137 			int minI = -1;
138 			int secI = -1;
139 			double sign = 1.0;
140 
141 			number = number.trim();
142 
143 			if (number.charAt(0) == '-') {
144 				sign = -1.;
145 				number = number.substring(1);
146 			}
147 
148 			degI = number.indexOf(degreeSeparator);
149 
150 			if (degI == 0) {
151 				number = number.substring(1);
152 			} else if (degI > 0) {
153 				deg = Double.parseDouble(number.substring(0, degI));
154 				number = number.substring(degI + 1);
155 			}
156 
157 			minI = number.indexOf(minuteSeparator);
158 
159 			if (minI == 0) {
160 				number = number.substring(1);
161 			} else if (minI > 0) {
162 				min = Double.parseDouble(number.substring(0, minI)) / 60.0;
163 				number = number.substring(minI + 1);
164 			}
165 
166 			if (secondSeparator > 0) {
167 				secI = number.indexOf(secondSeparator);
168 
169 				if (secI == 0) {
170 					number = number.substring(1);
171 				} else if (secI > 0) {
172 					sec = Double.parseDouble(number.substring(0, secI)) / 3600.0;
173 					number = number.substring(secI + 1);
174 				}
175 			}
176 
177 			/*if (degI > -1 || minI > -1) {
178 			    sec = StringUtilities.parseDouble(number) / 3600.0;
179 			    number = "";
180 			}*/
181 			if (degI < 0 && minI < 0 && secI < 0) {
182 				deg = StringUtilities.parseDouble(number);
183 			} else if (number.length() > 0) {
184 				if (degI > -1 && minI < 0 && secI < 0) {
185 					min = StringUtilities.parseDouble(number) / 60.0;
186 				} else if (minI > -1 && secI < 0) {
187 					sec = StringUtilities.parseDouble(number) / 3600.0;
188 				} else {
189 					logger.info("returning 'null'");
190 
191 					return null;
192 				}
193 			}
194 
195 			double d = sign * (deg + min + sec);
196 
197 			if (Double.isNaN(d)) {
198 				logger.info("returning 'null' for NaN");
199 
200 				return null;
201 			}
202 
203 			logger.info("returning '" + d + "'");
204 
205 			return new Double(d);
206 		} catch (Exception e) {
207 			logger.info("returning 'null' for " + e);
208 
209 			return null;
210 		}
211 	}
212 
213 	/*
214 	 * (non-Javadoc)
215 	 *
216 	 * @see com.cosylab.gui.components.numberfield.NumberDescriptor#toString(java.lang.Number)
217 	 */
218 	public String printString(Number number)
219 	{
220 		logger.info("value '" + number + "'");
221 
222 		double value = number.doubleValue();
223 		StringBuffer sb = new StringBuffer();
224 
225 		if (value < 0) {
226 			sb.append('-');
227 			value = Math.abs(value);
228 		}
229 
230 		double tmp1 = Math.floor(value);
231 		value = (value - tmp1) * 60.0;
232 		double tmp2 = Math.floor(value);
233 		value = (value - tmp2) * 60.0;
234 
235 		// solve seconds rounding problem
236 		if (formatter != null) {
237 			if (decimals==0) {
238 				value= Math.round(value);
239 			} else {
240 				value= Math.floor(value*Math.pow(10.0,decimals)+0.5)/Math.pow(10.0,decimals);
241 			}
242 			if (value>=60.0) {
243 				value-=60.0;
244 				tmp2+=1.0;
245 				if (tmp2>=60.0) {
246 					tmp2-=60;
247 					tmp1+=1.0;
248 				}
249 			}
250 		}
251 		
252 		if (((int)tmp1) < 10) {
253 			sb.append('0');
254 		}
255 
256 		sb.append((int)tmp1);
257 		sb.append(degreeSeparator);
258 
259 
260 		if (tmp2 > 0.0000001 || useFullFormat) {
261 			if (((int)tmp2) < 10) {
262 				sb.append('0');
263 			}
264 
265 			sb.append((int)tmp2);
266 			sb.append(minuteSeparator);
267 
268 
269 			//tmp= Math.floor(value);
270 			if (value > 0.0000001 || useFullFormat) {
271 				if (((int)value) < 10) {
272 					sb.append('0');
273 				}
274 
275 				if (formatter != null) {
276 					String s = formatter.sprintf(value).trim();
277 
278 					if (s.charAt(0) == '+') {
279 						s = s.substring(1);
280 					}
281 
282 					sb.append(s);
283 				} else {
284 					sb.append(value);
285 				}
286 
287 				if (secondSeparator != 0) {
288 					sb.append(secondSeparator);
289 				}
290 			}
291 		}
292 
293 		logger.info("string '" + sb.toString() + "'");
294 
295 		return sb.toString();
296 	}
297 
298 	/* (non-Javadoc)
299 	 * @see com.cosylab.gui.components.numberfield.NumberDescriptor#toEditString(java.lang.Number)
300 	 */
301 	public String printEditString(Number number)
302 	{
303 		return printString(number).trim();
304 	}
305 
306 	/*
307 	 * (non-Javadoc)
308 	 *
309 	 * @see com.cosylab.gui.components.numberfield.NumberDescriptor#getFormat()
310 	 */
311 	public String getFormat()
312 	{
313 		return format;
314 	}
315 
316 	/*
317 	 * (non-Javadoc)
318 	 *
319 	 * @see com.cosylab.gui.components.numberfield.NumberDescriptor#setFormt(java.lang.String)
320 	 */
321 	public void setFormat(String newFormat)
322 	{
323 		format = newFormat;
324 		if (format==null) {
325 			formatter=null;
326 		} else {
327 			formatter = new PrintfFormat(format);
328 			decimals=0;
329 			int dot= format.indexOf('.');
330 			if (dot>0) {
331 				int f= format.indexOf('f',dot);
332 				if (f>0) {
333 					decimals= Integer.parseInt(format.substring(dot+1,f));
334 				}
335 			}
336 		}
337 	}
338 
339 	/*
340 	 * (non-Javadoc)
341 	 *
342 	 * @see com.cosylab.gui.components.numberfield.NumberDescriptor#setNumberType(java.lang.Class)
343 	 */
344 	public void setNumberType(Class newNumberFormat)
345 	{
346 		numberType = newNumberFormat;
347 	}
348 
349 	/*
350 	 * (non-Javadoc)
351 	 *
352 	 * @see com.cosylab.gui.components.numberfield.NumberDescriptor#getNumberType()
353 	 */
354 	public Class getNumberType()
355 	{
356 		return numberType;
357 	}
358 
359 	/**
360 	 * Separator printed after integral part of number, thus degree sign \u00B0
361 	 * by default.
362 	 *
363 	 * @return separator after degree part
364 	 */
365 	public char getDegreeSeparator()
366 	{
367 		return degreeSeparator;
368 	}
369 
370 	/**
371 	 * Separator printed after integral part of minutes, thus minutes sign ' in
372 	 * degree notation by default.
373 	 *
374 	 * @return separator after minutes part
375 	 */
376 	public char getMinuteSeparator()
377 	{
378 		return minuteSeparator;
379 	}
380 
381 	/**
382 	 * Sets separator printed after integral part of minutes (60 minutes is one
383 	 * degree), thus minutes sign ' in degree notation by default.
384 	 *
385 	 * @param minuteSeparator new separator after minutes part
386 	 */
387 	public void setMinuteSeparator(char minuteSeparator)
388 	{
389 		this.minuteSeparator = minuteSeparator;
390 	}
391 
392 	/**
393 	 * Separator printed after seconds (60 seconds is one minute), thus seconds
394 	 * sign " in degree notation by default. If 0 then is not printed.
395 	 *
396 	 * @return separator after seconds part
397 	 */
398 	public char getSecondSeparator()
399 	{
400 		return secondSeparator;
401 	}
402 
403 	/**
404 	 * Sets separator printed after seconds (60 seconds is one minute), thus
405 	 * seconds sign " in degree notation by default. If 0 then is not printed.
406 	 *
407 	 * @param secondSeparator new separator after seconds part
408 	 */
409 	public void setSecondSeparator(char secondSeparator)
410 	{
411 		this.secondSeparator = secondSeparator;
412 	}
413 
414 	/**
415 	 * Separator printed after integral part of number, thus degree sign \u00B0
416 	 * by default.
417 	 *
418 	 * @param degreeSeparator new separator after degree part
419 	 */
420 	public void setDegreeSeparator(char degreeSeparator)
421 	{
422 		this.degreeSeparator = degreeSeparator;
423 	}
424 
425 	/**
426 	 * If <code>true</code> then value is printed in full format with all
427 	 * separators, thus 0 is printed as 00\u00B000'00"
428 	 *
429 	 * @return if <code>true</code> number is printed in full format
430 	 */
431 	public boolean isUseFullFormat()
432 	{
433 		return useFullFormat;
434 	}
435 
436 	/**
437 	 * If set to <code>true</code> then value is printed in full format with
438 	 * all separators, thus 0 is printed as 00\u00B000'00"
439 	 *
440 	 * @param useFullFormat new full print flag
441 	 */
442 	public void setUseFullFormat(boolean useFullFormat)
443 	{
444 		this.useFullFormat = useFullFormat;
445 	}
446 }
447 
448 /* __oOo__ */