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

History | View | Annotate | Download (51.1 KB)

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

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

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

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

    
185
    protected void createListeners() {
186
            viewDocListener = new ViewDocListener();
187
            ownMapContextListener = new OwnMapContextListener();
188
    }
189

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

    
200
        return "FFrameView " + num + ": " + getView().getName();
201
    }
202

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

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

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

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

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

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

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

    
330
    }
331

    
332
    /**
333
     * Sets the View associated with this FFrameView, which will
334
     * be used to clone the MapContext and the layers. It will
335
     * also used to synchronize the FFrameView with
336
     * the associated View, depending on the selected scale type
337
     *
338
     * @param viewMapContext
339
     */
340
    public void setView(ViewDocument dvd) {
341
            ViewDocument oldDoc = viewDocument;
342
            if (oldDoc!=null) {
343
                    if (oldDoc.getMapContext()!=null) {
344
                            clearViewListeners(oldDoc.getMapContext());
345
                    }
346
            }
347
        viewDocument = dvd;
348
        if (dvd!=null) {
349
            setViewMapContext(dvd.getMapContext());
350
        }
351
        else {
352
                setViewMapContext(null);
353
        }
354
    }
355

    
356
    /**
357
     * Gets the associated View
358
     *
359
     * @return The associated view
360
     * @see {@link #setView(ViewDocument)}
361
     */
362
    public ViewDocument getView() {
363
        return viewDocument;
364
    }
365

    
366
    /**
367
     * Draws the FFrameView on the provided Graphics, according to the
368
     * provided affine transform and the visible rectangle.
369
     *
370
     * @param g Graphics2D
371
     * @param at Affine transform to translate sheet coordinates (in cm)
372
     *                                 to screen coordinates (in pixels)
373
     * @param visibleLayoutDocRect visible rectangle
374
     * @param imgBase Image used to speed up the drawing process
375
     */
376
    public void draw(Graphics2D g, AffineTransform at, Rectangle2D visibleLayoutDocRect, BufferedImage imgBase) {
377
        Rectangle2D.Double fframeViewRect = getBoundingBox(at);
378
        Rectangle2D.Double visibleArea = (Rectangle2D.Double) getVisibleRect(visibleLayoutDocRect, fframeViewRect);
379
        if (visibleArea==null) {
380
                return;
381
        }
382
        preDraw(g, fframeViewRect, visibleArea);
383
        if (getMapContext() == null) {
384
                drawEmpty(g);
385
        } else {
386
                if (FLayoutUtilities.hasEditingLayers(getView())) {
387

    
388
                        /*
389
                         * We are not drawing if any layer is in editing mode
390
                         */
391
                        drawMessage(g, Messages.getText(
392
                                        "_Cannot_draw_view_if_layers_in_editing_mode"));
393

    
394
                } else {
395
                        if (getQuality() == PRESENTATION) {
396
                                try {
397
                                        drawPresentation(g, at, fframeViewRect, visibleArea, imgBase);
398
                                } catch (Exception exc) {
399
                                        drawMessage(g, FLayoutFunctions.getLastMessage(exc));
400
                                }
401

    
402
                        } else {
403
                                drawDraft(g);
404
                        }
405
                }
406
        }
407
        postDraw(g, fframeViewRect, at);
408
        if (showGrid && grid != null) {
409
            grid.draw(g, at, visibleLayoutDocRect, imgBase);
410
        }
411
    }
412

    
413
    private void drawMessage(Graphics2D g, String msg) {
414

    
415
        Rectangle2D r = getBoundingBox(null);
416
        g.setColor(Color.lightGray);
417
        g.fillRect((int) r.getX(), (int) r.getY(), (int) r.getWidth(),
418
            (int) r.getHeight());
419
        g.setColor(Color.darkGray);
420
        g.setStroke(new BasicStroke(2));
421
        g.drawRect((int) r.getX(), (int) r.getY(), (int) r.getWidth(),
422
            (int) r.getHeight());
423
        g.setColor(Color.black);
424

    
425
        int scale = (int) (r.getWidth() / 24);
426
        Font f = new Font("SansSerif", Font.PLAIN, scale);
427
        g.setFont(f);
428
        if (msg==null) {
429
                msg = Messages.getText("error");
430
        }
431
        g.drawString(msg, (int) (r.getCenterX() - ((msg.length() * scale) / 4)),
432
                        (int) (r.getCenterY()));
433
    }
434

    
435
    /**
436
     * Gets the visible envelope, in map coordinates
437
     *
438
     * @param fframeViewRect Rectangle defining the bounding box of the
439
     * FFrameView, in screen coordinates
440
     * @param visiblefframeViewRect Rectangle defining the bounding box
441
     * of the visible area of the fframeView, in screen coordinates
442
     * @return
443
     */
444
    protected Envelope getVisibleEnvelope(Rectangle2D.Double fframeViewRect,
445
            Rectangle2D.Double visiblefframeViewRect) {
446
            Envelope oldEnv = getMapContext().getViewPort().getAdjustedEnvelope();
447
            double widthFactor = ((int)visiblefframeViewRect.width) / fframeViewRect.width;
448
            double heightFactor = ((int)visiblefframeViewRect.height) / fframeViewRect.height;
449

    
450
            double newWidth = oldEnv.getLength(0)*widthFactor;
451
            double newHeight = oldEnv.getLength(1)*heightFactor;
452

    
453
        double translateX = visiblefframeViewRect.x - fframeViewRect.x;
454
        double translateY = visiblefframeViewRect.y - fframeViewRect.y;
455
        double translateFactorX = translateX / fframeViewRect.width;
456
        double translateFactorY = translateY / fframeViewRect.height;
457

    
458
        double newX = oldEnv.getMinimum(0) + translateFactorX*oldEnv.getLength(0);
459
        double newMaxY =  oldEnv.getMaximum(1) - translateFactorY*oldEnv.getLength(1);
460
        double newMaxX = newX + newWidth;
461
        double newY = newMaxY - newHeight;
462

    
463
        Envelope newEnv = null;
464
                try {
465
                        newEnv = geomManager.createEnvelope(newX, newY, newMaxX, newMaxY, SUBTYPES.GEOM2D);
466
                } catch (CreateEnvelopeException e) {
467
                        logger.error("Error calculating visible extent", e);
468
                }
469
        return newEnv;
470

    
471
    }
472

    
473
    protected void drawPresentation(
474
        Graphics2D g,
475
        AffineTransform affineTransform,
476
        Rectangle2D.Double fframeViewRect,
477
        Rectangle2D.Double visibleRect,
478
        BufferedImage imgBase) throws Exception {
479

    
480
            b_drawing = true;
481
            int drawWidth = (int)visibleRect.width;
482
            int drawHeight = (int)visibleRect.height;
483

    
484
            Envelope oldEnvelope = null;
485
        if (!visibleRect.equals(fframeViewRect)) {
486
                // if visible area is smaller than the fframe, we will only draw this area,
487
                // so we need to tell the ViewPort the image size and extent for drawing,
488
                // and restore the real extent after drawing
489
            oldEnvelope = getMapContext().getViewPort().getEnvelope();
490
            if (oldEnvelope==null) {
491
                    return;
492
            }
493

    
494
                Envelope newEnvelope = getVisibleEnvelope(fframeViewRect, visibleRect);
495
                // image size must be set before the envelope, as it has influence on the adjustedExtent
496
                getMapContext().getViewPort().setImageSize(new Dimension(drawWidth, drawHeight));
497
                getMapContext().getViewPort().setEnvelope(newEnvelope);
498
        }
499
        else {
500
                getMapContext().getViewPort().setImageSize(new Dimension(drawWidth, drawHeight));
501
                getMapContext().getViewPort().refreshExtent();
502
        }
503

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

    
507
        // paint the MapContext on m_image, if not already cached
508
        createImage(affineTransform, drawWidth, drawHeight, mapOrigin);
509

    
510
        //Draw the created image
511
        drawImage(g, m_image, visibleRect);
512

    
513
        if (oldEnvelope!=null) {
514
                // restore real envelope and image size
515
                getMapContext().getViewPort().setImageSize(new Dimension((int)fframeViewRect.width, (int) fframeViewRect.height));
516
                getMapContext().getViewPort().setEnvelope(oldEnvelope);
517
        }
518

    
519
        scaleAnt = affineTransform.getScaleX();
520
        origin = mapOrigin;
521
        b_drawing = false;
522
    }
523

    
524
    protected void createImage(AffineTransform affineTransform,
525
                    int width, int height, Point mapOrigin) throws ReadException, MapContextException {
526
            ViewPort viewPort = this.getMapContext().getViewPort();
527

    
528
        //If the image has to be created...
529
            if (origin == null ||
530
                            !origin.equals(mapOrigin) ||
531
                            affineTransform.getScaleX() != scaleAnt ||
532
                            m_image == null ||
533
                            !b_validCache) {
534

    
535
                    viewPort.setDPI(getDrawPaperDPI());
536
                viewPort.setImageSize(new Dimension(width, height));
537

    
538
            m_image =
539
                    new BufferedImage(
540
                                    width,
541
                                    height,
542
                                    BufferedImage.TYPE_INT_ARGB);
543

    
544
            Graphics2D gimg = (Graphics2D) m_image.createGraphics();
545
            getMapContext().draw(m_image, gimg, getScale());
546
            gimg.dispose();
547
            b_validCache = true;
548
        }
549

    
550
    }
551

    
552
    protected void drawImage(Graphics2D g, BufferedImage image,
553
                    Rectangle2D.Double visibleRectangle) {
554

    
555
            Color theBackColor = getMapContext().getViewPort().getBackColor();
556
        if (theBackColor != null) {
557
            g.setColor(theBackColor);
558
            g.fillRect((int) visibleRectangle.x, (int) visibleRectangle.y,
559
                            (int)visibleRectangle.width,
560
                            (int)visibleRectangle.height);
561
        }
562
        g.drawImage(m_image,
563
                        (int) visibleRectangle.x,
564
                        (int) visibleRectangle.y,
565
                        null);
566
    }
567

    
568
    protected void preDraw(Graphics2D g, Rectangle2D.Double fframeViewRect, Rectangle2D.Double visibleRect){
569
            originalGraphicsAT = (AffineTransform) g.getTransform().clone();
570

    
571
        if (g.getClipBounds() != null) {
572
            originalClip = (Rectangle) g.getClipBounds().clone();
573
        }
574
        AffineTransform rotationAT = getRotationAT();
575
        if (rotationAT!=null) {
576
                g.transform(rotationAT);
577
        }
578
        g.setClip((int) visibleRect.getMinX(), (int) visibleRect.getMinY(),
579
            (int) visibleRect.getWidth(), (int) visibleRect.getHeight());
580
    }
581

    
582
    protected void postDraw(Graphics2D g, Rectangle2D.Double fframeViewRect, AffineTransform at){
583
            g.setTransform(originalGraphicsAT);
584
        if (getMapContext() != null) {
585
            setATMap(getMapContext().getViewPort().getAffineTransform());
586
        }
587
        if (originalClip != null) {
588
            g.setClip(originalClip.x, originalClip.y, originalClip.width, originalClip.height);
589
        }
590
    }
591

    
592

    
593
    /**
594
     * @deprecated Use {@link #postDraw(Graphics2D, java.awt.geom.Rectangle2D.Double, AffineTransform)} instead.
595
     */
596
    @Deprecated
597
    protected void postDraw(Graphics2D g, Rectangle2D.Double rectangleLayout, Rectangle2D rectangleView, BufferedImage imgBase, Rectangle originalClip, AffineTransform at) {
598
            postDraw(g, rectangleLayout, at);
599

    
600
    }
601

    
602
    /**
603
     * @deprecated Use {@link #preDraw(Graphics2D, java.awt.geom.Rectangle2D.Double, java.awt.geom.Rectangle2D.Double) instead
604
     */
605
    @Deprecated
606
    protected Rectangle preDraw(Graphics2D g, Rectangle2D.Double rectangleLayout){
607
            Rectangle originalClip = null;
608
        if (g.getClipBounds() != null) {
609
            originalClip = (Rectangle) g.getClipBounds().clone();
610
        }
611
            preDraw(g, rectangleLayout, rectangleLayout);
612
            return originalClip;
613
    }
614

    
615
    public void print(Graphics2D g, AffineTransform at, Geometry geom,
616
        PrintAttributes printAttributes) {
617
        Rectangle2D.Double rectangleLayout = getBoundingBox(at);
618

    
619
        preDraw(g, rectangleLayout, rectangleLayout);
620
        print(g, at, printAttributes);
621
        postDraw(g, rectangleLayout, at);
622
        if (showGrid && grid != null) {
623
            grid.print(g, at, geom, printAttributes);
624
        }
625
    }
626

    
627
    protected void print(Graphics2D g, AffineTransform at, PrintAttributes printAttributes) {
628
        Rectangle2D.Double layoutRectangle = getBoundingBox(at);
629

    
630
        // FIXME: should we clone the mapcontext and viewport before printing ??
631
        // otherwise we will probably have unexpected results if the user modifies
632
        // the layout while printing (answer: not an issue at the moment as printing is
633
        // a blocking operation)
634
        ViewPort viewPort = this.getMapContext().getViewPort();
635

    
636
        Point2D old_offset = viewPort.getOffset();
637
        Dimension old_imgsize = viewPort.getImageSize();
638
        double oldDpi = viewPort.getDPI();
639

    
640
        viewPort.setOffset(new Point2D.Double(layoutRectangle.x, layoutRectangle.y));
641
        viewPort.setImageSize(new Dimension((int) layoutRectangle.width, (int) layoutRectangle.height));
642
        double dpi = PrintAttributes.PRINT_QUALITY_DPI[printAttributes.getPrintQuality()];
643
        viewPort.setDPI(dpi);
644

    
645
        //Draw the backgroung color of the map
646
        Color theBackColor = viewPort.getBackColor();
647
        if (theBackColor != null) {
648
            g.setColor(theBackColor);
649
            g.fillRect((int) layoutRectangle.x, (int) layoutRectangle.y, viewPort
650
                    .getImageWidth(), viewPort
651
                    .getImageHeight());
652
        }
653

    
654
        //Print the map
655
        try {
656
            this.getMapContext().print(g, getScale(), printAttributes);
657
        } catch (ReadException e) {
658
            NotificationManager.addError(e.getMessage(), e);
659
        } catch (MapContextException e) {
660
            NotificationManager.addError(e.getMessage(), e);
661
        }
662

    
663
        // Restore offset, imgsize
664
        viewPort.setOffset(old_offset);
665
        viewPort.setImageSize(old_imgsize);
666
        viewPort.setDPI(oldDpi);
667

    
668
    }
669

    
670
    /**
671
     * Rellena la unidad de medida en la que est? la vista.
672
     *
673
     * @param i
674
     *            entero que representa la unidad de medida de la vista.
675
     */
676
    public void setMapUnits(int i) {
677
        mapUnits = i;
678
    }
679

    
680
    /**
681
     * Obtiene la unidad de medida en la que est? la vista.
682
     *
683
     * @return Unidad de medida.
684
     */
685
    public int getMapUnits() {
686
        return mapUnits;
687
    }
688

    
689
    /**
690
     * Devuelve la escala seg?n el tipo de escala que se haya seleccionado al
691
     * a?adida la vista.
692
     *
693
     * @return escala.
694
     */
695
    public long getScale() {
696
            return (long) getMapContext().getScaleView();
697
    }
698

    
699
    /**
700
     * Inserta la imagen para repintar el FFrameView.
701
     *
702
     * @param bi
703
     *            Imagen para repintar.
704
     */
705
    public void setBufferedImage(BufferedImage bi) {
706
        m_image = bi;
707
    }
708

    
709
    /**
710
     * Devuelve la imagen para repintar.
711
     *
712
     * @return Imagen para repintar.
713
     */
714
    public BufferedImage getBufferedImage() {
715
        return m_image;
716
    }
717

    
718
    /**
719
     * Devuelve la MAtriz de transformaci?n utilizada por la FFrameView.
720
     *
721
     * @return MAtriz de transformaci?n.
722
     */
723
    public AffineTransform getATMap() {
724
        return mapAT;
725
    }
726

    
727
    /**
728
     * Inserta la matriz de transformaci?n.
729
     *
730
     * @param transform
731
     *            Matriz de transformaci?n.
732
     */
733
    public void setATMap(AffineTransform transform) {
734
        mapAT = transform;
735
    }
736

    
737
    /**
738
     * Inserta el proyecto.
739
     *
740
     * @param p
741
     *            Proyecto.
742
     */
743
    public void setProject(Project p) {
744
        project = p;
745
    }
746

    
747
    /**
748
     * @see org.gvsig.app.project.documents.layout.fframes.IFFrame#getNameFFrame()
749
     */
750
    public String getNameFFrame() {
751
        return PluginServices.getText(this, "Vista") + num;
752
    }
753

    
754
    public String getName() {
755
        return PERSISTENCE_DEFINITION_NAME;
756
    }
757

    
758
    /**
759
     * DOCUMENT ME!
760
     *
761
     * @param arg0
762
     *            DOCUMENT ME!
763
     *
764
     * @return DOCUMENT ME!
765
     */
766
    public boolean compare(Object arg0) {
767
        if (!(arg0 instanceof FFrameView)) {
768
            return false;
769
        }
770

    
771
        if (!this.getName().equals(((FFrameView) arg0).getName())) {
772
            return false;
773
        }
774

    
775
        if (Math.abs(this.getBoundBox().getWidth()
776
            - (((FFrameView) arg0).getBoundBox().getWidth())) > 0.05) {
777
            return false;
778
        }
779
        if (Math.abs(this.getBoundBox().getHeight()
780
            - (((FFrameView) arg0).getBoundBox().getHeight())) > 0.05) {
781
            return false;
782
        }
783

    
784
        if (!this.toString().equals(((FFrameView) arg0).toString())) {
785
            return false;
786
        }
787

    
788
        if (this.getMapContext() != null
789
            && !this.getMapContext()
790
                .equals(((FFrameView) arg0).getMapContext())) {
791
            return false;
792
        }
793

    
794
        if (this.getRotation() != ((FFrameView) arg0).getRotation()) {
795
            return false;
796
        }
797
        return true;
798
    }
799

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

    
827
    public void fullExtent() throws ReadException {
828
        setNewEnvelope(getMapContext().getFullEnvelope());
829
    }
830

    
831
    public void setPointsToZoom(Point2D px1, Point2D px2) {
832
        p1 = px1;
833
        p2 = px2;
834
    }
835

    
836
    public void movePoints(Point2D px1, Point2D px2) {
837
        double difX = -px2.getX() + px1.getX();
838
        double difY = -px2.getY() + px1.getY();
839
        if (p1 != null) {
840
            p1.setLocation(p1.getX() + difX, p1.getY() + difY);
841
            p2.setLocation(p2.getX() + difX, p2.getY() + difY);
842
        }
843
    }
844

    
845
    /**
846
     * This method deals with places where this fframeview and the cloned
847
     * fframeview (frame) are registered as listeners. The goal should be
848
     * leaving the cloned instance (frame) as listener in the same way
849
     * that 'this' instance is doing.
850
     */
851
    protected void cloneActions(FFrameView frame) {
852
    }
853

    
854
    public Object clone() throws CloneNotSupportedException {
855
        FFrameView frame = (FFrameView) super.clone();
856
        frame.createListeners(); // necessary to create the listeners within the right scope
857
        frame.setView(this.getView());
858

    
859
        if (grid != null) {
860
            FFrameGrid newGrid = (FFrameGrid) this.grid.clone();
861
            newGrid.setFFrameDependence(frame);
862
            frame.setGrid(newGrid);
863
        }
864
        cloneActions(frame);
865
        return frame;
866
    }
867

    
868
    public void setGrid(IFFrame grid) {
869
        this.grid = grid;
870
        this.grid.setRotation(this.getRotation());
871
    }
872

    
873
    public IFFrame getGrid() {
874
        return this.grid;
875
    }
876

    
877
    public void setRotation(double rotation) {
878
        super.setRotation(rotation);
879
        if (grid != null) {
880
            grid.setRotation(rotation);
881
        }
882
    }
883

    
884
    public void showGrid(boolean b) {
885
        showGrid = b;
886
    }
887

    
888
    public boolean isShowGrid() {
889
        return showGrid;
890
    }
891

    
892
    public void refreshOriginalExtent() {
893
    }
894

    
895
    public static void registerPersistent() {
896
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
897
        if (manager.getDefinition(PERSISTENCE_DEFINITION_NAME) == null) {
898
            DynStruct definition =
899
                manager.addDefinition(FFrameView.class,
900
                    PERSISTENCE_DEFINITION_NAME,
901
                    "FFrameView persistence definition", null, null);
902
            definition.extend(manager
903
                .getDefinition(FFrame.PERSISTENCE_DEFINITION_NAME));
904
            definition.addDynFieldInt(QUALITY_FIELD).setMandatory(true);
905
            definition.addDynFieldInt(MAPUNITS_FIELD).setMandatory(true);
906
            definition.addDynFieldDouble(SCALE_FIELD).setMandatory(false);
907
            definition.addDynFieldObject(VIEW_FIELD)
908
                .setClassOfValue(ViewDocument.class).setMandatory(false);
909
            definition.addDynFieldObject(ENVELOPE_FIELD)
910
                .setClassOfValue(Envelope.class).setMandatory(false);
911
            definition.addDynFieldBoolean(SHOWGRID_FIELD).setMandatory(true);
912
            definition.addDynFieldObject(GRID_FIELD)
913
                .setClassOfValue(IFFrame.class).setMandatory(false);
914
            definition.addDynFieldBoolean(HAS_TOC_FIELD).setMandatory(false);
915
            definition.addDynFieldBoolean(EXTENT_SYNC_FIELD).setMandatory(false);
916
            definition.addDynFieldBoolean(LAYER_SYNC_FIELD).setMandatory(false);
917
            definition.addDynFieldInt(SCALE_TYPE_FIELD).setMandatory(false);
918
            // unused fields, kept for backward compatibility
919
            definition.addDynFieldInt(MODE_FIELD).setMandatory(false);
920
            definition.addDynFieldInt(TYPESCALE_FIELD).setMandatory(false);
921
            definition.addDynFieldBoolean(BLINKED_FIELD).setMandatory(false);
922
            definition.addDynFieldObject(MAPCONTEXT_FIELD)
923
            .setClassOfValue(MapContext.class).setMandatory(false);
924
            definition.addDynFieldInt(VIEWING_FIELD).setMandatory(false);
925
            definition.addDynFieldInt(EXTENSION_FIELD).setMandatory(false);
926
        }
927
    }
928

    
929
    @Override
930
    public void loadFromState(PersistentState state)
931
        throws PersistenceException {
932
        super.loadFromState(state);
933
        b_frameInitialized = false;
934
        if (state.hasValue(EXTENT_SYNC_FIELD)) {
935
                syncExtents = state.getBoolean(EXTENT_SYNC_FIELD);
936
        }
937
        else {
938
                syncExtents = true;
939
        }
940
        if (state.hasValue(LAYER_SYNC_FIELD)) {
941
                syncLayers = state.getBoolean(LAYER_SYNC_FIELD);
942
        }
943
        else {
944
                syncLayers = true;
945
        }
946
        Double layoutScale = null;
947
        if (state.hasValue(SCALE_FIELD)) {
948
                layoutScale = state.getDouble(SCALE_FIELD);
949
        }
950
            Envelope envelope = (Envelope) state.get(ENVELOPE_FIELD);
951

    
952
        if (state.hasValue(SCALE_TYPE_FIELD)) {
953
                int value = state.getInt(SCALE_TYPE_FIELD);
954
                if (value==SCALE_TYPE.FIXED_EXTENT.ordinal()) {
955
                        scaleType = SCALE_TYPE.FIXED_EXTENT;
956
                        fixedExtent = envelope;
957
                }
958
                else if (value==SCALE_TYPE.FIXED_SCALE.ordinal()) {
959
                        scaleType = SCALE_TYPE.FIXED_SCALE;
960
                        fixedScale = layoutScale;
961
                }
962
                // else use the default value
963
        }
964
        quality = state.getInt(QUALITY_FIELD);
965
        mapUnits = state.getInt(MAPUNITS_FIELD);
966
        if (state.hasValue(HAS_TOC_FIELD)) {
967
                this.b_hasToc = state.getBoolean(HAS_TOC_FIELD);
968
        }
969

    
970
        // When copying and pasting layout documents (in project manager), the view
971
        // is first persisted (copy action) and then re-created from persistence (paste action).
972
        // This is a problem, as the re-created view is not the same view as the original one
973
        // and thus layout stops being synchronized with the right view.
974
        // Therefore, we try to get first the "live" view if available, and get the persisted
975
        // one otherwise, which will be used when opening projects.
976
        ViewDocument persistenceView = (ViewDocument) state.get(VIEW_FIELD);
977
        if (persistenceView!= null) {
978
                ViewDocument view = (ViewDocument) ProjectManager.getInstance().getCurrentProject().getDocument(persistenceView.getName(), persistenceView.getTypeName());
979
                if (view==null) {
980
                        view = persistenceView;
981
                }
982
                this.setView(view);
983
                // it is crucial to don't persist the MapContext and get a cloned one from the View instead,
984
                // as the cloned instance is different from the one created using persistence. In particular,
985
                // the cloned one will share the EventBuffer with the original one, while persistence would
986
                // create 2 separate EventBuffers, which will then have a very stange behaviour
987
        }
988
        if (getMapContext()!=null) {
989
                if (layoutScale!=null) {
990
                        getMapContext().setScaleView(layoutScale.longValue());
991
                }
992
                getMapContext().getViewPort().setEnvelope(envelope);
993
                if (this.getLayoutContext()!=null) {
994
                        this.getLayoutContext().setTocModel(getMapContext());
995
                }
996

    
997
        }
998
        showGrid = state.getBoolean(SHOWGRID_FIELD);
999
        grid = (IFFrame) state.get(GRID_FIELD);
1000
    }
1001

    
1002
    @Override
1003
    public void saveToState(PersistentState state) throws PersistenceException {
1004
        super.saveToState(state);
1005
        state.set(EXTENT_SYNC_FIELD, syncExtents);
1006
        state.set(LAYER_SYNC_FIELD, syncLayers);
1007
        state.set(QUALITY_FIELD, quality);
1008
        state.set(MAPUNITS_FIELD, mapUnits);
1009
        state.set(VIEW_FIELD, viewDocument);
1010
        state.set(HAS_TOC_FIELD, b_hasToc);
1011
        state.set(SCALE_TYPE_FIELD, scaleType.ordinal());
1012

    
1013
        if (getMapContext() != null
1014
            && getMapContext().getViewPort().getEnvelope() != null) {
1015
                if (scaleType==SCALE_TYPE.FIXED_SCALE) {
1016
                        if (fixedScale==null) {
1017
                                fixedScale = new Double(getMapContext().getScaleView());
1018
                        }
1019
                        state.set(SCALE_FIELD, (double)fixedScale);
1020
                }
1021
                else {
1022
                        state.set(SCALE_FIELD, (double)getMapContext().getScaleView());
1023
                }
1024
                if (scaleType == SCALE_TYPE.FIXED_EXTENT) {
1025
                        if (fixedExtent==null) {
1026
                                fixedExtent = getMapContext().getViewPort().getAdjustedEnvelope();
1027
                        }
1028
                        state.set(ENVELOPE_FIELD, fixedExtent);
1029
                }
1030
                else {
1031
                        state.set(ENVELOPE_FIELD, getMapContext().getViewPort()
1032
                        .getAdjustedEnvelope());
1033
                }
1034
        }
1035

    
1036
        state.set(SHOWGRID_FIELD, showGrid);
1037
        state.set(GRID_FIELD, grid);
1038
    }
1039

    
1040
    @Override
1041
    public void setBoundBox(Rectangle2D r) {
1042
            super.setBoundBox(r);
1043
            if (this.getMapContext()!=null && this.getLayoutContext()!=null) {
1044
                    AffineTransform at = this.getLayoutContext().getAT();
1045
                    long scale = getMapContext().getScaleView();
1046
                    getMapContext().getViewPort().setImageSize(
1047
                                    new Dimension((int)getBoundingBox(at).getWidth(), (int)getBoundingBox(at).getHeight()));
1048
                    getMapContext().getViewPort().setDPI(getDrawPaperDPI());
1049
                    if (getScaleType()==SCALE_TYPE.FIXED_SCALE) {
1050
                            getMapContext().setScaleView((long) scale);
1051
                    }
1052
                    updateScaleCtrl();
1053
                    refresh();
1054
            }
1055
    }
1056

    
1057
    /**
1058
     * Gets the rotation of the frame
1059
     *
1060
     * @return Rotation in degrees
1061
     */
1062
    public double getMapRotation() {
1063
        return 0;
1064
    }
1065

    
1066
        protected void invalidateLayout() {
1067
                b_validCache = false;
1068
                if (getLayoutContext()!=null) {
1069
                        getLayoutContext().notifAllObservers();
1070
                }
1071
        observers.notifyObservers(this,
1072
                new DefaultLayoutNotification(LayoutNotification.LAYOUT_REFRESH));
1073
        }
1074

    
1075
        protected void invalidateToc() {
1076
                if (getLayoutContext()!=null) {
1077
                        getLayoutContext().notifyTocUpdated(TocModelChangedNotification.Type.ITEM_UPDATED);
1078
                }
1079
        }
1080

    
1081
        protected void refreshToc() {
1082
                if (getLayoutContext()!=null) {
1083
                        getLayoutContext().notifyTocUpdated(TocModelChangedNotification.Type.MODEL_CHANGED);
1084
                }
1085
        }
1086

    
1087
        public void refresh() {
1088
                // force re-creating the cache on the next drawing cycle
1089
                b_validCache = false;
1090
        }
1091

    
1092
    protected void resetListeners() {
1093
                if (this.getMapContext()!=null) {
1094
                        clearOwnListeners(this.getMapContext());
1095
                }
1096
                if (this.getView()!=null && this.getView().getMapContext()!=null) {
1097
                        clearViewListeners(this.getView().getMapContext());
1098
                }
1099
            setListeners();
1100
    }
1101

    
1102
    protected void setListeners() {
1103
            if (getView()!=null) {
1104
                    if (syncLayers) {
1105
                            getView().getMapContext().addLayerListener(viewDocListener);
1106
                            getView().getMapContext().getLayers().addLayerCollectionListener(viewDocListener);
1107
                            getView().getMapContext().addAtomicEventListener(viewDocListener);
1108
                    }
1109
                    if (getExtentSynced()) {
1110
                            getView().getMapContext().getViewPort().addViewPortListener(viewDocListener);
1111
                    }
1112
            }
1113
            if (getMapContext()!=null) {
1114
                    getMapContext().addLayerListener(ownMapContextListener);
1115
                    getMapContext().getLayers().addLayerCollectionListener(ownMapContextListener);
1116
                    getMapContext().getViewPort().addViewPortListener(ownMapContextListener);
1117
            }
1118
    }
1119
    protected void clearOwnListeners(MapContext mapContext) {
1120
            mapContext.removeLayerListener(ownMapContextListener);
1121
            mapContext.getViewPort().removeViewPortListener(ownMapContextListener);
1122
            mapContext.getLayers().removeLayerCollectionListener(ownMapContextListener);
1123
    }
1124
    protected void clearViewListeners(MapContext mapContext) {
1125
            mapContext.removeLayerListener(viewDocListener);
1126
            mapContext.getViewPort().removeViewPortListener(viewDocListener);
1127
            mapContext.getLayers().removeLayerCollectionListener(viewDocListener);
1128
            mapContext.removeAtomicEventListener(viewDocListener);
1129
    }
1130

    
1131
    /*
1132
     * (non-Javadoc)
1133
     * @see org.gvsig.tools.dispose.Disposable#dispose()
1134
     */
1135
        public void dispose() {
1136
                try {
1137
                        if (this.getMapContext()!=null) {
1138
                                clearOwnListeners(this.getMapContext());
1139
                        }
1140
                        if (this.getView()!=null && this.getView().getMapContext()!=null) {
1141
                                clearViewListeners(this.getView().getMapContext());
1142
                        }
1143
                }
1144
                catch (Exception ex) {}
1145
                this.viewDocument = null;
1146
                this.mapContext = null;
1147
        }
1148

    
1149
        public void frameRemoved() {
1150
                if (mapContext!=null) {
1151
                        clearOwnListeners(mapContext);
1152
                }
1153
                if (this.getView()!=null && this.getView().getMapContext()!=null) {
1154
                        clearViewListeners(this.getView().getMapContext());
1155
                }
1156
                if (b_hasToc && getLayoutContext()!=null) {
1157
                        getLayoutContext().setTocModel(null);
1158
                }
1159
                m_image = null; // FIXME: we could instead move it to a LRU cache to keep the last N images
1160
        }
1161

    
1162
        public void frameAdded() {
1163
                setListeners();
1164
                setTocModel();
1165
                updateScaleCtrl();
1166
        }
1167

    
1168
        public void setHasToc(boolean hasToc) {
1169
                this.b_hasToc = hasToc;
1170
                setTocModel();
1171
        }
1172

    
1173
        protected void setTocModel() {
1174
                if (getLayoutContext()!=null) {
1175
                        if (b_hasToc && getMapContext()!=null) {
1176
                                getLayoutContext().setTocModel(getMapContext());
1177
                        }
1178
                        else {
1179
                                getLayoutContext().setTocModel(null);
1180
                        }
1181
                }
1182
        }
1183

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

    
1194
        public boolean getLayerSynced() {
1195
                return syncLayers;
1196
        }
1197

    
1198
        public void setLayerSynced(boolean synced) {
1199
        syncLayers = synced;
1200
        resetListeners();
1201
        }
1202

    
1203
        public boolean getExtentSynced() {
1204
                return syncExtents;
1205
        }
1206

    
1207
        public void setExtentSynced(boolean synced) {
1208
                syncExtents = synced;
1209
        resetListeners();
1210
        }
1211

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

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

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

    
1253
                                double minX = envelope.getMinimum(0) + shiftX;
1254
                                double minY = envelope.getMinimum(1) + shiftY;
1255
                                double maxX = envelope.getMaximum(0) + shiftX;
1256
                                double maxY = envelope.getMaximum(1) + shiftY;
1257

    
1258
                                return GeometryLocator.getGeometryManager().createEnvelope(minX, minY, maxX, maxY, SUBTYPES.GEOM2D);
1259
                        }
1260
                }
1261
                catch (LocatorException e) {}
1262
                catch (CreateEnvelopeException e) {}
1263
                return newEnvelope;
1264
        }
1265

    
1266
        private class ViewDocListener
1267
        implements ViewPortListener, LegendListener, LayerCollectionListener, AtomicEventListener {
1268

    
1269
                public void extentChanged(ExtentEvent e) {
1270
                        if (!b_updating && getExtentSynced()) {
1271
                                if (!b_frameInitialized) {
1272
                                        b_frameInitialized = true;
1273
                                        return;
1274
                                }
1275
                                b_updating = true;
1276
                                if (getMapContext()!=null) {
1277
                                        if (scaleType==SCALE_TYPE.FIXED_EXTENT) {
1278
                                                getView().getMapContext().getViewPort().setEnvelope(fixedExtent);
1279
                                        }
1280
                                        else {
1281
                                                getMapContext().getViewPort().setEnvelope(calculateNewExtent());
1282
                                                if (scaleType==SCALE_TYPE.FIXED_SCALE) {
1283
                                                        getMapContext().setScaleView(Math.round(fixedScale));
1284
                                                        getView().getMapContext().getViewPort().setEnvelope(getMapContext().getViewPort().getAdjustedEnvelope());
1285
                                                }
1286
                                                updateScaleCtrl();
1287
                                                invalidateLayout();
1288
                                        }
1289
                                }
1290
                                b_updating = false;
1291
                        }
1292
                }
1293

    
1294
                public void backColorChanged(ColorEvent e) {
1295
                        if (!b_updating && syncLayers) {
1296
                                if (getMapContext()!=null) {
1297
                                        b_updating = true;
1298
                                        mapContext.getViewPort().setBackColor(e.getNewColor());
1299
                                        invalidateLayout();
1300
                                        b_updating = true;
1301
                                }
1302
                        }
1303
                }
1304

    
1305
                public void projectionChanged(ProjectionEvent e) {
1306
                        if (!b_updating && getExtentSynced()) {
1307
                                if (getMapContext()!=null) {
1308
                                        b_updating = true;
1309
                                        getMapContext().getViewPort().setProjection(e.getNewProjection());
1310
                                        invalidateLayout();
1311
                                        // FIXME: force also a view redraw someway??
1312
                                        b_updating = false;
1313
                                }
1314
                        }
1315
                }
1316

    
1317
                public void conditionalRedraw() {
1318
                        if (!b_updating && syncLayers) {
1319
                                b_updating = true;
1320
                                invalidateLayout();
1321
                                // the view should also receive the event and update automatically
1322
                                b_updating = false;
1323
                        }
1324
                }
1325

    
1326
                public void legendChanged(LegendChangedEvent e) {
1327
                        conditionalRedraw();
1328
                        refreshToc();
1329
                }
1330

    
1331
                public void layerAdded(LayerCollectionEvent e) {
1332
                        conditionalRedraw();
1333
                        // no need to invalidate the toc as it is down by the OwnMapContextListener
1334
                }
1335

    
1336
                public void layerMoved(LayerPositionEvent e) {
1337
                        conditionalRedraw();
1338
                        // no need to invalidate the toc as it is down by the OwnMapContextListener
1339
                }
1340

    
1341
                public void layerRemoved(LayerCollectionEvent e) {
1342
                        conditionalRedraw();
1343
                        // no need to invalidate the toc as it is down by the OwnMapContextListener
1344
                }
1345

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

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

    
1356
                public void layerRemoving(LayerCollectionEvent e)
1357
                                throws CancelationException {
1358
                        // nothing needed
1359
                }
1360

    
1361
                public void visibilityChanged(LayerCollectionEvent e)
1362
                                throws CancelationException {
1363
                        // AtomicEvent is catching visibility changes instead of this one,
1364
                        // as this event is not being received. Maybe is only triggered if the
1365
                        // visibility of the whole group changes??
1366
                        conditionalRedraw();
1367
                        invalidateToc();
1368
                }
1369

    
1370
                public void atomicEvent(AtomicEvent e) {
1371
                        boolean layoutRedraw = false;
1372
                        // not all the events require a fframeview redraw
1373
                        for (int i=e.getLayerEvents().length-1; i>=0; i--) {
1374
                                FMapEvent at = e.getEvent(i);
1375
                                if (at instanceof LayerEvent) {
1376
                                        if (at.getEventType()==LayerEvent.DRAW_VALUES_CHANGED) {
1377
                                                layoutRedraw = true;
1378
                                                break;
1379
                                        }
1380
                                }
1381
                        }
1382
                        if (layoutRedraw) {
1383
                                conditionalRedraw();
1384
                        }
1385
                        invalidateToc();
1386
                }
1387
        }
1388

    
1389
        private class OwnMapContextListener
1390
                implements ViewPortListener, LegendListener, LayerCollectionListener {
1391

    
1392
                public void extentChanged(ExtentEvent e) {
1393
                        if (!b_drawing && !b_updating) {
1394
                                b_updating = true;
1395
                                if (scaleType==SCALE_TYPE.FIXED_EXTENT) {
1396
                                        getMapContext().getViewPort().setEnvelope(fixedExtent);
1397
                                }
1398
                                else {
1399
                                        Envelope newEnvelope;
1400
                                        if (scaleType==SCALE_TYPE.FIXED_SCALE && fixedScale!=null) {
1401
                                                getMapContext().setScaleView(Math.round(fixedScale));
1402
                                                newEnvelope = getMapContext().getViewPort().getAdjustedEnvelope();
1403
                                        }
1404
                                        else {
1405
                                                newEnvelope = e.getNewExtent();
1406
                                        }
1407
                                        if (getView()!=null) {
1408
                                                if (getExtentSynced()){
1409
                                                        getView().getMapContext().getViewPort().setEnvelope(newEnvelope);
1410
                                                }
1411
                                        }
1412
                                }
1413
                                updateScaleCtrl();
1414
                                invalidateLayout();
1415
                                b_updating = false;
1416
                        }
1417
                }
1418

    
1419
                public void backColorChanged(ColorEvent e) {
1420
                        if (!b_updating) {
1421
                                if (getView()!=null) {
1422
                                        b_updating = true;
1423
                                        if (getLayerSynced()) {
1424
                                                getView().getMapContext().getViewPort().setBackColor(e.getNewColor());
1425
                                        }
1426
                                        invalidateLayout();
1427
                                        b_updating = false;
1428
                                }
1429
                        }
1430
                }
1431

    
1432
                public void projectionChanged(ProjectionEvent e) {
1433
                        if (!b_updating && getExtentSynced()) {
1434
                                if (getView()!=null) {
1435
                                        b_updating = true;
1436
                                        if (getLayerSynced()) {
1437
                                                getView().getMapContext().getViewPort().setProjection(e.getNewProjection());
1438
                                        }
1439
                                        invalidateLayout();
1440
                                        // FIXME: force also a view redraw someway??
1441
                                        b_updating = false;
1442
                                }
1443
                        }
1444
                }
1445

    
1446
                public void conditionalRedraw() {
1447
                        if (!b_updating) {
1448
                                b_updating = true;
1449
                                invalidateLayout();
1450
                                // the view should also receive the event and update automatically
1451
                                b_updating = false;
1452
                        }
1453
                }
1454

    
1455
                public void legendChanged(final LegendChangedEvent e) {
1456
                        conditionalRedraw();
1457
                        refreshToc();
1458
                }
1459

    
1460
                public void layerAdded(final LayerCollectionEvent e) {
1461
                        // necessary to set an envelope when the first layer is added
1462
                        if (!b_updating && getMapContext().getViewPort().getEnvelope()==null) {
1463
                                try {
1464
                                        b_updating = true;
1465
                                        fullExtent();
1466

    
1467
                                } catch (ReadException e1) {
1468
                                } finally {
1469
                                        b_updating = false;
1470
                                }
1471
                        }
1472
                        conditionalRedraw();
1473
                        refreshToc();
1474
                }
1475

    
1476
                public void layerMoved(final LayerPositionEvent e) {
1477
                        conditionalRedraw();
1478
                        refreshToc();
1479
                }
1480

    
1481
                public void layerRemoved(final LayerCollectionEvent e) {
1482
                        conditionalRedraw();
1483
                        refreshToc();
1484
                }
1485

    
1486
                public void layerAdding(LayerCollectionEvent e)
1487
                                throws CancelationException {
1488
                        // nothing neededO
1489

    
1490
                }
1491

    
1492
                public void layerMoving(LayerPositionEvent e)
1493
                                throws CancelationException {
1494
                        // nothing needed
1495

    
1496
                }
1497

    
1498
                public void layerRemoving(LayerCollectionEvent e)
1499
                                throws CancelationException {
1500
                        // nothing needed
1501

    
1502
                }
1503

    
1504
                public void visibilityChanged(LayerCollectionEvent e)
1505
                                throws CancelationException {
1506
                        conditionalRedraw();
1507
                }
1508
        }
1509

    
1510
        public void setExtent(Envelope extent) {
1511
                if (getScaleType()==SCALE_TYPE.NORMAL) {
1512
                        getMapContext().getViewPort().setEnvelope(extent);
1513
                }
1514
        }
1515

    
1516
        public SCALE_TYPE getScaleType() {
1517
                return scaleType ;
1518
        }
1519

    
1520
        public void setScaleType(SCALE_TYPE scaleType) {
1521
                this.scaleType = scaleType;
1522
        }
1523

    
1524
        public void setScaleType(SCALE_TYPE scaleType, double fixedScale) {
1525
                if (scaleType == SCALE_TYPE.FIXED_SCALE) {
1526
                        this.scaleType = scaleType;
1527
                        this.fixedScale = new Double(fixedScale);
1528
                        setScale(fixedScale);
1529
                }
1530
        }
1531

    
1532
        public void setScaleType(SCALE_TYPE scaleType, Envelope fixedExtent) {
1533
                if (scaleType == SCALE_TYPE.FIXED_EXTENT) {
1534
                        this.scaleType = scaleType;
1535
                        this.fixedExtent  = fixedExtent;
1536
                        setNewEnvelope(fixedExtent);
1537
                }
1538
        }
1539

    
1540
        @Deprecated
1541
        public int getTypeScale() {
1542
                return AUTOMATICO;
1543
        }
1544

    
1545
        @Deprecated
1546
        public void setLinked(boolean b) {}
1547

    
1548
        @Deprecated
1549
        public boolean getLinked() {
1550
                return false;
1551
        }
1552

    
1553
        public void windowActivated() {
1554
                if (isSelected()
1555
                                && getLayoutContext().getSelectedFFrames(IFFrameUseFMap.class).length==1) {
1556
                        // update the scale control whenever the panel window gets activated,
1557
                        // as the control instance is shared for all the windows
1558
                        updateScaleCtrl();
1559
                }
1560

    
1561
        }
1562

    
1563
        public void windowClosed() {
1564
        }
1565
}