Statistics
| Revision:

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

History | View | Annotate | Download (17 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.GradientPaint;
25
import java.awt.Graphics;
26
import java.awt.Graphics2D;
27
import java.awt.Image;
28
import java.awt.Point;
29
import java.awt.RenderingHints;
30
import java.awt.event.KeyEvent;
31
import java.awt.event.KeyListener;
32
import java.awt.event.MouseEvent;
33
import java.awt.event.MouseListener;
34
import java.awt.event.MouseMotionListener;
35
import java.awt.event.MouseWheelEvent;
36
import java.awt.event.MouseWheelListener;
37

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

    
64
        private Image                 image          = null;
65
        private Graphics2D            widgetGraphics = null;
66
        private Image                 imageCache     = null;
67
        private Graphics2D            cacheGraphics  = null;
68

    
69
        private double                zoom           = 1.0;
70
        private double                x1             = 0.0;
71
        private double                y1             = 0.0;
72
        private boolean               yInverted      = false;
73
        private boolean               xInverted      = false;
74
        private int                   width          = 0;
75
        private int                   height         = 0;
76
        private boolean               showHelp       = false;
77
        ImageIcon                     imageIconClose;
78
        ImageIcon                     imageIconHelp;
79

    
80
        /**
81
         * Crea un <code>ImageNavigator</code> especificandole quien pintara el
82
         * componente
83
         * @param iClient
84
         */
85
        public ImageNavigator(IClientImageNavigator iClient) {
86
                this.iClient = iClient;
87

    
88
                this.setFocusable(true);
89
                this.addKeyListener(this);
90
                this.addMouseMotionListener(this);
91
                this.addMouseListener(this);
92
                this.addMouseWheelListener(this);
93
        }
94

    
95
        double initX1 = 0.0;
96
        double initY1 = 0.0;
97
        double initX2 = 100.0;
98
        double initY2 = 100.0;
99
        double initZoom = 1.0;
100
        boolean autoAdjusted = true;
101

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

    
114
        /**
115
         * Centra la imagen
116
         */
117
        public void imageCenter() {
118
                x1 = initX1;
119
                y1 = initY1;
120

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

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

    
146
                yInverted = (y2 < y1);
147
                if (yInverted) {
148
                        this.initY1 = y2;
149
                        this.initY2 = y1;
150
                }
151

    
152
                xInverted = (x2 < x1);
153
                if (xInverted) {
154
                        this.initX1 = x2;
155
                        this.initX2 = x1;
156
                }
157

    
158
                this.updateDimensions();
159
        }
160

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

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

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

    
188
                updateImageCache(true);
189
                refreshImage(0, 0);
190
        }
191

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

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

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

    
259
        /**
260
         * Mostrar o ocultar la ayuda
261
         *
262
         */
263
        private void callShowHelp() {
264
                showHelp = !showHelp;
265
                updateImageCache(true);
266
                refreshImage(0, 0);
267
        }
268

    
269
        /*
270
         * (non-Javadoc)
271
         * @see java.awt.event.KeyListener#keyPressed(java.awt.event.KeyEvent)
272
         */
273
        public void keyPressed(KeyEvent e) {
274
                switch (e.getKeyChar()) {
275
                        case 'h':
276
                        case 'H':
277
                                callShowHelp();
278
                                break;
279
                        case '+':
280
                                ZoomIn(width / 2.0, height / 2.0);
281
                                autoAdjusted = false;
282
                                break;
283
                        case '-':
284
                                ZoomOut(width / 2.0, height / 2.0);
285
                                autoAdjusted = false;
286
                                break;
287
                        case '1':
288
                                autoAdjusted = false;
289
                                this.zoom = initZoom;
290
                                imageCenter();
291
                                updateImageCache(true);
292
                                refreshImage(0, 0);
293
                                break;
294
                        case '2':
295
                                autoAdjusted = false;
296
                                this.zoom = initZoom * 2.0;
297
                                imageCenter();
298
                                updateImageCache(true);
299
                                refreshImage(0, 0);
300
                                break;
301
                        case '3':
302
                                autoAdjusted = false;
303
                                this.zoom = initZoom * 4.0;
304
                                imageCenter();
305
                                updateImageCache(true);
306
                                refreshImage(0, 0);
307
                                break;
308
                        case '4':
309
                                autoAdjusted = false;
310
                                this.zoom = initZoom * 8.0;
311
                                imageCenter();
312
                                updateImageCache(true);
313
                                refreshImage(0, 0);
314
                                break;
315
                        case '5':
316
                                autoAdjusted = false;
317
                                this.zoom = initZoom * 16.0;
318
                                imageCenter();
319
                                updateImageCache(true);
320
                                refreshImage(0, 0);
321
                                break;
322
                        case 'c':
323
                        case 'C':
324
                                imageCenter();
325
                                updateImageCache(true);
326
                                refreshImage(0, 0);
327
                                break;
328
                        case '0':
329
                        case ' ':
330
                                autoAdjusted = true;
331
                                updateDimensions();
332
                                updateImageCache(true);
333
                                refreshImage(0, 0);
334
                                break;
335
                }
336
        }
337

    
338
        double updateWidth = 0;
339
        double updateHeight = 0;
340
        /**
341
         * M?todo que hara la invocaci?n al cliente del pintado del trozo de imagen a
342
         * visualizar
343
         * @param forceUpdate
344
         */
345
        private void updateImageCache(boolean forceUpdate) {
346
                if (getWidgetImage() == null ||
347
                                (updateWidth == getWidgetImage().getWidth(this) &&
348
                                updateHeight == getWidgetImage().getHeight(this) &&
349
                                !forceUpdate))
350
                        return;
351
                updateWidth = getWidgetImage().getWidth(this);
352
                updateHeight = getWidgetImage().getHeight(this);
353

    
354
                getCacheGraphics().setColor(Color.WHITE);
355
                getCacheGraphics().fillRect(0, 0, width, height);
356

    
357
                double newY1 = 0.0;
358
                double newY2 = 0.0;
359
                double newX1 = 0.0;
360
                double newX2 = 0.0;
361
                if (isYInverted()) {
362
                        newY1 = y1 + this.getHeight() / zoom - ((y1 - initY1) * 2.0);
363
                        newY2 = newY1 - this.getHeight() / zoom;
364
                } else {
365
                        newY1 = y1;
366
                        newY2 = y1 + this.getHeight() / zoom;
367
                }
368
                if (isXInverted()) {
369
                        newX1 = x1 + this.getWidth() / zoom - ((x1 - initX1) * 2.0);
370
                        newX2 = newX1 - this.getWidth() / zoom;
371
                } else {
372
                        newX1 = x1;
373
                        newX2 = x1 + this.getWidth() / zoom;
374
                }
375
                iClient.drawImage(getCacheGraphics(), newX1, newY1, newX2, newY2, zoom, this.getWidth(), this.getHeight());
376
        }
377

    
378
        private Image getWidgetImage() {
379
                int width2 = getBounds().width;
380
                int height2 = getBounds().height;
381
                if (width2 <= 0)
382
                        width2 = 1;
383
                if (height2 <= 0)
384
                        height2=1;
385

    
386
                if ((width != width2) || (height != height2)) {
387
                        image = createImage(width2, height2);
388
                        imageCache = createImage(width2, height2);
389
                        if (image == null)
390
                                return null;
391
                        widgetGraphics = (Graphics2D) image.getGraphics();
392
                        cacheGraphics = (Graphics2D) imageCache.getGraphics();
393

    
394
                        RenderingHints hints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
395
                        hints.add(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY));
396
                        cacheGraphics.setRenderingHints(hints);
397
                }
398

    
399
                width = width2;
400
                height = height2;
401
                return image;
402
        }
403

    
404
        private Graphics2D getWidgetGraphics() {
405
                getWidgetImage();
406
                return widgetGraphics;
407
        }
408

    
409
        private Graphics2D getCacheGraphics() {
410
                getWidgetImage();
411
                return cacheGraphics;
412
        }
413

    
414
        /**
415
         * Redibujar el componente en el graphics temporal
416
         */
417
        private void redrawBuffer(int x, int y) {
418
                getWidgetGraphics().setColor(Color.white);
419
                getWidgetGraphics().fillRect(0, 0, width, height);
420

    
421
                getWidgetGraphics().drawImage(imageCache, x, y, null);
422

    
423
                if (showHelp)
424
                        paintHelp((Graphics2D) getWidgetGraphics());
425
                else
426
                        getWidgetGraphics().drawImage(getIconHelp().getImage(), width - getIconHelp().getIconWidth() - 4, 3, null);
427
        }
428

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

    
440
                updateImageCache(false);
441

    
442
                redrawBuffer(0, 0);
443

    
444
                if (image != null)
445
                        g.drawImage(image, 0, 0, this);
446

    
447
//                paintHelp((Graphics2D) g);
448
        }
449

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

    
463
                if (image != null)
464
                        getGraphics().drawImage(image, 0, 0, this);
465

    
466
//                paintHelp((Graphics2D) getGraphics());
467
        }
468

    
469
        /**
470
         * Devuelve el icono de cerrar
471
         * @return
472
         */
473
        private ImageIcon getIconClose() {
474
                if (imageIconClose == null) {
475
                        imageIconClose = new ImageIcon(getClass().getResource("images/close.png"));
476
                }
477
                return imageIconClose;
478
        }
479

    
480
        /**
481
         * Devuelve el icono ayuda
482
         * @return
483
         */
484
        private ImageIcon getIconHelp() {
485
                if (imageIconHelp == null) {
486
                        imageIconHelp = new ImageIcon(getClass().getResource("images/help.png"));
487
                }
488
                return imageIconHelp;
489
        }
490

    
491
        private void paintHelp(Graphics2D g) {
492
                int sep = 13;
493
                int pos = sep + 1;
494

    
495
                int alto = sep * 7 + 6;
496

    
497
                Image image2 = createImage(width, alto);
498
                Graphics2D graphics2 = (Graphics2D) image2.getGraphics();
499

    
500
                RenderingHints hints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
501
                hints.add(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY));
502
                graphics2.setRenderingHints(hints);
503

    
504
                alto--;
505

    
506
                Color color1 = new Color(255, 255, 178);
507
                Color color2 = new Color(255, 255, 74);
508
                graphics2.setPaint(new GradientPaint(0, 0, color1, 0, alto, color2, false));
509
                graphics2.fillRect(0, 0, width, alto);
510

    
511
                graphics2.setColor(new Color(0, 0, 0));
512

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

    
515
                graphics2.drawString("Teclas:", 10, pos);
516

    
517
                graphics2.setFont(new java.awt.Font("Tahoma", 0, sep - 2));
518
                pos+=sep;
519
                graphics2.drawString("H: Ayuda", 20, pos);
520
                pos+=sep;
521
                graphics2.drawString("1-5: Zoom", 20, pos);
522
                pos+=sep;
523
                graphics2.drawString("+: Acercar", 20, pos);
524
                pos+=sep;
525
                graphics2.drawString("-: Alejar", 20, pos);
526
                pos+=sep;
527
                graphics2.drawString("C: Centrar", 20, pos);
528
                pos+=sep;
529
                graphics2.drawString("Espacio, 0: Ver todo", 20, pos);
530

    
531
                graphics2.setColor(new Color(185, 185, 185));
532
                graphics2.drawLine(0, alto, width, alto);
533

    
534
                graphics2.drawImage(getIconClose().getImage(), width - getIconClose().getIconWidth() - 4, 3, null);
535

    
536
                AlphaComposite myAlpha = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.7f);
537
                g.setComposite(myAlpha);
538

    
539
                g.drawImage(image2, 0, 0, this);
540

    
541
                myAlpha = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f);
542
                g.setComposite(myAlpha);
543
        }
544

    
545
        Point mouse = null;
546
        /*
547
         * (non-Javadoc)
548
         * @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent)
549
         */
550
        public void mousePressed(MouseEvent e) {
551
                if ((e.getX() > (width - 20)) && (e.getY() < 20)) {
552
                        callShowHelp();
553
                        return;
554
                }
555

    
556
                requestFocus();
557
                if ((e.getButton() != MouseEvent.BUTTON1) && (e.getButton() != MouseEvent.BUTTON2))
558
                        return;
559

    
560
                Color gris = new Color(0, 0, 0, 16);
561
                getCacheGraphics().setColor(gris);
562
                getCacheGraphics().fillRect(0, 0, width-1, height-1);
563
                getCacheGraphics().setColor(Color.gray);
564
                getCacheGraphics().drawRect(0, 0, width-1, height-1);
565

    
566
                mouse = new Point(e.getX(), e.getY());
567
                changePos(e.getX(), e.getY());
568
                autoAdjusted = false;
569
        }
570

    
571
        /*
572
         * (non-Javadoc)
573
         * @see java.awt.event.MouseMotionListener#mouseDragged(java.awt.event.MouseEvent)
574
         */
575
        public void mouseDragged(MouseEvent e) {
576
                changePos(e.getX(), e.getY());
577
        }
578

    
579
        /*
580
         * (non-Javadoc)
581
         * @see java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent)
582
         */
583
        public void mouseReleased(MouseEvent e) {
584
                if (mouse != null) {
585
                        x1 = x1 - ((e.getX() - mouse.getX())/zoom);
586
                        y1 = y1 - ((e.getY() - mouse.getY())/zoom);
587
                        updateImageCache(true);
588
                        refreshImage(0, 0);
589
                }
590
                mouse = null;
591
        }
592

    
593
        private void changePos(int x, int y) {
594
                if (mouse != null)
595
                        refreshImage((int) (x - mouse.getX()), (int) (y - mouse.getY()));
596
        }
597

    
598
        /**
599
         * Evento de la rueda del rat?n para hacer Zoom In o Zoom Out en la posici?n
600
         * del puntero.
601
         */
602
        public void mouseWheelMoved(MouseWheelEvent e) {
603
                if (e.getWheelRotation() > 0) {
604
                        ZoomOut(isXInverted() ? this.getWidth() - e.getX() : e.getX(), isYInverted() ? this.getHeight() - e.getY() : e.getY());
605
                        autoAdjusted = false;
606
                }
607
                if (e.getWheelRotation() < 0) {
608
                        ZoomIn(isXInverted() ? this.getWidth() - e.getX() : e.getX(), isYInverted() ? this.getHeight() - e.getY() : e.getY());
609
                        autoAdjusted = false;
610
                }
611
        }
612

    
613
        /**
614
         * Obtener si el eje de las Y esta invertido
615
         * @return
616
         */
617
        private boolean isYInverted() {
618
                return yInverted;
619
        }
620

    
621
        /**
622
         * Obtener si el eje de las X esta invertido
623
         * @return
624
         */
625
        private boolean isXInverted() {
626
                return xInverted;
627
        }
628

    
629
        /*
630
         * (non-Javadoc)
631
         * @see java.awt.event.MouseMotionListener#mouseMoved(java.awt.event.MouseEvent)
632
         */
633
        public void mouseMoved(MouseEvent e) {
634
                if ((e.getX() > (width - 20)) && (e.getY() < 20)) {
635
                        setCursor(new Cursor(Cursor.HAND_CURSOR));
636
                } else {
637
                        setCursor(new Cursor(Cursor.MOVE_CURSOR));
638
                }
639
        }
640

    
641
        public void keyReleased(KeyEvent e) {}
642
        public void keyTyped(KeyEvent e) {}
643
        public void mouseClicked(MouseEvent e) {}
644
        public void mouseEntered(MouseEvent e) {}
645
        public void mouseExited(MouseEvent e) {}
646

    
647
}