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

History | View | Annotate | Download (50.5 KB)

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