Source Code Cross Referenced for CoordinateChooser.java in  » GIS » GeoTools-2.4.1 » org » geotools » gui » swing » referencing » 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.gui.swing.referencing 
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) 2001, Institut de Recherche pour le Développement
006:         *
007:         *    This library is free software; you can redistribute it and/or
008:         *    modify it under the terms of the GNU Lesser General Public
009:         *    License as published by the Free Software Foundation; either
010:         *    version 2.1 of the License, or (at your option) any later version.
011:         *
012:         *    This library is distributed in the hope that it will be useful,
013:         *    but WITHOUT ANY WARRANTY; without even the implied warranty of
014:         *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015:         *    Lesser General Public License for more details.
016:         */
017:        package org.geotools.gui.swing.referencing;
018:
019:        // Time
020:        import java.util.Date;
021:        import java.util.TimeZone;
022:        import java.util.Calendar;
023:
024:        // Geometry and coordinates
025:        import java.awt.Dimension;
026:        import java.awt.geom.Dimension2D;
027:        import java.awt.geom.Rectangle2D;
028:
029:        // User interface (Swing)
030:        import java.awt.Insets;
031:        import java.awt.Component;
032:        import java.awt.BorderLayout;
033:        import java.awt.GridBagLayout;
034:        import java.awt.GridBagConstraints;
035:        import javax.swing.JComponent;
036:        import javax.swing.JPanel;
037:        import javax.swing.JLabel;
038:        import javax.swing.JComboBox;
039:        import javax.swing.JTextField;
040:        import javax.swing.JOptionPane;
041:        import javax.swing.ButtonGroup;
042:        import javax.swing.ButtonModel;
043:        import javax.swing.JRadioButton;
044:        import javax.swing.BorderFactory;
045:        import javax.swing.AbstractButton;
046:        import javax.swing.JSpinner;
047:        import javax.swing.SpinnerModel;
048:        import javax.swing.SpinnerDateModel;
049:        import javax.swing.SpinnerNumberModel;
050:        import javax.swing.AbstractSpinnerModel;
051:        import javax.swing.JFormattedTextField;
052:        import javax.swing.text.InternationalFormatter;
053:
054:        // Events
055:        import java.awt.EventQueue;
056:        import java.util.EventListener;
057:        import java.awt.event.ActionEvent;
058:        import java.awt.event.ActionListener;
059:        import javax.swing.event.ChangeEvent;
060:        import javax.swing.event.ChangeListener;
061:
062:        // Parsing and formating
063:        import java.text.Format;
064:        import java.text.DateFormat;
065:        import java.text.NumberFormat;
066:        import java.text.ParseException;
067:
068:        // Miscellaneous
069:        import java.util.Arrays;
070:        import java.util.Locale;
071:
072:        // Geotools dependencies
073:        import org.geotools.measure.Angle;
074:        import org.geotools.measure.Latitude;
075:        import org.geotools.measure.Longitude;
076:        import org.geotools.measure.AngleFormat;
077:
078:        // Resources
079:        import org.geotools.resources.SwingUtilities;
080:        import org.geotools.resources.i18n.Errors;
081:        import org.geotools.resources.i18n.ErrorKeys;
082:        import org.geotools.resources.i18n.Vocabulary;
083:        import org.geotools.resources.i18n.VocabularyKeys;
084:        import org.geotools.resources.geometry.XDimension2D;
085:
086:        /**
087:         * A pane of controls designed to allow a user to select spatio-temporal coordinates.
088:         * Current implementation uses geographic coordinates (longitudes/latitudes) and dates
089:         * according some locale calendar. Future version may allow the use of user-specified
090:         * coordinate system. Latitudes are constrained in the range 90°S to 90°N inclusive.
091:         * Longitudes are constrained in the range 180°W to 180°E inclusive. By default, dates
092:         * are constrained in the range January 1st, 1970 up to the date at the time the widget
093:         * was created.
094:         *
095:         * <p>&nbsp;</p>
096:         * <p align="center"><img src="doc-files/CoordinateChooser.png"></p>
097:         * <p>&nbsp;</p>
098:         *
099:         * @since 2.3
100:         * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/extension/widgets-swing/src/main/java/org/geotools/gui/swing/referencing/CoordinateChooser.java $
101:         * @version $Id: CoordinateChooser.java 20883 2006-08-07 13:48:09Z jgarnett $
102:         * @author Martin Desruisseaux
103:         */
104:        public class CoordinateChooser extends JPanel {
105:            /**
106:             * An enumeration constant for showing or hidding the geographic area selector.
107:             * Used as argument for {@link #isSelectorVisible} and {@link #setSelectorVisible}.
108:             *
109:             * @see #TIME_RANGE
110:             * @see #RESOLUTION
111:             * @see #isSelectorVisible
112:             * @see #setSelectorVisible
113:             * @see #addChangeListener
114:             * @see #removeChangeListener
115:             */
116:            public static final int GEOGRAPHIC_AREA = 1;
117:
118:            /**
119:             * An enumeration constant for showing or hidding the time range selector.
120:             * Used as argument for {@link #isSelectorVisible} and {@link #setSelectorVisible}.
121:             *
122:             * @see #GEOGRAPHIC_AREA
123:             * @see #RESOLUTION
124:             * @see #isSelectorVisible
125:             * @see #setSelectorVisible
126:             * @see #addChangeListener
127:             * @see #removeChangeListener
128:             */
129:            public static final int TIME_RANGE = 2;
130:
131:            /**
132:             * An enumeration constant for showing or hidding the resolution selector.
133:             * Used as argument for {@link #isSelectorVisible} and {@link #setSelectorVisible}.
134:             *
135:             * @see #GEOGRAPHIC_AREA
136:             * @see #TIME_RANGE
137:             * @see #isSelectorVisible
138:             * @see #setSelectorVisible
139:             * @see #addChangeListener
140:             * @see #removeChangeListener
141:             */
142:            public static final int RESOLUTION = 4;
143:
144:            /**
145:             * The three mean panels in this dialog box:
146:             * geographic area, time and preferred resolution.
147:             */
148:            private final JComponent areaPanel, timePanel, resoPanel;
149:
150:            /**
151:             * Liste de choix dans laquelle l'utilisateur
152:             * choisira le fuseau horaire de ses dates.
153:             */
154:            private final JComboBox timezone;
155:
156:            /**
157:             * Dates de début et de fin de la plage de temps demandée par l'utilisateur.
158:             * Ces dates sont gérées par un modèle {@link SpinnerDateModel}.
159:             */
160:            private final JSpinner tmin, tmax;
161:
162:            /**
163:             * Longitudes et latitudes minimales et maximales demandées par l'utilisateur.
164:             * Ces coordonnées sont gérées par un modèle {@link SpinnerNumberModel}.
165:             */
166:            private final JSpinner xmin, xmax, ymin, ymax;
167:
168:            /**
169:             * Résolution (en minutes de longitudes et de latitudes) demandée par l'utilisateur.
170:             * Ces résolution sont gérées par un modèle {@link SpinnerNumberModel}.
171:             */
172:            private final JSpinner xres, yres;
173:
174:            /**
175:             * Bouton radio pour sélectioner la meilleure résolution possible.
176:             */
177:            private final AbstractButton radioBestRes;
178:
179:            /**
180:             * Bouton radio pour sélectioner la résolution spécifiée.
181:             */
182:            private final AbstractButton radioPrefRes;
183:
184:            /**
185:             * Composante facultative à afficher à la droite du paneau {@code CoordinateChooser}.
186:             */
187:            private JComponent accessory;
188:
189:            /**
190:             * Class encompassing various listeners for users selections.
191:             *
192:             * @version $Id: CoordinateChooser.java 20883 2006-08-07 13:48:09Z jgarnett $
193:             * @author Martin Desruisseaux
194:             */
195:            private final class Listeners implements  ActionListener,
196:                    ChangeListener {
197:                /**
198:                 * List of components to toggle.
199:                 */
200:                private final JComponent[] toggle;
201:
202:                /**
203:                 * Constructs a {@code Listeners} object.
204:                 */
205:                public Listeners(final JComponent[] toggle) {
206:                    this .toggle = toggle;
207:                }
208:
209:                /**
210:                 * Invoked when user select a new timezone.
211:                 */
212:                public void actionPerformed(final ActionEvent event) {
213:                    update(getTimeZone());
214:                }
215:
216:                /**
217:                 * Invoked when user change the button radio state
218:                 * ("use best resolution" / "set resolution").
219:                 */
220:                public void stateChanged(final ChangeEvent event) {
221:                    setEnabled(radioPrefRes.isSelected());
222:                }
223:
224:                /**
225:                 * Enable or disable {@link #toggle} components.
226:                 */
227:                final void setEnabled(final boolean state) {
228:                    for (int i = 0; i < toggle.length; i++) {
229:                        toggle[i].setEnabled(state);
230:                    }
231:                }
232:            }
233:
234:            /**
235:             * Constructs a default coordinate chooser. Date will be constrained in the range from
236:             * January 1st, 1970 00:00 UTC up to the {@linkplain System#currentTimeMillis current time}.
237:             */
238:            public CoordinateChooser() {
239:                this (new Date(0), new Date());
240:            }
241:
242:            /**
243:             * Constructs a coordinate chooser with date constrained in the specified range.
244:             * Note that the {@code [minTime..maxTime]} range is not the same than the
245:             * range given to {@link #setTimeRange}. The later set only the time range shown
246:             * in the widget, while this constructor set also the minimum and maximum dates
247:             * allowed.
248:             *
249:             * @param minTime The minimal date allowed.
250:             * @param maxTime the maximal date allowed.
251:             */
252:            public CoordinateChooser(final Date minTime, final Date maxTime) {
253:                super (new GridBagLayout());
254:                final Locale locale = getDefaultLocale();
255:                final int timeField = Calendar.DAY_OF_YEAR;
256:                final Vocabulary resources = Vocabulary.getResources(locale);
257:
258:                radioBestRes = new JRadioButton(resources
259:                        .getString(VocabularyKeys.USE_BEST_RESOLUTION), true);
260:                radioPrefRes = new JRadioButton(resources
261:                        .getString(VocabularyKeys.SET_PREFERRED_RESOLUTION));
262:
263:                tmin = new JSpinner(new SpinnerDateModel(minTime, minTime,
264:                        maxTime, timeField));
265:                tmax = new JSpinner(new SpinnerDateModel(maxTime, minTime,
266:                        maxTime, timeField));
267:                xmin = new JSpinner(new SpinnerAngleModel(new Longitude(
268:                        Longitude.MIN_VALUE)));
269:                xmax = new JSpinner(new SpinnerAngleModel(new Longitude(
270:                        Longitude.MAX_VALUE)));
271:                ymin = new JSpinner(new SpinnerAngleModel(new Latitude(
272:                        Latitude.MIN_VALUE)));
273:                ymax = new JSpinner(new SpinnerAngleModel(new Latitude(
274:                        Latitude.MAX_VALUE)));
275:                xres = new JSpinner(new SpinnerNumberModel(1, 0, 360 * 60, 1));
276:                yres = new JSpinner(new SpinnerNumberModel(1, 0, 180 * 60, 1));
277:
278:                final AngleFormat angleFormat = new AngleFormat("D°MM.m'",
279:                        locale);
280:                final DateFormat dateFormat = DateFormat.getDateTimeInstance(
281:                        DateFormat.SHORT, DateFormat.SHORT, locale);
282:                final NumberFormat numberFormat = NumberFormat
283:                        .getNumberInstance(locale);
284:                xmin.setEditor(new SpinnerAngleModel.Editor(xmin, angleFormat));
285:                xmax.setEditor(new SpinnerAngleModel.Editor(xmax, angleFormat));
286:                ymin.setEditor(new SpinnerAngleModel.Editor(ymin, angleFormat));
287:                ymax.setEditor(new SpinnerAngleModel.Editor(ymax, angleFormat));
288:
289:                setup(tmin, 10, dateFormat);
290:                setup(tmax, 10, dateFormat);
291:                setup(xmin, 7, null);
292:                setup(xmax, 7, null);
293:                setup(ymin, 7, null);
294:                setup(ymax, 7, null);
295:                setup(xres, 3, numberFormat);
296:                setup(yres, 3, numberFormat);
297:
298:                final String[] timezones = TimeZone.getAvailableIDs();
299:                Arrays.sort(timezones);
300:                timezone = new JComboBox(timezones);
301:                timezone.setSelectedItem(dateFormat.getTimeZone().getID());
302:
303:                final JLabel labelSize1 = new JLabel(resources
304:                        .getLabel(VocabularyKeys.SIZE_IN_MINUTES));
305:                final JLabel labelSize2 = new JLabel("\u00D7" /* Multiplication symbol */);
306:                final ButtonGroup group = new ButtonGroup();
307:                group.add(radioBestRes);
308:                group.add(radioPrefRes);
309:
310:                final Listeners listeners = new Listeners(new JComponent[] {
311:                        labelSize1, labelSize2, xres, yres });
312:                listeners.setEnabled(false);
313:                timezone.addActionListener(listeners);
314:                radioPrefRes.addChangeListener(listeners);
315:
316:                areaPanel = getPanel(resources
317:                        .getString(VocabularyKeys.GEOGRAPHIC_COORDINATES));
318:                timePanel = getPanel(resources
319:                        .getString(VocabularyKeys.TIME_RANGE));
320:                resoPanel = getPanel(resources
321:                        .getString(VocabularyKeys.PREFERRED_RESOLUTION));
322:                final GridBagConstraints c = new GridBagConstraints();
323:
324:                c.weightx = 1;
325:                c.gridx = 1;
326:                c.gridy = 0;
327:                areaPanel.add(ymax, c);
328:                c.gridx = 0;
329:                c.gridy = 1;
330:                areaPanel.add(xmin, c);
331:                c.gridx = 2;
332:                c.gridy = 1;
333:                areaPanel.add(xmax, c);
334:                c.gridx = 1;
335:                c.gridy = 2;
336:                areaPanel.add(ymin, c);
337:
338:                JLabel label;
339:                c.gridx = 0;
340:                c.anchor = c.WEST;
341:                c.insets.right = 3;
342:                c.weightx = 0;
343:                c.gridy = 0;
344:                timePanel.add(label = new JLabel(resources
345:                        .getLabel(VocabularyKeys.START_TIME)), c);
346:                label.setLabelFor(tmin);
347:                c.gridy = 1;
348:                timePanel.add(label = new JLabel(resources
349:                        .getLabel(VocabularyKeys.END_TIME)), c);
350:                label.setLabelFor(tmax);
351:                c.gridy = 2;
352:                timePanel.add(label = new JLabel(resources
353:                        .getLabel(VocabularyKeys.TIME_ZONE)), c);
354:                label.setLabelFor(timezone);
355:                c.gridwidth = 4;
356:                c.gridy = 0;
357:                resoPanel.add(radioBestRes, c);
358:                c.gridy = 1;
359:                resoPanel.add(radioPrefRes, c);
360:                c.gridy = 2;
361:                c.gridwidth = 1;
362:                c.anchor = c.EAST;
363:                c.insets.right = c.insets.left = 1;
364:                c.weightx = 1;
365:                c.gridx = 0;
366:                resoPanel.add(labelSize1, c);
367:                labelSize1.setLabelFor(xres);
368:                c.weightx = 0;
369:                c.gridx = 1;
370:                resoPanel.add(xres, c);
371:                c.gridx = 2;
372:                resoPanel.add(labelSize2, c);
373:                labelSize2.setLabelFor(yres);
374:                c.gridx = 3;
375:                resoPanel.add(yres, c);
376:
377:                c.gridx = 1;
378:                c.fill = c.HORIZONTAL;
379:                c.insets.right = c.insets.left = 0;
380:                c.weightx = 1;
381:                c.gridy = 0;
382:                timePanel.add(tmin, c);
383:                c.gridy = 1;
384:                timePanel.add(tmax, c);
385:                c.gridy = 2;
386:                timePanel.add(timezone, c);
387:
388:                c.insets.right = c.insets.left = c.insets.top = c.insets.bottom = 3;
389:                c.gridx = 0;
390:                c.anchor = c.CENTER;
391:                c.fill = c.BOTH;
392:                c.weighty = 1;
393:                c.gridy = 0;
394:                add(areaPanel, c);
395:                c.gridy = 1;
396:                add(timePanel, c);
397:                c.gridy = 2;
398:                add(resoPanel, c);
399:            }
400:
401:            /**
402:             * Retourne un panneau avec une bordure titrée.
403:             */
404:            private static JPanel getPanel(final String title) {
405:                final JPanel panel = new JPanel(new GridBagLayout());
406:                panel.setBorder(BorderFactory.createCompoundBorder(
407:                        BorderFactory.createTitledBorder(title), BorderFactory
408:                                .createEmptyBorder(6, 6, 6, 6)));
409:                return panel;
410:            }
411:
412:            /**
413:             * Définit la largeur (en nombre de colonnes) d'un champ.
414:             * Eventuellement, cette méthode peut aussi redéfinir le format.
415:             */
416:            private static void setup(final JSpinner spinner, final int width,
417:                    final Format format) {
418:                final JFormattedTextField field = ((JSpinner.DefaultEditor) spinner
419:                        .getEditor()).getTextField();
420:                field.setMargin(new Insets(/*top*/0, /*left*/6, /*bottom*/0, /*right*/
421:                        3));
422:                field.setColumns(width);
423:                if (format != null) {
424:                    ((InternationalFormatter) field.getFormatter())
425:                            .setFormat(format);
426:                }
427:            }
428:
429:            /**
430:             * Tells if a selector is currently visible or not. The default {@code CoordinateChooser}
431:             * contains three selectors: one for geographic area, one for time range and one for the
432:             * preferred resolution.
433:             *
434:             * @param selector One of the following constants:
435:             *                 {@link #GEOGRAPHIC_AREA},
436:             *                 {@link #TIME_RANGE} or
437:             *                 {@link #RESOLUTION}.
438:             * @return {@code true} if the specified selector is visible, or {@code false} otherwise.
439:             * @throws IllegalArgumentException if {@code selector} is not legal.
440:             */
441:            public boolean isSelectorVisible(final int selector) {
442:                switch (selector) {
443:                case GEOGRAPHIC_AREA:
444:                    return areaPanel.isVisible();
445:                case TIME_RANGE:
446:                    return timePanel.isVisible();
447:                case RESOLUTION:
448:                    return resoPanel.isVisible();
449:                default:
450:                    throw new IllegalArgumentException();
451:                    // TODO: provide some error message.
452:                }
453:            }
454:
455:            /**
456:             * Set the visible state of one or many selectors.
457:             * All selectors are visible by default.
458:             *
459:             * @param selectors Any bitwise combinaisons of
460:             *                  {@link #GEOGRAPHIC_AREA},
461:             *                  {@link #TIME_RANGE} and/or
462:             *                  {@link #RESOLUTION}.
463:             * @param visible {@code true} to show the selectors, or {@code false} to hide them.
464:             * @throws IllegalArgumentException if {@code selectors} contains illegal bits.
465:             */
466:            public void setSelectorVisible(final int selectors,
467:                    final boolean visible) {
468:                ensureValidSelectors(selectors);
469:                if ((selectors & GEOGRAPHIC_AREA) != 0)
470:                    areaPanel.setVisible(visible);
471:                if ((selectors & TIME_RANGE) != 0)
472:                    timePanel.setVisible(visible);
473:                if ((selectors & RESOLUTION) != 0)
474:                    resoPanel.setVisible(visible);
475:            }
476:
477:            /**
478:             * Ensure that the specified bitwise combinaison of selectors is valid.
479:             *
480:             * @param selectors Any bitwise combinaisons of
481:             *                  {@link #GEOGRAPHIC_AREA},
482:             *                  {@link #TIME_RANGE} and/or
483:             *                  {@link #RESOLUTION}.
484:             * @throws IllegalArgumentException if {@code selectors} contains illegal bits.
485:             *
486:             * @todo Provide a better error message.
487:             */
488:            private static void ensureValidSelectors(final int selectors)
489:                    throws IllegalArgumentException {
490:                if ((selectors & ~(GEOGRAPHIC_AREA | TIME_RANGE | RESOLUTION)) != 0) {
491:                    throw new IllegalArgumentException(String
492:                            .valueOf(selectors));
493:                }
494:            }
495:
496:            /**
497:             * Returns the value for the specified number, or NaN if {@code value} is not a number.
498:             */
499:            private static double doubleValue(final JSpinner spinner) {
500:                final Object value = spinner.getValue();
501:                return (value instanceof  Number) ? ((Number) value)
502:                        .doubleValue() : Double.NaN;
503:            }
504:
505:            /**
506:             * Returns the value for the specified angle, or NaN if {@code value} is not an angle.
507:             */
508:            private static double degrees(final JSpinner spinner,
509:                    final boolean expectLatitude) {
510:                final Object value = spinner.getValue();
511:                if (value instanceof  Angle) {
512:                    if (expectLatitude ? (value instanceof  Longitude)
513:                            : (value instanceof  Latitude)) {
514:                        return Double.NaN;
515:                    }
516:                    return ((Angle) value).degrees();
517:                }
518:                return Double.NaN;
519:            }
520:
521:            /**
522:             * Gets the geographic area, in latitude and longitude degrees.
523:             */
524:            public Rectangle2D getGeographicArea() {
525:                final double xmin = degrees(this .xmin, false);
526:                final double ymin = degrees(this .ymin, true);
527:                final double xmax = degrees(this .xmax, false);
528:                final double ymax = degrees(this .ymax, true);
529:                return new Rectangle2D.Double(Math.min(xmin, xmax), Math.min(
530:                        ymin, ymax), Math.abs(xmax - xmin), Math.abs(ymax
531:                        - ymin));
532:            }
533:
534:            /**
535:             * Sets the geographic area, in latitude and longitude degrees.
536:             */
537:            public void setGeographicArea(final Rectangle2D area) {
538:                xmin.setValue(new Longitude(area.getMinX()));
539:                xmax.setValue(new Longitude(area.getMaxX()));
540:                ymin.setValue(new Latitude(area.getMinY()));
541:                ymax.setValue(new Latitude(area.getMaxY()));
542:            }
543:
544:            /**
545:             * Returns the preferred resolution. A {@code null} value means that the
546:             * best available resolution should be used.
547:             */
548:            public Dimension2D getPreferredResolution() {
549:                if (radioPrefRes.isSelected()) {
550:                    return new XDimension2D.Double(doubleValue(xres),
551:                            doubleValue(yres));
552:                }
553:                return null;
554:            }
555:
556:            /**
557:             * Sets the preferred resolution. A {@code null} value means that the best
558:             * available resolution should be used.
559:             */
560:            public void setPreferredResolution(final Dimension2D resolution) {
561:                if (resolution != null) {
562:                    xres.setValue(new Double(resolution.getWidth() * 60));
563:                    yres.setValue(new Double(resolution.getHeight() * 60));
564:                    radioPrefRes.setSelected(true);
565:                } else {
566:                    radioBestRes.setSelected(true);
567:                }
568:            }
569:
570:            /**
571:             * Returns the time zone used for displaying dates.
572:             */
573:            public TimeZone getTimeZone() {
574:                return TimeZone.getTimeZone(timezone.getSelectedItem()
575:                        .toString());
576:            }
577:
578:            /**
579:             * Sets the time zone. This method change the control's display.
580:             * It doesn't change the date values, i.e. it have no effect
581:             * on previous or future call to {@link #setTimeRange}.
582:             */
583:            public void setTimeZone(final TimeZone timezone) {
584:                this .timezone.setSelectedItem(timezone.getID());
585:            }
586:
587:            /**
588:             * Updates the time zone in text fields. This method is automatically invoked
589:             * by {@link JComboBox} on user's selection. It is also (indirectly) invoked
590:             * on {@link #setTimeZone} call.
591:             */
592:            private void update(final TimeZone timezone) {
593:                boolean refresh = true;
594:                try {
595:                    tmin.commitEdit();
596:                    tmax.commitEdit();
597:                } catch (ParseException exception) {
598:                    refresh = false;
599:                }
600:                ((JSpinner.DateEditor) tmin.getEditor()).getFormat()
601:                        .setTimeZone(timezone);
602:                ((JSpinner.DateEditor) tmax.getEditor()).getFormat()
603:                        .setTimeZone(timezone);
604:                if (refresh) {
605:                    // TODO: If a "JSpinner.reformat()" method was available, we would use it here.
606:                    fireStateChanged((AbstractSpinnerModel) tmin.getModel());
607:                    fireStateChanged((AbstractSpinnerModel) tmax.getModel());
608:                }
609:            }
610:
611:            /**
612:             * Run each {@link ChangeListener#stateChanged()} method for the specified spinner model.
613:             */
614:            private static void fireStateChanged(
615:                    final AbstractSpinnerModel model) {
616:                final ChangeEvent changeEvent = new ChangeEvent(model);
617:                final EventListener[] listeners = model
618:                        .getListeners(ChangeListener.class);
619:                for (int i = listeners.length; --i >= 0;) {
620:                    ((ChangeListener) listeners[i]).stateChanged(changeEvent);
621:                }
622:            }
623:
624:            /**
625:             * Returns the start time, or {@code null} if there is none.
626:             */
627:            public Date getStartTime() {
628:                return (Date) tmin.getValue();
629:            }
630:
631:            /**
632:             * Returns the end time, or {@code null} if there is none.
633:             */
634:            public Date getEndTime() {
635:                return (Date) tmax.getValue();
636:            }
637:
638:            /**
639:             * Sets the time range.
640:             *
641:             * @param startTime The start time.
642:             * @param   endTime The end time.
643:             *
644:             * @see #getStartTime
645:             * @see #getEndTime
646:             */
647:            public void setTimeRange(final Date startTime, final Date endTime) {
648:                tmin.setValue(startTime);
649:                tmax.setValue(endTime);
650:            }
651:
652:            /**
653:             * Returns the accessory component.
654:             *
655:             * @return The accessory component, or {@code null} if there is none.
656:             */
657:            public JComponent getAccessory() {
658:                return accessory;
659:            }
660:
661:            /**
662:             * Sets the accessory component. An accessory is often used to show available data.
663:             * However, it can be used for anything that the programmer wishes, such as extra
664:             * custom coordinate chooser controls.
665:             * <p>
666:             * <strong>Note:</strong> If there was a previous accessory, you should unregister any
667:             * listeners that the accessory might have registered with the coordinate chooser.
668:             *
669:             * @param accessory The accessory component, or {@code null} to remove any previous accessory.
670:             */
671:            public void setAccessory(final JComponent accessory) {
672:                synchronized (getTreeLock()) {
673:                    if (this .accessory != null) {
674:                        remove(this .accessory);
675:                    }
676:                    this .accessory = accessory;
677:                    if (accessory != null) {
678:                        final GridBagConstraints c = new GridBagConstraints();
679:                        c.insets.right = c.insets.left = c.insets.top = c.insets.bottom = 3;
680:                        c.gridx = 1;
681:                        c.weightx = 1;
682:                        c.gridwidth = 1;
683:                        c.gridy = 0;
684:                        c.weighty = 1;
685:                        c.gridheight = 3;
686:                        c.anchor = c.CENTER;
687:                        c.fill = c.BOTH;
688:                        add(accessory, c);
689:                    }
690:                    validate();
691:                }
692:            }
693:
694:            /**
695:             * Check if an angle is of expected type (latitude or longitude).
696:             */
697:            private void checkAngle(final JSpinner field,
698:                    final boolean expectLatitude) throws ParseException {
699:                final Object angle = field.getValue();
700:                if (expectLatitude ? (angle instanceof  Longitude)
701:                        : (angle instanceof  Latitude)) {
702:                    throw new ParseException(Errors.getResources(getLocale())
703:                            .getString(ErrorKeys.BAD_COORDINATE_$1, angle), 0);
704:                }
705:            }
706:
707:            /**
708:             * Commits the currently edited values. If commit fails, focus will be set on the offending
709:             * field.
710:             *
711:             * @throws ParseException If at least one of currently edited value couldn't be commited.
712:             */
713:            public void commitEdit() throws ParseException {
714:                JSpinner focus = null;
715:                try {
716:                    (focus = tmin).commitEdit();
717:                    (focus = tmax).commitEdit();
718:                    (focus = xmin).commitEdit();
719:                    (focus = xmax).commitEdit();
720:                    (focus = ymin).commitEdit();
721:                    (focus = ymax).commitEdit();
722:                    (focus = xres).commitEdit();
723:                    (focus = yres).commitEdit();
724:
725:                    checkAngle(focus = xmin, false);
726:                    checkAngle(focus = xmax, false);
727:                    checkAngle(focus = ymin, true);
728:                    checkAngle(focus = ymax, true);
729:                } catch (ParseException exception) {
730:                    focus.requestFocus();
731:                    throw exception;
732:                }
733:            }
734:
735:            /**
736:             * Prend en compte les valeurs des champs édités par l'utilisateur.
737:             * Si les entrés ne sont pas valide, affiche un message d'erreur en
738:             * utilisant la fenêtre parente {@code owner} spécifiée.
739:             *
740:             * @param  owner Fenêtre dans laquelle faire apparaître d'eventuels messages d'erreur.
741:             * @return {@code true} si la prise en compte des paramètres à réussie.
742:             */
743:            private boolean commitEdit(final Component owner) {
744:                try {
745:                    commitEdit();
746:                } catch (ParseException exception) {
747:                    SwingUtilities.showMessageDialog(owner, exception
748:                            .getLocalizedMessage(), Errors.getResources(
749:                            getLocale()).getString(ErrorKeys.BAD_ENTRY),
750:                            JOptionPane.ERROR_MESSAGE);
751:                    return false;
752:                }
753:                return true;
754:            }
755:
756:            /**
757:             * Adds a change listener to the listener list. This change listener will be notify when
758:             * a value changed. The change may be in a geographic coordinate field, a date field, a
759:             * resolution field, etc. The watched values depend on the {@code selectors} arguments:
760:             * {@link #GEOGRAPHIC_AREA} will watches for the bounding box (East, West, North and South
761:             * value); {@link #TIME_RANGE} watches for start time and end time; {@link #RESOLUTION}
762:             * watches for the resolution along East-West and North-South axis. Bitwise combinaisons
763:             * are allowed. For example, <code>GEOGRAPHIC_AREA | TIME_RANGE</code> will register a
764:             * listener for both geographic area and time range.
765:             * <p>
766:             * The source of {@link ChangeEvent}s delivered to {@link ChangeListener}s will be in most
767:             * case the {@link SpinnerModel} for the edited field.
768:             *
769:             * @param  selectors Any bitwise combinaisons of
770:             *                   {@link #GEOGRAPHIC_AREA},
771:             *                   {@link #TIME_RANGE} and/or
772:             *                   {@link #RESOLUTION}.
773:             * @param  listener The listener to add to the specified selectors.
774:             * @throws IllegalArgumentException if {@code selectors} contains illegal bits.
775:             */
776:            public void addChangeListener(final int selectors,
777:                    final ChangeListener listener) {
778:                ensureValidSelectors(selectors);
779:                if ((selectors & GEOGRAPHIC_AREA) != 0) {
780:                    xmin.getModel().addChangeListener(listener);
781:                    xmax.getModel().addChangeListener(listener);
782:                    ymin.getModel().addChangeListener(listener);
783:                    ymax.getModel().addChangeListener(listener);
784:                }
785:                if ((selectors & TIME_RANGE) != 0) {
786:                    tmin.getModel().addChangeListener(listener);
787:                    tmax.getModel().addChangeListener(listener);
788:                }
789:                if ((selectors & RESOLUTION) != 0) {
790:                    xres.getModel().addChangeListener(listener);
791:                    yres.getModel().addChangeListener(listener);
792:                    radioPrefRes.getModel().addChangeListener(listener);
793:                }
794:            }
795:
796:            /**
797:             * Removes a change listener from the listener list.
798:             *
799:             * @param  selectors Any bitwise combinaisons of
800:             *                   {@link #GEOGRAPHIC_AREA},
801:             *                   {@link #TIME_RANGE} and/or
802:             *                   {@link #RESOLUTION}.
803:             * @param  listener The listener to remove from the specified selectors.
804:             * @throws IllegalArgumentException if {@code selectors} contains illegal bits.
805:             */
806:            public void removeChangeListener(final int selectors,
807:                    final ChangeListener listener) {
808:                ensureValidSelectors(selectors);
809:                if ((selectors & GEOGRAPHIC_AREA) != 0) {
810:                    xmin.getModel().removeChangeListener(listener);
811:                    xmax.getModel().removeChangeListener(listener);
812:                    ymin.getModel().removeChangeListener(listener);
813:                    ymax.getModel().removeChangeListener(listener);
814:                }
815:                if ((selectors & TIME_RANGE) != 0) {
816:                    tmin.getModel().removeChangeListener(listener);
817:                    tmax.getModel().removeChangeListener(listener);
818:                }
819:                if ((selectors & RESOLUTION) != 0) {
820:                    xres.getModel().removeChangeListener(listener);
821:                    yres.getModel().removeChangeListener(listener);
822:                    radioPrefRes.getModel().removeChangeListener(listener);
823:                }
824:            }
825:
826:            /**
827:             * Shows a dialog box requesting input from the user. The dialog box will be
828:             * parented to {@code owner}. If {@code owner} is contained into a
829:             * {@link javax.swing.JDesktopPane}, the dialog box will appears as an internal
830:             * frame. This method can be invoked from any thread (may or may not be the
831:             * <cite>Swing</cite> thread).
832:             *
833:             * @param  owner The parent component for the dialog box, or {@code null} if there is no parent.
834:             * @return {@code true} if user pressed the "Ok" button, or {@code false} otherwise
835:             *         (e.g. pressing "Cancel" or closing the dialog box from the title bar).
836:             */
837:            public boolean showDialog(final Component owner) {
838:                return showDialog(owner, Vocabulary.getResources(getLocale())
839:                        .getString(VocabularyKeys.COORDINATES_SELECTION));
840:            }
841:
842:            /**
843:             * Shows a dialog box requesting input from the user. If {@code owner} is contained into a
844:             * {@link javax.swing.JDesktopPane}, the dialog box will appears as an internal frame. This
845:             * method can be invoked from any thread (may or may not be the <cite>Swing</cite> thread).
846:             *
847:             * @param  owner The parent component for the dialog box, or {@code null} if there is no parent.
848:             * @param  title The dialog box title.
849:             * @return {@code true} if user pressed the "Ok" button, or {@code false} otherwise
850:             *         (e.g. pressing "Cancel" or closing the dialog box from the title bar).
851:             */
852:            public boolean showDialog(final Component owner, final String title) {
853:                while (SwingUtilities.showOptionDialog(owner, this , title)) {
854:                    if (commitEdit(owner)) {
855:                        return true;
856:                    }
857:                }
858:                return false;
859:            }
860:
861:            /**
862:             * Show the dialog box. This method is provided only as an easy
863:             * way to test the dialog appearance from the command line.
864:             */
865:            public static void main(final String[] args) {
866:                new CoordinateChooser().showDialog(null);
867:            }
868:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.