Statistics
| Revision:

root / trunk / libraries / libUIComponent / src / org / gvsig / gui / beans / imagenavigator / ImageNavigator.java @ 12385

History | View | Annotate | Download (15.4 KB)

1
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
2
 *
3
 * Copyright (C) 2005 IVER T.I. and Generalitat Valenciana.
4
 *
5
 * This program is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU General Public License
7
 * as published by the Free Software Foundation; either version 2
8
 * of the License, or (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
18
 */
19
package org.gvsig.gui.beans.imagenavigator;
20

    
21
import java.awt.AlphaComposite;
22
import java.awt.Color;
23
import java.awt.Cursor;
24
import java.awt.Graphics;
25
import java.awt.Graphics2D;
26
import java.awt.Image;
27
import java.awt.Point;
28
import java.awt.RenderingHints;
29
import java.awt.event.KeyEvent;
30
import java.awt.event.KeyListener;
31
import java.awt.event.MouseEvent;
32
import java.awt.event.MouseListener;
33
import java.awt.event.MouseMotionListener;
34
import java.awt.event.MouseWheelEvent;
35
import java.awt.event.MouseWheelListener;
36

    
37
import javax.swing.JComponent;
38
/**
39
 * <code>ImageNavigator</code> es un componente que representa un manejador
40
 * de im?genes. En ?l se puede desplazar, hacer un zoom out o un zoom in a una
41
 * imagen virtual. El componente no trata la imagen en si, solo lanza los
42
 * eventos indicando la nueva posici?n y zoom de la imagen, luego es el usuario
43
 * el que se encargar? de dibujar esa imagen en la posici?n correspondiente.
44
 *
45
 * El modo de uso es el siguiente:
46
 * - Se puede desplazar una imagen con el bot?n izquierdo del rat?n.
47
 * - Se puede hacer zoom in/out con las teclas +/- del teclado.
48
 * - Se puede hacer zoom in/out con la rueda del rat?n teniendo en cuenta la
49
 * posici?n del mismo.
50
 * - Se puede resetear los valores con las teclas 'Espacio' o 0;
51
 * - Las teclas 1, 2, 3, 4 y 5 equivalen a zoom 1, 2, 4, 8 y 16 respectivamente.
52
 * - La tecla C sirve para centrar la imagen.
53
 *
54
 * @version 04/05/2007
55
 * @author BorSanZa - Borja S?nchez Zamorano (borja.sanchez@iver.es)
56
 *
57
 */
58
public class ImageNavigator extends JComponent implements KeyListener, MouseMotionListener, MouseListener, MouseWheelListener {
59
        private static final long serialVersionUID = 1164788214432359272L;
60
        private IClientImageNavigator iClient = null;
61

    
62
        private Image                                image = null;
63
        private Graphics2D        widgetGraphics = null;
64
        private Image                                imageCache = null;
65
        private Graphics2D        cacheGraphics = null;
66

    
67
        private double                        zoom = 1.0;
68
        private double                        x1 = 0.0;
69
        private double                        y1 = 0.0;
70
        private boolean                        yInverted = false;
71
        private boolean                        xInverted = false;
72
        private int                                        width = 0, height = 0;
73
        private boolean     showHelp = false;
74

    
75
        /**
76
         * Crea un <code>ImageNavigator</code> especificandole quien pintara el
77
         * componente
78
         *
79
         * @param iClient
80
         */
81
        public ImageNavigator(IClientImageNavigator iClient) {
82
                this.iClient = iClient;
83

    
84
                this.setFocusable(true);
85
                this.addKeyListener(this);
86
                this.addMouseMotionListener(this);
87
                this.addMouseListener(this);
88
                this.addMouseWheelListener(this);
89
                this.setCursor(new Cursor(Cursor.MOVE_CURSOR));
90
        }
91

    
92
        double initX1 = 0.0;
93
        double initY1 = 0.0;
94
        double initX2 = 100.0;
95
        double initY2 = 100.0;
96
        double initZoom = 1.0;
97
        boolean autoAdjusted = true;
98

    
99
        /**
100
         * Actualiza las dimensiones para ajustar la imagen a los bordes especificados
101
         * con setViewDimensions.
102
         */
103
        private void updateDimensions() {
104
                double factor = this.getWidth() / (initX2 - initX1);
105
                if (factor > (this.getHeight() / (initY2 - initY1)))
106
                        factor = this.getHeight() / (initY2 - initY1);
107
                zoom = factor;
108
                imageCenter();
109
        }
110

    
111
        /**
112
         * Centra la imagen
113
         */
114
        public void imageCenter() {
115
                x1 = initX1;
116
                y1 = initY1;
117

    
118
                if (isXInverted())
119
                        x1 -= ((initX2 - initX1) - this.getWidth() / zoom) / 2.0;
120
                else
121
                        x1 += ((initX2 - initX1) - this.getWidth() / zoom) / 2.0;
122
                if (isYInverted())
123
                        y1 -= ((initY2 - initY1) - this.getHeight() / zoom) / 2.0;
124
                else
125
                        y1 += ((initY2 - initY1) - this.getHeight() / zoom) / 2.0;
126
        }
127

    
128
        /**
129
         * Especifica el rectangulo de la imagen a visualizar, pudiendo tener
130
         * cualquiera de los ejes X e Y invertidos
131
         *
132
         * @param x1 Coordenada izquierda
133
         * @param y1 Coordenada superior
134
         * @param x2 Coordenada derecha
135
         * @param y2 Coordenada inferior
136
         */
137
        public void setViewDimensions(double x1, double y1, double x2, double y2) {
138
                this.initX1 = x1;
139
                this.initX2 = x2;
140
                this.initY1 = y1;
141
                this.initY2 = y2;
142

    
143
                yInverted = (y2 < y1);
144
                if (yInverted) {
145
                        this.initY1 = y2;
146
                        this.initY2 = y1;
147
                }
148

    
149
                xInverted = (x2 < x1);
150
                if (xInverted) {
151
                        this.initX1 = x2;
152
                        this.initX2 = x1;
153
                }
154

    
155
                this.updateDimensions();
156
        }
157

    
158
        /**
159
         * Hace un forzado de pintado del buffer temporal de la imagen. Este m?todo
160
         * forzar? una llamada a la funci?n de pintado del cliente.
161
         */
162
        public void updateBuffer() {
163
                updateImageCache(true);
164
                refreshImage(0, 0);
165
        }
166

    
167
        /**
168
         * Especifica el zoom que usar? por defecto el componente.
169
         * @param zoom
170
         */
171
        public void setZoom(double zoom) {
172
                initZoom = zoom;
173
                this.zoom = initZoom;
174
                autoAdjusted = false;
175
                imageCenter();
176
        }
177

    
178
        /*
179
         * (non-Javadoc)
180
         * @see javax.swing.JComponent#addNotify()
181
         */
182
        public void addNotify() {
183
                super.addNotify();
184

    
185
                updateImageCache(true);
186
                refreshImage(0, 0);
187
        }
188

    
189
        /**
190
         * Hace un zoom de aumento en las coordenadas especificadas
191
         * @param x
192
         * @param y
193
         */
194
        private void ZoomIn(double x, double y) {
195
                if ((int) (zoom * 100.0) >= (25600.0 / initZoom))
196
                        return;
197
                double xcent = (x / zoom);
198
                double ycent = (y / zoom);
199
                if (isXInverted())
200
                        x1 -= xcent;
201
                else
202
                        x1 += xcent;
203
                if (isYInverted())
204
                        y1 -= ycent;
205
                else
206
                        y1 += ycent;
207
                zoom = zoom * 2.0;
208
                xcent = (x / zoom);
209
                ycent = (y / zoom);
210
                if (isXInverted())
211
                        x1 += xcent;
212
                else
213
                        x1 -= xcent;
214
                if (isYInverted())
215
                        y1 += ycent;
216
                else
217
                        y1 -= ycent;
218
                updateImageCache(true);
219
                refreshImage(0, 0);
220
        }
221

    
222
        /**
223
         * Hace un zoom hacia afuera en las coordenadas especificadas
224
         * @param x
225
         * @param y
226
         */
227
        private void ZoomOut(double x, double y) {
228
                if ((int) ((1.0 / zoom) * 100.0) >= (25600.0 / initZoom))
229
                        return;
230

    
231
                double xcent = (x / zoom);
232
                double ycent = (y / zoom);
233
                if (isXInverted())
234
                        x1 -= xcent;
235
                else
236
                        x1 += xcent;
237
                if (isYInverted())
238
                        y1 -= ycent;
239
                else
240
                        y1 += ycent;
241
                zoom = zoom / 2.0;
242
                xcent = (x / zoom);
243
                ycent = (y / zoom);
244
                if (isXInverted())
245
                        x1 += xcent;
246
                else
247
                        x1 -= xcent;
248
                if (isYInverted())
249
                        y1 += ycent;
250
                else
251
                        y1 -= ycent;
252
                updateImageCache(true);
253
                refreshImage(0, 0);
254
        }
255

    
256
        /**
257
         * Mostrar o ocultar la ayuda
258
         *
259
         */
260
        private void callShowHelp() {
261
                showHelp = !showHelp;
262
                if (showHelp)
263
                        this.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
264
                else
265
                        this.setCursor(new Cursor(Cursor.MOVE_CURSOR));
266
                updateImageCache(true);
267
                refreshImage(0, 0);
268
        }
269

    
270
        /*
271
         * (non-Javadoc)
272
         * @see java.awt.event.KeyListener#keyPressed(java.awt.event.KeyEvent)
273
         */
274
        public void keyPressed(KeyEvent e) {
275
                switch (e.getKeyChar()) {
276
                        case 'h':
277
                        case 'H':
278
                                callShowHelp();
279
                                break;
280
                }
281

    
282
                if (showHelp)
283
                        return;
284

    
285
                switch (e.getKeyChar()) {
286
                        case '+':
287
                                ZoomIn(width / 2.0, height / 2.0);
288
                                autoAdjusted = false;
289
                                break;
290
                        case '-':
291
                                ZoomOut(width / 2.0, height / 2.0);
292
                                autoAdjusted = false;
293
                                break;
294
                        case '1':
295
                                autoAdjusted = false;
296
                                this.zoom = initZoom;
297
                                imageCenter();
298
                                updateImageCache(true);
299
                                refreshImage(0, 0);
300
                                break;
301
                        case '2':
302
                                autoAdjusted = false;
303
                                this.zoom = initZoom * 2.0;
304
                                imageCenter();
305
                                updateImageCache(true);
306
                                refreshImage(0, 0);
307
                                break;
308
                        case '3':
309
                                autoAdjusted = false;
310
                                this.zoom = initZoom * 4.0;
311
                                imageCenter();
312
                                updateImageCache(true);
313
                                refreshImage(0, 0);
314
                                break;
315
                        case '4':
316
                                autoAdjusted = false;
317
                                this.zoom = initZoom * 8.0;
318
                                imageCenter();
319
                                updateImageCache(true);
320
                                refreshImage(0, 0);
321
                                break;
322
                        case '5':
323
                                autoAdjusted = false;
324
                                this.zoom = initZoom * 16.0;
325
                                imageCenter();
326
                                updateImageCache(true);
327
                                refreshImage(0, 0);
328
                                break;
329
                        case 'c':
330
                        case 'C':
331
                                imageCenter();
332
                                updateImageCache(true);
333
                                refreshImage(0, 0);
334
                                break;
335
                        case '0':
336
                        case ' ':
337
                                autoAdjusted = true;
338
                                updateDimensions();
339
                                updateImageCache(true);
340
                                refreshImage(0, 0);
341
                                break;
342
                }
343
        }
344

    
345
        double updateWidth = 0;
346
        double updateHeight = 0;
347
        /**
348
         * M?todo que hara la invocaci?n al cliente del pintado del trozo de imagen a
349
         * visualizar
350
         * @param forceUpdate
351
         */
352
        private void updateImageCache(boolean forceUpdate) {
353
                if (getWidgetImage() == null ||
354
                                (updateWidth == getWidgetImage().getWidth(this) &&
355
                                updateHeight == getWidgetImage().getHeight(this) &&
356
                                !forceUpdate))
357
                        return;
358
                updateWidth = getWidgetImage().getWidth(this);
359
                updateHeight = getWidgetImage().getHeight(this);
360

    
361
                getCacheGraphics().setColor(Color.WHITE);
362
                getCacheGraphics().fillRect(0, 0, width, height);
363

    
364
                double newY1 = 0.0;
365
                double newY2 = 0.0;
366
                double newX1 = 0.0;
367
                double newX2 = 0.0;
368
                if (isYInverted()) {
369
                        newY1 = y1 + this.getHeight() / zoom - ((y1 - initY1) * 2.0);
370
                        newY2 = newY1 - this.getHeight() / zoom;
371
                } else {
372
                        newY1 = y1;
373
                        newY2 = y1 + this.getHeight() / zoom;
374
                }
375
                if (isXInverted()) {
376
                        newX1 = x1 + this.getWidth() / zoom - ((x1 - initX1) * 2.0);
377
                        newX2 = newX1 - this.getWidth() / zoom;
378
                } else {
379
                        newX1 = x1;
380
                        newX2 = x1 + this.getWidth() / zoom;
381
                }
382
                iClient.drawImage(getCacheGraphics(), newX1, newY1, newX2, newY2, zoom, this.getWidth(), this.getHeight());
383
        }
384

    
385
        private Image getWidgetImage() {
386
                int width2 = getBounds().width;
387
                int height2 = getBounds().height;
388
                if (width2 <= 0)
389
                        width2 = 1;
390
                if (height2 <= 0)
391
                        height2=1;
392

    
393
                if ((width != width2) || (height != height2)) {
394
                        image = createImage(width2, height2);
395
                        imageCache = createImage(width2, height2);
396
                        if (image == null)
397
                                return null;
398
                        widgetGraphics = (Graphics2D) image.getGraphics();
399
                        cacheGraphics = (Graphics2D) imageCache.getGraphics();
400

    
401
                        RenderingHints hints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
402
                        hints.add(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY));
403
                        cacheGraphics.setRenderingHints(hints);
404
                }
405

    
406
                width = width2;
407
                height = height2;
408
                return image;
409
        }
410

    
411
        private Graphics2D getWidgetGraphics() {
412
                getWidgetImage();
413
                return widgetGraphics;
414
        }
415

    
416
        private Graphics2D getCacheGraphics() {
417
                getWidgetImage();
418
                return cacheGraphics;
419
        }
420

    
421
        /**
422
         * Redibujar el componente en el graphics temporal
423
         */
424
        private void redrawBuffer(int x, int y) {
425
                getWidgetGraphics().setColor(Color.white);
426
                getWidgetGraphics().fillRect(0, 0, width, height);
427

    
428
                getWidgetGraphics().drawImage(imageCache, x, y, null);
429
        }
430

    
431
        /*
432
         * (non-Javadoc)
433
         * @see javax.swing.JComponent#paint(java.awt.Graphics)
434
         */
435
        public void paint(Graphics g) {
436
                if (autoAdjusted) updateDimensions();
437
                Graphics2D g2d = (Graphics2D) g;
438
                RenderingHints hints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
439
                hints.add(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY));
440
                g2d.setRenderingHints(hints);
441

    
442
                updateImageCache(false);
443

    
444
                redrawBuffer(0, 0);
445

    
446
                if (image != null)
447
                        g.drawImage(image, 0, 0, this);
448

    
449
                paintHelp((Graphics2D) g);
450
        }
451

    
452
        /**
453
         * Redibujar el componente en el graphics temporal y representarlo en el
454
         * componente
455
         */
456
        private void refreshImage(int x, int y) {
457
                Graphics2D g2d = (Graphics2D) getGraphics();
458
                if (g2d == null)
459
                        return;
460
                RenderingHints hints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
461
                hints.add(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY));
462
                g2d.setRenderingHints(hints);
463
                redrawBuffer(x, y);
464

    
465
                if (image != null)
466
                        getGraphics().drawImage(image, 0, 0, this);
467

    
468
                paintHelp((Graphics2D) getGraphics());
469
        }
470

    
471
        private void paintHelp(Graphics2D g) {
472
                if (!showHelp)
473
                        return;
474

    
475
                int sep = 13;
476
                int pos = sep + 1;
477

    
478
                int alto = sep * 6 + 19;
479

    
480
                Image image2 = createImage(width, alto);
481
                Graphics graphics2 = image2.getGraphics();
482
                alto--;
483

    
484
                for (int i=0; i<alto; i++) {
485
                        graphics2.setColor(new Color(255, 255, 152 - ((i*52)/alto)));
486
                        graphics2.drawLine(0, i, width, i);
487
                }
488

    
489
                graphics2.setColor(new Color(0, 0, 0));
490

    
491
                graphics2.setFont(new java.awt.Font("Tahoma", 1, sep - 2));
492

    
493
                graphics2.drawString("Teclas:", 10, pos);
494

    
495
                graphics2.setFont(new java.awt.Font("Tahoma", 0, sep - 2));
496
                pos+=sep;
497
                graphics2.drawString("H: Ayuda", 20, pos);
498
                pos+=sep;
499
                graphics2.drawString("1-5: Zoom", 20, pos);
500
                pos+=sep;
501
                graphics2.drawString("+: Acercar", 20, pos);
502
                pos+=sep;
503
                graphics2.drawString("-: Alejar", 20, pos);
504
                pos+=sep;
505
                graphics2.drawString("C: Centrar", 20, pos);
506
                pos+=sep;
507
                graphics2.drawString("Espacio, 0: Ver todo", 20, pos);
508

    
509
                graphics2.setColor(new Color(185, 185, 185));
510
                graphics2.drawLine(0, alto, width, alto);
511

    
512
                AlphaComposite myAlpha = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.9f);
513
                g.setComposite(myAlpha);
514

    
515
                g.drawImage(image2, 0, 0, this);
516
        }
517

    
518
        Point mouse = null;
519
        /*
520
         * (non-Javadoc)
521
         * @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent)
522
         */
523
        public void mousePressed(MouseEvent e) {
524
                if (showHelp) return;
525
                requestFocus();
526
                if ((e.getButton() != MouseEvent.BUTTON1) && (e.getButton() != MouseEvent.BUTTON2))
527
                        return;
528

    
529
                Color gris = new Color(0, 0, 0, 16);
530
                getCacheGraphics().setColor(gris);
531
                getCacheGraphics().fillRect(0, 0, width-1, height-1);
532
                getCacheGraphics().setColor(Color.gray);
533
                getCacheGraphics().drawRect(0, 0, width-1, height-1);
534

    
535
                mouse = new Point(e.getX(), e.getY());
536
                changePos(e.getX(), e.getY());
537
                autoAdjusted = false;
538
        }
539

    
540
        /*
541
         * (non-Javadoc)
542
         * @see java.awt.event.MouseMotionListener#mouseDragged(java.awt.event.MouseEvent)
543
         */
544
        public void mouseDragged(MouseEvent e) {
545
                if (showHelp) return;
546
                changePos(e.getX(), e.getY());
547
        }
548

    
549
        /*
550
         * (non-Javadoc)
551
         * @see java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent)
552
         */
553
        public void mouseReleased(MouseEvent e) {
554
                if (showHelp) return;
555
                if (mouse != null) {
556
                        x1 = x1 - ((e.getX() - mouse.getX())/zoom);
557
                        y1 = y1 - ((e.getY() - mouse.getY())/zoom);
558
                        updateImageCache(true);
559
                        refreshImage(0, 0);
560
                }
561
                mouse = null;
562
        }
563

    
564
        private void changePos(int x, int y) {
565
                if (mouse != null)
566
                        refreshImage((int) (x - mouse.getX()), (int) (y - mouse.getY()));
567
        }
568

    
569
        /**
570
         * Evento de la rueda del rat?n para hacer Zoom In o Zoom Out en la posici?n
571
         * del puntero.
572
         */
573
        public void mouseWheelMoved(MouseWheelEvent e) {
574
                if (showHelp) return;
575
                if (e.getWheelRotation() > 0) {
576
                        ZoomOut(isXInverted() ? this.getWidth() - e.getX() : e.getX(), isYInverted() ? this.getHeight() - e.getY() : e.getY());
577
                        autoAdjusted = false;
578
                }
579
                if (e.getWheelRotation() < 0) {
580
                        ZoomIn(isXInverted() ? this.getWidth() - e.getX() : e.getX(), isYInverted() ? this.getHeight() - e.getY() : e.getY());
581
                        autoAdjusted = false;
582
                }
583
        }
584

    
585
        /**
586
         * Obtener si el eje de las Y esta invertido
587
         * @return
588
         */
589
        private boolean isYInverted() {
590
                return yInverted;
591
        }
592

    
593
        /**
594
         * Obtener si el eje de las X esta invertido
595
         * @return
596
         */
597
        private boolean isXInverted() {
598
                return xInverted;
599
        }
600

    
601
        public void keyReleased(KeyEvent e) {}
602
        public void keyTyped(KeyEvent e) {}
603
        public void mouseMoved(MouseEvent e) {}
604
        public void mouseClicked(MouseEvent e) {}
605
        public void mouseEntered(MouseEvent e) {}
606
        public void mouseExited(MouseEvent e) {}
607

    
608
}