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

History | View | Annotate | Download (55.4 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,
109
                IFFrameUseFMap, LayoutPanelListener{
110

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

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

    
132
    private static final Logger logger = LoggerFactory
133
        .getLogger(FFrameView.class);
134
    public static final int PRESENTATION = 0;
135
    public static final int DRAFT = 1;
136

    
137
    protected boolean syncLayers = true;
138
    protected boolean syncExtents = true;
139
    protected int quality = PRESENTATION;
140
    protected ViewDocument viewDocument = null;
141
    protected MapContext mapContext = null;
142
    protected int mapUnits = 1; // Meters.
143

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

    
154
        private boolean b_updating = false;
155
        protected boolean b_validCache = false;
156
        protected boolean b_drawing = false;
157
        protected ViewDocListener viewDocListener;
158
        protected OwnMapContextListener ownMapContextListener;
159
        private boolean b_hasToc = true;
160
    protected static final GeometryManager geomManager = GeometryLocator.getGeometryManager();
161

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

    
169
        protected AffineTransform originalGraphicsAT = null;
170
        protected Rectangle originalClip = null;
171

    
172
        private SCALE_TYPE scaleType = SCALE_TYPE.NORMAL;
173
        private Double fixedScale = null;
174
        private Envelope fixedExtent = null;
175

    
176

    
177
    /**
178
     * Creates a new FFrameView object.
179
     */
180
    public FFrameView() {
181
        num++;
182
//        logger.info("Create FFrameView "+ Integer.toHexString(this.hashCode()));
183
        createListeners();
184
    }
185

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

    
196
        return "FFrameView " + num + ": " + getView().getName();
197
    }
198

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

    
210
    /**
211
     * Sets a new Envelope on the MapContext contained in
212
     * this FFrameView
213
     *
214
     * @param r Envelope to be set
215
     */
216
    public void setNewEnvelope(Envelope r) {
217
            getMapContext().getViewPort().setEnvelope(r);
218
            updateScaleCtrl();
219
    }
220

    
221
    /**
222
     * Calculates the resolution (measured on dots per inch, DPI) to be
223
     * considered to draw the FFrameView on screen. It is calculated by
224
     * dividing the width (in pixels) of the FFrame divided by the width
225
     * in inches of the paper.
226
     */
227
    protected double getDrawPaperDPI() {
228
            AffineTransform at = null;
229
            if (getLayoutContext()!=null) {
230
                    at = getLayoutContext().getAT();
231
            }
232
            return (2.54*getBoundingBox(at).width)/getBoundBox().width;
233
    }
234

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

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

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

    
273
    /**
274
     * Sets the MapContext associated with this FFrameView, which will
275
     * be used to clone the layers and synchronize the FFrameView with
276
     * the associated View
277
     *
278
     * @param viewMapContext
279
     */
280
    public void setViewMapContext(MapContext viewMapContext) {
281
            Envelope oldEnvelope = null;
282
            if (mapContext!=null) {
283
                    removeOwnListeners();
284
                    if (mapContext.getViewPort()!=null) {
285
                            oldEnvelope = mapContext.getViewPort().getEnvelope();
286
                    }
287
            }
288
            if (viewMapContext==null) { // disconnect the view from the map
289
                    this.mapContext=null;
290
                    return;
291
            }
292
            try {
293
                    if (syncLayers){
294
                            mapContext =
295
                                            viewMapContext.createNewFMap(
296
                                                            (ViewPort) viewMapContext.getViewPort().clone());
297
                    }
298
                    else {
299
                            mapContext = viewMapContext.cloneFMap();
300
                            mapContext.setViewPort((ViewPort) viewMapContext
301
                                            .getViewPort().clone());
302
                    }
303
                    ViewPort newViewPort = getMapContext().getViewPort();
304
                    if (!syncExtents && oldEnvelope!=null) {
305
                            // if extent is not synced with the view, restore the previous
306
                            // envelope if existing
307
                            newViewPort.setEnvelope(oldEnvelope);
308
                    }
309
                    AffineTransform at;
310
                    if (getLayoutContext()!=null) {
311
                            at = getLayoutContext().getAT();
312
                    }
313
                    else {
314
                            at = null;
315
                    }
316
                    newViewPort.setImageSize(new Dimension((int) getBoundingBox(at).width,
317
                                    (int) getBoundingBox(at).height));
318
                    newViewPort.setDPI(getDrawPaperDPI());
319
                    addAllListeners();
320
                    updateScaleCtrl();
321
                    setTocModel();
322
            } catch (CloneNotSupportedException e1) {
323
                    NotificationManager.addError("Excepci?n :", e1);
324
            }
325

    
326
    }
327

    
328
    /**
329
     * Sets the View associated with this FFrameView, which will
330
     * be used to clone the MapContext and the layers. It will
331
     * also used to synchronize the FFrameView with
332
     * the associated View, depending on the selected scale type
333
     *
334
     * @param dvd
335
     */
336
    public void setView(ViewDocument dvd) {
337
            removeViewListeners();
338
        viewDocument = dvd;
339
        if (dvd!=null) {
340
            setViewMapContext(dvd.getMapContext());
341
        } else {
342
            setViewMapContext(null);
343
        }
344
    }
345

    
346
    /**
347
     * Gets the associated View
348
     *
349
     * @return The associated view
350
     * @see {@link #setView(ViewDocument)}
351
     */
352
    public ViewDocument getView() {
353
        return viewDocument;
354
    }
355

    
356
    /**
357
     * Draws the FFrameView on the provided Graphics, according to the
358
     * provided affine transform and the visible rectangle.
359
     *
360
     * @param g Graphics2D
361
     * @param at Affine transform to translate sheet coordinates (in cm)
362
     *                                 to screen coordinates (in pixels)
363
     * @param visibleLayoutDocRect visible rectangle
364
     * @param imgBase Image used to speed up the drawing process
365
     */
366
    public void draw(Graphics2D g, AffineTransform at, Rectangle2D visibleLayoutDocRect, BufferedImage imgBase) {
367
        Rectangle2D.Double fframeViewRect = getBoundingBox(at);
368
        Rectangle2D.Double visibleArea = (Rectangle2D.Double) getVisibleRect(visibleLayoutDocRect, fframeViewRect);
369
        if (visibleArea==null) {
370
                return;
371
        }
372
        preDraw(g, fframeViewRect, visibleArea);
373
        if (getMapContext() == null) {
374
                drawEmpty(g);
375
        } else {
376
                if (FLayoutUtilities.hasEditingLayers(getView())) {
377

    
378
                        /*
379
                         * We are not drawing if any layer is in editing mode
380
                         */
381
                        drawMessage(g, Messages.getText(
382
                                        "_Cannot_draw_view_if_layers_in_editing_mode"));
383

    
384
                } else {
385
                        if (getQuality() == PRESENTATION) {
386
                                try {
387
                                        drawPresentation(g, at, fframeViewRect, visibleArea, imgBase);
388
                                } catch (Exception exc) {
389
                                        drawMessage(g, FLayoutFunctions.getLastMessage(exc));
390
                                }
391

    
392
                        } else {
393
                                drawDraft(g);
394
                        }
395
                }
396
        }
397
        postDraw(g, fframeViewRect, at);
398
        if (showGrid && grid != null) {
399
            grid.draw(g, at, visibleLayoutDocRect, imgBase);
400
        }
401
    }
402

    
403
    private void drawMessage(Graphics2D g, String msg) {
404

    
405
        Rectangle2D r = getBoundingBox(null);
406
        g.setColor(Color.lightGray);
407
        g.fillRect((int) r.getX(), (int) r.getY(), (int) r.getWidth(),
408
            (int) r.getHeight());
409
        g.setColor(Color.darkGray);
410
        g.setStroke(new BasicStroke(2));
411
        g.drawRect((int) r.getX(), (int) r.getY(), (int) r.getWidth(),
412
            (int) r.getHeight());
413
        g.setColor(Color.black);
414

    
415
        int scale = (int) (r.getWidth() / 24);
416
        Font f = new Font("SansSerif", Font.PLAIN, scale);
417
        g.setFont(f);
418
        if (msg==null) {
419
                msg = Messages.getText("error");
420
        }
421
        g.drawString(msg, (int) (r.getCenterX() - ((msg.length() * scale) / 4)),
422
                        (int) (r.getCenterY()));
423
    }
424

    
425
    /**
426
     * Gets the visible envelope, in map coordinates
427
     *
428
     * @param fframeViewRect Rectangle defining the bounding box of the
429
     * FFrameView, in screen coordinates
430
     * @param visiblefframeViewRect Rectangle defining the bounding box
431
     * of the visible area of the fframeView, in screen coordinates
432
     * @return
433
     */
434
    protected Envelope getVisibleEnvelope(Rectangle2D.Double fframeViewRect,
435
            Rectangle2D.Double visiblefframeViewRect) {
436
            Envelope oldEnv = getMapContext().getViewPort().getAdjustedEnvelope();
437
            double widthFactor = ((int)visiblefframeViewRect.width) / fframeViewRect.width;
438
            double heightFactor = ((int)visiblefframeViewRect.height) / fframeViewRect.height;
439

    
440
            double newWidth = oldEnv.getLength(0)*widthFactor;
441
            double newHeight = oldEnv.getLength(1)*heightFactor;
442

    
443
        double translateX = visiblefframeViewRect.x - fframeViewRect.x;
444
        double translateY = visiblefframeViewRect.y - fframeViewRect.y;
445
        double translateFactorX = translateX / fframeViewRect.width;
446
        double translateFactorY = translateY / fframeViewRect.height;
447

    
448
        double newX = oldEnv.getMinimum(0) + translateFactorX*oldEnv.getLength(0);
449
        double newMaxY =  oldEnv.getMaximum(1) - translateFactorY*oldEnv.getLength(1);
450
        double newMaxX = newX + newWidth;
451
        double newY = newMaxY - newHeight;
452

    
453
        Envelope newEnv = null;
454
                try {
455
                        newEnv = geomManager.createEnvelope(newX, newY, newMaxX, newMaxY, SUBTYPES.GEOM2D);
456
                } catch (CreateEnvelopeException e) {
457
                        logger.error("Error calculating visible extent", e);
458
                }
459
        return newEnv;
460

    
461
    }
462

    
463
    protected void drawPresentation(
464
        Graphics2D g,
465
        AffineTransform affineTransform,
466
        Rectangle2D.Double fframeViewRect,
467
        Rectangle2D.Double visibleRect,
468
        BufferedImage imgBase) throws Exception {
469

    
470
            b_drawing = true;
471
            int drawWidth = (int)visibleRect.width;
472
            int drawHeight = (int)visibleRect.height;
473

    
474
            Envelope oldEnvelope = null;
475
        if (!visibleRect.equals(fframeViewRect)) {
476
                // if visible area is smaller than the fframe, we will only draw this area,
477
                // so we need to tell the ViewPort the image size and extent for drawing,
478
                // and restore the real extent after drawing
479
            oldEnvelope = getMapContext().getViewPort().getEnvelope();
480
            if (oldEnvelope==null) {
481
                    return;
482
            }
483

    
484
                Envelope newEnvelope = getVisibleEnvelope(fframeViewRect, visibleRect);
485
                // image size must be set before the envelope, as it has influence on the adjustedExtent
486
                getMapContext().getViewPort().setImageSize(new Dimension(drawWidth, drawHeight));
487
                getMapContext().getViewPort().setEnvelope(newEnvelope);
488
        }
489
        else {
490
                getMapContext().getViewPort().setImageSize(new Dimension(drawWidth, drawHeight));
491
                getMapContext().getViewPort().refreshExtent();
492
        }
493

    
494
        // map origin should be calculated using the full fframeview, as the visible position will be relative
495
        Point mapOrigin = new Point((int)fframeViewRect.getMinX(), (int)fframeViewRect.getMaxY());
496

    
497
        // paint the MapContext on m_image, if not already cached
498
        createImage(affineTransform, drawWidth, drawHeight, mapOrigin);
499

    
500
        //Draw the created image
501
        drawImage(g, m_image, visibleRect);
502

    
503
        if (oldEnvelope!=null) {
504
                // restore real envelope and image size
505
                getMapContext().getViewPort().setImageSize(new Dimension((int)fframeViewRect.width, (int) fframeViewRect.height));
506
                getMapContext().getViewPort().setEnvelope(oldEnvelope);
507
        }
508

    
509
        scaleAnt = affineTransform.getScaleX();
510
        origin = mapOrigin;
511
        b_drawing = false;
512
    }
513

    
514
    protected void createImage(AffineTransform affineTransform,
515
                    int width, int height, Point mapOrigin) throws ReadException, MapContextException {
516
            ViewPort viewPort = this.getMapContext().getViewPort();
517

    
518
        //If the image has to be created...
519
            if (origin == null ||
520
                            !origin.equals(mapOrigin) ||
521
                            affineTransform.getScaleX() != scaleAnt ||
522
                            m_image == null ||
523
                            !b_validCache) {
524

    
525
                    viewPort.setDPI(getDrawPaperDPI());
526
                viewPort.setImageSize(new Dimension(width, height));
527

    
528
            m_image =
529
                    new BufferedImage(
530
                                    width,
531
                                    height,
532
                                    BufferedImage.TYPE_INT_ARGB);
533

    
534
            Graphics2D gimg = (Graphics2D) m_image.createGraphics();
535
            getMapContext().draw(m_image, gimg, getScale());
536
            gimg.dispose();
537
            b_validCache = true;
538
        }
539

    
540
    }
541

    
542
    protected void drawImage(Graphics2D g, BufferedImage image,
543
                    Rectangle2D.Double visibleRectangle) {
544

    
545
            Color theBackColor = getMapContext().getViewPort().getBackColor();
546
        if (theBackColor != null) {
547
            g.setColor(theBackColor);
548
            g.fillRect((int) visibleRectangle.x, (int) visibleRectangle.y,
549
                            (int)visibleRectangle.width,
550
                            (int)visibleRectangle.height);
551
        }
552
        g.drawImage(m_image,
553
                        (int) visibleRectangle.x,
554
                        (int) visibleRectangle.y,
555
                        null);
556
    }
557

    
558
    protected void preDraw(Graphics2D g, Rectangle2D.Double fframeViewRect, Rectangle2D.Double visibleRect){
559
            originalGraphicsAT = (AffineTransform) g.getTransform().clone();
560

    
561
        if (g.getClipBounds() != null) {
562
            originalClip = (Rectangle) g.getClipBounds().clone();
563
        }
564
        AffineTransform rotationAT = getRotationAT();
565
        if (rotationAT!=null) {
566
                g.transform(rotationAT);
567
        }
568
        g.setClip((int) visibleRect.getMinX(), (int) visibleRect.getMinY(),
569
            (int) visibleRect.getWidth(), (int) visibleRect.getHeight());
570
    }
571

    
572
    protected void postDraw(Graphics2D g, Rectangle2D.Double fframeViewRect, AffineTransform at){
573
            g.setTransform(originalGraphicsAT);
574
        if (getMapContext() != null) {
575
            setATMap(getMapContext().getViewPort().getAffineTransform());
576
        }
577
        if (originalClip != null) {
578
            g.setClip(originalClip.x, originalClip.y, originalClip.width, originalClip.height);
579
        }
580
    }
581

    
582

    
583
    /**
584
     * @deprecated Use {@link #postDraw(Graphics2D, java.awt.geom.Rectangle2D.Double, AffineTransform)} instead.
585
     */
586
    @Deprecated
587
    protected void postDraw(Graphics2D g, Rectangle2D.Double rectangleLayout, Rectangle2D rectangleView, BufferedImage imgBase, Rectangle originalClip, AffineTransform at) {
588
            postDraw(g, rectangleLayout, at);
589

    
590
    }
591

    
592
    /**
593
     * @deprecated Use {@link #preDraw(Graphics2D, java.awt.geom.Rectangle2D.Double, java.awt.geom.Rectangle2D.Double) instead
594
     */
595
    @Deprecated
596
    protected Rectangle preDraw(Graphics2D g, Rectangle2D.Double rectangleLayout){
597
            Rectangle originalClip = null;
598
        if (g.getClipBounds() != null) {
599
            originalClip = (Rectangle) g.getClipBounds().clone();
600
        }
601
            preDraw(g, rectangleLayout, rectangleLayout);
602
            return originalClip;
603
    }
604

    
605
    public void print(Graphics2D g, AffineTransform at, Geometry geom,
606
        PrintAttributes printAttributes) {
607
        Rectangle2D.Double rectangleLayout = getBoundingBox(at);
608

    
609
        preDraw(g, rectangleLayout, rectangleLayout);
610
        print(g, at, printAttributes);
611
        postDraw(g, rectangleLayout, at);
612
        if (showGrid && grid != null) {
613
            grid.print(g, at, geom, printAttributes);
614
        }
615
    }
616

    
617
    protected void print(Graphics2D g, AffineTransform at, PrintAttributes printAttributes) {
618
        Rectangle2D.Double layoutRectangle = getBoundingBox(at);
619

    
620
        // FIXME: should we clone the mapcontext and viewport before printing ??
621
        // otherwise we will probably have unexpected results if the user modifies
622
        // the layout while printing (answer: not an issue at the moment as printing is
623
        // a blocking operation)
624
        ViewPort viewPort = this.getMapContext().getViewPort();
625

    
626
        Point2D old_offset = viewPort.getOffset();
627
        Dimension old_imgsize = viewPort.getImageSize();
628
        double oldDpi = viewPort.getDPI();
629

    
630
        viewPort.setOffset(new Point2D.Double(layoutRectangle.x, layoutRectangle.y));
631
        viewPort.setImageSize(new Dimension((int) layoutRectangle.width, (int) layoutRectangle.height));
632
        double dpi = PrintAttributes.PRINT_QUALITY_DPI[printAttributes.getPrintQuality()];
633
        viewPort.setDPI(dpi);
634

    
635
        //Draw the backgroung color of the map
636
        Color theBackColor = viewPort.getBackColor();
637
        if (theBackColor != null) {
638
            g.setColor(theBackColor);
639
            g.fillRect((int) layoutRectangle.x, (int) layoutRectangle.y, viewPort
640
                    .getImageWidth(), viewPort
641
                    .getImageHeight());
642
        }
643

    
644
        //Print the map
645
        try {
646
            this.getMapContext().print(g, getScale(), printAttributes);
647
        } catch (ReadException e) {
648
            NotificationManager.addError(e.getMessage(), e);
649
        } catch (MapContextException e) {
650
            NotificationManager.addError(e.getMessage(), e);
651
        }
652

    
653
        // Restore offset, imgsize
654
        viewPort.setOffset(old_offset);
655
        viewPort.setImageSize(old_imgsize);
656
        viewPort.setDPI(oldDpi);
657

    
658
    }
659

    
660
    /**
661
     * Rellena la unidad de medida en la que est? la vista.
662
     *
663
     * @param i
664
     *            entero que representa la unidad de medida de la vista.
665
     */
666
    public void setMapUnits(int i) {
667
        mapUnits = i;
668
    }
669

    
670
    /**
671
     * Obtiene la unidad de medida en la que est? la vista.
672
     *
673
     * @return Unidad de medida.
674
     */
675
    public int getMapUnits() {
676
        return mapUnits;
677
    }
678

    
679
    /**
680
     * Devuelve la escala seg?n el tipo de escala que se haya seleccionado al
681
     * a?adida la vista.
682
     *
683
     * @return escala.
684
     */
685
    public long getScale() {
686
            return (long) getMapContext().getScaleView();
687
    }
688

    
689
    /**
690
     * Inserta la imagen para repintar el FFrameView.
691
     *
692
     * @param bi
693
     *            Imagen para repintar.
694
     */
695
    public void setBufferedImage(BufferedImage bi) {
696
        m_image = bi;
697
    }
698

    
699
    /**
700
     * Devuelve la imagen para repintar.
701
     *
702
     * @return Imagen para repintar.
703
     */
704
    public BufferedImage getBufferedImage() {
705
        return m_image;
706
    }
707

    
708
    /**
709
     * Devuelve la MAtriz de transformaci?n utilizada por la FFrameView.
710
     *
711
     * @return MAtriz de transformaci?n.
712
     */
713
    public AffineTransform getATMap() {
714
        return mapAT;
715
    }
716

    
717
    /**
718
     * Inserta la matriz de transformaci?n.
719
     *
720
     * @param transform
721
     *            Matriz de transformaci?n.
722
     */
723
    public void setATMap(AffineTransform transform) {
724
        mapAT = transform;
725
    }
726

    
727
    /**
728
     * Inserta el proyecto.
729
     *
730
     * @param p
731
     *            Proyecto.
732
     */
733
    public void setProject(Project p) {
734
        project = p;
735
    }
736

    
737
    /**
738
     * @see org.gvsig.app.project.documents.layout.fframes.IFFrame#getNameFFrame()
739
     */
740
    public String getNameFFrame() {
741
        return PluginServices.getText(this, "Vista") + num;
742
    }
743

    
744
    public String getName() {
745
        return PERSISTENCE_DEFINITION_NAME;
746
    }
747

    
748
    /**
749
     * DOCUMENT ME!
750
     *
751
     * @param arg0
752
     *            DOCUMENT ME!
753
     *
754
     * @return DOCUMENT ME!
755
     */
756
    public boolean compare(Object arg0) {
757
        if (!(arg0 instanceof FFrameView)) {
758
            return false;
759
        }
760

    
761
        if (!this.getName().equals(((FFrameView) arg0).getName())) {
762
            return false;
763
        }
764

    
765
        if (Math.abs(this.getBoundBox().getWidth()
766
            - (((FFrameView) arg0).getBoundBox().getWidth())) > 0.05) {
767
            return false;
768
        }
769
        if (Math.abs(this.getBoundBox().getHeight()
770
            - (((FFrameView) arg0).getBoundBox().getHeight())) > 0.05) {
771
            return false;
772
        }
773

    
774
        if (!this.toString().equals(((FFrameView) arg0).toString())) {
775
            return false;
776
        }
777

    
778
        if (this.getMapContext() != null
779
            && !this.getMapContext()
780
                .equals(((FFrameView) arg0).getMapContext())) {
781
            return false;
782
        }
783

    
784
        if (this.getRotation() != ((FFrameView) arg0).getRotation()) {
785
            return false;
786
        }
787
        return true;
788
    }
789

    
790
    public void updateScaleCtrl() {
791
            NewStatusBar statusbar = PluginServices.getMainFrame().getStatusBar();
792
            MapContext mapContext = this.getMapContext();
793
            if (mapContext==null) {
794
                    return;
795
            }
796
            statusbar.setMessage("units",
797
                            PluginServices.getText(this, mapContext.getDistanceName()));
798
            String scale;
799
            if (fixedScale!=null && getScaleType()==SCALE_TYPE.FIXED_SCALE) {
800
                    // prefer fixedScale as getScaleView() may offer slight differences
801
                    // because the influence of the adjusted envelope
802
                    scale = String.valueOf(fixedScale.longValue());
803
            }
804
            else {
805
                    scale = String.valueOf(getMapContext().getScaleView());
806
            }
807
            statusbar.setControlValue("layout-view-change-scale",
808
                            scale);
809
            IProjection proj = mapContext.getViewPort().getProjection();
810
            if (proj != null) {
811
                    statusbar.setMessage("projection", proj.getAbrev());
812
            } else {
813
                    statusbar.setMessage("projection", "");
814
            }
815
    }
816

    
817
    public void fullExtent() throws ReadException {
818
        setNewEnvelope(getMapContext().getFullEnvelope());
819
    }
820

    
821
    public void setPointsToZoom(Point2D px1, Point2D px2) {
822
        p1 = px1;
823
        p2 = px2;
824
    }
825

    
826
    public void movePoints(Point2D px1, Point2D px2) {
827
        double difX = -px2.getX() + px1.getX();
828
        double difY = -px2.getY() + px1.getY();
829
        if (p1 != null) {
830
            p1.setLocation(p1.getX() + difX, p1.getY() + difY);
831
            p2.setLocation(p2.getX() + difX, p2.getY() + difY);
832
        }
833
    }
834

    
835
    @Override
836
    public FFrameView clone() throws CloneNotSupportedException {
837
//        logger.info("clone FFrameView "+ Integer.toHexString(this.hashCode()));
838
        FFrameView frame = (FFrameView) super.clone();
839
        frame.createListeners(); // necessary to create the listeners within the right scope
840
        frame.setView(this.getView());
841
        frame.removeAllListeners(); // remove listeners add by setView
842
        
843
        if (grid != null) {
844
            FFrameGrid newGrid = (FFrameGrid) this.grid.clone();
845
            newGrid.setFFrameDependence(frame);
846
            frame.setGrid(newGrid);
847
        }
848
//        logger.info("cloned FFrameView "+ Integer.toHexString(frame.hashCode()));
849
        return frame;
850
    }
851

    
852
    public void setGrid(IFFrame grid) {
853
        this.grid = grid;
854
        this.grid.setRotation(this.getRotation());
855
    }
856

    
857
    public IFFrame getGrid() {
858
        return this.grid;
859
    }
860

    
861
    public void setRotation(double rotation) {
862
        super.setRotation(rotation);
863
        if (grid != null) {
864
            grid.setRotation(rotation);
865
        }
866
    }
867

    
868
    public void showGrid(boolean b) {
869
        showGrid = b;
870
    }
871

    
872
    public boolean isShowGrid() {
873
        return showGrid;
874
    }
875

    
876
    public void refreshOriginalExtent() {
877
    }
878

    
879
    public static void registerPersistent() {
880
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
881
        if (manager.getDefinition(PERSISTENCE_DEFINITION_NAME) == null) {
882
            DynStruct definition =
883
                manager.addDefinition(FFrameView.class,
884
                    PERSISTENCE_DEFINITION_NAME,
885
                    "FFrameView persistence definition", null, null);
886
            definition.extend(manager
887
                .getDefinition(FFrame.PERSISTENCE_DEFINITION_NAME));
888
            definition.addDynFieldInt(QUALITY_FIELD).setMandatory(true);
889
            definition.addDynFieldInt(MAPUNITS_FIELD).setMandatory(true);
890
            definition.addDynFieldDouble(SCALE_FIELD).setMandatory(false);
891
            definition.addDynFieldObject(VIEW_FIELD)
892
                .setClassOfValue(ViewDocument.class).setMandatory(false);
893
            definition.addDynFieldObject(ENVELOPE_FIELD)
894
                .setClassOfValue(Envelope.class).setMandatory(false);
895
            definition.addDynFieldBoolean(SHOWGRID_FIELD).setMandatory(true);
896
            definition.addDynFieldObject(GRID_FIELD)
897
                .setClassOfValue(IFFrame.class).setMandatory(false);
898
            definition.addDynFieldBoolean(HAS_TOC_FIELD).setMandatory(false);
899
            definition.addDynFieldBoolean(EXTENT_SYNC_FIELD).setMandatory(false);
900
            definition.addDynFieldBoolean(LAYER_SYNC_FIELD).setMandatory(false);
901
            definition.addDynFieldInt(SCALE_TYPE_FIELD).setMandatory(false);
902
            // unused fields, kept for backward compatibility
903
            definition.addDynFieldInt(MODE_FIELD).setMandatory(false);
904
            definition.addDynFieldInt(TYPESCALE_FIELD).setMandatory(false);
905
            definition.addDynFieldBoolean(BLINKED_FIELD).setMandatory(false);
906
            definition.addDynFieldObject(MAPCONTEXT_FIELD)
907
            .setClassOfValue(MapContext.class).setMandatory(false);
908
            definition.addDynFieldInt(VIEWING_FIELD).setMandatory(false);
909
            definition.addDynFieldInt(EXTENSION_FIELD).setMandatory(false);
910
        }
911
    }
912

    
913
    @Override
914
    public void loadFromState(PersistentState state)
915
        throws PersistenceException {
916
        super.loadFromState(state);
917
        b_frameInitialized = false;
918
        if (state.hasValue(EXTENT_SYNC_FIELD)) {
919
                syncExtents = state.getBoolean(EXTENT_SYNC_FIELD);
920
        }
921
        else {
922
                syncExtents = true;
923
        }
924
        if (state.hasValue(LAYER_SYNC_FIELD)) {
925
                syncLayers = state.getBoolean(LAYER_SYNC_FIELD);
926
        }
927
        else {
928
                syncLayers = true;
929
        }
930
        Double layoutScale = null;
931
        if (state.hasValue(SCALE_FIELD)) {
932
                layoutScale = state.getDouble(SCALE_FIELD);
933
        }
934
            Envelope envelope = (Envelope) state.get(ENVELOPE_FIELD);
935

    
936
        if (state.hasValue(SCALE_TYPE_FIELD)) {
937
                int value = state.getInt(SCALE_TYPE_FIELD);
938
                if (value==SCALE_TYPE.FIXED_EXTENT.ordinal()) {
939
                        scaleType = SCALE_TYPE.FIXED_EXTENT;
940
                        fixedExtent = envelope;
941
                }
942
                else if (value==SCALE_TYPE.FIXED_SCALE.ordinal()) {
943
                        scaleType = SCALE_TYPE.FIXED_SCALE;
944
                        fixedScale = layoutScale;
945
                }
946
                // else use the default value
947
        }
948
        quality = state.getInt(QUALITY_FIELD);
949
        mapUnits = state.getInt(MAPUNITS_FIELD);
950
        if (state.hasValue(HAS_TOC_FIELD)) {
951
                this.b_hasToc = state.getBoolean(HAS_TOC_FIELD);
952
        }
953

    
954
        // When copying and pasting layout documents (in project manager), the view
955
        // is first persisted (copy action) and then re-created from persistence (paste action).
956
        // This is a problem, as the re-created view is not the same view as the original one
957
        // and thus layout stops being synchronized with the right view.
958
        // Therefore, we try to get first the "live" view if available, and get the persisted
959
        // one otherwise, which will be used when opening projects.
960
        ViewDocument persistenceView = (ViewDocument) state.get(VIEW_FIELD);
961
        if (persistenceView!= null) {
962
                ViewDocument view = (ViewDocument) ProjectManager.getInstance().getCurrentProject().getDocument(persistenceView.getName(), persistenceView.getTypeName());
963
                if (view==null) {
964
                        view = persistenceView;
965
                }
966
                this.setView(view);
967
                // it is crucial to don't persist the MapContext and get a cloned one from the View instead,
968
                // as the cloned instance is different from the one created using persistence. In particular,
969
                // the cloned one will share the EventBuffer with the original one, while persistence would
970
                // create 2 separate EventBuffers, which will then have a very stange behaviour
971
        }
972
        if (getMapContext()!=null) {
973
                if (layoutScale!=null) {
974
                        getMapContext().setScaleView(layoutScale.longValue());
975
                }
976
                getMapContext().getViewPort().setEnvelope(envelope);
977
                if (this.getLayoutContext()!=null) {
978
                        this.getLayoutContext().setTocModel(getMapContext());
979
                }
980

    
981
        }
982
        showGrid = state.getBoolean(SHOWGRID_FIELD);
983
        grid = (IFFrame) state.get(GRID_FIELD);
984
    }
985

    
986
    @Override
987
    public void saveToState(PersistentState state) throws PersistenceException {
988
        super.saveToState(state);
989
        state.set(EXTENT_SYNC_FIELD, syncExtents);
990
        state.set(LAYER_SYNC_FIELD, syncLayers);
991
        state.set(QUALITY_FIELD, quality);
992
        state.set(MAPUNITS_FIELD, mapUnits);
993
        state.set(VIEW_FIELD, viewDocument);
994
        state.set(HAS_TOC_FIELD, b_hasToc);
995
        state.set(SCALE_TYPE_FIELD, scaleType.ordinal());
996

    
997
        if (getMapContext() != null
998
            && getMapContext().getViewPort().getEnvelope() != null) {
999
                if (scaleType==SCALE_TYPE.FIXED_SCALE) {
1000
                        if (fixedScale==null) {
1001
                                fixedScale = new Double(getMapContext().getScaleView());
1002
                        }
1003
                        state.set(SCALE_FIELD, (double)fixedScale);
1004
                }
1005
                else {
1006
                        state.set(SCALE_FIELD, (double)getMapContext().getScaleView());
1007
                }
1008
                if (scaleType == SCALE_TYPE.FIXED_EXTENT) {
1009
                        if (fixedExtent==null) {
1010
                                fixedExtent = getMapContext().getViewPort().getAdjustedEnvelope();
1011
                        }
1012
                        state.set(ENVELOPE_FIELD, fixedExtent);
1013
                }
1014
                else {
1015
                        state.set(ENVELOPE_FIELD, getMapContext().getViewPort()
1016
                        .getAdjustedEnvelope());
1017
                }
1018
        }
1019

    
1020
        state.set(SHOWGRID_FIELD, showGrid);
1021
        state.set(GRID_FIELD, grid);
1022
    }
1023

    
1024
    @Override
1025
    public void setBoundBox(Rectangle2D r) {
1026
            super.setBoundBox(r);
1027
            if (this.getMapContext()!=null && this.getLayoutContext()!=null) {
1028
                    AffineTransform at = this.getLayoutContext().getAT();
1029
                    long scale = getMapContext().getScaleView();
1030
                    getMapContext().getViewPort().setImageSize(
1031
                                    new Dimension((int)getBoundingBox(at).getWidth(), (int)getBoundingBox(at).getHeight()));
1032
                    getMapContext().getViewPort().setDPI(getDrawPaperDPI());
1033
                    if (getScaleType()==SCALE_TYPE.FIXED_SCALE) {
1034
                            getMapContext().setScaleView((long) scale);
1035
                    }
1036
                    updateScaleCtrl();
1037
                    refresh();
1038
            }
1039
    }
1040

    
1041
    /**
1042
     * Gets the rotation of the frame
1043
     *
1044
     * @return Rotation in degrees
1045
     */
1046
    public double getMapRotation() {
1047
        return 0;
1048
    }
1049

    
1050
        protected void invalidateLayout() {
1051
                b_validCache = false;
1052
                if (getLayoutContext()!=null) {
1053
                        getLayoutContext().notifAllObservers();
1054
                }
1055
        observers.notifyObservers(this,
1056
                new DefaultLayoutNotification(LayoutNotification.LAYOUT_REFRESH));
1057
        }
1058

    
1059
        protected void invalidateToc() {
1060
                if (getLayoutContext()!=null) {
1061
                        getLayoutContext().notifyTocUpdated(TocModelChangedNotification.Type.ITEM_UPDATED);
1062
                }
1063
        }
1064

    
1065
        protected void refreshToc() {
1066
                if (getLayoutContext()!=null) {
1067
                        getLayoutContext().notifyTocUpdated(TocModelChangedNotification.Type.MODEL_CHANGED);
1068
                }
1069
        }
1070

    
1071
        public void refresh() {
1072
                // force re-creating the cache on the next drawing cycle
1073
                b_validCache = false;
1074
        }
1075

    
1076
    protected void createListeners() {
1077
            this.removeAllListeners();
1078
        viewDocListener = new ViewDocListener(this);
1079
            ownMapContextListener = new OwnMapContextListener(this);
1080
//        logger.info("createListeners.viewDocListener "+ viewDocListener.getID());
1081
//        logger.info("createListeners.ownMapContextListener "+ ownMapContextListener.getID());
1082
    }
1083

    
1084
    protected void addAllListeners() {
1085
        if( viewDocListener == null && ownMapContextListener == null ) {
1086
            this.createListeners();
1087
        }
1088
        if (getView() != null) {
1089
            if (syncLayers) {
1090
                getView().getMapContext().addLayerListener(viewDocListener);
1091
                getView().getMapContext().getLayers().addLayerCollectionListener(viewDocListener);
1092
                getView().getMapContext().addAtomicEventListener(viewDocListener);
1093
            }
1094
            if (getExtentSynced()) {
1095
                getView().getMapContext().getViewPort().addViewPortListener(viewDocListener);
1096
            }
1097
        }
1098
        if (getMapContext() != null) {
1099
            getMapContext().addLayerListener(ownMapContextListener);
1100
            getMapContext().getLayers().addLayerCollectionListener(ownMapContextListener);
1101
            getMapContext().getViewPort().addViewPortListener(ownMapContextListener);
1102
        }
1103
//        logger.info("addAllListeners.viewDocListener " + viewDocListener.getID());
1104
//        logger.info("addAllListeners.ownMapContextListener " + ownMapContextListener.getID());
1105

    
1106
    }
1107

    
1108
    protected void resetAllListeners() {
1109
        this.removeAllListeners();
1110
        this.addAllListeners();
1111
    }
1112

    
1113
    protected void removeAllListeners() {
1114
        removeOwnListeners();
1115
        removeViewListeners();
1116
    }
1117

    
1118
    protected void removeOwnListeners() {
1119
        if( this.ownMapContextListener == null ) {
1120
            return;
1121
        }
1122
        if( this.mapContext==null ) {
1123
            return;
1124
        }
1125
        this.mapContext.removeLayerListener(ownMapContextListener);
1126
        this.mapContext.getViewPort().removeViewPortListener(ownMapContextListener);
1127
        this.mapContext.getLayers().removeLayerCollectionListener(ownMapContextListener);
1128
//        logger.info("removeOwnListeners.ownMapContextListener " + ownMapContextListener.getID());
1129
    }
1130

    
1131
    protected void removeViewListeners() {
1132
        if( this.viewDocListener == null ) {
1133
            return;
1134
        }
1135
        if( this.getView()==null ) {
1136
            return;
1137
        }
1138
        MapContext mapContext = this.getView().getMapContext();
1139
        if( mapContext == null ) {
1140
            return;
1141
        }
1142
        mapContext.removeLayerListener(viewDocListener);
1143
        mapContext.getViewPort().removeViewPortListener(viewDocListener);
1144
        mapContext.getLayers().removeLayerCollectionListener(viewDocListener);
1145
        mapContext.removeAtomicEventListener(viewDocListener);
1146
//        logger.info("removeViewListeners.viewDocListener " + viewDocListener.getID());
1147
    }
1148

    
1149
    @Override
1150
    public void dispose() {
1151
        this.removeAllListeners();
1152
        this.viewDocListener = null;
1153
        this.ownMapContextListener = null;
1154
        this.viewDocument = null;
1155
        this.mapContext = null;
1156
    }
1157

    
1158
        public void frameRemoved() {
1159
                this.removeAllListeners();
1160
                if (b_hasToc && getLayoutContext()!=null) {
1161
                        getLayoutContext().setTocModel(null);
1162
                }
1163
                m_image = null; // FIXME: we could instead move it to a LRU cache to keep the last N images
1164
        }
1165

    
1166
        public void frameAdded() {
1167
                addAllListeners();
1168
                setTocModel();
1169
                updateScaleCtrl();
1170
        }
1171

    
1172
        public void setHasToc(boolean hasToc) {
1173
                this.b_hasToc = hasToc;
1174
                setTocModel();
1175
        }
1176

    
1177
        protected void setTocModel() {
1178
                if (getLayoutContext()!=null) {
1179
                        if (b_hasToc && getMapContext()!=null) {
1180
                                getLayoutContext().setTocModel(getMapContext());
1181
                        }
1182
                        else {
1183
                                getLayoutContext().setTocModel(null);
1184
                        }
1185
                }
1186
        }
1187

    
1188
        @Override
1189
        protected void doSetSelected(int selectedStatus) {
1190
                boolean oldSelectedStatus = isSelected();
1191
                super.doSetSelected(selectedStatus);
1192
                if (!oldSelectedStatus && isSelected()) { // changed from not selected to selected
1193
                        setTocModel();
1194
                        updateScaleCtrl();
1195
                }
1196
        }
1197

    
1198
        public boolean getLayerSynced() {
1199
                return syncLayers;
1200
        }
1201

    
1202
        public void setLayerSynced(boolean synced) {
1203
        syncLayers = synced;
1204
        resetAllListeners();
1205
        }
1206

    
1207
        public boolean getExtentSynced() {
1208
                return syncExtents;
1209
        }
1210

    
1211
        public void setExtentSynced(boolean synced) {
1212
                syncExtents = synced;
1213
        resetAllListeners();
1214
        }
1215

    
1216
        /**
1217
         * Returns true if the newEnvelope represents a pan operation on oldEnvelope,
1218
         * (both extents have the same height and width)
1219
         */
1220
        public static boolean isPan(Envelope oldEnvelope, Envelope newEnvelope) {
1221
                if (oldEnvelope!=null && newEnvelope!=null) {
1222
                        double toleranceX = 0.00000001*Math.min(oldEnvelope.getLength(0), newEnvelope.getLength(0));
1223
                        double toleranceY = 0.00000001*Math.min(oldEnvelope.getLength(1), newEnvelope.getLength(1));
1224

    
1225
                        // we consider it to be a pan if both lengths are equal
1226
                        // (we use tolerance to avoid direct comparison of double values)
1227
                        if ( ((oldEnvelope.getLength(0)-newEnvelope.getLength(0))<toleranceX)
1228
                                        && ((oldEnvelope.getLength(1)-newEnvelope.getLength(1))<toleranceY) ) {
1229
                                return true;
1230
                        }
1231
                }
1232
                return false;
1233
        }
1234

    
1235
        /**
1236
         * Calculates the new extent for the FFrame. It is necessary to avoid
1237
         * scale changes when a pan is triggered from the view, as the different
1238
         * size factors from View/FFrameView introduces scale changes even for
1239
         * pans
1240
         *
1241
         * @param newEnvelope
1242
         * @return
1243
         */
1244
        protected Envelope calculateNewExtent() {
1245
                Envelope newEnvelope = getView().getMapContext().getViewPort().getEnvelope();
1246
                Envelope oldViewEnvelope = null;
1247
                try {
1248
                        if (getView().getMapContext().getViewPort().getEnvelopes().hasPrevious()) {
1249
                                Rectangle2D r = getView().getMapContext().getViewPort().getEnvelopes().getPrev();
1250
                                oldViewEnvelope = GeometryLocator.getGeometryManager().createEnvelope(r.getMinX(), r.getMinY(), r.getMaxX(), r.getMaxY(), SUBTYPES.GEOM2D);
1251
                        }
1252
                        if (isPan(oldViewEnvelope, newEnvelope)) {
1253
                                Envelope envelope = getMapContext().getViewPort().getAdjustedEnvelope();
1254
                                double shiftX = newEnvelope.getMinimum(0) - oldViewEnvelope.getMinimum(0);
1255
                                double shiftY = newEnvelope.getMinimum(1) - oldViewEnvelope.getMinimum(1);
1256

    
1257
                                double minX = envelope.getMinimum(0) + shiftX;
1258
                                double minY = envelope.getMinimum(1) + shiftY;
1259
                                double maxX = envelope.getMaximum(0) + shiftX;
1260
                                double maxY = envelope.getMaximum(1) + shiftY;
1261

    
1262
                                return GeometryLocator.getGeometryManager().createEnvelope(minX, minY, maxX, maxY, SUBTYPES.GEOM2D);
1263
                        }
1264
                } catch (Exception e) {
1265
                }
1266
                return newEnvelope;
1267
        }
1268

    
1269
        protected boolean isDrawing() {
1270
            return this.b_drawing;
1271
        }
1272
        
1273
        protected boolean isUpdating() {
1274
            return this.b_updating;
1275
        }
1276
        
1277
        protected boolean skipFirstChangeExtent() {
1278
            if( this.b_frameInitialized ) {
1279
                return false;
1280
            }
1281
            this.b_frameInitialized = true;
1282
            return true;
1283
        }
1284
        
1285
        protected boolean isSyncLayers() {
1286
            return this.syncLayers;
1287
        }
1288
        
1289
        protected void beginUpdate() {
1290
            this.b_updating = true;
1291
        }
1292
        
1293
        protected void endUpdate() {
1294
            this.b_updating = false;
1295
        }
1296
        
1297
    @Override
1298
        public SCALE_TYPE getScaleType() {
1299
                return this.scaleType ;
1300
        }      
1301
        
1302
        public Double getFixedScale() {
1303
            return this.fixedScale;
1304
        }
1305
        
1306
        public Envelope getFixedExtent() {
1307
            return this.fixedExtent;
1308
        }
1309
        
1310
    private class ViewDocListener 
1311
        implements ViewPortListener, LegendListener, LayerCollectionListener, AtomicEventListener {
1312

    
1313
        public ViewDocListener(FFrameView fview) {
1314

    
1315
        }
1316
        
1317
            @Override
1318
            public void extentChanged(ExtentEvent e) {
1319
                if( isUpdating() ) {
1320
                    return;
1321
                }
1322
                if( skipFirstChangeExtent() ) {
1323
                    return;
1324
                }
1325
                if( !getExtentSynced() ) {
1326
                    return;
1327
                }
1328
//                logger.info("viewdoc-mapcontext.extentChanged " + this.getID());
1329
                try {
1330
                    beginUpdate();
1331
                    if (getMapContext() != null) {
1332
                        if (null == getScaleType()) {
1333
                            getMapContext().getViewPort().setEnvelope(calculateNewExtent());
1334
                        } else switch (getScaleType()) {
1335
                            case FIXED_EXTENT:
1336
                                getView().getMapContext().getViewPort().setEnvelope(getFixedExtent());
1337
                                break;
1338
                            case FIXED_SCALE:
1339
                                getMapContext().setScaleView(Math.round(getFixedScale()));
1340
                                getView().getMapContext().getViewPort().setEnvelope(getMapContext().getViewPort().getAdjustedEnvelope());
1341
                                break;
1342
                            default:
1343
                                getMapContext().getViewPort().setEnvelope(calculateNewExtent());
1344
                                break;
1345
                        }
1346
                        updateScaleCtrl();
1347
                        invalidateLayout();
1348
                    }
1349
                } finally {
1350
                    endUpdate();
1351
                }
1352
            }
1353

    
1354
                public void backColorChanged(ColorEvent e) {
1355
                        if (!isUpdating() && isSyncLayers()) {
1356
                                if (getMapContext()!=null) {
1357
                                        beginUpdate();
1358
                                        getMapContext().getViewPort().setBackColor(e.getNewColor());
1359
                                        invalidateLayout();
1360
                                        endUpdate();
1361
                                }
1362
                        }
1363
                }
1364

    
1365
                public void projectionChanged(ProjectionEvent e) {
1366
                        if (!isUpdating() && getExtentSynced()) {
1367
                                if (getMapContext()!=null) {
1368
                                        beginUpdate();
1369
                                        getMapContext().getViewPort().setProjection(e.getNewProjection());
1370
                                        invalidateLayout();
1371
                                        // FIXME: force also a view redraw someway??
1372
                                        endUpdate();
1373
                                }
1374
                        }
1375
                }
1376

    
1377
                public void conditionalRedraw() {
1378
                        if (!isUpdating() && isSyncLayers()) {
1379
                                beginUpdate();
1380
                                invalidateLayout();
1381
                                // the view should also receive the event and update automatically
1382
                                endUpdate();
1383
                        }
1384
                }
1385

    
1386
                public void legendChanged(LegendChangedEvent e) {
1387
                        conditionalRedraw();
1388
                        refreshToc();
1389
                }
1390

    
1391
                public void layerAdded(LayerCollectionEvent e) {
1392
                        conditionalRedraw();
1393
                        // no need to invalidate the toc as it is down by the OwnMapContextListener
1394
                }
1395

    
1396
                public void layerMoved(LayerPositionEvent e) {
1397
                        conditionalRedraw();
1398
                        // no need to invalidate the toc as it is down by the OwnMapContextListener
1399
                }
1400

    
1401
                public void layerRemoved(LayerCollectionEvent e) {
1402
                        conditionalRedraw();
1403
                        // no need to invalidate the toc as it is down by the OwnMapContextListener
1404
                }
1405

    
1406
                public void layerAdding(LayerCollectionEvent e)
1407
                                throws CancelationException {
1408
                        // nothing needed
1409
                }
1410

    
1411
                public void layerMoving(LayerPositionEvent e)
1412
                                throws CancelationException {
1413
                        // nothing needed
1414
                }
1415

    
1416
                public void layerRemoving(LayerCollectionEvent e)
1417
                                throws CancelationException {
1418
                        // nothing needed
1419
                }
1420

    
1421
                public void visibilityChanged(LayerCollectionEvent e)
1422
                                throws CancelationException {
1423
                        // AtomicEvent is catching visibility changes instead of this one,
1424
                        // as this event is not being received. Maybe is only triggered if the
1425
                        // visibility of the whole group changes??
1426
                        conditionalRedraw();
1427
                        invalidateToc();
1428
                }
1429

    
1430
                public void atomicEvent(AtomicEvent e) {
1431
                        boolean layoutRedraw = false;
1432
                        // not all the events require a fframeview redraw
1433
                        for (int i=e.getLayerEvents().length-1; i>=0; i--) {
1434
                                FMapEvent at = e.getEvent(i);
1435
                                if (at instanceof LayerEvent) {
1436
                                        if (at.getEventType()==LayerEvent.DRAW_VALUES_CHANGED) {
1437
                                                layoutRedraw = true;
1438
                                                break;
1439
                                        }
1440
                                }
1441
                        }
1442
                        if (layoutRedraw) {
1443
                                conditionalRedraw();
1444
                        }
1445
                        invalidateToc();
1446
                }
1447
        }
1448

    
1449
    
1450
    private  class OwnMapContextListener
1451
            implements ViewPortListener, LegendListener, LayerCollectionListener {
1452

    
1453
        public OwnMapContextListener(FFrameView fview) {
1454

    
1455
        }
1456
        
1457
        @Override
1458
        public void extentChanged(ExtentEvent e) {
1459
            if( isDrawing() ) {
1460
                return;
1461
            }
1462
            if( isUpdating() ) {
1463
                return;
1464
            }
1465
            try {
1466
//                logger.info("layout-mapcontext.extentChanged "+this.getID());
1467
                beginUpdate();
1468
                if (getScaleType() == SCALE_TYPE.FIXED_EXTENT) {
1469
                    getMapContext().getViewPort().setEnvelope(getFixedExtent());
1470
                } else {
1471
                    Envelope newEnvelope;
1472
                    if (getScaleType() == SCALE_TYPE.FIXED_SCALE && getFixedScale() != null) {
1473
                        getMapContext().setScaleView(Math.round(getFixedScale()));
1474
                        newEnvelope = getMapContext().getViewPort().getAdjustedEnvelope();
1475
                    } else {
1476
                        newEnvelope = e.getNewExtent();
1477
                    }
1478
                    if (getView() != null) {
1479
                        if (getExtentSynced()) {
1480
                            getView().getMapContext().getViewPort().setEnvelope(newEnvelope);
1481
                        }
1482
                    }
1483
                }
1484
                updateScaleCtrl();
1485
                invalidateLayout();
1486
            } finally {
1487
                endUpdate();
1488
            }
1489
        }
1490

    
1491
        @Override
1492
        public void backColorChanged(ColorEvent e) {
1493
            if (!isUpdating()) {
1494
                if (getView() != null) {
1495
                    try {
1496
                        beginUpdate();
1497
                        if (getLayerSynced()) {
1498
                            getView().getMapContext().getViewPort().setBackColor(e.getNewColor());
1499
                        }
1500
                        invalidateLayout();
1501
                    } finally {
1502
                        endUpdate();
1503
                    }
1504
                }
1505
            }
1506
        }
1507

    
1508
        @Override
1509
        public void projectionChanged(ProjectionEvent e) {
1510
            if (!isUpdating() && getExtentSynced()) {
1511
                if (getView() != null) {
1512
                    try {
1513
                        beginUpdate();
1514
                        if (getLayerSynced()) {
1515
                            getView().getMapContext().getViewPort().setProjection(e.getNewProjection());
1516
                        }
1517
                        invalidateLayout();
1518
                        // FIXME: force also a view redraw someway??
1519
                    } finally {
1520
                        endUpdate();
1521
                    }
1522
                }
1523
            }
1524
        }
1525

    
1526
        public void conditionalRedraw() {
1527
            if (!isUpdating()) {
1528
                try {
1529
                    beginUpdate();
1530
                    invalidateLayout();
1531
                    // the view should also receive the event and update automatically
1532
                } finally {
1533
                    endUpdate();
1534
                }
1535
            }
1536
        }
1537

    
1538
        @Override
1539
        public void legendChanged(final LegendChangedEvent e) {
1540
            conditionalRedraw();
1541
            refreshToc();
1542
        }
1543

    
1544
        @Override
1545
        public void layerAdded(final LayerCollectionEvent e) {
1546
            // necessary to set an envelope when the first layer is added
1547
            if (!isUpdating() && getMapContext().getViewPort().getEnvelope() == null) {
1548
                try {
1549
                    beginUpdate();
1550
                    fullExtent();
1551

    
1552
                } catch (ReadException e1) {
1553
                } finally {
1554
                    endUpdate();
1555
                }
1556
            }
1557
            conditionalRedraw();
1558
            refreshToc();
1559
        }
1560

    
1561
        @Override
1562
        public void layerMoved(final LayerPositionEvent e) {
1563
            conditionalRedraw();
1564
            refreshToc();
1565
        }
1566

    
1567
        @Override
1568
        public void layerRemoved(final LayerCollectionEvent e) {
1569
            conditionalRedraw();
1570
            refreshToc();
1571
        }
1572

    
1573
        @Override
1574
        public void layerAdding(LayerCollectionEvent e)
1575
                throws CancelationException {
1576
            // nothing neededO
1577

    
1578
        }
1579

    
1580
        @Override
1581
        public void layerMoving(LayerPositionEvent e)
1582
                throws CancelationException {
1583
            // nothing needed
1584

    
1585
        }
1586

    
1587
        @Override
1588
        public void layerRemoving(LayerCollectionEvent e)
1589
                throws CancelationException {
1590
            // nothing needed
1591

    
1592
        }
1593

    
1594
        @Override
1595
        public void visibilityChanged(LayerCollectionEvent e)
1596
                throws CancelationException {
1597
            conditionalRedraw();
1598
        }
1599
    }
1600

    
1601
        public void setExtent(Envelope extent) {
1602
                if (getScaleType()==SCALE_TYPE.NORMAL) {
1603
                        getMapContext().getViewPort().setEnvelope(extent);
1604
                }
1605
        }
1606

    
1607
        public void setScaleType(SCALE_TYPE scaleType) {
1608
                this.scaleType = scaleType;
1609
        }
1610

    
1611
        public void setScaleType(SCALE_TYPE scaleType, double fixedScale) {
1612
                if (scaleType == SCALE_TYPE.FIXED_SCALE) {
1613
                        this.scaleType = scaleType;
1614
                        this.fixedScale = new Double(fixedScale);
1615
                        setScale(fixedScale);
1616
                }
1617
        }
1618

    
1619
        public void setScaleType(SCALE_TYPE scaleType, Envelope fixedExtent) {
1620
                if (scaleType == SCALE_TYPE.FIXED_EXTENT) {
1621
                        this.scaleType = scaleType;
1622
                        this.fixedExtent  = fixedExtent;
1623
                        setNewEnvelope(fixedExtent);
1624
                }
1625
        }
1626

    
1627
        @Deprecated
1628
        public int getTypeScale() {
1629
                return AUTOMATICO;
1630
        }
1631

    
1632
        @Deprecated
1633
        public void setLinked(boolean b) {}
1634

    
1635
        @Deprecated
1636
        public boolean getLinked() {
1637
                return false;
1638
        }
1639

    
1640
        public void windowActivated() {
1641
                if (isSelected()
1642
                                && getLayoutContext().getSelectedFFrames(IFFrameUseFMap.class).length==1) {
1643
                        // update the scale control whenever the panel window gets activated,
1644
                        // as the control instance is shared for all the windows
1645
                        updateScaleCtrl();
1646
                }
1647

    
1648
        }
1649

    
1650
        public void windowClosed() {
1651
        }
1652
}