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 @ 772

History | View | Annotate | Download (58.8 KB)

1 5 jldominguez
/* 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 93 jldominguez
import java.awt.BasicStroke;
25 5 jldominguez
import java.awt.Color;
26
import java.awt.Dimension;
27 93 jldominguez
import java.awt.Font;
28 5 jldominguez
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.Point2D;
33
import java.awt.geom.Rectangle2D;
34
import java.awt.image.BufferedImage;
35
36
import org.cresques.cts.IProjection;
37
import org.gvsig.andami.PluginServices;
38 140 cmartinez
import org.gvsig.andami.ui.mdiFrame.NewStatusBar;
39 5 jldominguez
import org.gvsig.app.project.Project;
40 147 cmartinez
import org.gvsig.app.project.ProjectManager;
41 5 jldominguez
import org.gvsig.app.project.documents.layout.DefaultLayoutNotification;
42 110 jldominguez
import org.gvsig.app.project.documents.layout.FLayoutFunctions;
43 5 jldominguez
import org.gvsig.app.project.documents.layout.FLayoutUtilities;
44
import org.gvsig.app.project.documents.layout.LayoutNotification;
45 168 cmartinez
import org.gvsig.app.project.documents.layout.TocModelChangedNotification;
46 5 jldominguez
import org.gvsig.app.project.documents.view.ViewDocument;
47
import org.gvsig.compat.print.PrintAttributes;
48
import org.gvsig.fmap.dal.exception.ReadException;
49
import org.gvsig.fmap.geom.Geometry;
50 181 cmartinez
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
51
import org.gvsig.fmap.geom.GeometryLocator;
52
import org.gvsig.fmap.geom.GeometryManager;
53
import org.gvsig.fmap.geom.exception.CreateEnvelopeException;
54 5 jldominguez
import org.gvsig.fmap.geom.primitive.Envelope;
55
import org.gvsig.fmap.mapcontext.MapContext;
56
import org.gvsig.fmap.mapcontext.MapContextException;
57
import org.gvsig.fmap.mapcontext.ViewPort;
58 146 cmartinez
import org.gvsig.fmap.mapcontext.events.AtomicEvent;
59 5 jldominguez
import org.gvsig.fmap.mapcontext.events.ColorEvent;
60
import org.gvsig.fmap.mapcontext.events.ExtentEvent;
61 176 cmartinez
import org.gvsig.fmap.mapcontext.events.FMapEvent;
62 5 jldominguez
import org.gvsig.fmap.mapcontext.events.ProjectionEvent;
63 146 cmartinez
import org.gvsig.fmap.mapcontext.events.listeners.AtomicEventListener;
64 5 jldominguez
import org.gvsig.fmap.mapcontext.events.listeners.ViewPortListener;
65 142 cmartinez
import org.gvsig.fmap.mapcontext.layers.CancelationException;
66
import org.gvsig.fmap.mapcontext.layers.LayerCollectionEvent;
67
import org.gvsig.fmap.mapcontext.layers.LayerCollectionListener;
68 168 cmartinez
import org.gvsig.fmap.mapcontext.layers.LayerEvent;
69 142 cmartinez
import org.gvsig.fmap.mapcontext.layers.LayerPositionEvent;
70 5 jldominguez
import org.gvsig.fmap.mapcontext.rendering.legend.events.LegendChangedEvent;
71
import org.gvsig.fmap.mapcontext.rendering.legend.events.listeners.LegendListener;
72 93 jldominguez
import org.gvsig.gui.beans.Messages;
73 5 jldominguez
import org.gvsig.tools.ToolsLocator;
74
import org.gvsig.tools.dynobject.DynStruct;
75
import org.gvsig.tools.persistence.PersistenceManager;
76
import org.gvsig.tools.persistence.PersistentState;
77
import org.gvsig.tools.persistence.exception.PersistenceException;
78 143 cmartinez
import org.slf4j.Logger;
79
import org.slf4j.LoggerFactory;
80 5 jldominguez
81
/**
82 176 cmartinez
 * FFrame used for embedding a View in the Layout. The View is not actually
83 761 jjdelcerro
 * inserted on the Layout, but it is used together with the MapContext in order
84
 * do draw an image which is then painted on the FFrame. Therefore, no
85
 * MapControl is used in current implementation, but a similar behavior is
86
 * simulated by the FFrameView. The original MapContext is cloned when assigned
87
 * to the FFrameView, which is then used for drawing.
88 383 fdiaz
 *
89 761 jjdelcerro
 * The FFrameView and the associated View can be synchronized, depending on the
90
 * values of {@link #getTypeScale()} and {@link #getLinked()}.
91 383 fdiaz
 *
92
 * The main synchronization logic is kept on two internal classes:
93 176 cmartinez
 * {@link OwnMapContextListener} and {@link ViewDocListener}. The first one
94
 * listens for events on the FFrameView and synchronizes the View accordingly.
95
 * The second one listens for events on the View and synchronizes the FFrameView
96
 * accordingly. There synchronization process is flagged using
97 761 jjdelcerro
 * {@link #b_updating} and {@link #b_updating}, in order to avoid incurring on
98
 * infinite synchronization loops.
99 383 fdiaz
 *
100 5 jldominguez
 */
101 308 cmartinez
public class FFrameView extends FFrame implements IFFrameUseProject,
102 761 jjdelcerro
        IFFrameUseFMap, LayoutPanelListener {
103 5 jldominguez
104 761 jjdelcerro
    private static final Logger logger = LoggerFactory.getLogger(FFrameView.class);
105
106 5 jldominguez
    public static final String PERSISTENCE_DEFINITION_NAME = "FFrameView";
107
108
    private static final String QUALITY_FIELD = "quality";
109
    private static final String MAPUNITS_FIELD = "mapUnits";
110
    private static final String SCALE_FIELD = "scale";
111
    private static final String VIEW_FIELD = "view";
112
    private static final String ENVELOPE_FIELD = "envelope";
113
    private static final String SHOWGRID_FIELD = "showGrid";
114
    private static final String GRID_FIELD = "gridview";
115 235 cmartinez
    private static final String HAS_TOC_FIELD = "hasToc";
116 219 cmartinez
    private static final String LAYER_SYNC_FIELD = "layerSync";
117
    private static final String EXTENT_SYNC_FIELD = "extentSync";
118 250 cmartinez
    private static final String SCALE_TYPE_FIELD = "scaleType";
119 761 jjdelcerro
120 383 fdiaz
    // following fields are unused - they are kept for backward-compatibility
121 143 cmartinez
    private static final String EXTENSION_FIELD = "extension";
122 219 cmartinez
    private static final String BLINKED_FIELD = "bLinked";
123
    private static final String MODE_FIELD = "mode";
124
    private static final String TYPESCALE_FIELD = "typeScale";
125
    private static final String MAPCONTEXT_FIELD = "mapContext";
126
    private static final String VIEWING_FIELD = "viewing";
127 5 jldominguez
128
    public static final int PRESENTATION = 0;
129
    public static final int DRAFT = 1;
130 250 cmartinez
131 219 cmartinez
    protected boolean syncLayers = true;
132
    protected boolean syncExtents = true;
133 5 jldominguez
    protected int quality = PRESENTATION;
134
    protected ViewDocument viewDocument = null;
135
    protected MapContext mapContext = null;
136
    protected int mapUnits = 1; // Meters.
137
138 64 jldominguez
    protected BufferedImage m_image = null;
139 232 cmartinez
    protected AffineTransform mapAT = null;
140 5 jldominguez
    protected Project project = null;
141 64 jldominguez
    protected double scaleAnt;
142
    protected Point origin;
143
    protected Point2D p1;
144
    protected Point2D p2;
145
    protected IFFrame grid;
146
    protected boolean showGrid = false;
147 5 jldominguez
148 761 jjdelcerro
    private boolean b_updating = false;
149
    protected boolean b_validCache = false;
150
    protected boolean b_drawing = false;
151
    private ViewDocListener viewDocListener;
152
    private OwnMapContextListener ownMapContextListener;
153
    private boolean b_hasToc = true;
154 181 cmartinez
    protected static final GeometryManager geomManager = GeometryLocator.getGeometryManager();
155
156 761 jjdelcerro
    /**
157
     * When we load a FFrameview from project, it will receive a wrong
158
     * extentChanged event the first time the View is painted, so we must ignore
159
     * this first event.
160
     */
161
    private boolean b_frameInitialized = true;
162 142 cmartinez
163 761 jjdelcerro
    protected AffineTransform originalGraphicsAT = null;
164
    protected Rectangle originalClip = null;
165 145 cmartinez
166 761 jjdelcerro
    private SCALE_TYPE scaleType = SCALE_TYPE.NORMAL;
167
    private Double fixedScale = null;
168
    private Envelope fixedExtent = null;
169 226 cmartinez
170 5 jldominguez
    /**
171
     * Creates a new FFrameView object.
172
     */
173
    public FFrameView() {
174
        num++;
175 760 jjdelcerro
//        logger.info("Create FFrameView "+ Integer.toHexString(this.hashCode()));
176 144 cmartinez
        createListeners();
177 5 jldominguez
    }
178 383 fdiaz
179 5 jldominguez
    /**
180 176 cmartinez
     * Returns a description of the FFrame
181 383 fdiaz
     *
182 176 cmartinez
     * @return Description.
183 5 jldominguez
     */
184 761 jjdelcerro
    @Override
185 5 jldominguez
    public String toString() {
186
        if (getView() == null) {
187
            return "FFrameView " + num + ": " + "Vacio";
188
        }
189
        return "FFrameView " + num + ": " + getView().getName();
190
    }
191
192
    /**
193 176 cmartinez
     * Sets the scale of the MapContext contained in this FFrameView
194 383 fdiaz
     *
195 176 cmartinez
     * @param d Scale to be set
196 5 jldominguez
     */
197 761 jjdelcerro
    @Override
198 5 jldominguez
    public void setScale(double d) {
199 761 jjdelcerro
        if (getMapContext() != null) {
200
            getMapContext().setScaleView((long) d);
201
        }
202 5 jldominguez
    }
203
204
    /**
205 761 jjdelcerro
     * Sets a new Envelope on the MapContext contained in this FFrameView
206 383 fdiaz
     *
207 176 cmartinez
     * @param r Envelope to be set
208 5 jldominguez
     */
209 761 jjdelcerro
    @Override
210 5 jldominguez
    public void setNewEnvelope(Envelope r) {
211 761 jjdelcerro
        getMapContext().getViewPort().setEnvelope(r);
212
        updateScaleCtrl();
213 5 jldominguez
    }
214 383 fdiaz
215 141 cmartinez
    /**
216
     * Calculates the resolution (measured on dots per inch, DPI) to be
217 761 jjdelcerro
     * considered to draw the FFrameView on screen. It is calculated by dividing
218
     * the width (in pixels) of the FFrame divided by the width in inches of the
219
     * paper.
220
     *
221
     * @return
222 141 cmartinez
     */
223
    protected double getDrawPaperDPI() {
224 761 jjdelcerro
        AffineTransform at = null;
225
        if (getLayoutContext() != null) {
226
            at = getLayoutContext().getAT();
227
        }
228
        return (2.54 * getBoundingBox(at).width) / getBoundBox().width;
229 141 cmartinez
    }
230 5 jldominguez
231
    /**
232 761 jjdelcerro
     * Returns the MapContext contained in this FFrameView, which is usually a
233
     * clone of the associated View. This MapContext may be synchronized with
234
     * the View one, depending on the scale type that has been set (see
235
     * {{@link #getTypeScale()}.
236 383 fdiaz
     *
237 176 cmartinez
     * @return The mapContext object
238 5 jldominguez
     */
239 761 jjdelcerro
    @Override
240 5 jldominguez
    public MapContext getMapContext() {
241
        return mapContext;
242
    }
243
244
    /**
245 761 jjdelcerro
     * Sets the quality of the visualization of the FFrame on screen. Valid
246
     * values include {@link #DRAFT} and {@link #PRESENTATION}. Draft will
247
     * disable the frame normal drawing, which will be replaced by an empty
248
     * rectangle only showing the name of the frame.
249 383 fdiaz
     *
250 176 cmartinez
     * @param q Integer representing the quality.
251 5 jldominguez
     */
252
    public void setQuality(int q) {
253
        quality = q;
254
    }
255
256
    /**
257 761 jjdelcerro
     * Gets the quality of the visualization of the FFrame on screen. Valid
258
     * values include {@link #DRAFT} and {@link #PRESENTATION}. Draft will
259
     * disable the frame normal drawing, which will be replaced by an empty
260
     * rectangle only showing the name of the frame.
261 383 fdiaz
     *
262 761 jjdelcerro
     * @return
263 5 jldominguez
     */
264
    public int getQuality() {
265
        return quality;
266
    }
267
268 176 cmartinez
    /**
269 761 jjdelcerro
     * Sets the MapContext associated with this FFrameView, which will be used
270
     * to clone the layers and synchronize the FFrameView with the associated
271
     * View
272 383 fdiaz
     *
273 176 cmartinez
     * @param viewMapContext
274
     */
275 142 cmartinez
    public void setViewMapContext(MapContext viewMapContext) {
276 761 jjdelcerro
        Envelope oldEnvelope = null;
277
        if (mapContext != null) {
278
            removeOwnListeners();
279
            if (mapContext.getViewPort() != null) {
280
                oldEnvelope = mapContext.getViewPort().getEnvelope();
281
            }
282
        }
283
        if (viewMapContext == null) { // disconnect the view from the map
284
            this.mapContext = null;
285
            return;
286
        }
287
        try {
288
            if (syncLayers) {
289
                mapContext
290
                        = viewMapContext.createNewFMap(
291
                                (ViewPort) viewMapContext.getViewPort().clone());
292
            } else {
293
                mapContext = viewMapContext.cloneFMap();
294
                mapContext.setViewPort((ViewPort) viewMapContext
295
                        .getViewPort().clone());
296
            }
297
            ViewPort newViewPort = getMapContext().getViewPort();
298
            if (!syncExtents && oldEnvelope != null) {
299
                // if extent is not synced with the view, restore the previous
300
                // envelope if existing
301
                newViewPort.setEnvelope(oldEnvelope);
302
            }
303
            AffineTransform at;
304
            if (getLayoutContext() != null) {
305
                at = getLayoutContext().getAT();
306
            } else {
307
                at = null;
308
            }
309
            newViewPort.setImageSize(new Dimension((int) getBoundingBox(at).width,
310
                    (int) getBoundingBox(at).height));
311
            newViewPort.setDPI(getDrawPaperDPI());
312
            addAllListeners();
313
            updateScaleCtrl();
314
            setTocModel();
315
        } catch (CloneNotSupportedException e1) {
316
            logger.warn("Can't set mapcontext of the fframeview", e1);
317
        }
318 142 cmartinez
319
    }
320 176 cmartinez
321 5 jldominguez
    /**
322 761 jjdelcerro
     * Sets the View associated with this FFrameView, which will be used to
323
     * clone the MapContext and the layers. It will also used to synchronize the
324
     * FFrameView with the associated View, depending on the selected scale type
325 383 fdiaz
     *
326 761 jjdelcerro
     * @param viewDocument
327 5 jldominguez
     */
328 761 jjdelcerro
    public void setView(ViewDocument viewDocument) {
329
        removeViewListeners();
330
        this.viewDocument = viewDocument;
331
        if (this.viewDocument != null) {
332
            setViewMapContext(this.viewDocument.getMapContext());
333 760 jjdelcerro
        } else {
334
            setViewMapContext(null);
335 5 jldominguez
        }
336
    }
337
338
    /**
339 176 cmartinez
     * Gets the associated View
340 383 fdiaz
     *
341 176 cmartinez
     * @return The associated view
342
     * @see {@link #setView(ViewDocument)}
343 5 jldominguez
     */
344
    public ViewDocument getView() {
345
        return viewDocument;
346
    }
347
348
    /**
349 761 jjdelcerro
     * Draws the FFrameView on the provided Graphics, according to the provided
350
     * affine transform and the visible rectangle.
351 383 fdiaz
     *
352 141 cmartinez
     * @param g Graphics2D
353 761 jjdelcerro
     * @param at Affine transform to translate sheet coordinates (in cm) to
354
     * screen coordinates (in pixels)
355 141 cmartinez
     * @param visibleLayoutDocRect visible rectangle
356
     * @param imgBase Image used to speed up the drawing process
357 5 jldominguez
     */
358 761 jjdelcerro
    @Override
359 141 cmartinez
    public void draw(Graphics2D g, AffineTransform at, Rectangle2D visibleLayoutDocRect, BufferedImage imgBase) {
360 228 cmartinez
        Rectangle2D.Double fframeViewRect = getBoundingBox(at);
361
        Rectangle2D.Double visibleArea = (Rectangle2D.Double) getVisibleRect(visibleLayoutDocRect, fframeViewRect);
362 761 jjdelcerro
        if (visibleArea == null) {
363
            return;
364 5 jldominguez
        }
365 228 cmartinez
        preDraw(g, fframeViewRect, visibleArea);
366
        if (getMapContext() == null) {
367 761 jjdelcerro
            drawEmpty(g);
368 228 cmartinez
        } else {
369 761 jjdelcerro
            if (FLayoutUtilities.hasEditingLayers(getView())) {
370
                // We are not drawing if any layer is in editing mode
371
                drawMessage(g, Messages.getText(
372
                        "_Cannot_draw_view_if_layers_in_editing_mode"));
373 228 cmartinez
374 761 jjdelcerro
            } else {
375
                if (getQuality() == PRESENTATION) {
376
                    try {
377
                        drawPresentation(g, at, fframeViewRect, visibleArea, imgBase);
378
                    } catch (Exception exc) {
379
                        drawMessage(g, FLayoutFunctions.getLastMessage(exc));
380
                    }
381 228 cmartinez
382 761 jjdelcerro
                } else {
383
                    drawDraft(g);
384
                }
385
            }
386 228 cmartinez
        }
387 383 fdiaz
        postDraw(g, fframeViewRect, at);
388
        if (showGrid && grid != null) {
389 141 cmartinez
            grid.draw(g, at, visibleLayoutDocRect, imgBase);
390 383 fdiaz
        }
391 5 jldominguez
    }
392 383 fdiaz
393 110 jldominguez
    private void drawMessage(Graphics2D g, String msg) {
394 383 fdiaz
395 93 jldominguez
        Rectangle2D r = getBoundingBox(null);
396
        g.setColor(Color.lightGray);
397 761 jjdelcerro
        g.fillRect((int) r.getX(), (int) r.getY(), (int) r.getWidth(), (int) r.getHeight());
398 93 jldominguez
        g.setColor(Color.darkGray);
399
        g.setStroke(new BasicStroke(2));
400 761 jjdelcerro
        g.drawRect((int) r.getX(), (int) r.getY(), (int) r.getWidth(), (int) r.getHeight());
401 93 jldominguez
        g.setColor(Color.black);
402
403
        int scale = (int) (r.getWidth() / 24);
404
        Font f = new Font("SansSerif", Font.PLAIN, scale);
405
        g.setFont(f);
406 761 jjdelcerro
        if (msg == null) {
407
            msg = Messages.getText("error");
408 243 cmartinez
        }
409 110 jldominguez
        g.drawString(msg, (int) (r.getCenterX() - ((msg.length() * scale) / 4)),
410 761 jjdelcerro
                (int) (r.getCenterY())
411
        );
412 93 jldominguez
    }
413
414 228 cmartinez
    /**
415
     * Gets the visible envelope, in map coordinates
416 383 fdiaz
     *
417 228 cmartinez
     * @param fframeViewRect Rectangle defining the bounding box of the
418
     * FFrameView, in screen coordinates
419 761 jjdelcerro
     * @param visiblefframeViewRect Rectangle defining the bounding box of the
420
     * visible area of the fframeView, in screen coordinates
421 228 cmartinez
     * @return
422
     */
423 181 cmartinez
    protected Envelope getVisibleEnvelope(Rectangle2D.Double fframeViewRect,
424
            Rectangle2D.Double visiblefframeViewRect) {
425 761 jjdelcerro
        Envelope oldEnv = getMapContext().getViewPort().getAdjustedEnvelope();
426
        double widthFactor = ((int) visiblefframeViewRect.width) / fframeViewRect.width;
427
        double heightFactor = ((int) visiblefframeViewRect.height) / fframeViewRect.height;
428 383 fdiaz
429 761 jjdelcerro
        double newWidth = oldEnv.getLength(0) * widthFactor;
430
        double newHeight = oldEnv.getLength(1) * heightFactor;
431 383 fdiaz
432 181 cmartinez
        double translateX = visiblefframeViewRect.x - fframeViewRect.x;
433
        double translateY = visiblefframeViewRect.y - fframeViewRect.y;
434
        double translateFactorX = translateX / fframeViewRect.width;
435
        double translateFactorY = translateY / fframeViewRect.height;
436 383 fdiaz
437 761 jjdelcerro
        double newX = oldEnv.getMinimum(0) + translateFactorX * oldEnv.getLength(0);
438
        double newMaxY = oldEnv.getMaximum(1) - translateFactorY * oldEnv.getLength(1);
439 181 cmartinez
        double newMaxX = newX + newWidth;
440
        double newY = newMaxY - newHeight;
441
442
        Envelope newEnv = null;
443 761 jjdelcerro
        try {
444
            newEnv = geomManager.createEnvelope(newX, newY, newMaxX, newMaxY, SUBTYPES.GEOM2D);
445
        } catch (CreateEnvelopeException ex) {
446
            logger.warn("Can't calculate the envelope of the visible area.", ex);
447
        }
448 181 cmartinez
        return newEnv;
449 383 fdiaz
450 181 cmartinez
    }
451 383 fdiaz
452 110 jldominguez
    protected void drawPresentation(
453 761 jjdelcerro
            Graphics2D g,
454
            AffineTransform affineTransform,
455
            Rectangle2D.Double fframeViewRect,
456
            Rectangle2D.Double visibleRect,
457
            BufferedImage imgBase) throws Exception {
458 383 fdiaz
459 761 jjdelcerro
        b_drawing = true;
460
        int drawWidth = (int) visibleRect.width;
461
        int drawHeight = (int) visibleRect.height;
462 181 cmartinez
463 761 jjdelcerro
        Envelope oldEnvelope = null;
464 232 cmartinez
        if (!visibleRect.equals(fframeViewRect)) {
465 761 jjdelcerro
            // if visible area is smaller than the fframe, we will only draw this area,
466
            // so we need to tell the ViewPort the image size and extent for drawing,
467
            // and restore the real extent after drawing
468 232 cmartinez
            oldEnvelope = getMapContext().getViewPort().getEnvelope();
469 761 jjdelcerro
            if (oldEnvelope == null) {
470
                return;
471 232 cmartinez
            }
472 308 cmartinez
473 761 jjdelcerro
            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
        } else {
478
            getMapContext().getViewPort().setImageSize(new Dimension(drawWidth, drawHeight));
479
            getMapContext().getViewPort().refreshExtent();
480 181 cmartinez
        }
481 383 fdiaz
482 232 cmartinez
        // map origin should be calculated using the full fframeview, as the visible position will be relative
483 761 jjdelcerro
        Point mapOrigin = new Point((int) fframeViewRect.getMinX(), (int) fframeViewRect.getMaxY());
484 181 cmartinez
485 147 cmartinez
        // paint the MapContext on m_image, if not already cached
486 176 cmartinez
        createImage(affineTransform, drawWidth, drawHeight, mapOrigin);
487 144 cmartinez
488 147 cmartinez
        //Draw the created image
489 228 cmartinez
        drawImage(g, m_image, visibleRect);
490 383 fdiaz
491 761 jjdelcerro
        if (oldEnvelope != null) {
492
            // restore real envelope and image size
493
            getMapContext().getViewPort().setImageSize(new Dimension((int) fframeViewRect.width, (int) fframeViewRect.height));
494
            getMapContext().getViewPort().setEnvelope(oldEnvelope);
495 181 cmartinez
        }
496 383 fdiaz
497 147 cmartinez
        scaleAnt = affineTransform.getScaleX();
498 181 cmartinez
        origin = mapOrigin;
499
        b_drawing = false;
500 147 cmartinez
    }
501 383 fdiaz
502 176 cmartinez
    protected void createImage(AffineTransform affineTransform,
503 761 jjdelcerro
            int width, int height, Point mapOrigin) throws ReadException, MapContextException {
504
        ViewPort viewPort = this.getMapContext().getViewPort();
505 147 cmartinez
506 144 cmartinez
        //If the image has to be created...
507 761 jjdelcerro
        if (origin == null
508
                || !origin.equals(mapOrigin)
509
                || affineTransform.getScaleX() != scaleAnt
510
                || m_image == null
511
                || !b_validCache) {
512 39 jldominguez
513 761 jjdelcerro
            viewPort.setDPI(getDrawPaperDPI());
514
            viewPort.setImageSize(new Dimension(width, height));
515 383 fdiaz
516 761 jjdelcerro
            m_image = new BufferedImage(
517
                    width,
518
                    height,
519
                    BufferedImage.TYPE_INT_ARGB
520
            );
521 39 jldominguez
522 142 cmartinez
            Graphics2D gimg = (Graphics2D) m_image.createGraphics();
523 772 jjdelcerro
            gimg.setBackground(viewPort.getBackColor());
524
            gimg.fillRect(0, 0, width, height);
525 142 cmartinez
            getMapContext().draw(m_image, gimg, getScale());
526
            gimg.dispose();
527
            b_validCache = true;
528 383 fdiaz
        }
529 5 jldominguez
530 147 cmartinez
    }
531 383 fdiaz
532 147 cmartinez
    protected void drawImage(Graphics2D g, BufferedImage image,
533 761 jjdelcerro
            Rectangle2D.Double visibleRectangle) {
534 147 cmartinez
535 761 jjdelcerro
        Color theBackColor = getMapContext().getViewPort().getBackColor();
536 5 jldominguez
        if (theBackColor != null) {
537
            g.setColor(theBackColor);
538 147 cmartinez
            g.fillRect((int) visibleRectangle.x, (int) visibleRectangle.y,
539 761 jjdelcerro
                    (int) visibleRectangle.width,
540
                    (int) visibleRectangle.height);
541 5 jldominguez
        }
542 383 fdiaz
        g.drawImage(m_image,
543 761 jjdelcerro
                (int) visibleRectangle.x,
544
                (int) visibleRectangle.y,
545
                null);
546 5 jldominguez
    }
547 39 jldominguez
548 761 jjdelcerro
    protected void preDraw(Graphics2D g, Rectangle2D.Double fframeViewRect, Rectangle2D.Double visibleRect) {
549
        originalGraphicsAT = (AffineTransform) g.getTransform().clone();
550 383 fdiaz
551 5 jldominguez
        if (g.getClipBounds() != null) {
552
            originalClip = (Rectangle) g.getClipBounds().clone();
553
        }
554 234 cmartinez
        AffineTransform rotationAT = getRotationAT();
555 761 jjdelcerro
        if (rotationAT != null) {
556
            g.transform(rotationAT);
557 181 cmartinez
        }
558 228 cmartinez
        g.setClip((int) visibleRect.getMinX(), (int) visibleRect.getMinY(),
559 761 jjdelcerro
                (int) visibleRect.getWidth(), (int) visibleRect.getHeight());
560 5 jldominguez
    }
561 383 fdiaz
562 761 jjdelcerro
    protected void postDraw(Graphics2D g, Rectangle2D.Double fframeViewRect, AffineTransform at) {
563
        g.setTransform(originalGraphicsAT);
564 5 jldominguez
        if (getMapContext() != null) {
565
            setATMap(getMapContext().getViewPort().getAffineTransform());
566
        }
567 228 cmartinez
        if (originalClip != null) {
568 5 jldominguez
            g.setClip(originalClip.x, originalClip.y, originalClip.width, originalClip.height);
569 383 fdiaz
        }
570 5 jldominguez
    }
571
572 303 cmartinez
    /**
573 761 jjdelcerro
     * @param g
574
     * @param rectangleLayout
575
     * @param rectangleView
576
     * @param originalClip
577
     * @param imgBase
578
     * @param at
579
     * @deprecated Use
580
     * {@link #postDraw(Graphics2D, java.awt.geom.Rectangle2D.Double, AffineTransform)}
581
     * instead.
582 303 cmartinez
     */
583
    @Deprecated
584
    protected void postDraw(Graphics2D g, Rectangle2D.Double rectangleLayout, Rectangle2D rectangleView, BufferedImage imgBase, Rectangle originalClip, AffineTransform at) {
585 761 jjdelcerro
        postDraw(g, rectangleLayout, at);
586 383 fdiaz
587 303 cmartinez
    }
588 383 fdiaz
589 303 cmartinez
    /**
590 761 jjdelcerro
     * @param g
591
     * @param rectangleLayout
592
     * @return
593 303 cmartinez
     * @deprecated Use {@link #preDraw(Graphics2D, java.awt.geom.Rectangle2D.Double, java.awt.geom.Rectangle2D.Double) instead
594
     */
595
    @Deprecated
596 761 jjdelcerro
    protected Rectangle preDraw(Graphics2D g, Rectangle2D.Double rectangleLayout) {
597
        Rectangle originalClip = null;
598 303 cmartinez
        if (g.getClipBounds() != null) {
599
            originalClip = (Rectangle) g.getClipBounds().clone();
600
        }
601 761 jjdelcerro
        preDraw(g, rectangleLayout, rectangleLayout);
602
        return originalClip;
603 303 cmartinez
    }
604
605 761 jjdelcerro
    @Override
606 5 jldominguez
    public void print(Graphics2D g, AffineTransform at, Geometry geom,
607 761 jjdelcerro
            PrintAttributes printAttributes) {
608 383 fdiaz
        Rectangle2D.Double rectangleLayout = getBoundingBox(at);
609
610 228 cmartinez
        preDraw(g, rectangleLayout, rectangleLayout);
611 5 jldominguez
        print(g, at, printAttributes);
612 228 cmartinez
        postDraw(g, rectangleLayout, at);
613 5 jldominguez
        if (showGrid && grid != null) {
614
            grid.print(g, at, geom, printAttributes);
615 383 fdiaz
        }
616 5 jldominguez
    }
617
618 65 jldominguez
    protected void print(Graphics2D g, AffineTransform at, PrintAttributes printAttributes) {
619 5 jldominguez
        Rectangle2D.Double layoutRectangle = getBoundingBox(at);
620 383 fdiaz
621 142 cmartinez
        // FIXME: should we clone the mapcontext and viewport before printing ??
622
        // otherwise we will probably have unexpected results if the user modifies
623 308 cmartinez
        // the layout while printing (answer: not an issue at the moment as printing is
624
        // a blocking operation)
625 5 jldominguez
        ViewPort viewPort = this.getMapContext().getViewPort();
626 383 fdiaz
627 57 jldominguez
        Point2D old_offset = viewPort.getOffset();
628
        Dimension old_imgsize = viewPort.getImageSize();
629 318 cmartinez
        double oldDpi = viewPort.getDPI();
630 383 fdiaz
631 5 jldominguez
        viewPort.setOffset(new Point2D.Double(layoutRectangle.x, layoutRectangle.y));
632 761 jjdelcerro
        viewPort.setImageSize(
633
                new Dimension(
634
                        (int) layoutRectangle.width,
635
                        (int) layoutRectangle.height
636
                )
637
        );
638 318 cmartinez
        double dpi = PrintAttributes.PRINT_QUALITY_DPI[printAttributes.getPrintQuality()];
639
        viewPort.setDPI(dpi);
640 5 jldominguez
641
        //Draw the backgroung color of the map
642
        Color theBackColor = viewPort.getBackColor();
643
        if (theBackColor != null) {
644
            g.setColor(theBackColor);
645 761 jjdelcerro
            g.fillRect(
646
                    (int) layoutRectangle.x,
647
                    (int) layoutRectangle.y,
648
                    viewPort.getImageWidth(),
649
                    viewPort.getImageHeight()
650
            );
651 383 fdiaz
        }
652
653 5 jldominguez
        //Print the map
654
        try {
655
            this.getMapContext().print(g, getScale(), printAttributes);
656 761 jjdelcerro
        } catch (Exception ex) {
657
            logger.warn("Can't print frame view.", ex);
658 383 fdiaz
        }
659
660 57 jldominguez
        // Restore offset, imgsize
661
        viewPort.setOffset(old_offset);
662
        viewPort.setImageSize(old_imgsize);
663 318 cmartinez
        viewPort.setDPI(oldDpi);
664
665 5 jldominguez
    }
666
667
    /**
668
     * Rellena la unidad de medida en la que est? la vista.
669 383 fdiaz
     *
670 761 jjdelcerro
     * @param i entero que representa la unidad de medida de la vista.
671 5 jldominguez
     */
672
    public void setMapUnits(int i) {
673
        mapUnits = i;
674
    }
675
676
    /**
677
     * Obtiene la unidad de medida en la que est? la vista.
678 383 fdiaz
     *
679 5 jldominguez
     * @return Unidad de medida.
680
     */
681
    public int getMapUnits() {
682
        return mapUnits;
683
    }
684
685
    /**
686
     * Devuelve la escala seg?n el tipo de escala que se haya seleccionado al
687
     * a?adida la vista.
688 383 fdiaz
     *
689 5 jldominguez
     * @return escala.
690
     */
691
    public long getScale() {
692 761 jjdelcerro
        return (long) getMapContext().getScaleView();
693 5 jldominguez
    }
694
695
    /**
696
     * Inserta la imagen para repintar el FFrameView.
697 383 fdiaz
     *
698 761 jjdelcerro
     * @param bi Imagen para repintar.
699 5 jldominguez
     */
700
    public void setBufferedImage(BufferedImage bi) {
701
        m_image = bi;
702
    }
703
704
    /**
705
     * Devuelve la imagen para repintar.
706 383 fdiaz
     *
707 5 jldominguez
     * @return Imagen para repintar.
708
     */
709 761 jjdelcerro
    @Override
710 5 jldominguez
    public BufferedImage getBufferedImage() {
711
        return m_image;
712
    }
713
714
    /**
715
     * Devuelve la MAtriz de transformaci?n utilizada por la FFrameView.
716 383 fdiaz
     *
717 5 jldominguez
     * @return MAtriz de transformaci?n.
718
     */
719 761 jjdelcerro
    @Override
720 5 jldominguez
    public AffineTransform getATMap() {
721 232 cmartinez
        return mapAT;
722 5 jldominguez
    }
723
724
    /**
725
     * Inserta la matriz de transformaci?n.
726 383 fdiaz
     *
727 761 jjdelcerro
     * @param transform Matriz de transformaci?n.
728 5 jldominguez
     */
729 761 jjdelcerro
    @Override
730 5 jldominguez
    public void setATMap(AffineTransform transform) {
731 232 cmartinez
        mapAT = transform;
732 5 jldominguez
    }
733
734
    /**
735
     * Inserta el proyecto.
736 383 fdiaz
     *
737 761 jjdelcerro
     * @param p Proyecto.
738 5 jldominguez
     */
739 761 jjdelcerro
    @Override
740 5 jldominguez
    public void setProject(Project p) {
741
        project = p;
742
    }
743
744
    /**
745 761 jjdelcerro
     * @see
746
     * org.gvsig.app.project.documents.layout.fframes.IFFrame#getNameFFrame()
747 5 jldominguez
     */
748 761 jjdelcerro
    @Override
749 5 jldominguez
    public String getNameFFrame() {
750
        return PluginServices.getText(this, "Vista") + num;
751
    }
752
753 761 jjdelcerro
    @Override
754 5 jldominguez
    public String getName() {
755
        return PERSISTENCE_DEFINITION_NAME;
756
    }
757
758
    public boolean compare(Object arg0) {
759
        if (!(arg0 instanceof FFrameView)) {
760
            return false;
761
        }
762
763
        if (!this.getName().equals(((FFrameView) arg0).getName())) {
764
            return false;
765
        }
766
767
        if (Math.abs(this.getBoundBox().getWidth()
768 761 jjdelcerro
                - (((FFrameView) arg0).getBoundBox().getWidth())) > 0.05) {
769 5 jldominguez
            return false;
770
        }
771
        if (Math.abs(this.getBoundBox().getHeight()
772 761 jjdelcerro
                - (((FFrameView) arg0).getBoundBox().getHeight())) > 0.05) {
773 5 jldominguez
            return false;
774
        }
775
776
        if (!this.toString().equals(((FFrameView) arg0).toString())) {
777
            return false;
778
        }
779
780
        if (this.getMapContext() != null
781 761 jjdelcerro
                && !this.getMapContext()
782
                        .equals(((FFrameView) arg0).getMapContext())) {
783 5 jldominguez
            return false;
784
        }
785
786
        if (this.getRotation() != ((FFrameView) arg0).getRotation()) {
787
            return false;
788
        }
789
        return true;
790
    }
791 383 fdiaz
792 140 cmartinez
    public void updateScaleCtrl() {
793 761 jjdelcerro
        NewStatusBar statusbar = PluginServices.getMainFrame().getStatusBar();
794
        MapContext mapContext = this.getMapContext();
795
        if (mapContext == null) {
796
            return;
797
        }
798
        statusbar.setMessage("units",
799
                PluginServices.getText(this, mapContext.getDistanceName())
800
        );
801
        String scale;
802
        if (fixedScale != null && getScaleType() == SCALE_TYPE.FIXED_SCALE) {
803
            // prefer fixedScale as getScaleView() may offer slight differences
804
            // because the influence of the adjusted envelope
805
            scale = String.valueOf(fixedScale.longValue());
806
        } else {
807
            scale = String.valueOf(getMapContext().getScaleView());
808
        }
809
        statusbar.setControlValue("layout-view-change-scale",
810
                scale);
811
        IProjection proj = mapContext.getViewPort().getProjection();
812
        if (proj != null) {
813
            statusbar.setMessage("projection", proj.getAbrev());
814
        } else {
815
            statusbar.setMessage("projection", "");
816
        }
817 140 cmartinez
    }
818 5 jldominguez
819 761 jjdelcerro
    @Override
820 5 jldominguez
    public void fullExtent() throws ReadException {
821
        setNewEnvelope(getMapContext().getFullEnvelope());
822
    }
823
824 761 jjdelcerro
    @Override
825 5 jldominguez
    public void setPointsToZoom(Point2D px1, Point2D px2) {
826
        p1 = px1;
827
        p2 = px2;
828
    }
829
830 761 jjdelcerro
    @Override
831 5 jldominguez
    public void movePoints(Point2D px1, Point2D px2) {
832
        double difX = -px2.getX() + px1.getX();
833
        double difY = -px2.getY() + px1.getY();
834
        if (p1 != null) {
835
            p1.setLocation(p1.getX() + difX, p1.getY() + difY);
836
            p2.setLocation(p2.getX() + difX, p2.getY() + difY);
837
        }
838
    }
839
840 760 jjdelcerro
    @Override
841
    public FFrameView clone() throws CloneNotSupportedException {
842
//        logger.info("clone FFrameView "+ Integer.toHexString(this.hashCode()));
843 5 jldominguez
        FFrameView frame = (FFrameView) super.clone();
844 147 cmartinez
        frame.createListeners(); // necessary to create the listeners within the right scope
845 219 cmartinez
        frame.setView(this.getView());
846 760 jjdelcerro
        frame.removeAllListeners(); // remove listeners add by setView
847 761 jjdelcerro
848 5 jldominguez
        if (grid != null) {
849
            FFrameGrid newGrid = (FFrameGrid) this.grid.clone();
850
            newGrid.setFFrameDependence(frame);
851
            frame.setGrid(newGrid);
852
        }
853 760 jjdelcerro
//        logger.info("cloned FFrameView "+ Integer.toHexString(frame.hashCode()));
854 5 jldominguez
        return frame;
855
    }
856
857
    public void setGrid(IFFrame grid) {
858
        this.grid = grid;
859
        this.grid.setRotation(this.getRotation());
860
    }
861
862
    public IFFrame getGrid() {
863
        return this.grid;
864
    }
865
866 761 jjdelcerro
    @Override
867 5 jldominguez
    public void setRotation(double rotation) {
868
        super.setRotation(rotation);
869
        if (grid != null) {
870
            grid.setRotation(rotation);
871
        }
872
    }
873
874
    public void showGrid(boolean b) {
875
        showGrid = b;
876
    }
877
878
    public boolean isShowGrid() {
879
        return showGrid;
880
    }
881
882 761 jjdelcerro
    @Override
883 5 jldominguez
    public void refreshOriginalExtent() {
884
    }
885
886
    public static void registerPersistent() {
887
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
888 383 fdiaz
        if (manager.getDefinition(PERSISTENCE_DEFINITION_NAME) == null) {
889 761 jjdelcerro
            DynStruct definition = manager.addDefinition(
890
                    FFrameView.class,
891 5 jldominguez
                    PERSISTENCE_DEFINITION_NAME,
892 761 jjdelcerro
                    "FFrameView persistence definition", null, null
893
            );
894
            definition.extend(
895
                    manager.getDefinition(FFrame.PERSISTENCE_DEFINITION_NAME)
896
            );
897 5 jldominguez
            definition.addDynFieldInt(QUALITY_FIELD).setMandatory(true);
898
            definition.addDynFieldInt(MAPUNITS_FIELD).setMandatory(true);
899 142 cmartinez
            definition.addDynFieldDouble(SCALE_FIELD).setMandatory(false);
900 5 jldominguez
            definition.addDynFieldObject(VIEW_FIELD)
901 761 jjdelcerro
                    .setClassOfValue(ViewDocument.class).setMandatory(false);
902 5 jldominguez
            definition.addDynFieldObject(ENVELOPE_FIELD)
903 761 jjdelcerro
                    .setClassOfValue(Envelope.class).setMandatory(false);
904 5 jldominguez
            definition.addDynFieldBoolean(SHOWGRID_FIELD).setMandatory(true);
905
            definition.addDynFieldObject(GRID_FIELD)
906 761 jjdelcerro
                    .setClassOfValue(IFFrame.class).setMandatory(false);
907 235 cmartinez
            definition.addDynFieldBoolean(HAS_TOC_FIELD).setMandatory(false);
908
            definition.addDynFieldBoolean(EXTENT_SYNC_FIELD).setMandatory(false);
909
            definition.addDynFieldBoolean(LAYER_SYNC_FIELD).setMandatory(false);
910 250 cmartinez
            definition.addDynFieldInt(SCALE_TYPE_FIELD).setMandatory(false);
911 219 cmartinez
            // unused fields, kept for backward compatibility
912
            definition.addDynFieldInt(MODE_FIELD).setMandatory(false);
913
            definition.addDynFieldInt(TYPESCALE_FIELD).setMandatory(false);
914
            definition.addDynFieldBoolean(BLINKED_FIELD).setMandatory(false);
915
            definition.addDynFieldObject(MAPCONTEXT_FIELD)
916 761 jjdelcerro
                    .setClassOfValue(MapContext.class).setMandatory(false);
917 219 cmartinez
            definition.addDynFieldInt(VIEWING_FIELD).setMandatory(false);
918 235 cmartinez
            definition.addDynFieldInt(EXTENSION_FIELD).setMandatory(false);
919 5 jldominguez
        }
920
    }
921
922
    @Override
923
    public void loadFromState(PersistentState state)
924 761 jjdelcerro
            throws PersistenceException {
925 5 jldominguez
        super.loadFromState(state);
926 176 cmartinez
        b_frameInitialized = false;
927 219 cmartinez
        if (state.hasValue(EXTENT_SYNC_FIELD)) {
928 761 jjdelcerro
            syncExtents = state.getBoolean(EXTENT_SYNC_FIELD);
929
        } else {
930
            syncExtents = true;
931 219 cmartinez
        }
932
        if (state.hasValue(LAYER_SYNC_FIELD)) {
933 761 jjdelcerro
            syncLayers = state.getBoolean(LAYER_SYNC_FIELD);
934
        } else {
935
            syncLayers = true;
936 219 cmartinez
        }
937 326 cmartinez
        Double layoutScale = null;
938 383 fdiaz
        if (state.hasValue(SCALE_FIELD)) {
939 761 jjdelcerro
            layoutScale = state.getDouble(SCALE_FIELD);
940 326 cmartinez
        }
941 761 jjdelcerro
        Envelope envelope = (Envelope) state.get(ENVELOPE_FIELD);
942 308 cmartinez
943 250 cmartinez
        if (state.hasValue(SCALE_TYPE_FIELD)) {
944 761 jjdelcerro
            int value = state.getInt(SCALE_TYPE_FIELD);
945
            if (value == SCALE_TYPE.FIXED_EXTENT.ordinal()) {
946
                scaleType = SCALE_TYPE.FIXED_EXTENT;
947
                fixedExtent = envelope;
948
            } else if (value == SCALE_TYPE.FIXED_SCALE.ordinal()) {
949
                scaleType = SCALE_TYPE.FIXED_SCALE;
950
                fixedScale = layoutScale;
951
            }
952
            // else use the default value
953 250 cmartinez
        }
954 5 jldominguez
        quality = state.getInt(QUALITY_FIELD);
955 345 cmartinez
        mapUnits = state.getInt(MAPUNITS_FIELD);
956 235 cmartinez
        if (state.hasValue(HAS_TOC_FIELD)) {
957 761 jjdelcerro
            this.b_hasToc = state.getBoolean(HAS_TOC_FIELD);
958 345 cmartinez
        }
959 383 fdiaz
960 345 cmartinez
        // When copying and pasting layout documents (in project manager), the view
961
        // is first persisted (copy action) and then re-created from persistence (paste action).
962
        // This is a problem, as the re-created view is not the same view as the original one
963
        // and thus layout stops being synchronized with the right view.
964
        // Therefore, we try to get first the "live" view if available, and get the persisted
965
        // one otherwise, which will be used when opening projects.
966
        ViewDocument persistenceView = (ViewDocument) state.get(VIEW_FIELD);
967 761 jjdelcerro
        if (persistenceView != null) {
968
            ViewDocument view = (ViewDocument) ProjectManager.getInstance().getCurrentProject().getDocument(persistenceView.getName(), persistenceView.getTypeName());
969
            if (view == null) {
970
                view = persistenceView;
971
            }
972
            this.setView(view);
973
            // it is crucial to don't persist the MapContext and get a cloned one from the View instead,
974
            // as the cloned instance is different from the one created using persistence. In particular,
975
            // the cloned one will share the EventBuffer with the original one, while persistence would
976
            // create 2 separate EventBuffers, which will then have a very stange behaviour
977 168 cmartinez
        }
978 761 jjdelcerro
        if (getMapContext() != null) {
979
            if (layoutScale != null) {
980
                getMapContext().setScaleView(layoutScale.longValue());
981
            }
982
            getMapContext().getViewPort().setEnvelope(envelope);
983
            if (this.getLayoutContext() != null) {
984
                this.getLayoutContext().setTocModel(getMapContext());
985
            }
986 5 jldominguez
        }
987
        showGrid = state.getBoolean(SHOWGRID_FIELD);
988
        grid = (IFFrame) state.get(GRID_FIELD);
989
    }
990
991
    @Override
992
    public void saveToState(PersistentState state) throws PersistenceException {
993
        super.saveToState(state);
994 219 cmartinez
        state.set(EXTENT_SYNC_FIELD, syncExtents);
995
        state.set(LAYER_SYNC_FIELD, syncLayers);
996 5 jldominguez
        state.set(QUALITY_FIELD, quality);
997
        state.set(MAPUNITS_FIELD, mapUnits);
998
        state.set(VIEW_FIELD, viewDocument);
999 235 cmartinez
        state.set(HAS_TOC_FIELD, b_hasToc);
1000 250 cmartinez
        state.set(SCALE_TYPE_FIELD, scaleType.ordinal());
1001 5 jldominguez
1002
        if (getMapContext() != null
1003 761 jjdelcerro
                && getMapContext().getViewPort().getEnvelope() != null) {
1004
            if (scaleType == SCALE_TYPE.FIXED_SCALE) {
1005
                if (fixedScale == null) {
1006
                    fixedScale = new Double(getMapContext().getScaleView());
1007
                }
1008
                state.set(SCALE_FIELD, (double) fixedScale);
1009
            } else {
1010
                state.set(SCALE_FIELD, (double) getMapContext().getScaleView());
1011
            }
1012
            if (scaleType == SCALE_TYPE.FIXED_EXTENT) {
1013
                if (fixedExtent == null) {
1014
                    fixedExtent = getMapContext().getViewPort().getAdjustedEnvelope();
1015
                }
1016
                state.set(ENVELOPE_FIELD, fixedExtent);
1017
            } else {
1018
                state.set(ENVELOPE_FIELD, getMapContext().getViewPort()
1019 383 fdiaz
                        .getAdjustedEnvelope());
1020 761 jjdelcerro
            }
1021 5 jldominguez
        }
1022
        state.set(SHOWGRID_FIELD, showGrid);
1023
        state.set(GRID_FIELD, grid);
1024
    }
1025 383 fdiaz
1026 5 jldominguez
    @Override
1027 142 cmartinez
    public void setBoundBox(Rectangle2D r) {
1028 761 jjdelcerro
        super.setBoundBox(r);
1029
        if (this.getMapContext() != null && this.getLayoutContext() != null) {
1030
            AffineTransform at = this.getLayoutContext().getAT();
1031
            long scale = getMapContext().getScaleView();
1032
            getMapContext().getViewPort().setImageSize(
1033
                    new Dimension(
1034
                            (int) getBoundingBox(at).getWidth(),
1035
                            (int) getBoundingBox(at).getHeight()
1036
                    )
1037
            );
1038
            getMapContext().getViewPort().setDPI(getDrawPaperDPI());
1039
            if (getScaleType() == SCALE_TYPE.FIXED_SCALE) {
1040
                getMapContext().setScaleView((long) scale);
1041
            }
1042
            updateScaleCtrl();
1043
            refresh();
1044
        }
1045 383 fdiaz
    }
1046 72 jldominguez
1047
    /**
1048 176 cmartinez
     * Gets the rotation of the frame
1049 383 fdiaz
     *
1050 176 cmartinez
     * @return Rotation in degrees
1051 72 jldominguez
     */
1052
    public double getMapRotation() {
1053
        return 0;
1054
    }
1055 383 fdiaz
1056 761 jjdelcerro
    protected void invalidateLayout() {
1057
        b_validCache = false;
1058
        if (getLayoutContext() != null) {
1059
            getLayoutContext().notifAllObservers();
1060
        }
1061 383 fdiaz
        observers.notifyObservers(this,
1062 761 jjdelcerro
                new DefaultLayoutNotification(LayoutNotification.LAYOUT_REFRESH)
1063
        );
1064
    }
1065 383 fdiaz
1066 761 jjdelcerro
    protected void invalidateToc() {
1067
        if (getLayoutContext() != null) {
1068
            getLayoutContext().notifyTocUpdated(TocModelChangedNotification.Type.ITEM_UPDATED);
1069
        }
1070
    }
1071 383 fdiaz
1072 761 jjdelcerro
    protected void refreshToc() {
1073
        if (getLayoutContext() != null) {
1074
            getLayoutContext().notifyTocUpdated(TocModelChangedNotification.Type.MODEL_CHANGED);
1075
        }
1076
    }
1077 144 cmartinez
1078 761 jjdelcerro
    @Override
1079
    public void refresh() {
1080
        // force re-creating the cache on the next drawing cycle
1081
        b_validCache = false;
1082
    }
1083 383 fdiaz
1084 760 jjdelcerro
    protected void createListeners() {
1085 761 jjdelcerro
        this.removeAllListeners();
1086 760 jjdelcerro
        viewDocListener = new ViewDocListener(this);
1087 761 jjdelcerro
        ownMapContextListener = new OwnMapContextListener(this);
1088 760 jjdelcerro
//        logger.info("createListeners.viewDocListener "+ viewDocListener.getID());
1089
//        logger.info("createListeners.ownMapContextListener "+ ownMapContextListener.getID());
1090 144 cmartinez
    }
1091 383 fdiaz
1092 760 jjdelcerro
    protected void addAllListeners() {
1093 761 jjdelcerro
        if (viewDocListener == null && ownMapContextListener == null) {
1094 760 jjdelcerro
            this.createListeners();
1095
        }
1096
        if (getView() != null) {
1097
            if (syncLayers) {
1098
                getView().getMapContext().addLayerListener(viewDocListener);
1099
                getView().getMapContext().getLayers().addLayerCollectionListener(viewDocListener);
1100
                getView().getMapContext().addAtomicEventListener(viewDocListener);
1101
            }
1102
            if (getExtentSynced()) {
1103
                getView().getMapContext().getViewPort().addViewPortListener(viewDocListener);
1104
            }
1105
        }
1106
        if (getMapContext() != null) {
1107
            getMapContext().addLayerListener(ownMapContextListener);
1108
            getMapContext().getLayers().addLayerCollectionListener(ownMapContextListener);
1109
            getMapContext().getViewPort().addViewPortListener(ownMapContextListener);
1110
        }
1111
//        logger.info("addAllListeners.viewDocListener " + viewDocListener.getID());
1112
//        logger.info("addAllListeners.ownMapContextListener " + ownMapContextListener.getID());
1113
1114 144 cmartinez
    }
1115 760 jjdelcerro
1116
    protected void resetAllListeners() {
1117
        this.removeAllListeners();
1118
        this.addAllListeners();
1119 144 cmartinez
    }
1120 760 jjdelcerro
1121
    protected void removeAllListeners() {
1122
        removeOwnListeners();
1123
        removeViewListeners();
1124 144 cmartinez
    }
1125 383 fdiaz
1126 760 jjdelcerro
    protected void removeOwnListeners() {
1127 761 jjdelcerro
        if (this.ownMapContextListener == null) {
1128 760 jjdelcerro
            return;
1129
        }
1130 761 jjdelcerro
        if (this.mapContext == null) {
1131 760 jjdelcerro
            return;
1132
        }
1133
        this.mapContext.removeLayerListener(ownMapContextListener);
1134
        this.mapContext.getViewPort().removeViewPortListener(ownMapContextListener);
1135
        this.mapContext.getLayers().removeLayerCollectionListener(ownMapContextListener);
1136
//        logger.info("removeOwnListeners.ownMapContextListener " + ownMapContextListener.getID());
1137
    }
1138 142 cmartinez
1139 760 jjdelcerro
    protected void removeViewListeners() {
1140 761 jjdelcerro
        if (this.viewDocListener == null) {
1141 760 jjdelcerro
            return;
1142
        }
1143 761 jjdelcerro
        if (this.getView() == null) {
1144 760 jjdelcerro
            return;
1145
        }
1146
        MapContext mapContext = this.getView().getMapContext();
1147 761 jjdelcerro
        if (mapContext == null) {
1148 760 jjdelcerro
            return;
1149
        }
1150
        mapContext.removeLayerListener(viewDocListener);
1151
        mapContext.getViewPort().removeViewPortListener(viewDocListener);
1152
        mapContext.getLayers().removeLayerCollectionListener(viewDocListener);
1153
        mapContext.removeAtomicEventListener(viewDocListener);
1154
//        logger.info("removeViewListeners.viewDocListener " + viewDocListener.getID());
1155
    }
1156
1157
    @Override
1158
    public void dispose() {
1159
        this.removeAllListeners();
1160
        this.viewDocListener = null;
1161
        this.ownMapContextListener = null;
1162
        this.viewDocument = null;
1163
        this.mapContext = null;
1164
    }
1165
1166 761 jjdelcerro
    @Override
1167
    public void frameRemoved() {
1168
        this.removeAllListeners();
1169
        if (b_hasToc && getLayoutContext() != null) {
1170
            getLayoutContext().setTocModel(null);
1171
        }
1172
        m_image = null; // FIXME: we could instead move it to a LRU cache to keep the last N images
1173
    }
1174 144 cmartinez
1175 761 jjdelcerro
    @Override
1176
    public void frameAdded() {
1177
        addAllListeners();
1178
        setTocModel();
1179
        updateScaleCtrl();
1180
    }
1181 383 fdiaz
1182 761 jjdelcerro
    public void setHasToc(boolean hasToc) {
1183
        this.b_hasToc = hasToc;
1184
        setTocModel();
1185
    }
1186 383 fdiaz
1187 761 jjdelcerro
    protected void setTocModel() {
1188
        if (getLayoutContext() != null) {
1189
            if (b_hasToc && getMapContext() != null) {
1190
                getLayoutContext().setTocModel(getMapContext());
1191
            } else {
1192
                getLayoutContext().setTocModel(null);
1193
            }
1194
        }
1195
    }
1196 383 fdiaz
1197 761 jjdelcerro
    @Override
1198
    protected void doSetSelected(int selectedStatus) {
1199
        boolean oldSelectedStatus = isSelected();
1200
        super.doSetSelected(selectedStatus);
1201
        if (!oldSelectedStatus && isSelected()) { // changed from not selected to selected
1202
            setTocModel();
1203
            updateScaleCtrl();
1204
        }
1205
    }
1206 383 fdiaz
1207 761 jjdelcerro
    @Override
1208
    public boolean getLayerSynced() {
1209
        return syncLayers;
1210
    }
1211 144 cmartinez
1212 761 jjdelcerro
    @Override
1213
    public void setLayerSynced(boolean synced) {
1214 219 cmartinez
        syncLayers = synced;
1215 760 jjdelcerro
        resetAllListeners();
1216 761 jjdelcerro
    }
1217 219 cmartinez
1218 761 jjdelcerro
    @Override
1219
    public boolean getExtentSynced() {
1220
        return syncExtents;
1221
    }
1222 219 cmartinez
1223 761 jjdelcerro
    @Override
1224
    public void setExtentSynced(boolean synced) {
1225
        syncExtents = synced;
1226 760 jjdelcerro
        resetAllListeners();
1227 761 jjdelcerro
    }
1228 383 fdiaz
1229 761 jjdelcerro
    /**
1230
     * Returns true if the newEnvelope represents a pan operation on
1231
     * oldEnvelope, (both extents have the same height and width)
1232
     *
1233
     * @param oldEnvelope
1234
     * @param newEnvelope
1235
     * @return
1236
     */
1237
    public static boolean isPan(Envelope oldEnvelope, Envelope newEnvelope) {
1238
        if (oldEnvelope != null && newEnvelope != null) {
1239
            double toleranceX = 0.00000001 * Math.min(
1240
                    oldEnvelope.getLength(0), newEnvelope.getLength(0)
1241
            );
1242
            double toleranceY = 0.00000001 * Math.min(
1243
                    oldEnvelope.getLength(1), newEnvelope.getLength(1)
1244
            );
1245 383 fdiaz
1246 761 jjdelcerro
            // we consider it to be a pan if both lengths are equal
1247
            // (we use tolerance to avoid direct comparison of double values)
1248
            if (((oldEnvelope.getLength(0) - newEnvelope.getLength(0)) < toleranceX)
1249
                    && ((oldEnvelope.getLength(1) - newEnvelope.getLength(1)) < toleranceY)) {
1250
                return true;
1251
            }
1252
        }
1253
        return false;
1254
    }
1255 383 fdiaz
1256 761 jjdelcerro
    /**
1257
     * Calculates the new extent for the FFrame. It is necessary to avoid scale
1258
     * changes when a pan is triggered from the view, as the different size
1259
     * factors from View/FFrameView introduces scale changes even for pans
1260
     *
1261
     * @return
1262
     */
1263
    protected Envelope calculateNewExtent() {
1264
        Envelope newEnvelope = getView().getMapContext().getViewPort().getEnvelope();
1265
        Envelope oldViewEnvelope = null;
1266
        try {
1267
            if (getView().getMapContext().getViewPort().getEnvelopes().hasPrevious()) {
1268
                Rectangle2D r = getView().getMapContext().getViewPort().getEnvelopes().getPrev();
1269
                oldViewEnvelope = GeometryLocator.getGeometryManager().createEnvelope(
1270
                        r.getMinX(), r.getMinY(), r.getMaxX(), r.getMaxY(), SUBTYPES.GEOM2D
1271
                );
1272
            }
1273
            if (isPan(oldViewEnvelope, newEnvelope)) {
1274
                Envelope envelope = getMapContext().getViewPort().getAdjustedEnvelope();
1275
                double shiftX = newEnvelope.getMinimum(0) - oldViewEnvelope.getMinimum(0);
1276
                double shiftY = newEnvelope.getMinimum(1) - oldViewEnvelope.getMinimum(1);
1277 219 cmartinez
1278 761 jjdelcerro
                double minX = envelope.getMinimum(0) + shiftX;
1279
                double minY = envelope.getMinimum(1) + shiftY;
1280
                double maxX = envelope.getMaximum(0) + shiftX;
1281
                double maxY = envelope.getMaximum(1) + shiftY;
1282 308 cmartinez
1283 761 jjdelcerro
                return GeometryLocator.getGeometryManager().createEnvelope(
1284
                        minX, minY, maxX, maxY, SUBTYPES.GEOM2D
1285
                );
1286 760 jjdelcerro
            }
1287 761 jjdelcerro
        } catch (Exception ex) {
1288 760 jjdelcerro
        }
1289 761 jjdelcerro
        return newEnvelope;
1290
    }
1291
1292
    protected boolean isDrawing() {
1293
        return this.b_drawing;
1294
    }
1295
1296
    protected boolean isUpdating() {
1297
        return this.b_updating;
1298
    }
1299
1300
    protected boolean skipFirstChangeExtent() {
1301
        if (this.b_frameInitialized) {
1302
            return false;
1303 760 jjdelcerro
        }
1304 761 jjdelcerro
        this.b_frameInitialized = true;
1305
        return true;
1306
    }
1307
1308
    protected boolean isSyncLayers() {
1309
        return this.syncLayers;
1310
    }
1311
1312
    protected void beginUpdate() {
1313
        this.b_updating = true;
1314
    }
1315
1316
    protected void endUpdate() {
1317
        this.b_updating = false;
1318
    }
1319
1320 760 jjdelcerro
    @Override
1321 761 jjdelcerro
    public SCALE_TYPE getScaleType() {
1322
        return this.scaleType;
1323
    }
1324 144 cmartinez
1325 761 jjdelcerro
    public Double getFixedScale() {
1326
        return this.fixedScale;
1327
    }
1328
1329
    public Envelope getFixedExtent() {
1330
        return this.fixedExtent;
1331
    }
1332
1333 762 jjdelcerro
    public void setExtent(Envelope extent) {
1334
        if (getScaleType() == SCALE_TYPE.NORMAL) {
1335
            getMapContext().getViewPort().setEnvelope(extent);
1336
        }
1337
    }
1338
1339
    @Override
1340
    public void setScaleType(SCALE_TYPE scaleType) {
1341
        this.scaleType = scaleType;
1342
    }
1343
1344
    public void setScaleType(SCALE_TYPE scaleType, double fixedScale) {
1345
        if (scaleType == SCALE_TYPE.FIXED_SCALE) {
1346
            this.scaleType = scaleType;
1347
            this.fixedScale = fixedScale;
1348
            setScale(fixedScale);
1349
        }
1350
    }
1351
1352
    public void setScaleType(SCALE_TYPE scaleType, Envelope fixedExtent) {
1353
        if (scaleType == SCALE_TYPE.FIXED_EXTENT) {
1354
            this.scaleType = scaleType;
1355
            this.fixedExtent = fixedExtent;
1356
            setNewEnvelope(fixedExtent);
1357
        }
1358
    }
1359
1360
    @Deprecated
1361
    @Override
1362
    public int getTypeScale() {
1363
        return AUTOMATICO;
1364
    }
1365
1366
    @Deprecated
1367
    @Override
1368
    public void setLinked(boolean b) {
1369
    }
1370
1371
    @Deprecated
1372
    @Override
1373
    public boolean getLinked() {
1374
        return false;
1375
    }
1376
1377
    @Override
1378
    public void windowActivated() {
1379
        if (isSelected()
1380
                && getLayoutContext().getSelectedFFrames(IFFrameUseFMap.class).length == 1) {
1381
            // update the scale control whenever the panel window gets activated,
1382
            // as the control instance is shared for all the windows
1383
            updateScaleCtrl();
1384
        }
1385
1386
    }
1387
1388
    @Override
1389
    public void windowClosed() {
1390
    }
1391
1392
1393 761 jjdelcerro
    private class ViewDocListener
1394
            implements ViewPortListener, LegendListener, LayerCollectionListener, AtomicEventListener {
1395
1396 760 jjdelcerro
        public ViewDocListener(FFrameView fview) {
1397 142 cmartinez
1398 760 jjdelcerro
        }
1399 761 jjdelcerro
1400
        @Override
1401
        public void extentChanged(ExtentEvent e) {
1402
            if (isUpdating()) {
1403
                return;
1404
            }
1405
            if (skipFirstChangeExtent()) {
1406
                return;
1407
            }
1408
            if (!getExtentSynced()) {
1409
                return;
1410
            }
1411 760 jjdelcerro
//                logger.info("viewdoc-mapcontext.extentChanged " + this.getID());
1412 761 jjdelcerro
            try {
1413
                beginUpdate();
1414
                if (getMapContext() != null) {
1415
                    if (null == getScaleType()) {
1416
                        getMapContext().getViewPort().setEnvelope(calculateNewExtent());
1417
                    } else {
1418
                        switch (getScaleType()) {
1419 760 jjdelcerro
                            case FIXED_EXTENT:
1420
                                getView().getMapContext().getViewPort().setEnvelope(getFixedExtent());
1421
                                break;
1422
                            case FIXED_SCALE:
1423
                                getMapContext().setScaleView(Math.round(getFixedScale()));
1424
                                getView().getMapContext().getViewPort().setEnvelope(getMapContext().getViewPort().getAdjustedEnvelope());
1425
                                break;
1426
                            default:
1427
                                getMapContext().getViewPort().setEnvelope(calculateNewExtent());
1428
                                break;
1429
                        }
1430
                    }
1431 761 jjdelcerro
                    updateScaleCtrl();
1432
                    invalidateLayout();
1433
                }
1434
            } finally {
1435
                endUpdate();
1436
            }
1437
        }
1438
1439
        @Override
1440
        public void backColorChanged(ColorEvent e) {
1441
            if (!isUpdating() && isSyncLayers()) {
1442
                if (getMapContext() != null) {
1443
                    beginUpdate();
1444
                    getMapContext().getViewPort().setBackColor(e.getNewColor());
1445
                    invalidateLayout();
1446 760 jjdelcerro
                    endUpdate();
1447
                }
1448
            }
1449 761 jjdelcerro
        }
1450 760 jjdelcerro
1451 761 jjdelcerro
        @Override
1452
        public void projectionChanged(ProjectionEvent e) {
1453
            if (!isUpdating() && getExtentSynced()) {
1454
                if (getMapContext() != null) {
1455
                    beginUpdate();
1456
                    getMapContext().getViewPort().setProjection(e.getNewProjection());
1457
                    invalidateLayout();
1458
                    // FIXME: force also a view redraw someway??
1459
                    endUpdate();
1460
                }
1461
            }
1462
        }
1463 142 cmartinez
1464 761 jjdelcerro
        public void conditionalRedraw() {
1465
            if (!isUpdating() && isSyncLayers()) {
1466
                beginUpdate();
1467
                invalidateLayout();
1468
                // the view should also receive the event and update automatically
1469
                endUpdate();
1470
            }
1471
        }
1472 142 cmartinez
1473 761 jjdelcerro
        @Override
1474
        public void legendChanged(LegendChangedEvent e) {
1475
            conditionalRedraw();
1476
            refreshToc();
1477
        }
1478 142 cmartinez
1479 761 jjdelcerro
        @Override
1480
        public void layerAdded(LayerCollectionEvent e) {
1481
            conditionalRedraw();
1482
            // no need to invalidate the toc as it is down by the OwnMapContextListener
1483
        }
1484 142 cmartinez
1485 761 jjdelcerro
        @Override
1486
        public void layerMoved(LayerPositionEvent e) {
1487
            conditionalRedraw();
1488
            // no need to invalidate the toc as it is down by the OwnMapContextListener
1489
        }
1490 142 cmartinez
1491 761 jjdelcerro
        @Override
1492
        public void layerRemoved(LayerCollectionEvent e) {
1493
            conditionalRedraw();
1494
            // no need to invalidate the toc as it is down by the OwnMapContextListener
1495
        }
1496 142 cmartinez
1497 761 jjdelcerro
        @Override
1498
        public void layerAdding(LayerCollectionEvent e)
1499
                throws CancelationException {
1500
            // nothing needed
1501
        }
1502 142 cmartinez
1503 761 jjdelcerro
        @Override
1504
        public void layerMoving(LayerPositionEvent e)
1505
                throws CancelationException {
1506
            // nothing needed
1507
        }
1508 142 cmartinez
1509 761 jjdelcerro
        @Override
1510
        public void layerRemoving(LayerCollectionEvent e)
1511
                throws CancelationException {
1512
            // nothing needed
1513
        }
1514 142 cmartinez
1515 761 jjdelcerro
        @Override
1516
        public void visibilityChanged(LayerCollectionEvent e)
1517
                throws CancelationException {
1518
            // AtomicEvent is catching visibility changes instead of this one,
1519
            // as this event is not being received. Maybe is only triggered if the
1520
            // visibility of the whole group changes??
1521
            conditionalRedraw();
1522
            invalidateToc();
1523
        }
1524 142 cmartinez
1525 761 jjdelcerro
        @Override
1526
        public void atomicEvent(AtomicEvent e) {
1527
            boolean layoutRedraw = false;
1528
            // not all the events require a fframeview redraw
1529
            for (int i = e.getLayerEvents().length - 1; i >= 0; i--) {
1530
                FMapEvent at = e.getEvent(i);
1531
                if (at instanceof LayerEvent) {
1532
                    if (at.getEventType() == LayerEvent.DRAW_VALUES_CHANGED) {
1533
                        layoutRedraw = true;
1534
                        break;
1535
                    }
1536
                }
1537
            }
1538
            if (layoutRedraw) {
1539
                conditionalRedraw();
1540
            }
1541
            invalidateToc();
1542
        }
1543
    }
1544 146 cmartinez
1545 761 jjdelcerro
    private class OwnMapContextListener
1546 760 jjdelcerro
            implements ViewPortListener, LegendListener, LayerCollectionListener {
1547 144 cmartinez
1548 760 jjdelcerro
        public OwnMapContextListener(FFrameView fview) {
1549 142 cmartinez
1550 760 jjdelcerro
        }
1551 761 jjdelcerro
1552 760 jjdelcerro
        @Override
1553
        public void extentChanged(ExtentEvent e) {
1554 761 jjdelcerro
            if (isDrawing()) {
1555 760 jjdelcerro
                return;
1556
            }
1557 761 jjdelcerro
            if (isUpdating()) {
1558 760 jjdelcerro
                return;
1559
            }
1560
            try {
1561
//                logger.info("layout-mapcontext.extentChanged "+this.getID());
1562
                beginUpdate();
1563
                if (getScaleType() == SCALE_TYPE.FIXED_EXTENT) {
1564
                    getMapContext().getViewPort().setEnvelope(getFixedExtent());
1565
                } else {
1566
                    Envelope newEnvelope;
1567
                    if (getScaleType() == SCALE_TYPE.FIXED_SCALE && getFixedScale() != null) {
1568
                        getMapContext().setScaleView(Math.round(getFixedScale()));
1569
                        newEnvelope = getMapContext().getViewPort().getAdjustedEnvelope();
1570
                    } else {
1571
                        newEnvelope = e.getNewExtent();
1572
                    }
1573
                    if (getView() != null) {
1574
                        if (getExtentSynced()) {
1575
                            getView().getMapContext().getViewPort().setEnvelope(newEnvelope);
1576
                        }
1577
                    }
1578
                }
1579
                updateScaleCtrl();
1580
                invalidateLayout();
1581
            } finally {
1582
                endUpdate();
1583
            }
1584
        }
1585 142 cmartinez
1586 760 jjdelcerro
        @Override
1587
        public void backColorChanged(ColorEvent e) {
1588
            if (!isUpdating()) {
1589
                if (getView() != null) {
1590
                    try {
1591
                        beginUpdate();
1592
                        if (getLayerSynced()) {
1593
                            getView().getMapContext().getViewPort().setBackColor(e.getNewColor());
1594
                        }
1595
                        invalidateLayout();
1596
                    } finally {
1597
                        endUpdate();
1598
                    }
1599
                }
1600
            }
1601
        }
1602 142 cmartinez
1603 760 jjdelcerro
        @Override
1604
        public void projectionChanged(ProjectionEvent e) {
1605
            if (!isUpdating() && getExtentSynced()) {
1606
                if (getView() != null) {
1607
                    try {
1608
                        beginUpdate();
1609
                        if (getLayerSynced()) {
1610
                            getView().getMapContext().getViewPort().setProjection(e.getNewProjection());
1611
                        }
1612
                        invalidateLayout();
1613
                        // FIXME: force also a view redraw someway??
1614
                    } finally {
1615
                        endUpdate();
1616
                    }
1617
                }
1618
            }
1619
        }
1620 144 cmartinez
1621 760 jjdelcerro
        public void conditionalRedraw() {
1622
            if (!isUpdating()) {
1623
                try {
1624
                    beginUpdate();
1625
                    invalidateLayout();
1626
                    // the view should also receive the event and update automatically
1627
                } finally {
1628
                    endUpdate();
1629
                }
1630
            }
1631
        }
1632 142 cmartinez
1633 760 jjdelcerro
        @Override
1634
        public void legendChanged(final LegendChangedEvent e) {
1635
            conditionalRedraw();
1636
            refreshToc();
1637
        }
1638 383 fdiaz
1639 760 jjdelcerro
        @Override
1640
        public void layerAdded(final LayerCollectionEvent e) {
1641
            // necessary to set an envelope when the first layer is added
1642
            if (!isUpdating() && getMapContext().getViewPort().getEnvelope() == null) {
1643
                try {
1644
                    beginUpdate();
1645
                    fullExtent();
1646 144 cmartinez
1647 760 jjdelcerro
                } catch (ReadException e1) {
1648
                } finally {
1649
                    endUpdate();
1650
                }
1651
            }
1652
            conditionalRedraw();
1653
            refreshToc();
1654
        }
1655 144 cmartinez
1656 760 jjdelcerro
        @Override
1657
        public void layerMoved(final LayerPositionEvent e) {
1658
            conditionalRedraw();
1659
            refreshToc();
1660
        }
1661 142 cmartinez
1662 760 jjdelcerro
        @Override
1663
        public void layerRemoved(final LayerCollectionEvent e) {
1664
            conditionalRedraw();
1665
            refreshToc();
1666
        }
1667 144 cmartinez
1668 760 jjdelcerro
        @Override
1669
        public void layerAdding(LayerCollectionEvent e)
1670
                throws CancelationException {
1671
            // nothing neededO
1672 142 cmartinez
1673 760 jjdelcerro
        }
1674 144 cmartinez
1675 760 jjdelcerro
        @Override
1676
        public void layerMoving(LayerPositionEvent e)
1677
                throws CancelationException {
1678
            // nothing needed
1679 142 cmartinez
1680 760 jjdelcerro
        }
1681 144 cmartinez
1682 760 jjdelcerro
        @Override
1683
        public void layerRemoving(LayerCollectionEvent e)
1684
                throws CancelationException {
1685
            // nothing needed
1686 142 cmartinez
1687 760 jjdelcerro
        }
1688 250 cmartinez
1689 760 jjdelcerro
        @Override
1690
        public void visibilityChanged(LayerCollectionEvent e)
1691
                throws CancelationException {
1692
            conditionalRedraw();
1693
        }
1694
    }
1695
1696 5 jldominguez
}