Source Code Cross Referenced for MouseSelectionTracker.java in  » GIS » GeoTools-2.4.1 » org » geotools » gui » swing » 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 
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;
018:
019:        // Geometry
020:        import java.awt.Shape;
021:        import java.awt.Rectangle;
022:        import java.awt.geom.Line2D;
023:        import java.awt.geom.Point2D;
024:        import java.awt.geom.Ellipse2D;
025:        import java.awt.geom.Rectangle2D;
026:        import java.awt.geom.RoundRectangle2D;
027:        import java.awt.geom.RectangularShape;
028:        import java.awt.geom.AffineTransform;
029:        import java.awt.geom.NoninvertibleTransformException;
030:
031:        // Graphics
032:        import java.awt.Color;
033:        import java.awt.Component;
034:        import java.awt.Graphics2D;
035:
036:        // Events
037:        import java.awt.event.MouseEvent;
038:        import javax.swing.event.MouseInputAdapter;
039:
040:        /**
041:         * Controller which allows the user to select a region of a component. The user must click on a
042:         * point in the component, then drag the mouse pointer whilst keeping the button pressed. During
043:         * the dragging, the shape which is drawn will normally be a rectangle.  Other shapes could always
044:         * be used such as, for example, an ellipse. To use this class, it is necessary to create a derived
045:         * class which defines the following methods:
046:         *
047:         * <ul>
048:         *   <li>{@link #selectionPerformed} (obligatory)</li>
049:         *   <li>{@link #getModel} (optional)</li>
050:         * </ul>
051:         *
052:         * This controller should then be registered with one, and only one, component
053:         * using the following syntax:
054:         *
055:         * <blockquote><pre>
056:         * {@link Component} component=...
057:         * MouseSelectionTracker control=...
058:         * component.addMouseListener(control);
059:         * </pre></blockquote>
060:         *
061:         * @since 2.0
062:         * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/extension/widgets-swing/src/main/java/org/geotools/gui/swing/MouseSelectionTracker.java $
063:         * @version $Id: MouseSelectionTracker.java 22482 2006-10-31 02:58:00Z desruisseaux $
064:         * @author Martin Desruisseaux
065:         */
066:        abstract class MouseSelectionTracker extends MouseInputAdapter {
067:            /**
068:             * Stippled rectangle representing the region which the user is currently
069:             * selecting.  This rectangle can be empty.  These coordinates are only
070:             * significant in the period between the user pressing the mouse button
071:             * and then releasing it to outline a region. Conventionally, the
072:             * {@code null} value indicates that a line should be used instead of
073:             * a rectangular shape.  The coordinates are always expressed in pixels.
074:             */
075:            private transient RectangularShape mouseSelectedArea;
076:
077:            /**
078:             * Colour to replace during XOR drawings on a graphic.
079:             * This colour is specified in {@link Graphics2D#setColor}.
080:             */
081:            private Color backXORColor = Color.white;
082:
083:            /**
084:             * Colour to replace with during the XOR drawings on a graphic.
085:             * This colour is specified in {@link Graphics2D#setXORMode}.
086:             */
087:            private Color lineXORColor = Color.black;
088:
089:            /**
090:             * <var>x</var> coordinate of the mouse when the button is pressed.
091:             */
092:            private transient int ox;
093:
094:            /**
095:             * <var>y</var> coordinate of the mouse when the button is pressed.
096:             */
097:            private transient int oy;
098:
099:            /**
100:             * <var>x</var> coordinate of the mouse during the last drag.
101:             */
102:            private transient int px;
103:
104:            /**
105:             * <var>y</var> coordinate of the mouse during the last drag.
106:             */
107:            private transient int py;
108:
109:            /**
110:             * Indicates whether a selection is underway.
111:             */
112:            private transient boolean isDragging;
113:
114:            /**
115:             * Constructs an object which will allow rectangular regions to be selected using the mouse.
116:             */
117:            public MouseSelectionTracker() {
118:            }
119:
120:            /**
121:             * Specifies the colours to be used for drawing the outline of a box when
122:             * the user selects a region.  All {@code a} colours will be replaced
123:             * by {@code b} colours and vice versa.
124:             */
125:            public void setXORColors(final Color a, final Color b) {
126:                backXORColor = a;
127:                lineXORColor = b;
128:            }
129:
130:            /**
131:             * Returns the geometric shape to use for marking the boundaries of a region.  This shape is
132:             * normally a rectangle but could also be an ellipse, an arrow or even other shapes. The
133:             * coordinates of the returned shape will not be taken into account. In fact, these coordinates
134:             * will regularly be discarded. Only the class of the returned shape will count (for example,
135:             * {@link java.awt.geom.Ellipse2D} vs {@link java.awt.geom.Rectangle2D}) and their parameters
136:             * which are not linked to their position (for example, the rounding of a rectangle's
137:             * corners).
138:             * <p>
139:             * The shape returned will normally be from a class derived from {@link RectangularShape},
140:             * but could also be from the {@link Line2D} class. <strong>Any other class risks throwing a
141:             * {@link ClassCastException} when executed</strong>.
142:             *
143:             * The default implementation always returns an object {@link Rectangle}.
144:             *
145:             * @param  event Mouse coordinate when the button is pressed.  This information can be used by
146:             *         the derived classes which like to be informed of the position of the mouse before
147:             *         chosing a geometric shape.
148:             * @return Shape from the class {link RectangularShape} or {link Line2D}, or {@code null}
149:             *         to indicate that we do not want to make a selection.
150:             */
151:            protected Shape getModel(final MouseEvent event) {
152:                return new Rectangle();
153:            }
154:
155:            /**
156:             * Method which is automatically called after the user selects a region with the mouse.
157:             * All coordinates passed in as parameters are expressed in pixels.
158:             *
159:             * @param ox <var>x</var> coordinate of the mouse when the user pressed the mouse button.
160:             * @param oy <var>y</var> coordinate of the mouse when the user pressed the mouse button.
161:             * @param px <var>x</var> coordinate of the mouse when the user released the mouse button.
162:             * @param py <var>y</var> coordinate of the mouse when the user released the mouse button.
163:             */
164:            protected abstract void selectionPerformed(int ox, int oy, int px,
165:                    int py);
166:
167:            /**
168:             * Returns the geometric shape surrounding the last region to be selected by the user. An
169:             * optional affine transform can be specified to convert the region selected by the user
170:             * into logical coordinates. The class of the shape returned depends on the model returned by
171:             * {@link #getModel}:
172:             *
173:             * <ul>
174:             *   <li>If the model is null (which means that this {@code MouseSelectionTracker} object only
175:             *       draws a line between points), the object returned will belong to the {@link Line2D}
176:             *       class.</li>
177:             *   <li>If the model is not null, the object returned can be from the same class (most often
178:             *       {@link java.awt.geom.Rectangle2D}). There could always be situations where the object
179:             *       returned is from another class, for example if the affine transform carries out a
180:             *       rotation.</li>
181:             * </ul>
182:             *
183:             * @param  transform Affine transform which converts logical coordinates into pixel coordinates.
184:             *         It is usually an affine transform which is used in a {@code paint(...)} method to
185:             *         draw shapes expressed in logical coordinates.
186:             * @return A geometric shape enclosing the last region to be selected by the user, or
187:             *         {@code null} if no selection has yet been made.
188:             * @throws NoninvertibleTransformException If the affine transform can't be inverted.
189:             */
190:            public Shape getSelectedArea(final AffineTransform transform)
191:                    throws NoninvertibleTransformException {
192:                if (ox == px && oy == py) {
193:                    return null;
194:                }
195:                RectangularShape shape = mouseSelectedArea;
196:                if (transform != null && !transform.isIdentity()) {
197:                    if (shape == null) {
198:                        final Point2D.Float po = new Point2D.Float(ox, oy);
199:                        final Point2D.Float pp = new Point2D.Float(px, py);
200:                        transform.inverseTransform(po, po);
201:                        transform.inverseTransform(pp, pp);
202:                        return new Line2D.Float(po, pp);
203:                    } else {
204:                        if (canReshape(shape, transform)) {
205:                            final Point2D.Double point = new Point2D.Double();
206:                            double xmin = Double.POSITIVE_INFINITY;
207:                            double ymin = Double.POSITIVE_INFINITY;
208:                            double xmax = Double.NEGATIVE_INFINITY;
209:                            double ymax = Double.NEGATIVE_INFINITY;
210:                            for (int i = 0; i < 4; i++) {
211:                                point.x = (i & 1) == 0 ? shape.getMinX()
212:                                        : shape.getMaxX();
213:                                point.y = (i & 2) == 0 ? shape.getMinY()
214:                                        : shape.getMaxY();
215:                                transform.inverseTransform(point, point);
216:                                if (point.x < xmin)
217:                                    xmin = point.x;
218:                                if (point.x > xmax)
219:                                    xmax = point.x;
220:                                if (point.y < ymin)
221:                                    ymin = point.y;
222:                                if (point.y > ymax)
223:                                    ymax = point.y;
224:                            }
225:                            if (shape instanceof  Rectangle) {
226:                                return new Rectangle2D.Float((float) xmin,
227:                                        (float) ymin, (float) (xmax - xmin),
228:                                        (float) (ymax - ymin));
229:                            } else {
230:                                shape = (RectangularShape) shape.clone();
231:                                shape.setFrame(xmin, ymin, xmax - xmin, ymax
232:                                        - ymin);
233:                                return shape;
234:                            }
235:                        } else {
236:                            return transform.createInverse()
237:                                    .createTransformedShape(shape);
238:                        }
239:                    }
240:                } else {
241:                    return (shape != null) ? (Shape) shape.clone()
242:                            : new Line2D.Float(ox, oy, px, py);
243:                }
244:            }
245:
246:            /**
247:             * Indicates whether we can transform {@code shape} simply by calling its
248:             * {@code shape.setFrame(...)} method rather than by using the heavy artillery
249:             * that is the {@code transform.createTransformedShape(shape)} method.
250:             */
251:            private static boolean canReshape(final RectangularShape shape,
252:                    final AffineTransform transform) {
253:                final int type = transform.getType();
254:                if ((type & AffineTransform.TYPE_GENERAL_TRANSFORM) != 0)
255:                    return false;
256:                if ((type & AffineTransform.TYPE_MASK_ROTATION) != 0)
257:                    return false;
258:                if ((type & AffineTransform.TYPE_FLIP) != 0) {
259:                    if (shape instanceof  Rectangle2D)
260:                        return true;
261:                    if (shape instanceof  Ellipse2D)
262:                        return true;
263:                    if (shape instanceof  RoundRectangle2D)
264:                        return true;
265:                    return false;
266:                }
267:                return true;
268:            }
269:
270:            /**
271:             * Returns a {@link Graphics2D} object to be used for drawing in the specified component. We
272:             * must not forget to call {@link Graphics2D#dispose} when the graphics object is no longer
273:             * needed.
274:             */
275:            private Graphics2D getGraphics(final Component c) {
276:                final Graphics2D graphics = (Graphics2D) c.getGraphics();
277:                graphics.setXORMode(lineXORColor);
278:                graphics.setColor(backXORColor);
279:                return graphics;
280:            }
281:
282:            /**
283:             * Informs this controller that the mouse button has been pressed.
284:             * The default implementation retains the mouse coordinate (which will
285:             * become one of the corners of the future rectangle to be drawn) 
286:             * and prepares {@code this} to observe the mouse movements.
287:             *
288:             * @throws ClassCastException if {@link #getModel} doesn't return a shape
289:             *         from the class {link RectangularShape} or {link Line2D}.
290:             */
291:            public void mousePressed(final MouseEvent event)
292:                    throws ClassCastException {
293:                if (!event.isConsumed()
294:                        && (event.getModifiers() & MouseEvent.BUTTON1_MASK) != 0) {
295:                    final Component source = event.getComponent();
296:                    if (source != null) {
297:                        Shape model = getModel(event);
298:                        if (model != null) {
299:                            isDragging = true;
300:                            ox = px = event.getX();
301:                            oy = py = event.getY();
302:                            if (model instanceof  Line2D) {
303:                                model = null;
304:                            }
305:                            mouseSelectedArea = (RectangularShape) model;
306:                            if (mouseSelectedArea != null) {
307:                                mouseSelectedArea.setFrame(ox, oy, 0, 0);
308:                            }
309:                            source.addMouseMotionListener(this );
310:                        }
311:                        source.requestFocus();
312:                        event.consume();
313:                    }
314:                }
315:            }
316:
317:            /**
318:             * Informs this controller that the mouse has been dragged.  The default
319:             * implementation uses this to move a corner of the rectangle used to
320:             * select the region. The other corner remains fixed at the point
321:             * where the mouse was at the moment its button was pressed..
322:             */
323:            public void mouseDragged(final MouseEvent event) {
324:                if (isDragging) {
325:                    final Graphics2D graphics = getGraphics(event
326:                            .getComponent());
327:                    if (mouseSelectedArea == null) {
328:                        graphics.drawLine(ox, oy, px, py);
329:                        px = event.getX();
330:                        py = event.getY();
331:                        graphics.drawLine(ox, oy, px, py);
332:                    } else {
333:                        graphics.draw(mouseSelectedArea);
334:                        int xmin = this .ox;
335:                        int ymin = this .oy;
336:                        int xmax = px = event.getX();
337:                        int ymax = py = event.getY();
338:                        if (xmin > xmax) {
339:                            final int xtmp = xmin;
340:                            xmin = xmax;
341:                            xmax = xtmp;
342:                        }
343:                        if (ymin > ymax) {
344:                            final int ytmp = ymin;
345:                            ymin = ymax;
346:                            ymax = ytmp;
347:                        }
348:                        mouseSelectedArea.setFrame(xmin, ymin, xmax - xmin,
349:                                ymax - ymin);
350:                        graphics.draw(mouseSelectedArea);
351:                    }
352:                    graphics.dispose();
353:                    event.consume();
354:                }
355:            }
356:
357:            /**
358:             * Informs this controller that the mouse button has been released.
359:             * The default implementation calls {@link #selectionPerformed} with
360:             * the bounds of the selected region as parameters.
361:             */
362:            public void mouseReleased(final MouseEvent event) {
363:                if (isDragging
364:                        && (event.getModifiers() & MouseEvent.BUTTON1_MASK) != 0) {
365:                    isDragging = false;
366:                    final Component component = event.getComponent();
367:                    component.removeMouseMotionListener(this );
368:
369:                    final Graphics2D graphics = getGraphics(event
370:                            .getComponent());
371:                    if (mouseSelectedArea == null) {
372:                        graphics.drawLine(ox, oy, px, py);
373:                    } else {
374:                        graphics.draw(mouseSelectedArea);
375:                    }
376:                    graphics.dispose();
377:                    px = event.getX();
378:                    py = event.getY();
379:                    selectionPerformed(ox, oy, px, py);
380:                    event.consume();
381:                }
382:            }
383:
384:            /**
385:             * Informs this controller that the mouse has been moved but not as a
386:             * result of the user selecting a region.  The default implementation
387:             * signals to the source component that {@code this} is no longer
388:             * interested in being informed about mouse movements.
389:             */
390:            public void mouseMoved(final MouseEvent event) {
391:                // Normally not necessary, but it seems that this "listener"
392:                // sometimes stays in place when it shouldn't.
393:                event.getComponent().removeMouseMotionListener(this);
394:            }
395:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.