Source Code Cross Referenced for DateIterator.java in  » GIS » GeoTools-2.4.1 » org » geotools » axis » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » GIS » GeoTools 2.4.1 » org.geotools.axis 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         *    GeoTools - OpenSource mapping toolkit
003:         *    http://geotools.org
004:         *    (C) 2003-2006, Geotools Project Managment Committee (PMC)
005:         *    (C) 2000, Institut de Recherche pour le Développement
006:         *    (C) 1999, Pêches et Océans Canada
007:         *
008:         *    This library is free software; you can redistribute it and/or
009:         *    modify it under the terms of the GNU Lesser General Public
010:         *    License as published by the Free Software Foundation; either
011:         *    version 2.1 of the License, or (at your option) any later version.
012:         *
013:         *    This library is distributed in the hope that it will be useful,
014:         *    but WITHOUT ANY WARRANTY; without even the implied warranty of
015:         *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
016:         *    Lesser General Public License for more details.
017:         */
018:        package org.geotools.axis;
019:
020:        // Date and time
021:        import java.io.PrintWriter;
022:        import java.io.StringWriter;
023:        import java.text.DateFormat;
024:        import java.util.Arrays;
025:        import java.util.Calendar;
026:        import java.util.Date;
027:        import java.util.Locale;
028:        import java.util.TimeZone;
029:
030:        /**
031:         * Itérateur balayant les barres et étiquettes de graduation d'un axe du temps. Cet itérateur
032:         * retourne les positions des graduations à partir de la date la plus ancienne jusqu'à la date
033:         * la plus récente. Il choisit les intervalles de graduation en supposant qu'on utilise un
034:         * calendrier grégorien.
035:         *
036:         * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/extension/widgets-swing/src/main/java/org/geotools/axis/DateIterator.java $
037:         * @version $Id: DateIterator.java 20883 2006-08-07 13:48:09Z jgarnett $
038:         * @author Martin Desruisseaux
039:         */
040:        final class DateIterator implements  TickIterator {
041:            /**
042:             * Nombre de millisecondes dans certaines unités de temps.
043:             */
044:            private static final long SEC = 1000, MIN = 60 * SEC,
045:                    HRE = 60 * MIN, DAY = 24 * HRE, YEAR = 365 * DAY
046:                            + (DAY / 4) - (DAY / 100) + (DAY / 400),
047:                    MNT = YEAR / 12;
048:
049:            /**
050:             * Liste des intervales souhaités pour la graduation. Les éléments de
051:             * cette table doivent obligatoirement apparaître en ordre croissant.
052:             * Voici un exemple d'interprétation: la présence de {@@code 5*MIN}
053:             * suivit de {@code 10*MIN} implique que si le pas estimé se trouve
054:             * entre 5 et 10 minutes, ce sera le pas de 10 minutes qui sera sélectionné.
055:             */
056:            private static final long[] INTERVAL = { SEC, 2 * SEC, 5 * SEC,
057:                    10 * SEC, 15 * SEC, 20 * SEC, 30 * SEC, MIN, 2 * MIN,
058:                    5 * MIN, 10 * MIN, 15 * MIN, 20 * MIN, 30 * MIN, HRE,
059:                    2 * HRE, 3 * HRE, 4 * HRE, 6 * HRE, 8 * HRE, 12 * HRE, DAY,
060:                    2 * DAY, 3 * DAY, 7 * DAY, 14 * DAY, 21 * DAY, MNT,
061:                    2 * MNT, 3 * MNT, 4 * MNT, 6 * MNT, YEAR, 2 * YEAR,
062:                    3 * YEAR, 4 * YEAR, 5 * YEAR };
063:
064:            /**
065:             * Intervalles des graduations principales et des sous-graduations correspondants
066:             * à chaque des intervalles du tableau {@link #INTERVAL}.  Cette classe cherchera
067:             * d'abord un intervalle en millisecondes dans le tableau {@link #INTERVAL}, puis
068:             * traduira cet intervalle en champ du calendrier grégorien en lisant les éléments
069:             * correspondants de ce tableau {@link #ROLL}.
070:             */
071:            private static final byte[] ROLL = {
072:                    1,
073:                    (byte) Calendar.SECOND,
074:                    25,
075:                    (byte) Calendar.MILLISECOND, // x10 millis
076:                    2,
077:                    (byte) Calendar.SECOND,
078:                    50,
079:                    (byte) Calendar.MILLISECOND, // x10 millis
080:                    5, (byte) Calendar.SECOND, 1, (byte) Calendar.SECOND, 10,
081:                    (byte) Calendar.SECOND, 2, (byte) Calendar.SECOND, 15,
082:                    (byte) Calendar.SECOND, 5, (byte) Calendar.SECOND, 20,
083:                    (byte) Calendar.SECOND, 5, (byte) Calendar.SECOND, 30,
084:                    (byte) Calendar.SECOND, 5, (byte) Calendar.SECOND, 1,
085:                    (byte) Calendar.MINUTE, 10, (byte) Calendar.SECOND, 2,
086:                    (byte) Calendar.MINUTE, 30, (byte) Calendar.SECOND, 5,
087:                    (byte) Calendar.MINUTE, 1, (byte) Calendar.MINUTE, 10,
088:                    (byte) Calendar.MINUTE, 2, (byte) Calendar.MINUTE, 15,
089:                    (byte) Calendar.MINUTE, 5, (byte) Calendar.MINUTE, 20,
090:                    (byte) Calendar.MINUTE, 5, (byte) Calendar.MINUTE, 30,
091:                    (byte) Calendar.MINUTE, 5, (byte) Calendar.MINUTE, 1,
092:                    (byte) Calendar.HOUR_OF_DAY, 15, (byte) Calendar.MINUTE, 2,
093:                    (byte) Calendar.HOUR_OF_DAY, 30, (byte) Calendar.MINUTE, 3,
094:                    (byte) Calendar.HOUR_OF_DAY, 30, (byte) Calendar.MINUTE, 4,
095:                    (byte) Calendar.HOUR_OF_DAY, 1,
096:                    (byte) Calendar.HOUR_OF_DAY, 6,
097:                    (byte) Calendar.HOUR_OF_DAY, 1,
098:                    (byte) Calendar.HOUR_OF_DAY, 8,
099:                    (byte) Calendar.HOUR_OF_DAY, 2,
100:                    (byte) Calendar.HOUR_OF_DAY, 12,
101:                    (byte) Calendar.HOUR_OF_DAY, 2,
102:                    (byte) Calendar.HOUR_OF_DAY, 1,
103:                    (byte) Calendar.DAY_OF_MONTH, 4,
104:                    (byte) Calendar.HOUR_OF_DAY, 2,
105:                    (byte) Calendar.DAY_OF_MONTH, 6,
106:                    (byte) Calendar.HOUR_OF_DAY, 3,
107:                    (byte) Calendar.DAY_OF_MONTH, 12,
108:                    (byte) Calendar.HOUR_OF_DAY, 7,
109:                    (byte) Calendar.DAY_OF_MONTH, 1,
110:                    (byte) Calendar.DAY_OF_MONTH, 14,
111:                    (byte) Calendar.DAY_OF_MONTH, 2,
112:                    (byte) Calendar.DAY_OF_MONTH, 21,
113:                    (byte) Calendar.DAY_OF_MONTH, 7,
114:                    (byte) Calendar.DAY_OF_MONTH, 1, (byte) Calendar.MONTH, 7,
115:                    (byte) Calendar.DAY_OF_MONTH, 2, (byte) Calendar.MONTH, 14,
116:                    (byte) Calendar.DAY_OF_MONTH, 3, (byte) Calendar.MONTH, 14,
117:                    (byte) Calendar.DAY_OF_MONTH, 4, (byte) Calendar.MONTH, 1,
118:                    (byte) Calendar.MONTH, 6, (byte) Calendar.MONTH, 1,
119:                    (byte) Calendar.MONTH, 1, (byte) Calendar.YEAR, 2,
120:                    (byte) Calendar.MONTH, 2, (byte) Calendar.YEAR, 4,
121:                    (byte) Calendar.MONTH, 3, (byte) Calendar.YEAR, 6,
122:                    (byte) Calendar.MONTH, 4, (byte) Calendar.YEAR, 1,
123:                    (byte) Calendar.YEAR, 5, (byte) Calendar.YEAR, 1,
124:                    (byte) Calendar.YEAR };
125:
126:            /**
127:             * Nombre de colonne dans le tableau {@link ROLL}. Le tableau {@link ROLL} doit être
128:             * interprété comme une matrice de 4 colonnes et d'un nombre indéterminé de lignes.
129:             */
130:            private static final int ROLL_WIDTH = 4;
131:
132:            /**
133:             * Liste des champs de dates qui apparaissent dans le tableau {@link ROLL}. Cette liste
134:             * doit être du champ le plus grand (YEAR) vers le champ le plus petit (MILLISECOND).
135:             */
136:            private static final int[] FIELD = { Calendar.YEAR, Calendar.MONTH,
137:                    Calendar.DAY_OF_MONTH, Calendar.HOUR_OF_DAY,
138:                    Calendar.MINUTE, Calendar.SECOND, Calendar.MILLISECOND };
139:
140:            /**
141:             * Liste des noms des champs (à des fins de déboguage seulement).
142:             * Cette liste doit être dans le même ordre que les éléments de {@link #FIELD}.
143:             */
144:            private static final String[] FIELD_NAME = { "YEAR", "MONTH",
145:                    "DAY", "HOUR", "MINUTE", "SECOND", "MILLISECOND" };
146:
147:            /**
148:             * Date de la première graduation principale. Cette valeur est fixée par {@link #init}.
149:             */
150:            private long minimum;
151:
152:            /**
153:             * Date limite des graduations. La dernière graduation ne sera pas nécessairement à
154:             * cette date. Cette valeur est fixée par {@link #init}.
155:             */
156:            private long maximum;
157:
158:            /**
159:             * Estimation de l'intervalle entre deux graduations principales.
160:             * Cette valeur est fixée par {@link #init}.
161:             */
162:            private long increment;
163:
164:            /**
165:             * Longueur de l'axe (en points). Cette information est conservée afin d'éviter de
166:             * refaire toute la procédure {@link #init} si les paramètres n'ont pas changés.
167:             */
168:            private float visualLength;
169:
170:            /**
171:             * Espace à laisser (en points) entre les graduations principales.
172:             * Cette information est conservée afin d'éviter de refaire toute
173:             * la procédure {@link #init} si les paramètres n'ont pas changés.
174:             */
175:            private float visualTickSpacing;
176:
177:            /**
178:             * Nombre de fois qu'il faut incrémenter le champ {@link #tickField} du
179:             * calendrier pour passer à la graduation suivante. Cette opération peut
180:             * se faire avec {@code calendar.add(tickField, tickAdd)}.
181:             */
182:            private int tickAdd;
183:
184:            /**
185:             * Champ du calendrier qu'il faut incrémenter pour passer à la graduation suivante.
186:             * Cette opération peut se faire avec {@code calendar.add(tickField, tickAdd)}.
187:             */
188:            private int tickField;
189:
190:            /**
191:             * Nombre de fois qu'il faut incrémenter le champ {@link #tickField} du calendrier pour
192:             * passer à la sous-graduation suivante. Cette opération peut se faire avec
193:             * {@code calendar.add(tickField, tickAdd)}.
194:             */
195:            private int subTickAdd;
196:
197:            /**
198:             * Champ du calendrier qu'il faut incrémenter pour passer à la sous-graduation suivante.
199:             * Cette opération peut se faire avec {@code calendar.add(tickField, tickAdd)}.
200:             */
201:            private int subTickField;
202:
203:            /**
204:             * Date de la graduation principale ou secondaire actuelle.
205:             * Cette valeur sera modifiée à chaque appel à {@link #next}.
206:             */
207:            private long value;
208:
209:            /**
210:             * Date de la prochaine graduation principale. Cette
211:             * valeur sera modifiée à chaque appel à {@link #next}.
212:             */
213:            private long nextTick;
214:
215:            /**
216:             * Date de la prochaine graduation secondaire. Cette
217:             * valeur sera modifiée à chaque appel à {@link #next}.
218:             */
219:            private long nextSubTick;
220:
221:            /**
222:             * Indique si {@link #value} représente une graduation principale.
223:             */
224:            private boolean isMajorTick;
225:
226:            /**
227:             * Valeurs de {@link #value}, {@link #nextTick} et {@link #nextSubTick0}
228:             * immédiatement après l'appel de {@link #rewind}.
229:             */
230:            private long value0, nextTick0, nextSubTick0;
231:
232:            /**
233:             * Valeur de {@link #isMajorTick} immédiatement après l'appel de {@link #rewind}.
234:             */
235:            private boolean isMajorTick0;
236:
237:            /**
238:             * Calendrier servant à avancer d'une certaine période de temps (jour, semaine, mois...).
239:             * <strong>Note: Par convention et pour des raisons de performances (pour éviter d'imposer
240:             * au calendrier de recalculer ses champs trop souvent), ce calendrier devrait toujours
241:             * contenir la date {@link #nextSubTick}.
242:             */
243:            private Calendar calendar;
244:
245:            /**
246:             * Objet temporaire à utiliser pour passer des dates
247:             * en argument à {@link #calendar} et {@link #format}.
248:             */
249:            private final Date date = new Date();
250:
251:            /**
252:             * Format à utiliser pour écrire les étiquettes de graduation. Ce format ne
253:             * sera construit que la première fois où {@link #currentLabel} sera appelée.
254:             */
255:            private transient DateFormat format;
256:
257:            /**
258:             * Code du format utilisé pour construire le champ de date de {@link #format}. Les codes
259:             * valides sont notamment  {@link DateFormat#SHORT}, {@link DateFormat#MEDIUM} ou {@link
260:             * DateFormat#LONG}. La valeur -1 indique que le format ne contient pas de champ de date,
261:             * seulement un champ des heures.
262:             */
263:            private transient int dateFormat = -1;
264:
265:            /**
266:             * Code du format utilisé pour construire le champ des heures de {@link #format}. Les codes
267:             * valides sont notamment  {@link DateFormat#SHORT},  {@link DateFormat#MEDIUM}  ou  {@link
268:             * DateFormat#LONG}. La valeur -1 indique que le format ne contient pas de champ des heures,
269:             * seulement un champ de date.
270:             */
271:            private transient int timeFormat = -1;
272:
273:            /**
274:             * Indique si {@link #format} est valide. Le format peut devenir invalide si {@link #init} a
275:             * été appelée. Dans ce cas, il peut falloir changer le nombre de chiffres après la virgule
276:             * qu'il écrit.
277:             */
278:            private transient boolean formatValid;
279:
280:            /**
281:             * Conventions à utiliser pour le formatage des nombres.
282:             */
283:            private Locale locale;
284:
285:            /**
286:             * Construit un itérateur pour la graduation d'un axe du temps. La méthode {@link #init}
287:             * <u>doit</u> être appelée avant que l'itérateur ne soit utilisable.
288:             *
289:             * @param timezone Fuseau horaire des dates.
290:             * @param locale   Conventions à utiliser pour le formatage des dates.
291:             */
292:            protected DateIterator(final TimeZone timezone, final Locale locale) {
293:                assert INTERVAL.length * ROLL_WIDTH == ROLL.length;
294:                calendar = Calendar.getInstance(timezone, locale);
295:                this .locale = locale;
296:            }
297:
298:            /**
299:             * Initialise l'itérateur.
300:             *
301:             * @param minimum         Date minimale de la première graduation.
302:             * @param maximum         Date limite des graduations. La dernière graduation
303:             *                        ne sera pas nécessairement à cette date.
304:             * @param visualLength    Longueur visuelle de l'axe sur laquelle tracer la graduation.
305:             *                        Cette longueur doit être exprimée en pixels ou en points.
306:             * @param visualTickSpace Espace à laisser visuellement entre deux marques de graduation.
307:             *                        Cet espace doit être exprimé en pixels ou en points (1/72 de pouce).
308:             */
309:            protected void init(final long minimum, final long maximum,
310:                    final float visualLength, final float visualTickSpacing) {
311:                if (minimum == this .minimum && maximum == this .maximum
312:                        && visualLength == this .visualLength
313:                        && visualTickSpacing == this .visualTickSpacing) {
314:                    rewind();
315:                    return;
316:                }
317:                AbstractGraduation.ensureNonNull("visualLength", visualLength);
318:                AbstractGraduation.ensureNonNull("visualTickSpacing",
319:                        visualTickSpacing);
320:                this .visualLength = visualLength;
321:                this .visualTickSpacing = visualTickSpacing;
322:                this .formatValid = false;
323:                this .minimum = minimum;
324:                this .maximum = maximum;
325:                this .increment = Math.round((maximum - minimum)
326:                        * ((double) visualTickSpacing / (double) visualLength));
327:                /*
328:                 * Après avoir fait une estimation de l'intervalle d'échantillonage,
329:                 * vérifie si on trouve cette estimation dans le tableau 'INTERVAL'.
330:                 * Si on trouve la valeur exacte, tant mieux! Sinon, on cherchera
331:                 * l'intervalle le plus proche.
332:                 */
333:                int index = Arrays.binarySearch(INTERVAL, increment);
334:                if (index < 0) {
335:                    index = ~index;
336:                    if (index == 0) {
337:                        // L'intervalle est plus petit que le
338:                        // plus petit élément de 'INTERVAL'.
339:                        round(Calendar.MILLISECOND);
340:                        findFirstTick();
341:                        return;
342:                    } else if (index >= INTERVAL.length) {
343:                        // L'intervalle est plus grand que le
344:                        // plus grand élément de 'INTERVAL'.
345:                        increment /= YEAR;
346:                        round(Calendar.YEAR);
347:                        increment *= YEAR;
348:                        findFirstTick();
349:                        return;
350:                    } else {
351:                        // L'index pointe vers un intervalle plus grand que
352:                        // l'intervalle demandé. Vérifie si l'intervalle
353:                        // inférieur ne serait pas plus proche.
354:                        if (increment - INTERVAL[index - 1] < INTERVAL[index]
355:                                - increment) {
356:                            index--;
357:                        }
358:                    }
359:                }
360:                this .increment = INTERVAL[index];
361:                index *= ROLL_WIDTH;
362:                this .tickAdd = ROLL[index + 0];
363:                this .tickField = ROLL[index + 1];
364:                this .subTickAdd = ROLL[index + 2];
365:                this .subTickField = ROLL[index + 3];
366:                if (subTickField == Calendar.MILLISECOND) {
367:                    subTickAdd *= 10;
368:                }
369:                findFirstTick();
370:            }
371:
372:            /**
373:             * Arrondi {@link #increment} à un nombre qui se lit bien. Le nombre
374:             * choisit sera un de ceux de la suite 1, 2, 5, 10, 20, 50, 100, 200, 500, etc.
375:             */
376:            private void round(final int field) {
377:                int factor = 1;
378:                while (factor <= increment) {
379:                    factor *= 10;
380:                }
381:                if (factor >= 10) {
382:                    factor /= 10;
383:                }
384:                increment /= factor;
385:                if (increment <= 0)
386:                    increment = 1;
387:                else if (increment >= 3 && increment <= 4)
388:                    increment = 5;
389:                else if (increment >= 6)
390:                    increment = 10;
391:                increment = Math.max(increment * factor, 5);
392:                tickAdd = (int) increment;
393:                subTickAdd = (int) (increment / (increment == 2 ? 4 : 5));
394:                tickField = field;
395:                subTickField = field;
396:            }
397:
398:            /**
399:             * Replace l'itérateur sur la première graduation. La position de la première graduation
400:             * sera calculée et retenue pour un positionnement plus rapide à l'avenir.
401:             */
402:            private void findFirstTick() {
403:                calendar.clear();
404:                value = minimum;
405:                date.setTime(value);
406:                calendar.setTime(date);
407:                if (true) {
408:                    // Arrondie la date de départ. Note: ce calcul exige que
409:                    // tous les champs commencent à 0 plutôt que 1, y compris
410:                    // les mois et le jour du mois.
411:                    final int offset = calendar.getActualMinimum(tickField);
412:                    int toRound = calendar.get(tickField) - offset;
413:                    toRound = (toRound / tickAdd) * tickAdd;
414:                    calendar.set(tickField, toRound + offset);
415:                }
416:                truncate(calendar, tickField);
417:                nextTick = calendar.getTime().getTime();
418:                nextSubTick = nextTick;
419:                while (nextTick < minimum) {
420:                    calendar.add(tickField, tickAdd);
421:                    nextTick = calendar.getTime().getTime();
422:                }
423:                date.setTime(nextSubTick);
424:                calendar.setTime(date);
425:                while (nextSubTick < minimum) {
426:                    calendar.add(subTickField, subTickAdd);
427:                    nextSubTick = calendar.getTime().getTime();
428:                }
429:                /* 'calendar' a maintenant la valeur 'nextSubTick', comme le veut la spécification de
430:                 * ce champ. On appelle maintenant 'next' pour transférer cette valeur 'nextSubTick'
431:                 * vers 'value'. Notez que 'next' peut être appelée même si value>maximum.
432:                 */
433:                next();
434:
435:                // Retient les positions trouvées.
436:                this .value0 = this .value;
437:                this .nextTick0 = this .nextTick;
438:                this .nextSubTick0 = this .nextSubTick;
439:                this .isMajorTick0 = this .isMajorTick;
440:
441:                assert calendar.getTime().getTime() == nextSubTick;
442:            }
443:
444:            /**
445:             * Met à 0 tous les champs du calendrier inférieur au champ {@code field}
446:             * spécifié. Note: si le calendrier spécifié est {@link #calendar},  il est de
447:             * la responsabilité de l'appelant de restituer {@link #calendar} dans son état
448:             * correct après l'appel de cette méthode.
449:             */
450:            private static void truncate(final Calendar calendar, int field) {
451:                for (int i = 0; i < FIELD.length; i++) {
452:                    if (FIELD[i] == field) {
453:                        calendar.get(field); // Force la mise à jour des champs.
454:                        while (++i < FIELD.length) {
455:                            field = FIELD[i];
456:                            calendar.set(field, calendar
457:                                    .getActualMinimum(field));
458:                        }
459:                        break;
460:                    }
461:                }
462:            }
463:
464:            /**
465:             * Indique s'il reste des graduations à retourner. Cette méthode retourne {@code true}
466:             * tant que {@link #currentValue} ou {@link #currentLabel} peuvent être appelées.
467:             */
468:            public boolean hasNext() {
469:                return value <= maximum;
470:            }
471:
472:            /**
473:             * Indique si la graduation courante est une graduation majeure.
474:             *
475:             * @return {@code true} si la graduation courante est une graduation majeure, ou
476:             *         {@code false} si elle est une graduation mineure.
477:             */
478:            public boolean isMajorTick() {
479:                return isMajorTick;
480:            }
481:
482:            /**
483:             * Returns the position where to draw the current tick. The position is scaled
484:             * from the graduation's minimum to maximum. This is usually the same number
485:             * than {@link #currentValue}.
486:             */
487:            public double currentPosition() {
488:                return value;
489:            }
490:
491:            /**
492:             * Retourne la valeur de la graduation courante. Cette méthode
493:             * peut être appelée pour une graduation majeure ou mineure.
494:             */
495:            public double currentValue() {
496:                return value;
497:            }
498:
499:            /**
500:             * Retourne l'étiquette de la graduation courante. On n'appele généralement
501:             * cette méthode que pour les graduations majeures, mais elle peut aussi
502:             * être appelée pour les graduations mineures. Cette méthode retourne
503:             * {@code null} s'il n'y a pas d'étiquette pour la graduation courante.
504:             */
505:            public String currentLabel() {
506:                if (!formatValid) {
507:                    date.setTime(minimum);
508:                    calendar.setTime(date);
509:                    final int firstDay = calendar.get(Calendar.DAY_OF_YEAR);
510:                    final int firstYear = calendar.get(Calendar.YEAR);
511:
512:                    date.setTime(maximum);
513:                    calendar.setTime(date);
514:                    final int lastDay = calendar.get(Calendar.DAY_OF_YEAR);
515:                    final int lastYear = calendar.get(Calendar.YEAR);
516:
517:                    final int dateFormat = (firstYear == lastYear && firstDay == lastDay) ? -1
518:                            : DateFormat.MEDIUM;
519:                    final int timeFormat;
520:
521:                    if (increment >= DAY)
522:                        timeFormat = -1;
523:                    else if (increment >= MIN)
524:                        timeFormat = DateFormat.SHORT;
525:                    else if (increment >= SEC)
526:                        timeFormat = DateFormat.MEDIUM;
527:                    else
528:                        timeFormat = DateFormat.LONG;
529:
530:                    if (dateFormat != this .dateFormat
531:                            || timeFormat != this .timeFormat || format == null) {
532:                        this .dateFormat = dateFormat;
533:                        this .timeFormat = timeFormat;
534:                        if (dateFormat == -1) {
535:                            if (timeFormat == -1) {
536:                                format = DateFormat.getDateInstance(
537:                                        DateFormat.DEFAULT, locale);
538:                            } else {
539:                                format = DateFormat.getTimeInstance(timeFormat,
540:                                        locale);
541:                            }
542:                        } else if (timeFormat == -1) {
543:                            format = DateFormat.getDateInstance(dateFormat,
544:                                    locale);
545:                        } else {
546:                            format = DateFormat.getDateTimeInstance(dateFormat,
547:                                    timeFormat, locale);
548:                        }
549:                        format.setCalendar(calendar);
550:                    }
551:                    formatValid = true;
552:                }
553:                date.setTime(value);
554:                final String label = format.format(date);
555:                // Remet 'calendar' dans l'état qu'il est sencé avoir
556:                // d'après la spécification du champ {@link #calendar}.
557:                date.setTime(nextSubTick);
558:                calendar.setTime(date);
559:                return label;
560:            }
561:
562:            /**
563:             * Passe à la graduation suivante.
564:             */
565:            public void next() {
566:                assert calendar.getTime().getTime() == nextSubTick;
567:                if (nextSubTick < nextTick) {
568:                    isMajorTick = false;
569:                    value = nextSubTick;
570:                    /*
571:                     * IMPORTANT: On suppose ici que 'calendar' a déjà la date 'nextSubTick'. Si ce
572:                     *            n'était pas le cas, il faudrait ajouter les lignes suivantes:
573:                     */
574:                    if (false) {
575:                        date.setTime(value);
576:                        calendar.setTime(date);
577:                        // 'setTime' oblige 'calendar' à recalculer ses
578:                        // champs, ce qui a un impact sur la performance.
579:                    }
580:                    calendar.add(subTickField, subTickAdd);
581:                    nextSubTick = calendar.getTime().getTime();
582:                    // 'calendar' contient maintenant la date 'nextSubTick',
583:                    // comme le veut la spécification du champ {@link #calendar}.
584:                } else {
585:                    nextMajor();
586:                }
587:            }
588:
589:            /**
590:             * Passe directement à la graduation majeure suivante.
591:             */
592:            public void nextMajor() {
593:                isMajorTick = true;
594:                value = nextTick;
595:                date.setTime(value);
596:
597:                calendar.setTime(date);
598:                calendar.add(tickField, tickAdd);
599:                truncate(calendar, tickField);
600:                nextTick = calendar.getTime().getTime();
601:
602:                calendar.setTime(date);
603:                calendar.add(subTickField, subTickAdd);
604:                nextSubTick = calendar.getTime().getTime();
605:                // 'calendar' contient maintenant la date 'nextSubTick',
606:                // comme le veut la spécification du champ {@link #calendar}.
607:            }
608:
609:            /**
610:             * Replace l'itérateur sur la première graduation.
611:             */
612:            public void rewind() {
613:                this .value = value0;
614:                this .nextTick = nextTick0;
615:                this .nextSubTick = nextSubTick0;
616:                this .isMajorTick = isMajorTick0;
617:                // Pour être en accord avec la spécification
618:                // du champs {@link #calendar}...
619:                date.setTime(nextSubTick);
620:                calendar.setTime(date);
621:            }
622:
623:            /**
624:             * Retourne les conventions à utiliser pour écrire les étiquettes de graduation.
625:             */
626:            public Locale getLocale() {
627:                return locale;
628:            }
629:
630:            /**
631:             * Modifie les conventions à utiliser pour écrire les étiquettes de graduation.
632:             */
633:            public void setLocale(final Locale locale) {
634:                if (!locale.equals(this .locale)) {
635:                    calendar = Calendar.getInstance(getTimeZone(), locale);
636:                    format = null;
637:                    formatValid = false;
638:                    // Pour être en accord avec la spécification du champs {@link #calendar}...
639:                    date.setTime(nextSubTick);
640:                    calendar.setTime(date);
641:                }
642:                assert calendar.getTime().getTime() == nextSubTick;
643:            }
644:
645:            /**
646:             * Retourne le fuseau horaire utilisé pour exprimer les dates dans la graduation.
647:             */
648:            public TimeZone getTimeZone() {
649:                return calendar.getTimeZone();
650:            }
651:
652:            /**
653:             * Modifie le fuseau horaire utilisé pour exprimer les dates dans la graduation.
654:             */
655:            public void setTimeZone(final TimeZone timezone) {
656:                if (!timezone.equals(getTimeZone())) {
657:                    calendar.setTimeZone(timezone);
658:                    format = null;
659:                    formatValid = false;
660:                    // Pour être en accord avec la spécification
661:                    // du champs {@link #calendar}...
662:                    date.setTime(nextSubTick);
663:                    calendar.setTime(date);
664:                }
665:                assert calendar.getTime().getTime() == nextSubTick;
666:            }
667:
668:            /**
669:             * Retourne le nom du champ de {@link Calendar} correspondant à la valeur spécifiée.
670:             */
671:            private static String getFieldName(final int field) {
672:                for (int i = 0; i < FIELD.length; i++) {
673:                    if (FIELD[i] == field) {
674:                        return FIELD_NAME[i];
675:                    }
676:                }
677:                return String.valueOf(field);
678:            }
679:
680:            /**
681:             * Returns a string representation of this iterator. Used for debugging purpose only.
682:             */
683:            public String toString() {
684:                if (true) {
685:                    // Note: in this particular case, using PrintWriter with 'println' generates
686:                    //       less bytecodes than chaining StringBuffer.append(...) calls.
687:                    final StringWriter buf = new StringWriter();
688:                    final PrintWriter out = new PrintWriter(buf);
689:                    final DateFormat format = DateFormat.getDateTimeInstance();
690:                    format.setTimeZone(calendar.getTimeZone());
691:                    out.print("Minimum      = ");
692:                    out.println(format.format(new Date(minimum)));
693:                    out.print("Maximum      = ");
694:                    out.println(format.format(new Date(maximum)));
695:                    out.print("Increment    = ");
696:                    out.print(increment / (24 * 3600000f));
697:                    out.println(" days");
698:                    out.print("Tick inc.    = ");
699:                    out.print(tickAdd);
700:                    out.print(' ');
701:                    out.println(getFieldName(tickField));
702:                    out.print("SubTick inc. = ");
703:                    out.print(subTickAdd);
704:                    out.print(' ');
705:                    out.println(getFieldName(subTickField));
706:                    out.print("Next tick    = ");
707:                    out.println(format.format(new Date(nextTick)));
708:                    out.print("Next subtick = ");
709:                    out.println(format.format(new Date(nextSubTick)));
710:                    out.flush();
711:                    return buf.toString();
712:                } else {
713:                    return super.toString();
714:                }
715:            }
716:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.