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 / FFrame.java @ 308

History | View | Annotate | Download (30.3 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.Font;
27
import java.awt.Graphics2D;
28
import java.awt.Image;
29
import java.awt.Rectangle;
30
import java.awt.event.MouseEvent;
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.gvsig.andami.PluginServices;
39
import org.gvsig.andami.ui.mdiManager.IWindowListener;
40
import org.gvsig.app.project.ProjectManager;
41
import org.gvsig.app.project.documents.Document;
42
import org.gvsig.app.project.documents.layout.Attributes;
43
import org.gvsig.app.project.documents.layout.DefaultLayoutManager;
44
import org.gvsig.app.project.documents.layout.FLayoutUtilities;
45
import org.gvsig.app.project.documents.layout.LayoutContext;
46
import org.gvsig.app.project.documents.layout.LayoutDocument;
47
import org.gvsig.app.project.documents.layout.LayoutManager;
48
import org.gvsig.tools.ToolsLocator;
49
import org.gvsig.tools.dynobject.DynStruct;
50
import org.gvsig.tools.observer.ObservableHelper;
51
import org.gvsig.tools.observer.Observer;
52
import org.gvsig.tools.persistence.PersistenceManager;
53
import org.gvsig.tools.persistence.PersistentState;
54
import org.gvsig.tools.persistence.exception.PersistenceException;
55
import org.slf4j.Logger;
56
import org.slf4j.LoggerFactory;
57

    
58
/**
59
 * Class implementing the IFFrame interface, that will be extended by all the
60
 * FFrames. It provides default methods useful for all fframes and abstract
61
 * methods to be implemented by them.
62
 * 
63
 * @author Vicente Caballero Navarro
64
 * @author Cesar Martinez Izquierdo
65
 */
66
public abstract class FFrame implements IFFrame {
67

    
68
    public static final String PERSISTENCE_DEFINITION_NAME = "FFrame";
69

    
70
    private static final String BOUNDINGBOX_FIELD = "boundingBox";
71
    private static final String SELECTED_FIELD = "selected";
72
    private static final String TAG_FIELD = "tag";
73
    private static final String ROTATION_FIELD = "rotation";
74
    private static final String LEVEL_FIELD = "level";
75
    private static final String NUM_FIELD = "num";
76
        private static final String DOCUMENT_FIELD = "layoutDocument";
77
        private static final String LAYOUT_CONTEXT_FIELD = "layoutContext";
78

    
79
    protected static final Logger LOG = LoggerFactory.getLogger(FFrame.class);
80

    
81
    protected Rectangle2D.Double m_BoundBox = new Rectangle2D.Double();
82
    // initially identity
83
    protected AffineTransform lastAT = AffineTransform.getShearInstance(0,0);
84
    // private Rectangle2D.Double m_BoundingBox = new Rectangle2D.Double();
85
    
86
    protected int m_Selected = 0;
87
    protected Rectangle n = new Rectangle();
88
    protected Rectangle ne = new Rectangle();
89
    protected Rectangle e = new Rectangle();
90
    protected Rectangle se = new Rectangle();
91
    protected Rectangle s = new Rectangle();
92
    protected Rectangle so = new Rectangle();
93
    protected Rectangle o = new Rectangle();
94
    protected Rectangle no = new Rectangle();
95
    private String tag = null;
96
    protected int num = 0;
97
    private double m_rotation = 0;
98
    private int level = -1;
99
    private Rectangle2D lastMoveRect;
100
    protected FrameFactory frameFactory;
101

    
102
    private static Image iNEResize = null;
103
    private static Image iEResize = null;
104
    private static Image iNResize = null;
105
    private static Image iMove = null;
106
    private static Image iSEResize = null;
107

    
108
    protected LayoutManager layoutManager = null;
109
    // user getters to access these variables:
110
    private LayoutContext layoutContext = null;
111
    private Document document = null;
112
        
113
    protected ObservableHelper observers;
114
    
115
    public FFrame() {
116
        super();
117
        layoutManager =
118
            (LayoutManager) ProjectManager.getInstance().getDocumentManager(
119
                DefaultLayoutManager.TYPENAME);
120
        observers = new ObservableHelper();
121
    }
122

    
123
    /**
124
     * Dibuja los handlers sobre el boundingBox en el graphics que se pasa como
125
     * par�metro.
126
     * 
127
     * @param g
128
     *            Graphics sobre el que dibujar.
129
     */
130
    public void drawHandlers(Graphics2D g) {
131
        int size = 10;
132
        Rectangle2D r = getBoundingBox(null);
133
        Point2D p = new Point2D.Double();
134
        g.rotate(Math.toRadians(getRotation()), r.getX() + (r.getWidth() / 2),
135
            r.getY() + (r.getHeight() / 2));
136

    
137
        AffineTransform atRotate = new AffineTransform();
138
        atRotate.rotate(Math.toRadians(getRotation()), r.getX()
139
            + (r.getWidth() / 2), r.getY() + (r.getHeight() / 2));
140

    
141
        g.fillRect((int) r.getX() - size, (int) r.getY() - size, size, size);
142
        atRotate.transform(
143
            new Point2D.Double(r.getX() - size, r.getY() - size), p);
144
        no.setRect((int) p.getX(), (int) p.getY(), size, size);
145

    
146
        g.fillRect((int) r.getMaxX(), (int) r.getY() - size, size, size);
147
        atRotate.transform(new Point2D.Double(r.getMaxX(), r.getY() - size), p);
148
        ne.setRect((int) p.getX(), (int) p.getY(), size, size);
149

    
150
        g.fillRect((int) r.getX() - size, (int) r.getMaxY(), size, size);
151
        atRotate.transform(new Point2D.Double(r.getX() - size, r.getMaxY()), p);
152
        so.setRect((int) p.getX(), (int) p.getY(), size, size);
153

    
154
        g.fillRect((int) r.getMaxX(), (int) r.getMaxY(), size, size);
155
        atRotate.transform(new Point2D.Double(r.getMaxX(), r.getMaxY()), p);
156
        se.setRect((int) p.getX(), (int) p.getY(), size, size);
157

    
158
        g.fillRect((int) r.getCenterX() - (size / 2), (int) r.getY() - size,
159
            size, size);
160
        atRotate
161
            .transform(new Point2D.Double(r.getCenterX() - (size / 2), r.getY()
162
                - size), p);
163
        n.setRect((int) p.getX(), (int) p.getY(), size, size);
164

    
165
        g.fillRect((int) r.getCenterX() - (size / 2), (int) r.getMaxY(), size,
166
            size);
167
        atRotate.transform(
168
            new Point2D.Double(r.getCenterX() - (size / 2), r.getMaxY()), p);
169
        s.setRect((int) p.getX(), (int) p.getY(), size, size);
170

    
171
        g.fillRect((int) r.getX() - size, (int) r.getCenterY() - (size / 2),
172
            size, size);
173
        atRotate.transform(new Point2D.Double(r.getX() - size, r.getCenterY()
174
            - (size / 2)), p);
175
        o.setRect((int) p.getX(), (int) p.getY(), size, size);
176

    
177
        g.fillRect((int) r.getMaxX(), (int) r.getCenterY() - (size / 2), size,
178
            size);
179
        atRotate.transform(new Point2D.Double(r.getMaxX(), r.getCenterY()
180
            - (size / 2)), p);
181
        e.setRect((int) p.getX(), (int) p.getY(), size, size);
182
        g.rotate(Math.toRadians(-getRotation()), r.getX() + (r.getWidth() / 2),
183
            r.getY() + (r.getHeight() / 2));
184
    }
185

    
186
    /**
187
     * Sets the type of selection performed on the frame, based on the position
188
     * of the provided Point compared with the boundaries of the FFrame.
189
     * This method is usually called when the user clicks on the FFrame
190
     * 
191
     * @param p
192
     *            Point which should be evaluated to establish if the FFrame must
193
     *            be selected or not
194
     * @param e   Mouse event that triggered this method call
195
     * @see {@link #isSelected()}, {@link #getSelected()}
196
     */
197
    public void setSelected(Point2D p, MouseEvent e) {
198
        doSetSelected(getContains(p));
199
    }
200

    
201
    /**
202
     * Actualiza el BoundBox del FFrame a partir de su rect�ngulo en pixels y
203
     * la matriz de transformaci�n.
204
     * 
205
     * @param r
206
     *            Rect�ngulo.
207
     * @param at
208
     *            Matriz de transformaci�n.
209
     */
210
    public void updateRect(Rectangle2D r, AffineTransform at) {
211
        Rectangle2D.Double rec = FLayoutUtilities.toSheetRect(r, at);
212
        rec.setRect((int) rec.getMinX(), (int) rec.getMinY(),
213
            (int) rec.getWidth(), (int) rec.getHeight());
214
        setBoundBox(rec);
215
    }
216

    
217
    /**
218
     * Devuelve el rect�ngulo a partir del desplazamiento en el eje x y el
219
     * desplazamiento en el eje y.
220
     * 
221
     * @param difx
222
     *            desplazamiento sobre el eje x.
223
     * @param dify
224
     *            desplazamiento sobre el eje y.
225
     * 
226
     * @return rect�ngulo modificado en funci�n del desplazamiento
227
     *         realizado.
228
     */
229
    public Rectangle2D getMovieRect(int difx, int dify) {
230
        double x = 0;
231
        double y = 0;
232
        double w = 0;
233
        double h = 0;
234

    
235
        lastMoveRect =
236
            new Rectangle2D.Double(this.getBoundingBox(null).x,
237
                this.getBoundingBox(null).y, this.getBoundingBox(null).width,
238
                this.getBoundingBox(null).height);
239
        Rectangle2D.Double rec = this.getBoundingBox(null);
240
        int difn = 0;
241
        difn = difx;
242
        x = lastMoveRect.getX();
243
        y = lastMoveRect.getY();
244
        w = lastMoveRect.getWidth();
245
        h = lastMoveRect.getHeight();
246

    
247
        switch (this.getSelected()) {
248
        case (RECT):
249
            lastMoveRect.setRect((x + difx), (y + dify), w, h);
250

    
251
            break;
252

    
253
        case (N):
254

    
255
            if ((y + dify) > rec.getMaxY()) {
256
                y = rec.getMaxY();
257
            } else {
258
                y = y + dify;
259
            }
260

    
261
            lastMoveRect.setRect(x, y, w, Math.abs(h - dify));
262

    
263
            break;
264

    
265
        case (O):
266

    
267
            if ((x + difx) > rec.getMaxX()) {
268
                x = rec.getMaxX();
269
            } else {
270
                x = x + difx;
271
            }
272

    
273
            lastMoveRect.setRect(x, y, Math.abs(w - difx), h);
274

    
275
            break;
276

    
277
        case (S):
278

    
279
            if (y > (rec.getMaxY() + dify)) {
280
                y = rec.getMaxY() + dify;
281
            }
282

    
283
            lastMoveRect.setRect(x, y, w, Math.abs(h + dify));
284

    
285
            break;
286

    
287
        case (E):
288

    
289
            if (x > (rec.getMaxX() + difx)) {
290
                x = rec.getMaxX() + difx;
291
            }
292

    
293
            lastMoveRect.setRect(x, y, Math.abs(w + difx), h);
294

    
295
            break;
296

    
297
        case (NE):
298

    
299
            if ((y - difn) > rec.getMaxY()) {
300
                y = rec.getMaxY();
301
                x = rec.getMaxX() + difn;
302
            } else {
303
                y = y - difn;
304
            }
305

    
306
            lastMoveRect.setRect(x, y, Math.abs(w + difn), Math.abs(h + difn));
307

    
308
            break;
309

    
310
        case (NO):
311

    
312
            if ((y + difn) > rec.getMaxY()) {
313
                y = rec.getMaxY();
314
                x = rec.getMaxX();
315
            } else {
316
                x = x + difn;
317
                y = y + difn;
318
            }
319

    
320
            lastMoveRect.setRect(x, y, Math.abs(w - difn), Math.abs(h - difn));
321

    
322
            break;
323

    
324
        case (SE):
325

    
326
            if (y > (rec.getMaxY() + difn)) {
327
                y = rec.getMaxY() + difn;
328
                x = rec.getMaxX() + difn;
329
            }
330

    
331
            lastMoveRect.setRect(x, y, Math.abs(w + difn), Math.abs(h + difn));
332

    
333
            break;
334

    
335
        case (SO):
336

    
337
            if ((x + difn) > rec.getMaxX()) {
338
                x = rec.getMaxX();
339
                y = rec.getMaxY() - difn;
340
            } else {
341
                x = x + difn;
342
            }
343

    
344
            lastMoveRect.setRect(x, y, Math.abs(w - difn), Math.abs(h - difn));
345

    
346
            break;
347

    
348
        default:
349
            lastMoveRect.setRect((x), (y), w, h);
350
        }
351

    
352
        return lastMoveRect;
353
    }
354

    
355
    /**
356
     * Devuelve el rect�ngulo que representa el �ltimo generado al desplazar
357
     * o modificar el tama�o del fframe.
358
     * 
359
     * @return Rectangle2D
360
     * 
361
     */
362
    public Rectangle2D getLastMoveRect() {
363
        return lastMoveRect;
364
    }
365

    
366
    /**
367
     * Returns an integer representing the type of selection applied to the
368
     * FFrame. Valid values are:
369
     * {@link IFFrame#NOSELECT},
370
     * {@link IFFrame#NO}, {@link IFFrame#N}, {@link IFFrame#NE},
371
     * {@link IFFrame#O}, {@link IFFrame#RECT}, {@link IFFrame#E},
372
     * {@link IFFrame#SO}, {@link IFFrame#S}, {@link IFFrame#SE}.
373
     * 
374
     * @see {@link #isSelected()}, {@link #setSelected(boolean)}
375
     * @return The type of selection that has been applied
376
     */
377
    public int getSelected() {
378
        return m_Selected;
379
    }
380
    
381
    /**
382
     * Gets the selection status of the frame
383
     * 
384
     * @return <code>true</code> if the frame is selected,
385
     *    <code>false</code> otherwise
386
     * @see {@link #getSelected()}, {@link #setSelected(boolean)}
387
     */
388
    public boolean isSelected() {
389
            return getSelected()!=IFFrame.NOSELECT;
390
    }
391

    
392
    /**
393
     * Devuelve true, si el punto que se pasa como par�metro esta contenido
394
     * dentro del boundingbox del fframe.
395
     * 
396
     * @param p
397
     *            punto a comprobar.
398
     * 
399
     * @return true si el punto esta dentro del boundingbox.
400
     */
401
    public boolean contains(Point2D p) {
402
        return getBoundingBox(null).contains(p.getX(), p.getY());
403
    }
404

    
405
    /*
406
     * (non-Javadoc)
407
     * @see org.gvsig.app.project.documents.layout.fframes.IFFrame#getContains(Point2D)
408
     */
409
    public int getContains(Point2D p) {
410
            Point2D point = new Point2D.Double();
411
            AffineTransform rotationAT = getRotationAT();
412
            if (rotationAT!=null) {
413
                    // if the frame is rotated, we need to inversely rotate the point in order
414
                    // to decide whether it is contained or not in the non-rotated frame
415
                    try {
416
                                rotationAT.createInverse().transform(p, point);
417
                        } catch (NoninvertibleTransformException e1) {}
418
            }
419
            else {
420
                    point = p;
421
            }
422
        if (n.contains(point.getX(), point.getY())) {
423
            return N;
424
        } else
425
            if (ne.contains(point.getX(), point.getY())) {
426
                return NE;
427
            } else
428
                if (e.contains(point.getX(), point.getY())) {
429
                    return E;
430
                } else
431
                    if (se.contains(point.getX(), point.getY())) {
432
                        return SE;
433
                    } else
434
                        if (s.contains(point.getX(), point.getY())) {
435
                            return S;
436
                        } else
437
                            if (so.contains(point.getX(), point.getY())) {
438
                                return SO;
439
                            } else
440
                                if (o.contains(point.getX(), point.getY())) {
441
                                    return O;
442
                                } else
443
                                    if (no.contains(point.getX(), point.getY())) {
444
                                        return NO;
445
                                    } else
446
                                        if (getBoundingBox(null).contains(
447
                                            point.getX(), point.getY())) {
448
                                            return RECT;
449
                                        }
450

    
451
        return NOSELECT;
452
    }
453

    
454
    /**
455
     * Devuelve el Cursor adecuado seg�n como est� contenido el punto, si es
456
     * para desplazamiento, o cambio de tama�o.
457
     * 
458
     * @param p
459
     *            punto a comprobar.
460
     * 
461
     * @return Cursor adecuado a la posici�n.
462
     */
463
    public Image getMapCursor(Point2D p) {
464
        int select = getContains(p);
465

    
466
        switch (select) {
467
        case (N):
468
            return iNResize;
469

    
470
        case (NE):
471
            return iNEResize;
472

    
473
        case (E):
474
            return iEResize;
475

    
476
        case (SE):
477
            return iSEResize;
478

    
479
        case (S):
480
            return iNResize;
481

    
482
        case (SO):
483
            return iNEResize;
484

    
485
        case (O):
486
            return iEResize;
487

    
488
        case (NO):
489
            return iSEResize;
490

    
491
        case (RECT):
492
            return iMove;
493
        }
494

    
495
        return null;
496
    }
497

    
498
    /**
499
     * Draws the FFrame on the provided Graphics, according to the
500
     * provided affine transform and the visible rectangle. It has to
501
     * to be implemented by each FFrame, as each of them usually draws
502
     * diffently.
503
     * 
504
     * @param g Graphics2D
505
     * @param at Affine transform to translate sheet coordinates (in cm)
506
     *                                 to screen coordinates (in pixels)
507
     * @param visibleLayoutDocRect visible rectangle
508
     * @param imgBase Image used to speed up the drawing process
509
     */
510
    public abstract void draw(Graphics2D g, AffineTransform at, Rectangle2D r,
511
        BufferedImage imgBase);
512

    
513
    /**
514
     * Returns the bounding box (in pixels) of this FFrame, based on the provided
515
     * AffineTransform. If the AffineTransform is null, it returns the last
516
     * calculated bounding box.
517
     * 
518
     * @param at Affine transform to apply to the sheet coordinates to get the
519
     *                  bounding box in pixels.
520
     * @return Rectangle representing the bounding box (in pixels) of this
521
     * FFrame
522
     */
523
    public Rectangle2D.Double getBoundingBox(AffineTransform at) {
524
        if (at != null) {
525
            lastAT = (AffineTransform) at.clone();
526
        }
527
        return FLayoutUtilities.fromSheetRect(m_BoundBox, lastAT);
528
    }
529

    
530
    /**
531
     * Sets the bounding box in centimeters of this FFrame, using  paper
532
     * coordinates.
533
     * 
534
     * @param r
535
     *            Rectangle in centimeters
536
     */
537
    public void setBoundBox(Rectangle2D r) {
538
        if (r == null) {
539
            LOG.info("Warning: BBOX set to NULL in FFrame!");
540
            m_BoundBox = null;
541
        } else {
542
            m_BoundBox = new Rectangle2D.Double(r.getX(), r.getY(),
543
                r.getWidth(), r.getHeight());
544
        }
545
    }
546

    
547
    /**
548
     * Returns the bounding box in centimeters of this FFrame, using paper
549
     * coordinates
550
     * 
551
     * @return The bounding box of this FFrame, measured in centimeters.
552
     */
553
    public Rectangle2D.Double getBoundBox() {
554
        return m_BoundBox;
555
    }
556

    
557
    /**
558
     * Sets the selected status of the frame.
559
     * 
560
     * @param selected
561
     *            <code>true</code> to select the frame, <code>false</code> to
562
     *            unselect it
563
     * @see {@link #isSelected()}, {@link #getSelected()}
564
     */
565
    public void setSelected(boolean selected) {
566
        if (selected) {
567
                doSetSelected(IFFrame.RECT);
568
        } else {
569
                doSetSelected(IFFrame.NOSELECT);
570
        }
571
    }
572
    
573
    protected void doSetSelected(int selectedStatus) {
574
            m_Selected = selectedStatus;
575
    }
576

    
577
    /**
578
     * Dibuja sobre el graphics el rect�ngulo del fframe en modo borrador.
579
     * 
580
     * @param g
581
     *            Graphics so bre el que dibujar.
582
     */
583
    public void drawDraft(Graphics2D g) {
584
        Rectangle2D r = getBoundingBox(null);
585

    
586
        g.setColor(Color.lightGray);
587
        g.fillRect((int) r.getX(), (int) r.getY(), (int) r.getWidth(),
588
            (int) r.getHeight());
589
        g.setColor(Color.black);
590
        g.drawRect((int) r.getX(), (int) r.getY(), (int) r.getWidth() - 1,
591
            (int) r.getHeight() - 1);
592
        int scale = (int) (r.getWidth() / 12);
593
        Font f = new Font("SansSerif", Font.PLAIN, scale);
594
        g.setFont(f);
595
        g.drawString(getName(),
596
            (int) (r.getCenterX() - ((getName().length() * scale) / 4)),
597
            (int) (r.getCenterY()));
598
    }
599

    
600
    /**
601
     * Rellena con el n�mero de FFrame.
602
     * 
603
     * @param i
604
     *            n�mero
605
     */
606
    public void setNum(int i) {
607
        num = i;
608
    }
609

    
610
    /**
611
     * Draws the FFrame rectangle on the provided Graphics2D, only showing the
612
     * FFrame name on an empty rectangle.
613
     * 
614
     * @param g The graphics to draw on
615
     */
616
    public void drawEmpty(Graphics2D g) {
617
        Rectangle2D r = getBoundingBox(null);
618
        g.setColor(Color.lightGray);
619
        g.fillRect((int) r.getX(), (int) r.getY(), (int) r.getWidth(),
620
            (int) r.getHeight());
621
        g.setColor(Color.darkGray);
622
        g.setStroke(new BasicStroke(2));
623
        g.drawRect((int) r.getX(), (int) r.getY(), (int) r.getWidth(),
624
            (int) r.getHeight());
625
        g.setColor(Color.black);
626

    
627
        int scale = (int) (r.getWidth() / 12);
628
        Font f = new Font("SansSerif", Font.PLAIN, scale);
629
        g.setFont(f);
630

    
631
        String s =
632
            this.getNameFFrame() + " " + PluginServices.getText(this, "vacia");
633

    
634
        g.drawString(s, (int) (r.getCenterX() - ((s.length() * scale) / 4)),
635
            (int) (r.getCenterY()));
636
    }
637

    
638
    /**
639
     * Devuelve true si el rect�ngulo primero es null o si es distinto de null
640
     * e intersecta.
641
     * 
642
     * @param rv
643
     *            Rect�ngulo
644
     * @param r
645
     *            Rect�ngulo
646
     * 
647
     * @return True si intersecta o es null.
648
     */
649
    public boolean intersects(Rectangle2D rv, Rectangle2D r) {
650
        return (((rv != null) && rv.intersects(r)) || (rv == null));
651
    }
652

    
653
    /**
654
     * Rellena el tag del FFrame.
655
     * 
656
     * @param s
657
     *            String que representa el valor a guardar en el tag.
658
     */
659
    public void setTag(String s) {
660
        tag = s;
661
    }
662

    
663
    /**
664
     * Devuelve el tag.
665
     * 
666
     * @return tag.
667
     */
668
    public String getTag() {
669
        return tag;
670
    }
671

    
672
    /**
673
     * Dibuja sobre el graphics que se pasa como par�metro el icono que
674
     * representa que contiene un tag.
675
     * 
676
     * @param g
677
     *            Graphics sobre el que dibujar el icono.
678
     */
679
    public void drawSymbolTag(Graphics2D g) {
680
        Rectangle2D rec = getBoundingBox(null);
681
        g.rotate(Math.toRadians(getRotation()), rec.getX()
682
            + (rec.getWidth() / 2), rec.getY() + (rec.getHeight() / 2));
683

    
684
        try {
685
            Image image =
686
                PluginServices.getIconTheme().get("symboltag-icon").getImage();
687
            g.drawImage(image, (int) rec.getX(), (int) rec.getCenterY(), 30,
688
                30, null);
689
        } catch (NullPointerException npe) {
690
        }
691

    
692
        g.rotate(Math.toRadians(-getRotation()), rec.getX()
693
            + (rec.getWidth() / 2), rec.getY() + (rec.getHeight() / 2));
694
    }
695

    
696
    /**
697
     * Sets the rotation of the frame, measured in arc degrees
698
     * 
699
     * @param rotation
700
     *            Rotation to apply to the frame
701
     */
702
    public void setRotation(double rotation) {
703
        m_rotation = rotation;
704
    }
705
    
706
    /**
707
     * Gets the affine transform used to rotate the graphics when rotation is not 0
708
     * 
709
     * @return
710
     */
711
    protected AffineTransform getRotationAT() {
712
            // it has to be calculated each time as the frameRect may change, for instance
713
            // because a zoom in/out to paper has been performed
714
            double rotation = getRotation();
715
            if (getLayoutContext()!=null && getLayoutContext().getAT()!=null && Math.abs(rotation)>0.00001) {
716
                    AffineTransform rotationAT = new AffineTransform();
717
                Rectangle2D.Double frameRect = getBoundingBox(getLayoutContext().getAT());
718
                rotationAT.rotate(Math.toRadians(getRotation()), frameRect.getCenterX(), frameRect.getCenterY());
719
                return rotationAT;
720
            }
721
            return null;
722
    }
723

    
724
    /**
725
     * Gets the rotation of the frame, measured in arc degrees
726
     * 
727
     * @return Rotation of the frame
728
     */
729
    public double getRotation() {
730
        return m_rotation;
731
    }
732

    
733
    /**
734
     * Devuelve el nivel en el que se encuentra el FFrame.
735
     * 
736
     * @return nivel
737
     */
738
    public int getLevel() {
739
        return level;
740
    }
741

    
742
    /**
743
     * Inserta el nivel al que se encuentra el FFrame.
744
     * 
745
     * @param l
746
     *            entero que refleja el nivel del FFrame.
747
     */
748
    public void setLevel(int l) {
749
        level = l;
750
    }
751

    
752
    @Override
753
    public Object clone() throws CloneNotSupportedException {
754
        IFFrame frame = (IFFrame) super.clone();
755
        frame.setBoundBox(this.getBoundBox());
756
        return frame;
757
    }
758

    
759
    public void setFrameFactory(FrameFactory flf) {
760
        frameFactory = flf;
761
    }
762

    
763
    public FrameFactory getFrameFactory() {
764
        return frameFactory;
765
    }
766

    
767
    /**
768
     * Initilizes the static icons
769
     */
770
    public static void initializeIcons() {
771
        iNEResize =
772
            PluginServices.getIconTheme().get("neresize-icon").getImage();
773
        iEResize = PluginServices.getIconTheme().get("eresize-icon").getImage();
774
        iNResize = PluginServices.getIconTheme().get("nresize-icon").getImage();
775
        iMove = PluginServices.getIconTheme().get("graphic-move-icon").getImage();
776
        iSEResize =
777
            PluginServices.getIconTheme().get("sereresize-icon").getImage();
778
    }
779

    
780
    public static void registerPersistent() {
781
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
782
        if (manager.getDefinition(PERSISTENCE_DEFINITION_NAME) == null) {
783
            DynStruct definition =
784
                manager.addDefinition(FFrame.class,
785
                    PERSISTENCE_DEFINITION_NAME,
786
                    "FFrame persistence definition", null, null);
787

    
788
            definition.addDynFieldObject(BOUNDINGBOX_FIELD)
789
                .setClassOfValue(Rectangle2D.class).setMandatory(true);
790
            definition.addDynFieldInt(SELECTED_FIELD).setMandatory(true);
791
            definition.addDynFieldString(TAG_FIELD).setMandatory(false);
792
            definition.addDynFieldDouble(ROTATION_FIELD).setMandatory(true);
793
            definition.addDynFieldInt(LEVEL_FIELD).setMandatory(true);
794
            definition.addDynFieldInt(NUM_FIELD).setMandatory(true);
795
            definition.addDynFieldObject(DOCUMENT_FIELD).setClassOfValue(LayoutDocument.class).setMandatory(false);
796
            definition.addDynFieldObject(LAYOUT_CONTEXT_FIELD).setClassOfValue(LayoutContext.class).setMandatory(false);
797
        }
798

    
799
        Attributes.registerPersistent();
800
        AbstractFFrameViewDependence.registerPersistent();
801
        FFrameBasic.registerPersistent();
802
        FFrameGraphics.registerPersistent();
803
        FFrameSymbol.registerPersistent();
804
        FFrameGrid.registerPersistent();
805
        FFrameGroup.registerPersistent();
806
        FFrameTable.registerPersistent();
807
        FFrameLegend.registerPersistent();
808
        FFramePicture.registerPersistent();
809
        FFrameNorth.registerPersistent();
810
        FFrameScaleBar.registerPersistent();
811
        FFrameText.registerPersistent();
812
        FFrameView.registerPersistent();
813
        FFrameOverView.registerPersistent();
814
    }
815

    
816
    public void loadFromState(PersistentState state)
817
        throws PersistenceException {
818
        m_BoundBox = (Rectangle2D.Double) state.get(BOUNDINGBOX_FIELD);
819
        m_Selected = state.getInt(SELECTED_FIELD);
820
        tag = state.getString(TAG_FIELD);
821
        m_rotation = state.getDouble(ROTATION_FIELD);
822
        level = state.getInt(LEVEL_FIELD);
823
        num = state.getInt(NUM_FIELD);
824
        if (state.hasValue(DOCUMENT_FIELD)) {
825
                setDocument((LayoutDocument)state.get(DOCUMENT_FIELD ));
826
        }
827
        if (state.hasValue(LAYOUT_CONTEXT_FIELD)) {
828
                setLayoutContext((LayoutContext) state.get(LAYOUT_CONTEXT_FIELD));
829
        }
830
    }
831

    
832
    public void saveToState(PersistentState state) throws PersistenceException {
833
        state.set(BOUNDINGBOX_FIELD, getBoundBox());
834
        state.set(SELECTED_FIELD, m_Selected);
835
        state.set(TAG_FIELD, getTag());
836
        state.set(ROTATION_FIELD, getRotation());
837
        state.set(LEVEL_FIELD, getLevel());
838
        state.set(NUM_FIELD, num);
839
        state.set(DOCUMENT_FIELD, getDocument());
840
        state.set(LAYOUT_CONTEXT_FIELD, getLayoutContext());
841
    }
842

    
843
    public void addObserver(Observer o) {
844
        observers.addObserver(o);        
845
    }
846

    
847
    public void deleteObserver(Observer o) {
848
      observers.deleteObserver(o);        
849
    }
850

    
851
    public void deleteObservers() {
852
       observers.deleteObservers();        
853
    }
854
    
855
    /*
856
     * (non-Javadoc)
857
     * @see org.gvsig.tools.dispose.Disposable#dispose()
858
     */
859
        public void dispose() {
860
                
861
        }
862
        
863
    /*
864
     * (non-Javadoc)
865
     * @see org.gvsig.app.project.documents.layout.fframes.IFFrame#frameRemoved()
866
     */
867
        public void frameRemoved() {}
868
        
869
    /*
870
     * (non-Javadoc)
871
     * @see org.gvsig.app.project.documents.layout.fframes.IFFrame#frameAdded()
872
     */
873
        public void frameAdded() {}
874
        
875
        public LayoutContext getLayoutContext() {
876
                return layoutContext;
877
        }
878

    
879
        public void setLayoutContext(LayoutContext layoutContext) {
880
                this.layoutContext = layoutContext;
881
        }
882

    
883
        public Document getDocument() {
884
                return document;
885
        }
886

    
887
        public void setDocument(Document document) {
888
                this.document = document;
889
        }
890
        
891
    /**
892
     * Gets the visible rectangle of the frame, taking rotation into
893
     * consideration. The result of this method is the rectangular area
894
     * of the unrotated frame that will be visible when the frame gets
895
     * rotated.
896
     * 
897
     * @param visibleLayoutDocRect
898
     *                         The visible area of the layout document
899
     * @param frame
900
     *                         The bounding box of this frame
901
     * @return
902
     *                         the rectangular area of the unrotated frame that will be
903
     * visible when the frame gets rotated, measured in screen coordinates  
904
     */
905
    protected Rectangle2D getVisibleRect(Rectangle2D visibleLayoutDocRect, Rectangle2D frame) {
906
            if (Math.abs(getRotation())>0.00001d) { // non-zero rotation
907
                    Area area = new Area(frame);
908
                    AffineTransform at = new AffineTransform();
909
                    at.rotate(Math.toRadians(getRotation()), frame.getCenterX(), frame.getCenterY());
910
                    Area rotatedArea = area.createTransformedArea(at);
911
                    Area visibleArea = new Area(visibleLayoutDocRect);
912
                    // this is the visible rectangle of the rotated fframeview in layout coordinates
913
                    visibleArea.intersect(rotatedArea);
914
                    if (visibleArea.isEmpty()) {
915
                            return null;
916
                    }
917
                    // now we need to calculate the corresponding visible area of the fframeview before rotating,
918
                    // in order to know which area of the non-rotated fframeview must be drawn
919
                    try {
920
                            Area nonRotatedVisibleArea = visibleArea.createTransformedArea(at.createInverse());
921
                            Rectangle2D nonRotatedVisibleBounds = nonRotatedVisibleArea.getBounds2D();
922
                            return nonRotatedVisibleBounds;
923
                        } catch (NoninvertibleTransformException e) {
924
                                LoggerFactory.getLogger(FFrame.class).error(e.getMessage(), e);
925
                                return null;
926
                        }
927
            }
928
            else {
929
                    Rectangle2D.Double visibleArea = new Rectangle2D.Double();
930
                    Rectangle2D.intersect(visibleLayoutDocRect, frame, visibleArea);
931
                    if (visibleArea.isEmpty()) {
932
                            return null;
933
                    }
934
                    return visibleArea;
935
            }
936
    }
937

    
938
}