Statistics
| Revision:

svn-document-layout / trunk / org.gvsig.app.document.layout2.app / org.gvsig.app.document.layout2.app.mainplugin / src / main / java / org / gvsig / app / project / documents / layout / fframes / FFrameView.java @ 245

History | View | Annotate | Download (45.1 KB)

1
/* gvSIG. Geographic Information System of the Valencian Government
2
 *
3
 * Copyright (C) 2007-2008 Infrastructures and Transports Department
4
 * of the Valencian Government (CIT)
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 2
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 */
22
package org.gvsig.app.project.documents.layout.fframes;
23

    
24
import java.awt.BasicStroke;
25
import java.awt.Color;
26
import java.awt.Dimension;
27
import java.awt.Font;
28
import java.awt.Graphics2D;
29
import java.awt.Point;
30
import java.awt.Rectangle;
31
import java.awt.geom.AffineTransform;
32
import java.awt.geom.Area;
33
import java.awt.geom.NoninvertibleTransformException;
34
import java.awt.geom.Point2D;
35
import java.awt.geom.Rectangle2D;
36
import java.awt.image.BufferedImage;
37

    
38
import org.cresques.cts.IProjection;
39
import org.gvsig.andami.PluginServices;
40
import org.gvsig.andami.messages.NotificationManager;
41
import org.gvsig.andami.ui.mdiFrame.NewStatusBar;
42
import org.gvsig.app.project.Project;
43
import org.gvsig.app.project.ProjectManager;
44
import org.gvsig.app.project.documents.Document;
45
import org.gvsig.app.project.documents.layout.DefaultLayoutNotification;
46
import org.gvsig.app.project.documents.layout.FLayoutFunctions;
47
import org.gvsig.app.project.documents.layout.FLayoutUtilities;
48
import org.gvsig.app.project.documents.layout.LayoutNotification;
49
import org.gvsig.app.project.documents.layout.TocModelChangedNotification;
50
import org.gvsig.app.project.documents.view.ViewDocument;
51
import org.gvsig.compat.print.PrintAttributes;
52
import org.gvsig.fmap.dal.exception.ReadException;
53
import org.gvsig.fmap.geom.Geometry;
54
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
55
import org.gvsig.fmap.geom.GeometryLocator;
56
import org.gvsig.fmap.geom.GeometryManager;
57
import org.gvsig.fmap.geom.exception.CreateEnvelopeException;
58
import org.gvsig.fmap.geom.primitive.Envelope;
59
import org.gvsig.fmap.mapcontext.MapContext;
60
import org.gvsig.fmap.mapcontext.MapContextException;
61
import org.gvsig.fmap.mapcontext.ViewPort;
62
import org.gvsig.fmap.mapcontext.events.AtomicEvent;
63
import org.gvsig.fmap.mapcontext.events.ColorEvent;
64
import org.gvsig.fmap.mapcontext.events.ExtentEvent;
65
import org.gvsig.fmap.mapcontext.events.FMapEvent;
66
import org.gvsig.fmap.mapcontext.events.ProjectionEvent;
67
import org.gvsig.fmap.mapcontext.events.listeners.AtomicEventListener;
68
import org.gvsig.fmap.mapcontext.events.listeners.ViewPortListener;
69
import org.gvsig.fmap.mapcontext.layers.CancelationException;
70
import org.gvsig.fmap.mapcontext.layers.LayerCollectionEvent;
71
import org.gvsig.fmap.mapcontext.layers.LayerCollectionListener;
72
import org.gvsig.fmap.mapcontext.layers.LayerEvent;
73
import org.gvsig.fmap.mapcontext.layers.LayerPositionEvent;
74
import org.gvsig.fmap.mapcontext.rendering.legend.events.LegendChangedEvent;
75
import org.gvsig.fmap.mapcontext.rendering.legend.events.listeners.LegendListener;
76
import org.gvsig.gui.beans.Messages;
77
import org.gvsig.tools.ToolsLocator;
78
import org.gvsig.tools.dynobject.DynStruct;
79
import org.gvsig.tools.locator.LocatorException;
80
import org.gvsig.tools.persistence.PersistenceManager;
81
import org.gvsig.tools.persistence.PersistentState;
82
import org.gvsig.tools.persistence.exception.PersistenceException;
83
import org.slf4j.Logger;
84
import org.slf4j.LoggerFactory;
85

    
86
/**
87
 * FFrame used for embedding a View in the Layout. The View is not actually
88
 * inserted on the Layout, but it is used together with the MapContext
89
 * in order do draw an image which is then painted on the FFrame. Therefore,
90
 * no MapControl is used in current implementation, but a similar behavior
91
 * is simulated by the FFrameView. The original MapContext is cloned when
92
 * assigned to the FFrameView, which is then used for drawing.
93
 * 
94
 * The FFrameView and the associated View can be synchronized, depending
95
 * on the values of {@link #getTypeScale()} and {@link #getLinked()}.
96
 * 
97
 * The main synchronization logic is kept on two internal classes: 
98
 * {@link OwnMapContextListener} and {@link ViewDocListener}. The first one
99
 * listens for events on the FFrameView and synchronizes the View accordingly.
100
 * The second one listens for events on the View and synchronizes the FFrameView
101
 * accordingly. There synchronization process is flagged using
102
 * {@link #b_updating} and {@link #b_updating}, in order
103
 * to avoid incurring on infinite synchronization loops. 
104
 * 
105
 * @author Vicente Caballero Navarro
106
 * @author Cesar Martinez Izquierdo
107
 */
108
public class FFrameView extends FFrame implements IFFrameUseProject, IFFrameUseFMap {
109

    
110
    public static final String PERSISTENCE_DEFINITION_NAME = "FFrameView";
111

    
112
    private static final String QUALITY_FIELD = "quality";
113
    private static final String MAPUNITS_FIELD = "mapUnits";
114
    private static final String SCALE_FIELD = "scale";
115
    private static final String VIEW_FIELD = "view";
116
    private static final String ENVELOPE_FIELD = "envelope";
117
    private static final String SHOWGRID_FIELD = "showGrid";
118
    private static final String GRID_FIELD = "gridview";
119
    private static final String HAS_TOC_FIELD = "hasToc";
120
    private static final String LAYER_SYNC_FIELD = "layerSync";
121
    private static final String EXTENT_SYNC_FIELD = "extentSync";
122
    // following fields are unused - they are kept for backward-compatibility 
123
    private static final String EXTENSION_FIELD = "extension";
124
    private static final String BLINKED_FIELD = "bLinked";
125
    private static final String MODE_FIELD = "mode";
126
    private static final String TYPESCALE_FIELD = "typeScale";
127
    private static final String MAPCONTEXT_FIELD = "mapContext";
128
    private static final String VIEWING_FIELD = "viewing";
129

    
130
    private static final Logger logger = LoggerFactory
131
        .getLogger(FFrameView.class);
132
    public static final int PRESENTATION = 0;
133
    public static final int DRAFT = 1;
134
    protected boolean syncLayers = true;
135
    protected boolean syncExtents = true;
136
    protected int quality = PRESENTATION;
137
    protected ViewDocument viewDocument = null;
138
    protected MapContext mapContext = null;
139
    protected int mapUnits = 1; // Meters.
140

    
141
    protected BufferedImage m_image = null;
142
    protected AffineTransform mapAT = null;
143
    protected Project project = null;
144
    protected double scaleAnt;
145
    protected Point origin;
146
    protected Point2D p1;
147
    protected Point2D p2;
148
    protected IFFrame grid;
149
    protected boolean showGrid = false;
150

    
151
        private boolean b_updating = false;
152
        protected boolean b_validCache = false;
153
        protected boolean b_drawing = false;
154
        protected ViewDocListener viewDocListener;
155
        protected OwnMapContextListener ownMapContextListener;
156
        private boolean b_hasToc = true;
157
    protected static final GeometryManager geomManager = GeometryLocator.getGeometryManager();
158
    protected Envelope oldViewEnvelope = null;
159

    
160
        /**
161
         * When we load a FFrameview from project, it will receive a wrong
162
         * extentChanged event the first time the View is painted, so we must
163
         * ignore this first event. 
164
         */
165
        private boolean b_frameInitialized = true;
166

    
167
        protected AffineTransform originalGraphicsAT = null;
168
        protected Rectangle originalClip = null;
169

    
170

    
171
    /**
172
     * Creates a new FFrameView object.
173
     */
174
    public FFrameView() {
175
        num++;
176
        createListeners();
177
    }
178
    
179
    protected void createListeners() {
180
            viewDocListener = new ViewDocListener();
181
            ownMapContextListener = new OwnMapContextListener();
182
    }
183

    
184
    /**
185
     * Returns a description of the FFrame
186
     * 
187
     * @return Description.
188
     */
189
    public String toString() {
190
        if (getView() == null) {
191
            return "FFrameView " + num + ": " + "Vacio";
192
        }
193

    
194
        return "FFrameView " + num + ": " + getView().getName();
195
    }
196

    
197
    /**
198
     * Sets the scale of the MapContext contained in this FFrameView
199
     * 
200
     * @param d Scale to be set
201
     */
202
    public void setScale(double d) {
203
            if (getMapContext()!=null) {
204
                    getMapContext().setScaleView((long) d);
205
            }
206
    }
207

    
208
    /**
209
     * Sets a new Envelope on the MapContext contained in
210
     * this FFrameView
211
     * 
212
     * @param r Envelope to be set
213
     */
214
    public void setNewEnvelope(Envelope r) {
215
            if (getView()!=null) {
216
                    oldViewEnvelope = getView().getMapContext().getViewPort().getAdjustedEnvelope();
217
            }
218
            getMapContext().getViewPort().setEnvelope(r);
219
            updateScaleCtrl();
220
    }
221
    
222
    /**
223
     * Calculates the resolution (measured on dots per inch, DPI) to be
224
     * considered to draw the FFrameView on screen. It is calculated by
225
     * dividing the width (in pixels) of the FFrame divided by the width
226
     * in inches of the paper.
227
     */
228
    protected double getDrawPaperDPI() {
229
            AffineTransform at = null;
230
            if (getLayoutContext()!=null) {
231
                    at = getLayoutContext().getAT();
232
            }
233
            return (2.54*getBoundingBox(at).width)/getBoundBox().width;        
234
    }
235

    
236
    /**
237
     * Returns the MapContext contained in this FFrameView, which is
238
     * usually a clone of the associated View. This MapContext
239
     * may be synchronized with the View one, depending on the
240
     * scale type that has been set (see {{@link #getTypeScale()}.
241
     * 
242
     * @return The mapContext object
243
     */
244
    public MapContext getMapContext() {
245
        return mapContext;
246
    }
247

    
248
    /**
249
     * Sets the quality of the visualization of the FFrame on screen.
250
     * Valid values include {@link #DRAFT} and {@link #PRESENTATION}.
251
     * Draft will disable the frame normal drawing, which will be
252
     * replaced by an empty rectangle only showing the name of the
253
     * frame.  
254
     * 
255
     * @param q Integer representing the quality.
256
     */
257
    public void setQuality(int q) {
258
        quality = q;
259
    }
260

    
261
    /**
262
     * Gets the quality of the visualization of the FFrame on screen.
263
     * Valid values include {@link #DRAFT} and {@link #PRESENTATION}.
264
     * Draft will disable the frame normal drawing, which will be
265
     * replaced by an empty rectangle only showing the name of the
266
     * frame.  
267
     * 
268
     * @param q The selected quality
269
     */
270
    public int getQuality() {
271
        return quality;
272
    }
273

    
274
    /**
275
     * Sets the MapContext associated with this FFrameView, which will
276
     * be used to clone the layers and synchronize the FFrameView with
277
     * the associated View 
278
     * 
279
     * @param viewMapContext
280
     */
281
    public void setViewMapContext(MapContext viewMapContext) {
282
            if (mapContext!=null) {
283
                    clearOwnListeners(mapContext);
284
            }
285
            try {
286
                    if (syncLayers){
287
                            mapContext =
288
                                            viewMapContext.createNewFMap(
289
                                                            (ViewPort) viewMapContext.getViewPort().clone());
290
                    }
291
                    else {
292
                            mapContext = viewMapContext.cloneFMap();
293
                            mapContext.setViewPort((ViewPort) viewMapContext
294
                                            .getViewPort().clone());
295
                    }
296
                    ViewPort newViewPort = getMapContext().getViewPort();
297
                    AffineTransform at;
298
                    if (getLayoutContext()!=null) {
299
                            at = getLayoutContext().getAT();
300
                    }
301
                    else {
302
                            at = null;
303
                    }
304
                    newViewPort.setImageSize(new Dimension((int) getBoundingBox(at).width,
305
                                    (int) getBoundingBox(at).height));
306
                    newViewPort.setDPI(getDrawPaperDPI());
307
                    setListeners();
308
                    updateScaleCtrl();
309
                    setTocModel();
310
            } catch (CloneNotSupportedException e1) {
311
                    NotificationManager.addError("Excepci?n :", e1);
312
            }
313

    
314
    }
315

    
316
    /**
317
     * Sets the View associated with this FFrameView, which will
318
     * be used to clone the MapContext and the layers. It will
319
     * also used to synchronize the FFrameView with
320
     * the associated View, depending on the selected scle type 
321
     * 
322
     * @param viewMapContext
323
     */
324
    public void setView(ViewDocument dvd) {
325
            ViewDocument oldDoc = viewDocument;
326
            if (oldDoc!=null && oldDoc.getMapContext()!=null) {
327
                    clearViewListeners(oldDoc.getMapContext());
328
            }
329
        viewDocument = dvd;
330
        if (dvd!=null) {
331
            setViewMapContext(dvd.getMapContext());
332
        }
333
    }
334

    
335
    /**
336
     * Gets the associated View
337
     * 
338
     * @return The associated view
339
     * @see {@link #setView(ViewDocument)}
340
     */
341
    public ViewDocument getView() {
342
        return viewDocument;
343
    }
344

    
345
    /**
346
     * Draws the FFrameView on the provided Graphics, according to the
347
     * provided affine transform and the visible rectangle.
348
     * 
349
     * @param g Graphics2D
350
     * @param at Affine transform to translate sheet coordinates (in cm)
351
     *                                 to screen coordinates (in pixels)
352
     * @param visibleLayoutDocRect visible rectangle
353
     * @param imgBase Image used to speed up the drawing process
354
     */
355
    public void draw(Graphics2D g, AffineTransform at, Rectangle2D visibleLayoutDocRect, BufferedImage imgBase) {
356
        Rectangle2D.Double fframeViewRect = getBoundingBox(at);
357
        Rectangle2D.Double visibleArea = (Rectangle2D.Double) getVisibleRect(visibleLayoutDocRect, fframeViewRect);
358
        if (visibleArea==null) {
359
                return;
360
        }
361
        preDraw(g, fframeViewRect, visibleArea);
362
        if (getMapContext() == null) {
363
                drawEmpty(g);
364
        } else {
365
                if (FLayoutUtilities.hasEditingLayers(getView())) {
366

    
367
                        /*
368
                         * We are not drawing if any layer is in editing mode
369
                         */
370
                        drawMessage(g, Messages.getText(
371
                                        "_Cannot_draw_view_if_layers_in_editing_mode"));
372

    
373
                } else {
374
                        if (getQuality() == PRESENTATION) {
375
                                try {
376
                                        drawPresentation(g, at, fframeViewRect, visibleArea, imgBase);
377
                                } catch (Exception exc) {
378
                                        drawMessage(g, FLayoutFunctions.getLastMessage(exc));
379
                                }
380

    
381
                        } else {
382
                                drawDraft(g);
383
                        }               
384
                }
385
                updateScaleCtrl(); // we need to update the scale whenever the window gets activated
386
        }
387
        postDraw(g, fframeViewRect, at); 
388
        if (showGrid && grid != null) {           
389
            grid.draw(g, at, visibleLayoutDocRect, imgBase);
390
        }    
391
    }
392
    
393
    private void drawMessage(Graphics2D g, String msg) {
394
        
395
        Rectangle2D r = getBoundingBox(null);
396
        g.setColor(Color.lightGray);
397
        g.fillRect((int) r.getX(), (int) r.getY(), (int) r.getWidth(),
398
            (int) r.getHeight());
399
        g.setColor(Color.darkGray);
400
        g.setStroke(new BasicStroke(2));
401
        g.drawRect((int) r.getX(), (int) r.getY(), (int) r.getWidth(),
402
            (int) r.getHeight());
403
        g.setColor(Color.black);
404

    
405
        int scale = (int) (r.getWidth() / 24);
406
        Font f = new Font("SansSerif", Font.PLAIN, scale);
407
        g.setFont(f);
408
        if (msg==null) {
409
                msg = Messages.getText("error");
410
        }
411
        g.drawString(msg, (int) (r.getCenterX() - ((msg.length() * scale) / 4)),
412
                        (int) (r.getCenterY()));
413
    }
414

    
415
    /**
416
     * Gets the visible envelope, in map coordinates
417
     * 
418
     * @param fframeViewRect Rectangle defining the bounding box of the
419
     * FFrameView, in screen coordinates
420
     * @param visiblefframeViewRect Rectangle defining the bounding box
421
     * of the visible area of the fframeView, in screen coordinates
422
     * @return
423
     */
424
    protected Envelope getVisibleEnvelope(Rectangle2D.Double fframeViewRect,
425
            Rectangle2D.Double visiblefframeViewRect) {
426
            Envelope oldEnv = getMapContext().getViewPort().getAdjustedEnvelope();
427
            double widthFactor = ((int)visiblefframeViewRect.width) / fframeViewRect.width;
428
            double heightFactor = ((int)visiblefframeViewRect.height) / fframeViewRect.height;
429
            
430
            double newWidth = oldEnv.getLength(0)*widthFactor;
431
            double newHeight = oldEnv.getLength(1)*heightFactor;
432
        
433
        double translateX = visiblefframeViewRect.x - fframeViewRect.x;
434
        double translateY = visiblefframeViewRect.y - fframeViewRect.y;
435
        double translateFactorX = translateX / fframeViewRect.width;
436
        double translateFactorY = translateY / fframeViewRect.height;
437
        
438
        double newX = oldEnv.getMinimum(0) + translateFactorX*oldEnv.getLength(0);
439
        double newMaxY =  oldEnv.getMaximum(1) - translateFactorY*oldEnv.getLength(1);
440
        double newMaxX = newX + newWidth;
441
        double newY = newMaxY - newHeight;
442

    
443
        Envelope newEnv = null;
444
                try {
445
                        newEnv = geomManager.createEnvelope(newX, newY, newMaxX, newMaxY, SUBTYPES.GEOM2D);
446
                } catch (CreateEnvelopeException e) {
447
                        logger.error("Error calculating visible extent", e);
448
                }
449
        return newEnv;
450
                    
451
    }
452
    
453
    protected void drawPresentation(
454
        Graphics2D g,
455
        AffineTransform affineTransform,
456
        Rectangle2D.Double fframeViewRect,
457
        Rectangle2D.Double visibleRect,
458
        BufferedImage imgBase) throws Exception {
459
            
460
            b_drawing = true;
461
            int drawWidth = (int)visibleRect.width;
462
            int drawHeight = (int)visibleRect.height;
463

    
464
            Envelope oldEnvelope = null;
465
        if (!visibleRect.equals(fframeViewRect)) {
466
                // if visible area is smaller than the fframe, we will only draw this area,
467
                // so we need to tell the ViewPort the image size and extent for drawing,
468
                // and restore the real extent after drawing
469
            oldEnvelope = getMapContext().getViewPort().getEnvelope();
470
            if (oldEnvelope==null) {
471
                    return;
472
            }
473
                Envelope newEnvelope = getVisibleEnvelope(fframeViewRect, visibleRect);
474
                // image size must be set before the envelope, as it has influence on the adjustedExtent
475
                getMapContext().getViewPort().setImageSize(new Dimension(drawWidth, drawHeight));
476
                getMapContext().getViewPort().setEnvelope(newEnvelope);
477
        }
478
        else {
479
                getMapContext().getViewPort().setImageSize(new Dimension(drawWidth, drawHeight));
480
                getMapContext().getViewPort().refreshExtent();
481
        }
482
        
483
        // map origin should be calculated using the full fframeview, as the visible position will be relative
484
        Point mapOrigin = new Point((int)fframeViewRect.getMinX(), (int)fframeViewRect.getMaxY());
485

    
486
        // paint the MapContext on m_image, if not already cached
487
        createImage(affineTransform, drawWidth, drawHeight, mapOrigin);
488

    
489
        //Draw the created image
490
        drawImage(g, m_image, visibleRect);
491
        
492
        if (oldEnvelope!=null) {
493
                // restore real envelope and image size
494
                getMapContext().getViewPort().setImageSize(new Dimension((int)fframeViewRect.width, (int) fframeViewRect.height));
495
                getMapContext().getViewPort().setEnvelope(oldEnvelope);
496
        }
497
        
498
        scaleAnt = affineTransform.getScaleX();
499
        origin = mapOrigin;
500
        b_drawing = false;
501
    }
502
    
503
    protected void createImage(AffineTransform affineTransform,
504
                    int width, int height, Point mapOrigin) throws ReadException, MapContextException {
505
            ViewPort viewPort = this.getMapContext().getViewPort();
506

    
507
        //If the image has to be created...
508
            if (origin == null ||
509
                            !origin.equals(mapOrigin) ||
510
                            affineTransform.getScaleX() != scaleAnt ||
511
                            m_image == null ||
512
                            !b_validCache) { 
513

    
514
                    viewPort.setDPI(getDrawPaperDPI());
515
                viewPort.setImageSize(new Dimension(width, height)); 
516
            
517
            m_image =
518
                    new BufferedImage(
519
                                    width,
520
                                    height,
521
                                    BufferedImage.TYPE_INT_ARGB);
522

    
523
            Graphics2D gimg = (Graphics2D) m_image.createGraphics();
524
            getMapContext().draw(m_image, gimg, getScale());
525
            gimg.dispose();
526
            b_validCache = true;
527
        } 
528

    
529
    }
530
    
531
    protected void drawImage(Graphics2D g, BufferedImage image,
532
                    Rectangle2D.Double visibleRectangle) {
533

    
534
            Color theBackColor = getMapContext().getViewPort().getBackColor();
535
        if (theBackColor != null) {
536
            g.setColor(theBackColor);
537
            g.fillRect((int) visibleRectangle.x, (int) visibleRectangle.y,
538
                            (int)visibleRectangle.width,
539
                            (int)visibleRectangle.height);
540
        }
541
        g.drawImage(m_image, 
542
                        (int) visibleRectangle.x,
543
                        (int) visibleRectangle.y,
544
                        null);            
545
    }
546

    
547
    protected void preDraw(Graphics2D g, Rectangle2D.Double fframeViewRect, Rectangle2D.Double visibleRect){
548
            originalGraphicsAT = (AffineTransform) g.getTransform().clone();
549
            
550
        if (g.getClipBounds() != null) {
551
            originalClip = (Rectangle) g.getClipBounds().clone();
552
        }
553
        AffineTransform rotationAT = getRotationAT();
554
        if (rotationAT!=null) {
555
                g.transform(rotationAT);
556
        }
557
        g.setClip((int) visibleRect.getMinX(), (int) visibleRect.getMinY(),
558
            (int) visibleRect.getWidth(), (int) visibleRect.getHeight());
559
    }
560
    
561
    protected void postDraw(Graphics2D g, Rectangle2D.Double fframeViewRect, AffineTransform at){
562
            g.setTransform(originalGraphicsAT);
563
        if (getMapContext() != null) {
564
            setATMap(getMapContext().getViewPort().getAffineTransform());
565
        }
566
        if (originalClip != null) {
567
            g.setClip(originalClip.x, originalClip.y, originalClip.width, originalClip.height);
568
        }            
569
    }
570

    
571
    public void print(Graphics2D g, AffineTransform at, Geometry geom,
572
        PrintAttributes printAttributes) {
573
        Rectangle2D.Double rectangleLayout = getBoundingBox(at);  
574
        
575
        preDraw(g, rectangleLayout, rectangleLayout);
576
        print(g, at, printAttributes);
577
        postDraw(g, rectangleLayout, at);
578
        if (showGrid && grid != null) {
579
            grid.print(g, at, geom, printAttributes);
580
        }    
581
    }
582

    
583
    protected void print(Graphics2D g, AffineTransform at, PrintAttributes printAttributes) {
584
        Rectangle2D.Double layoutRectangle = getBoundingBox(at);
585
        
586
        // FIXME: should we clone the mapcontext and viewport before printing ??
587
        // otherwise we will probably have unexpected results if the user modifies
588
        // the layout while printing
589
        ViewPort viewPort = this.getMapContext().getViewPort();
590
        
591
        Point2D old_offset = viewPort.getOffset();
592
        Dimension old_imgsize = viewPort.getImageSize();
593
        
594
        viewPort.setOffset(new Point2D.Double(layoutRectangle.x, layoutRectangle.y));
595
        viewPort.setImageSize(new Dimension((int) layoutRectangle.width, (int) layoutRectangle.height));
596

    
597
        //Draw the backgroung color of the map
598
        Color theBackColor = viewPort.getBackColor();
599
        if (theBackColor != null) {
600
            g.setColor(theBackColor);
601
            g.fillRect((int) layoutRectangle.x, (int) layoutRectangle.y, viewPort
602
                    .getImageWidth(), viewPort
603
                    .getImageHeight());
604
        }        
605
        
606
        //Print the map
607
        try {
608
            this.getMapContext().print(g, getScale(), printAttributes);
609
        } catch (ReadException e) {
610
            NotificationManager.addError(e.getMessage(), e);
611
        } catch (MapContextException e) {
612
            NotificationManager.addError(e.getMessage(), e);
613
        }      
614
        
615
        // Restore offset, imgsize
616
        viewPort.setOffset(old_offset);
617
        viewPort.setImageSize(old_imgsize);
618
    }
619

    
620
    /**
621
     * Rellena la unidad de medida en la que est? la vista.
622
     * 
623
     * @param i
624
     *            entero que representa la unidad de medida de la vista.
625
     */
626
    public void setMapUnits(int i) {
627
        mapUnits = i;
628
    }
629

    
630
    /**
631
     * Obtiene la unidad de medida en la que est? la vista.
632
     * 
633
     * @return Unidad de medida.
634
     */
635
    public int getMapUnits() {
636
        return mapUnits;
637
    }
638

    
639
    /**
640
     * Devuelve la escala seg?n el tipo de escala que se haya seleccionado al
641
     * a?adida la vista.
642
     * 
643
     * @return escala.
644
     */
645
    public long getScale() {
646
            return (long) getMapContext().getScaleView();
647
    }
648

    
649
    /**
650
     * Inserta la imagen para repintar el FFrameView.
651
     * 
652
     * @param bi
653
     *            Imagen para repintar.
654
     */
655
    public void setBufferedImage(BufferedImage bi) {
656
        m_image = bi;
657
    }
658

    
659
    /**
660
     * Devuelve la imagen para repintar.
661
     * 
662
     * @return Imagen para repintar.
663
     */
664
    public BufferedImage getBufferedImage() {
665
        return m_image;
666
    }
667

    
668
    /**
669
     * Devuelve la MAtriz de transformaci?n utilizada por la FFrameView.
670
     * 
671
     * @return MAtriz de transformaci?n.
672
     */
673
    public AffineTransform getATMap() {
674
        return mapAT;
675
    }
676

    
677
    /**
678
     * Inserta la matriz de transformaci?n.
679
     * 
680
     * @param transform
681
     *            Matriz de transformaci?n.
682
     */
683
    public void setATMap(AffineTransform transform) {
684
        mapAT = transform;
685
    }
686

    
687
    /**
688
     * Inserta el proyecto.
689
     * 
690
     * @param p
691
     *            Proyecto.
692
     */
693
    public void setProject(Project p) {
694
        project = p;
695
    }
696

    
697
    /**
698
     * @see org.gvsig.app.project.documents.layout.fframes.IFFrame#getNameFFrame()
699
     */
700
    public String getNameFFrame() {
701
        return PluginServices.getText(this, "Vista") + num;
702
    }
703

    
704
    public String getName() {
705
        return PERSISTENCE_DEFINITION_NAME;
706
    }
707

    
708
    /**
709
     * DOCUMENT ME!
710
     * 
711
     * @param arg0
712
     *            DOCUMENT ME!
713
     * 
714
     * @return DOCUMENT ME!
715
     */
716
    public boolean compare(Object arg0) {
717
        if (!(arg0 instanceof FFrameView)) {
718
            return false;
719
        }
720

    
721
        if (!this.getName().equals(((FFrameView) arg0).getName())) {
722
            return false;
723
        }
724

    
725
        if (Math.abs(this.getBoundBox().getWidth()
726
            - (((FFrameView) arg0).getBoundBox().getWidth())) > 0.05) {
727
            return false;
728
        }
729
        if (Math.abs(this.getBoundBox().getHeight()
730
            - (((FFrameView) arg0).getBoundBox().getHeight())) > 0.05) {
731
            return false;
732
        }
733

    
734
        if (!this.toString().equals(((FFrameView) arg0).toString())) {
735
            return false;
736
        }
737

    
738
        if (this.getMapContext() != null
739
            && !this.getMapContext()
740
                .equals(((FFrameView) arg0).getMapContext())) {
741
            return false;
742
        }
743

    
744
        if (this.getRotation() != ((FFrameView) arg0).getRotation()) {
745
            return false;
746
        }
747
        return true;
748
    }
749
    
750
    public void updateScaleCtrl() {
751
            NewStatusBar statusbar = PluginServices.getMainFrame().getStatusBar();
752
            MapContext mapContext = this.getMapContext();
753
            if (mapContext==null) {
754
                    return;
755
            }
756
            statusbar.setMessage("units",
757
                            PluginServices.getText(this, mapContext.getDistanceName()));
758
            statusbar.setControlValue("layout-view-change-scale",
759
                            String.valueOf(getMapContext().getScaleView()));
760
            IProjection proj = mapContext.getViewPort().getProjection();
761
            if (proj != null) {
762
                    statusbar.setMessage("projection", proj.getAbrev());
763
            } else {
764
                    statusbar.setMessage("projection", "");
765
            }
766
    }
767

    
768
    public void fullExtent() throws ReadException {
769
        setNewEnvelope(getMapContext().getFullEnvelope());
770
    }
771

    
772
    public void setPointsToZoom(Point2D px1, Point2D px2) {
773
        p1 = px1;
774
        p2 = px2;
775
    }
776

    
777
    public void movePoints(Point2D px1, Point2D px2) {
778
        double difX = -px2.getX() + px1.getX();
779
        double difY = -px2.getY() + px1.getY();
780
        if (p1 != null) {
781
            p1.setLocation(p1.getX() + difX, p1.getY() + difY);
782
            p2.setLocation(p2.getX() + difX, p2.getY() + difY);
783
        }
784
    }
785

    
786
    /**
787
     * This method deals with places where this fframeview and the cloned
788
     * fframeview (frame) are registered as listeners. The goal should be
789
     * leaving the cloned instance (frame) as listener in the same way
790
     * that 'this' instance is doing.
791
     */
792
    protected void cloneActions(FFrameView frame) {
793
    }
794

    
795
    public Object clone() throws CloneNotSupportedException {
796
            Document d = ProjectManager.getInstance().getCurrentProject().getDocuments().get(0);
797
        FFrameView frame = (FFrameView) super.clone();
798
        frame.createListeners(); // necessary to create the listeners within the right scope
799
        frame.setView(this.getView());
800

    
801
        if (grid != null) {
802
            FFrameGrid newGrid = (FFrameGrid) this.grid.clone();
803
            newGrid.setFFrameDependence(frame);
804
            frame.setGrid(newGrid);
805
        }
806
        cloneActions(frame);
807
        return frame;
808
    }
809

    
810
    public void setGrid(IFFrame grid) {
811
        this.grid = grid;
812
        this.grid.setRotation(this.getRotation());
813
    }
814

    
815
    public IFFrame getGrid() {
816
        return this.grid;
817
    }
818

    
819
    public void setRotation(double rotation) {
820
        super.setRotation(rotation);
821
        if (grid != null) {
822
            grid.setRotation(rotation);
823
        }
824
    }
825

    
826
    public void showGrid(boolean b) {
827
        showGrid = b;
828
    }
829

    
830
    public boolean isShowGrid() {
831
        return showGrid;
832
    }
833

    
834
    public void refreshOriginalExtent() {
835
    }
836

    
837
    public static void registerPersistent() {
838
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
839
        if (manager.getDefinition(PERSISTENCE_DEFINITION_NAME) == null) {          
840
            DynStruct definition =
841
                manager.addDefinition(FFrameView.class,
842
                    PERSISTENCE_DEFINITION_NAME,
843
                    "FFrameView persistence definition", null, null); 
844
            definition.extend(manager
845
                .getDefinition(FFrame.PERSISTENCE_DEFINITION_NAME));
846
            definition.addDynFieldInt(QUALITY_FIELD).setMandatory(true);
847
            definition.addDynFieldInt(MAPUNITS_FIELD).setMandatory(true);
848
            definition.addDynFieldDouble(SCALE_FIELD).setMandatory(false);
849
            definition.addDynFieldObject(VIEW_FIELD)
850
                .setClassOfValue(ViewDocument.class).setMandatory(false);
851
            definition.addDynFieldObject(ENVELOPE_FIELD)
852
                .setClassOfValue(Envelope.class).setMandatory(false);
853
            definition.addDynFieldBoolean(SHOWGRID_FIELD).setMandatory(true);
854
            definition.addDynFieldObject(GRID_FIELD)
855
                .setClassOfValue(IFFrame.class).setMandatory(false);
856
            definition.addDynFieldBoolean(HAS_TOC_FIELD).setMandatory(false);
857
            definition.addDynFieldBoolean(EXTENT_SYNC_FIELD).setMandatory(false);
858
            definition.addDynFieldBoolean(LAYER_SYNC_FIELD).setMandatory(false);
859
            // unused fields, kept for backward compatibility
860
            definition.addDynFieldInt(MODE_FIELD).setMandatory(false);
861
            definition.addDynFieldInt(TYPESCALE_FIELD).setMandatory(false);
862
            definition.addDynFieldBoolean(BLINKED_FIELD).setMandatory(false);
863
            definition.addDynFieldObject(MAPCONTEXT_FIELD)
864
            .setClassOfValue(MapContext.class).setMandatory(false);
865
            definition.addDynFieldInt(VIEWING_FIELD).setMandatory(false);
866
            definition.addDynFieldInt(EXTENSION_FIELD).setMandatory(false);
867
        }
868
    }
869

    
870
    @Override
871
    public void loadFromState(PersistentState state)
872
        throws PersistenceException {
873
        super.loadFromState(state);
874
        b_frameInitialized = false;
875
        if (state.hasValue(EXTENT_SYNC_FIELD)) {
876
                syncExtents = state.getBoolean(EXTENT_SYNC_FIELD);
877
        }
878
        else {
879
                syncExtents = true;
880
        }
881
        if (state.hasValue(LAYER_SYNC_FIELD)) {
882
                syncLayers = state.getBoolean(LAYER_SYNC_FIELD);
883
        }
884
        else {
885
                syncLayers = true;
886
        }
887
        quality = state.getInt(QUALITY_FIELD);
888
        mapUnits = state.getInt(MAPUNITS_FIELD);;
889
        viewDocument = (ViewDocument) state.get(VIEW_FIELD);
890
        if (state.hasValue(HAS_TOC_FIELD)) {
891
                this.b_hasToc = state.getBoolean(HAS_TOC_FIELD);
892
        }        
893
        if (viewDocument!=null) {
894
                this.setView(viewDocument);
895
                // it is crucial to don't persist the MapContext and get a cloned one from the View instead,
896
                // as the cloned instance is different from the one created using persistence. In particular,
897
                // the cloned one will share the EventBuffer with the original one, while persistence would
898
                // create 2 separate EventBuffers, which will then have a very stange behaviour
899
        }
900
        if (getMapContext()!=null) {
901
                double mapScale = state.getDouble(SCALE_FIELD);
902
                getMapContext().setScaleView((long)mapScale);
903
                getMapContext().getViewPort().setEnvelope(
904
                (Envelope) state.get(ENVELOPE_FIELD));
905
                if (this.getLayoutContext()!=null) {
906
                        this.getLayoutContext().setTocModel(getMapContext());
907
                }
908

    
909
        }
910
        showGrid = state.getBoolean(SHOWGRID_FIELD);
911
        grid = (IFFrame) state.get(GRID_FIELD);
912
    }
913

    
914
    @Override
915
    public void saveToState(PersistentState state) throws PersistenceException {
916
        super.saveToState(state);
917
        state.set(EXTENT_SYNC_FIELD, syncExtents);
918
        state.set(LAYER_SYNC_FIELD, syncLayers);
919
        state.set(QUALITY_FIELD, quality);
920
        state.set(MAPUNITS_FIELD, mapUnits);
921
        state.set(VIEW_FIELD, viewDocument);
922
        state.set(HAS_TOC_FIELD, b_hasToc);
923

    
924
        if (getMapContext() != null
925
            && getMapContext().getViewPort().getEnvelope() != null) {
926
            state.set(ENVELOPE_FIELD, getMapContext().getViewPort()
927
                .getEnvelope());
928
            state.set(SCALE_FIELD, (double)getMapContext().getScaleView());
929
        }
930

    
931
        state.set(SHOWGRID_FIELD, showGrid);
932
        state.set(GRID_FIELD, grid);
933
    }
934
    
935
    @Override
936
    public void setBoundBox(Rectangle2D r) {
937
            super.setBoundBox(r);
938
            if (getMapContext()!=null) {
939
                    AffineTransform at = this.getLayoutContext().getAT();
940
                    getMapContext().getViewPort().setImageSize(
941
                                    new Dimension((int)getBoundingBox(at).getWidth(), (int)getBoundingBox(at).getHeight()));
942
                    getMapContext().getViewPort().setDPI(getDrawPaperDPI());
943
                    updateScaleCtrl();
944
                    // FIXME: what should we do here? should we invalidate the cache?
945
                    // should we also trigger a Layout redraw?
946
                    refresh();
947
            }
948
    }   
949

    
950
    /**
951
     * Gets the rotation of the frame
952
     * 
953
     * @return Rotation in degrees
954
     */
955
    public double getMapRotation() {
956
        return 0;
957
    }
958
    
959
        protected void invalidateLayout() {
960
                b_validCache = false;
961
                if (getLayoutContext()!=null) {
962
                        getLayoutContext().notifAllObservers();
963
                }
964
        observers.notifyObservers(this, 
965
                new DefaultLayoutNotification(LayoutNotification.LAYOUT_REFRESH));
966
        }
967
        
968
        protected void invalidateToc() {
969
                if (getLayoutContext()!=null) {
970
                        getLayoutContext().notifyTocUpdated(TocModelChangedNotification.Type.MODEL_CHANGED);
971
                }
972
        }
973

    
974
        public void refresh() {
975
        // FIXME: what should we do here? do we really need to invalidate cache??
976
            b_validCache = false;                
977
        }
978
    
979
    protected void resetListeners() {
980
                if (this.getMapContext()!=null) {
981
                        clearOwnListeners(this.getMapContext());
982
                }
983
                if (this.getView()!=null && this.getView().getMapContext()!=null) {
984
                        clearViewListeners(this.getView().getMapContext());
985
                }
986
            setListeners();
987
    }
988
    
989
    protected void setListeners() {
990
            if (getView()!=null) {
991
                    if (syncLayers) {
992
                            getView().getMapContext().addLayerListener(viewDocListener);
993
                            getView().getMapContext().getLayers().addLayerCollectionListener(viewDocListener);
994
                            getView().getMapContext().addAtomicEventListener(viewDocListener);
995
                    }
996
                    if (getExtentSynced()) {
997
                            getView().getMapContext().getViewPort().addViewPortListener(viewDocListener);
998
                    }
999
            }
1000
            if (getMapContext()!=null) {
1001
                    getMapContext().addLayerListener(ownMapContextListener);
1002
                    getMapContext().getLayers().addLayerCollectionListener(ownMapContextListener);
1003
                    getMapContext().getViewPort().addViewPortListener(ownMapContextListener);
1004
            }
1005
    }
1006
    protected void clearOwnListeners(MapContext mapContext) {
1007
            mapContext.removeLayerListener(ownMapContextListener);
1008
            mapContext.getViewPort().removeViewPortListener(ownMapContextListener);
1009
            mapContext.getLayers().removeLayerCollectionListener(ownMapContextListener);
1010
    }
1011
    protected void clearViewListeners(MapContext mapContext) {
1012
            mapContext.removeLayerListener(viewDocListener);
1013
            mapContext.getViewPort().removeViewPortListener(viewDocListener);
1014
            mapContext.getLayers().removeLayerCollectionListener(viewDocListener);
1015
            mapContext.removeAtomicEventListener(viewDocListener);
1016
    }
1017
    
1018
    /*
1019
     * (non-Javadoc)
1020
     * @see org.gvsig.tools.dispose.Disposable#dispose()
1021
     */
1022
        public void dispose() {
1023
                try {
1024
                        if (this.getMapContext()!=null) {
1025
                                clearOwnListeners(this.getMapContext());
1026
                        }
1027
                        if (this.getView()!=null && this.getView().getMapContext()!=null) {
1028
                                clearViewListeners(this.getView().getMapContext());
1029
                        }
1030
                }
1031
                catch (Exception ex) {}
1032
                this.viewDocument = null;
1033
                this.mapContext = null;
1034
        }
1035

    
1036
        public void frameRemoved() {
1037
                if (mapContext!=null) {
1038
                        clearOwnListeners(mapContext);
1039
                }
1040
                if (this.getView()!=null && this.getView().getMapContext()!=null) {
1041
                        clearViewListeners(this.getView().getMapContext());
1042
                }
1043
                if (b_hasToc && getLayoutContext()!=null) {
1044
                        getLayoutContext().setTocModel(null);
1045
                }
1046
                m_image = null; // FIXME: we could instead move it to a LRU cache to keep the last N images
1047
        }
1048

    
1049
        public void frameAdded() {
1050
                setListeners();
1051
                setTocModel();
1052
                updateScaleCtrl();
1053
        }
1054
        
1055
        public void setHasToc(boolean hasToc) {
1056
                this.b_hasToc = hasToc;
1057
                setTocModel();
1058
        }
1059
        
1060
        protected void setTocModel() {
1061
                if (getLayoutContext()!=null) {
1062
                        if (b_hasToc && getMapContext()!=null) {
1063
                                getLayoutContext().setTocModel(getMapContext());
1064
                        }
1065
                        else {
1066
                                getLayoutContext().setTocModel(null);
1067
                        }
1068
                }
1069
        }
1070
        
1071
        @Override
1072
        protected void doSetSelected(int selectedStatus) {
1073
                boolean oldSelectedStatus = isSelected();
1074
                super.doSetSelected(selectedStatus);
1075
                if (!oldSelectedStatus && isSelected()) { // changed from not selected to selected
1076
                        setTocModel();
1077
                        updateScaleCtrl();
1078
                }
1079
        }
1080
        
1081
        public boolean getLayerSynced() {
1082
                return syncLayers;
1083
        }
1084

    
1085
        public void setLayerSynced(boolean synced) {
1086
        syncLayers = synced;
1087
        resetListeners();
1088
        }
1089

    
1090
        public boolean getExtentSynced() {
1091
                return syncExtents;
1092
        }
1093

    
1094
        public void setExtentSynced(boolean synced) {
1095
                syncExtents = synced;
1096
        resetListeners();
1097
        }
1098
        
1099
        /**
1100
         * Returns true if the newEnvelope represents a pan operation on oldEnvelope,
1101
         * (both extents have the same height and width)
1102
         */
1103
        public static boolean isPan(Envelope oldEnvelope, Envelope newEnvelope) {
1104
                if (oldEnvelope!=null && newEnvelope!=null) {
1105
                        double toleranceX = 0.00000001*Math.min(oldEnvelope.getLength(0), newEnvelope.getLength(0));
1106
                        double toleranceY = 0.00000001*Math.min(oldEnvelope.getLength(1), newEnvelope.getLength(1));
1107
                        
1108
                        // we consider it to be a pan if both lengths are equal 
1109
                        // (we use tolerance to avoid direct comparison of double values)
1110
                        if ( ((oldEnvelope.getLength(0)-newEnvelope.getLength(0))<toleranceX)
1111
                                        && ((oldEnvelope.getLength(1)-newEnvelope.getLength(1))<toleranceY) ) {
1112
                                return true;
1113
                        }
1114
                }
1115
                return false;
1116
        }
1117
        
1118
        /**
1119
         * Calculates the new extent for the FFrame. It is necessary to avoid
1120
         * scale changes when a pan is triggered from the view, as the different
1121
         * size factors from View/FFrameView introduces scale changes even for
1122
         * pans
1123
         * 
1124
         * @param newEnvelope
1125
         * @return
1126
         */
1127
        protected Envelope calculateNewExtent(Envelope newEnvelope) {
1128
                if (isPan(oldViewEnvelope, newEnvelope)) {
1129
                        Envelope envelope = getMapContext().getViewPort().getAdjustedEnvelope();
1130
                        double shiftX = newEnvelope.getMinimum(0) - oldViewEnvelope.getMinimum(0);
1131
                        double shiftY = newEnvelope.getMinimum(1) - oldViewEnvelope.getMinimum(1);
1132

    
1133
                        double minX = envelope.getMinimum(0) + shiftX;
1134
                        double minY = envelope.getMinimum(1) + shiftY;
1135
                        double maxX = envelope.getMaximum(0) + shiftX;
1136
                        double maxY = envelope.getMaximum(1) + shiftY;
1137
                        try {
1138
                                return GeometryLocator.getGeometryManager().createEnvelope(minX, minY, maxX, maxY, SUBTYPES.GEOM2D);
1139
                        }
1140
                        catch (LocatorException e) {}
1141
                        catch (CreateEnvelopeException e) {}
1142
                        
1143
                }
1144
                return newEnvelope;
1145
        }
1146

    
1147
        private class ViewDocListener
1148
        implements ViewPortListener, LegendListener, LayerCollectionListener, AtomicEventListener {
1149

    
1150
                public void extentChanged(ExtentEvent e) {
1151
                        if (!b_updating && getExtentSynced()) {
1152
                                if (!b_frameInitialized) {
1153
                                        b_frameInitialized = true;
1154
                                        return;
1155
                                }
1156
                                if (getMapContext()!=null) {
1157
                                        b_updating = true;
1158
                                        getMapContext().getViewPort().setEnvelope(calculateNewExtent(e.getNewExtent()));                                                
1159
                                        oldViewEnvelope = getView().getMapContext().getViewPort().getAdjustedEnvelope();
1160
                                        updateScaleCtrl();
1161
                                        invalidateLayout();
1162
                                        b_updating = false;
1163
                                }
1164
                        }                        
1165
                }
1166

    
1167
                public void backColorChanged(ColorEvent e) {
1168
                        if (!b_updating && syncLayers) {
1169
                                if (getMapContext()!=null) {
1170
                                        b_updating = true;
1171
                                        mapContext.getViewPort().setBackColor(e.getNewColor());
1172
                                        invalidateLayout();
1173
                                        b_updating = true;
1174
                                }
1175
                        }
1176
                }
1177

    
1178
                public void projectionChanged(ProjectionEvent e) {
1179
                        if (!b_updating && getExtentSynced()) {
1180
                                if (getMapContext()!=null) {
1181
                                        b_updating = true;
1182
                                        getMapContext().getViewPort().setProjection(e.getNewProjection());
1183
                                        invalidateLayout();
1184
                                        // FIXME: force also a view redraw someway??
1185
                                        b_updating = false;
1186
                                }
1187
                        }
1188
                }
1189

    
1190
                public void conditionalRedraw() {
1191
                        if (!b_updating && syncLayers) {
1192
                                b_updating = true;
1193
                                invalidateLayout();
1194
                                // the view should also receive the event and update automatically
1195
                                b_updating = false;
1196
                        }                        
1197
                }
1198

    
1199
                public void legendChanged(LegendChangedEvent e) {
1200
                        conditionalRedraw();
1201
                        invalidateToc();
1202
                }
1203

    
1204
                public void layerAdded(LayerCollectionEvent e) {
1205
                        conditionalRedraw();
1206
                        invalidateToc();
1207
                }
1208

    
1209
                public void layerMoved(LayerPositionEvent e) {
1210
                        conditionalRedraw();
1211
                        invalidateToc();
1212
                }
1213

    
1214
                public void layerRemoved(LayerCollectionEvent e) {
1215
                        conditionalRedraw();
1216
                        invalidateToc();
1217
                }
1218

    
1219
                public void layerAdding(LayerCollectionEvent e)
1220
                                throws CancelationException {
1221
                        // nothing needed
1222
                }
1223

    
1224
                public void layerMoving(LayerPositionEvent e)
1225
                                throws CancelationException {
1226
                        // nothing needed
1227
                }
1228

    
1229
                public void layerRemoving(LayerCollectionEvent e)
1230
                                throws CancelationException {
1231
                        // nothing needed
1232
                }
1233

    
1234
                public void visibilityChanged(LayerCollectionEvent e)
1235
                                throws CancelationException {
1236
                        // AtomicEvent is catching visibility changes instead of this one,
1237
                        // as this event is not being received. Maybe is only triggered if the
1238
                        // visibility of the whole group changes??
1239
                        conditionalRedraw();
1240
                        invalidateToc();
1241
                }
1242

    
1243
                public void atomicEvent(AtomicEvent e) {
1244
                        boolean needRedraw = false;
1245
                        // not all the events require a fframeview redraw
1246
                        for (int i=e.getLayerEvents().length-1; i>=0; i--) {
1247
                                FMapEvent at = e.getEvent(i);
1248
                                if (at instanceof LayerEvent) {
1249
                                        if (at.getEventType()==LayerEvent.DRAW_VALUES_CHANGED) {
1250
                                                needRedraw = true;
1251
                                                break;
1252
                                        }
1253
                                }
1254
                        }
1255
                        if (needRedraw) {
1256
                                conditionalRedraw();
1257
                        }
1258
                        invalidateToc();
1259
                }
1260
        }
1261

    
1262
        private class OwnMapContextListener
1263
                implements ViewPortListener, LegendListener, LayerCollectionListener {
1264

    
1265
                public void extentChanged(ExtentEvent e) {
1266
                        if (!b_drawing && !b_updating) {
1267
                                if (getView()!=null) {
1268
                                        b_updating = true;
1269
                                        if (getExtentSynced()){
1270
                                                getView().getMapContext().getViewPort().setEnvelope(e.getNewExtent());
1271
                                                oldViewEnvelope = getView().getMapContext().getViewPort().getAdjustedEnvelope();
1272
                                        }
1273
                                        updateScaleCtrl();
1274
                                        invalidateLayout();
1275
                                        b_updating = false;
1276
                                }
1277
                        }                        
1278
                }
1279

    
1280
                public void backColorChanged(ColorEvent e) {
1281
                        if (!b_updating) {
1282
                                if (getView()!=null) {
1283
                                        b_updating = true;
1284
                                        if (getLayerSynced()) {
1285
                                                getView().getMapContext().getViewPort().setBackColor(e.getNewColor());
1286
                                        }
1287
                                        invalidateLayout();
1288
                                        b_updating = false;
1289
                                }
1290
                        }
1291
                }
1292

    
1293
                public void projectionChanged(ProjectionEvent e) {
1294
                        if (!b_updating && getExtentSynced()) {
1295
                                if (getView()!=null) {
1296
                                        b_updating = true;
1297
                                        if (getLayerSynced()) {
1298
                                                getView().getMapContext().getViewPort().setProjection(e.getNewProjection());
1299
                                        }
1300
                                        invalidateLayout();
1301
                                        // FIXME: force also a view redraw someway??
1302
                                        b_updating = false;
1303
                                }
1304
                        }
1305
                }
1306

    
1307
                public void conditionalRedraw() {
1308
                        if (!b_updating) {
1309
                                b_updating = true;
1310
                                invalidateLayout();
1311
                                // the view should also receive the event and update automatically
1312
                                b_updating = false;
1313
                        }
1314
                }
1315

    
1316
                public void legendChanged(final LegendChangedEvent e) {
1317
                        conditionalRedraw();
1318
                        invalidateToc();
1319
                }
1320

    
1321
                public void layerAdded(final LayerCollectionEvent e) {
1322
                        // necessary to set an envelope when the first layer is added
1323
                        if (!b_updating && getMapContext().getViewPort().getEnvelope()==null) {
1324
                                try {
1325
                                        b_updating = true;
1326
                                        fullExtent();
1327
                                        
1328
                                } catch (ReadException e1) {
1329
                                } finally {
1330
                                        b_updating = false;
1331
                                }
1332
                        }
1333
                        conditionalRedraw();
1334
                        invalidateToc();
1335
                }
1336

    
1337
                public void layerMoved(final LayerPositionEvent e) {
1338
                        conditionalRedraw();
1339
                        invalidateToc();
1340
                }
1341

    
1342
                public void layerRemoved(final LayerCollectionEvent e) {
1343
                        conditionalRedraw();
1344
                        invalidateToc();
1345
                }
1346

    
1347
                public void layerAdding(LayerCollectionEvent e)
1348
                                throws CancelationException {
1349
                        // nothing neededO
1350

    
1351
                }
1352

    
1353
                public void layerMoving(LayerPositionEvent e)
1354
                                throws CancelationException {
1355
                        // nothing needed
1356

    
1357
                }
1358

    
1359
                public void layerRemoving(LayerCollectionEvent e)
1360
                                throws CancelationException {
1361
                        // nothing needed
1362

    
1363
                }
1364

    
1365
                public void visibilityChanged(LayerCollectionEvent e)
1366
                                throws CancelationException {
1367
                        conditionalRedraw();
1368
                }
1369
        }
1370
}