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

History | View | Annotate | Download (30.3 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
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 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.gvsig.andami.PluginServices;
39 308 cmartinez
import org.gvsig.andami.ui.mdiManager.IWindowListener;
40 5 jldominguez
import org.gvsig.app.project.ProjectManager;
41 147 cmartinez
import org.gvsig.app.project.documents.Document;
42 5 jldominguez
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 147 cmartinez
import org.gvsig.app.project.documents.layout.LayoutDocument;
47 5 jldominguez
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 142 cmartinez
import org.slf4j.Logger;
56
import org.slf4j.LoggerFactory;
57 5 jldominguez
58
/**
59 176 cmartinez
 * 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 5 jldominguez
 *
63
 * @author Vicente Caballero Navarro
64 176 cmartinez
 * @author Cesar Martinez Izquierdo
65 5 jldominguez
 */
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 147 cmartinez
        private static final String DOCUMENT_FIELD = "layoutDocument";
77
        private static final String LAYOUT_CONTEXT_FIELD = "layoutContext";
78 5 jldominguez
79
    protected static final Logger LOG = LoggerFactory.getLogger(FFrame.class);
80
81
    protected Rectangle2D.Double m_BoundBox = new Rectangle2D.Double();
82 26 jldominguez
    // initially identity
83
    protected AffineTransform lastAT = AffineTransform.getShearInstance(0,0);
84
    // private Rectangle2D.Double m_BoundingBox = new Rectangle2D.Double();
85
86 5 jldominguez
    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 213 cmartinez
    // user getters to access these variables:
110 145 cmartinez
    private LayoutContext layoutContext = null;
111 147 cmartinez
    private Document document = null;
112
113 5 jldominguez
    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 176 cmartinez
     * 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 5 jldominguez
     *
191
     * @param p
192 176 cmartinez
     *            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 5 jldominguez
     */
197
    public void setSelected(Point2D p, MouseEvent e) {
198 145 cmartinez
        doSetSelected(getContains(p));
199 5 jldominguez
    }
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 176 cmartinez
     * 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 5 jldominguez
     *
374 176 cmartinez
     * @see {@link #isSelected()}, {@link #setSelected(boolean)}
375
     * @return The type of selection that has been applied
376 5 jldominguez
     */
377
    public int getSelected() {
378
        return m_Selected;
379
    }
380 142 cmartinez
381 176 cmartinez
    /**
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 142 cmartinez
    public boolean isSelected() {
389
            return getSelected()!=IFFrame.NOSELECT;
390
    }
391 5 jldominguez
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 232 cmartinez
    /*
406
     * (non-Javadoc)
407
     * @see org.gvsig.app.project.documents.layout.fframes.IFFrame#getContains(Point2D)
408 5 jldominguez
     */
409
    public int getContains(Point2D p) {
410 232 cmartinez
            Point2D point = new Point2D.Double();
411 234 cmartinez
            AffineTransform rotationAT = getRotationAT();
412 232 cmartinez
            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 5 jldominguez
            return N;
424
        } else
425 232 cmartinez
            if (ne.contains(point.getX(), point.getY())) {
426 5 jldominguez
                return NE;
427
            } else
428 232 cmartinez
                if (e.contains(point.getX(), point.getY())) {
429 5 jldominguez
                    return E;
430
                } else
431 232 cmartinez
                    if (se.contains(point.getX(), point.getY())) {
432 5 jldominguez
                        return SE;
433
                    } else
434 232 cmartinez
                        if (s.contains(point.getX(), point.getY())) {
435 5 jldominguez
                            return S;
436
                        } else
437 232 cmartinez
                            if (so.contains(point.getX(), point.getY())) {
438 5 jldominguez
                                return SO;
439
                            } else
440 232 cmartinez
                                if (o.contains(point.getX(), point.getY())) {
441 5 jldominguez
                                    return O;
442
                                } else
443 232 cmartinez
                                    if (no.contains(point.getX(), point.getY())) {
444 5 jldominguez
                                        return NO;
445
                                    } else
446
                                        if (getBoundingBox(null).contains(
447 232 cmartinez
                                            point.getX(), point.getY())) {
448 5 jldominguez
                                            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 176 cmartinez
     * 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 5 jldominguez
     *
504 176 cmartinez
     * @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 5 jldominguez
     */
510
    public abstract void draw(Graphics2D g, AffineTransform at, Rectangle2D r,
511
        BufferedImage imgBase);
512
513
    /**
514 141 cmartinez
     * 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 5 jldominguez
     *
518 141 cmartinez
     * @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 5 jldominguez
     */
523
    public Rectangle2D.Double getBoundingBox(AffineTransform at) {
524 26 jldominguez
        if (at != null) {
525
            lastAT = (AffineTransform) at.clone();
526 5 jldominguez
        }
527 26 jldominguez
        return FLayoutUtilities.fromSheetRect(m_BoundBox, lastAT);
528 5 jldominguez
    }
529
530
    /**
531 176 cmartinez
     * Sets the bounding box in centimeters of this FFrame, using  paper
532
     * coordinates.
533 5 jldominguez
     *
534
     * @param r
535 176 cmartinez
     *            Rectangle in centimeters
536 5 jldominguez
     */
537
    public void setBoundBox(Rectangle2D r) {
538 26 jldominguez
        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 5 jldominguez
    }
546
547
    /**
548 176 cmartinez
     * Returns the bounding box in centimeters of this FFrame, using paper
549
     * coordinates
550 5 jldominguez
     *
551 141 cmartinez
     * @return The bounding box of this FFrame, measured in centimeters.
552 5 jldominguez
     */
553
    public Rectangle2D.Double getBoundBox() {
554
        return m_BoundBox;
555
    }
556
557
    /**
558 176 cmartinez
     * Sets the selected status of the frame.
559 5 jldominguez
     *
560 176 cmartinez
     * @param selected
561
     *            <code>true</code> to select the frame, <code>false</code> to
562
     *            unselect it
563
     * @see {@link #isSelected()}, {@link #getSelected()}
564 5 jldominguez
     */
565 176 cmartinez
    public void setSelected(boolean selected) {
566
        if (selected) {
567 145 cmartinez
                doSetSelected(IFFrame.RECT);
568 5 jldominguez
        } else {
569 145 cmartinez
                doSetSelected(IFFrame.NOSELECT);
570 5 jldominguez
        }
571
    }
572 145 cmartinez
573
    protected void doSetSelected(int selectedStatus) {
574
            m_Selected = selectedStatus;
575
    }
576 5 jldominguez
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 141 cmartinez
     * Draws the FFrame rectangle on the provided Graphics2D, only showing the
612
     * FFrame name on an empty rectangle.
613 5 jldominguez
     *
614 141 cmartinez
     * @param g The graphics to draw on
615 5 jldominguez
     */
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 232 cmartinez
     * Sets the rotation of the frame, measured in arc degrees
698 5 jldominguez
     *
699
     * @param rotation
700 232 cmartinez
     *            Rotation to apply to the frame
701 5 jldominguez
     */
702
    public void setRotation(double rotation) {
703
        m_rotation = rotation;
704 234 cmartinez
    }
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 232 cmartinez
                Rectangle2D.Double frameRect = getBoundingBox(getLayoutContext().getAT());
718
                rotationAT.rotate(Math.toRadians(getRotation()), frameRect.getCenterX(), frameRect.getCenterY());
719 234 cmartinez
                return rotationAT;
720
            }
721
            return null;
722 5 jldominguez
    }
723
724
    /**
725 232 cmartinez
     * Gets the rotation of the frame, measured in arc degrees
726 5 jldominguez
     *
727 232 cmartinez
     * @return Rotation of the frame
728 5 jldominguez
     */
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 26 jldominguez
        frame.setBoundBox(this.getBoundBox());
756 5 jldominguez
        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 125 jldominguez
        iMove = PluginServices.getIconTheme().get("graphic-move-icon").getImage();
776 5 jldominguez
        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 147 cmartinez
            definition.addDynFieldObject(DOCUMENT_FIELD).setClassOfValue(LayoutDocument.class).setMandatory(false);
796
            definition.addDynFieldObject(LAYOUT_CONTEXT_FIELD).setClassOfValue(LayoutContext.class).setMandatory(false);
797 5 jldominguez
        }
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 147 cmartinez
        if (state.hasValue(DOCUMENT_FIELD)) {
825
                setDocument((LayoutDocument)state.get(DOCUMENT_FIELD ));
826 145 cmartinez
        }
827 147 cmartinez
        if (state.hasValue(LAYOUT_CONTEXT_FIELD)) {
828
                setLayoutContext((LayoutContext) state.get(LAYOUT_CONTEXT_FIELD));
829
        }
830 5 jldominguez
    }
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 147 cmartinez
        state.set(DOCUMENT_FIELD, getDocument());
840
        state.set(LAYOUT_CONTEXT_FIELD, getLayoutContext());
841 5 jldominguez
    }
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 142 cmartinez
855
    /*
856
     * (non-Javadoc)
857
     * @see org.gvsig.tools.dispose.Disposable#dispose()
858
     */
859
        public void dispose() {
860
861
        }
862 144 cmartinez
863 232 cmartinez
    /*
864
     * (non-Javadoc)
865
     * @see org.gvsig.app.project.documents.layout.fframes.IFFrame#frameRemoved()
866
     */
867 167 cmartinez
        public void frameRemoved() {}
868 144 cmartinez
869 232 cmartinez
    /*
870
     * (non-Javadoc)
871
     * @see org.gvsig.app.project.documents.layout.fframes.IFFrame#frameAdded()
872
     */
873 167 cmartinez
        public void frameAdded() {}
874 144 cmartinez
875 145 cmartinez
        public LayoutContext getLayoutContext() {
876
                return layoutContext;
877
        }
878
879
        public void setLayoutContext(LayoutContext layoutContext) {
880
                this.layoutContext = layoutContext;
881
        }
882
883 147 cmartinez
        public Document getDocument() {
884
                return document;
885 145 cmartinez
        }
886
887 147 cmartinez
        public void setDocument(Document document) {
888
                this.document = document;
889 145 cmartinez
        }
890 228 cmartinez
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 229 cmartinez
            if (Math.abs(getRotation())>0.00001d) { // non-zero rotation
907 228 cmartinez
                    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 5 jldominguez
}