Source code: org/fudaa/ebli/calque/BCalque.java
1 /*
2 * @file BCalque.java
3 * @creation 1998-08-25
4 * @modification $Date: 2003/01/30 10:56:50 $
5 * @license GNU General Public License 2
6 * @copyright (c)1998-2001 CETMEF 2 bd Gambetta F-60231 Compiegne
7 * @mail devel@fudaa.org
8 */
9
10 package org.fudaa.ebli.calque;
11
12 import java.awt.Color;
13 import java.awt.Component;
14 import java.awt.Container;
15 import java.awt.Graphics;
16 import java.awt.event.MouseListener;
17 import java.awt.event.MouseMotionListener;
18 import java.lang.reflect.Method;
19 import java.util.Arrays;
20
21 import javax.swing.Icon;
22 import javax.swing.JMenuItem;
23
24 import org.fudaa.ebli.geometrie.GrBoite;
25 import org.fudaa.ebli.geometrie.GrMorphisme;
26 import org.fudaa.ebli.repere.AbstractCalque;
27
28 /**
29 * Une classe de base pour tous les calques. Elle gere les transformations
30 * du repere et l'organisation des calques en une hierarchie arborescente.
31 * Un calque peut etre de trois sortes:
32 * <UL>
33 * <LI>un groupe de calques:
34 * structurant, regroupant plusieurs calques ou familles de calques,
35 * <LI>un calque d'affichage:
36 * calque representant des donnees a l'ecran,
37 * <LI>un calque d'interaction:
38 * gerant les evenements exterieurs et generalement associe a un calque
39 * d'affichage (ex: BCalqueDessin et BCalqueDessinInteraction).
40 * </UL>
41 *
42 * @version $Id: BCalque.java,v 1.1 2003/01/30 10:56:50 deniger Exp $
43 * @author Guillaume Desnoix , Axel von Arnim
44 */
45 public abstract class BCalque
46 extends AbstractCalque implements Icon
47 {
48
49 String[] enabledActions_;
50
51 /**
52 * Constructeur.
53 * Le constructeur initialise les transformations versEcran et versReel
54 * avec la transformation identite. versEcran transforme les coordonnees reelles en coordonnees
55 * ecran et versReel fait l'inverse. versEcran sert a l'affichage des objets
56 * et versReel a la gestion de la souris dans le repere reel.
57 */
58 protected BCalque()
59 {
60 super();
61
62 // ajustement_ = false;
63 destructible_ = true;
64 versEcran_ = GrMorphisme.identite();
65 versReel_ = GrMorphisme.identite();
66
67 setOpaque(false);
68 setLayout(new CalqueLayout());
69 setRequestFocusEnabled(false);
70 setDoubleBuffered(false);
71 }
72
73 // Icon
74
75 /**
76 * la largeur de l'icone correspondant (vue de l'arbre)
77 * @return 24
78 */
79 public int getIconWidth()
80 {
81 return 24;
82 }
83
84 /**
85 * la hauteur de l'icone correspondant (vue de l'arbre)
86 * @return 24
87 */
88 public int getIconHeight()
89 {
90 return 24;
91 }
92
93 /**
94 * Dessin de l'icone.
95 * @param _c composant dont l'icone peut utiliser des proprietes
96 * (couleur, ...). Ce parametre est le calque lui-meme. Il est ignore ici.
97 * @param _g le graphics sur lequel dessiner l'icone
98 * @param _x lieu cible de l'icone (x)
99 * @param _y lieu cible de l'icone (y)
100 */
101 public void paintIcon(Component _c, Graphics _g, int _x, int _y)
102 {
103 int w = getIconWidth();
104 int h = getIconHeight();
105
106 _g.setColor(Color.white);
107 _g.fillRect(_x + 1, _y + 1, w - 1, h - 1);
108
109 _g.setColor(isVisible() ? Color.black : Color.lightGray);
110 _g.drawRect(_x, _y, w, h);
111 }
112
113 // Informations
114
115 /**
116 * Chaine affichee dans l'arbre des calques.
117 */
118 private String title_;
119 public String getTitle()
120 {
121 return title_;
122 }
123 public void setTitle(String _title)
124 {
125 title_ = _title;
126 }
127
128 public String toString()
129 {
130 String r = getTitle();
131 if ((r == null) || r.equals(""))
132 r = getName();
133 if ((r == null) || r.equals(""))
134 r = super.toString();
135 return r;
136 }
137
138 /**
139 * Permet de renvoyer des menus spécifiques pour ce calque. Ces item seront
140 * ajoutes a la fin du menu obtenu lors du clic avec le bouton droit dans
141 * l'arbre calque.
142 * @return null par defaut.
143 */
144 public JMenuItem[] getSpecificMenuItems()
145 {
146 return null;
147 }
148
149 /**
150 * Methode de la classe Container surchargee. Elle est appelee lors
151 * de l'ajout d'un nouveau sous-calque. Elle initialise les transformations
152 * versEcran et versReel aux valeurs du calque hote.
153 * @param _comp calque a ajouter
154 * @param _constraints contraintes de layout
155 * @param _index indice dans la liste de calques
156 * @see java.awt.Container#add(java.awt.Component)
157 */
158 protected void addImpl(Component _comp, Object _constraints, int _index)
159 {
160 if (_comp instanceof BCalque)
161 {
162 BCalque calque = (BCalque) _comp;
163 calque.setVersEcran(getVersEcran());
164 calque.setVersReel(getVersReel());
165 }
166 super.addImpl(_comp, _constraints, _index);
167 }
168
169 /**
170 * Renvoie les calques fils de ce calque.
171 * @return les calques fils
172 * @see #getTousCalques()
173 */
174 public BCalque[] getCalques()
175 {
176 int i, n;
177 Component[] c = getComponents();
178
179 n = 0;
180 for (i = 0; i < c.length; i++)
181 if (c[i] instanceof BCalque)
182 n++;
183
184 BCalque[] r = new BCalque[n];
185
186 n = 0;
187 for (i = 0; i < c.length; i++)
188 if (c[i] instanceof BCalque)
189 {
190 r[n] = (BCalque) c[i];
191 n++;
192 }
193
194 return r;
195 }
196
197 /**
198 * Renvoie tous les sous-calques de ce calque.
199 * parcourt toute l'arborescence des sous-calques jusqu'aux feuilles.
200 * @return les sous-calques
201 * @see #getCalques()
202 */
203 public BCalque[] getTousCalques()
204 {
205 int i, j, n;
206 BCalque[] c = getCalques();
207
208 n = 1;
209 for (i = 0; i < c.length; i++)
210 n += c[i].getTousCalques().length;
211
212 BCalque[] r = new BCalque[n];
213
214 r[0] = this;
215 n = 1;
216 for (i = 0; i < c.length; i++)
217 {
218 BCalque[] sc = c[i].getTousCalques();
219 for (j = 0; j < sc.length; j++)
220 {
221 r[n] = sc[j];
222 n++;
223 }
224 }
225
226 return r;
227 }
228
229 /**
230 * Renvoie le premier sous-calque de ce calque de nom donné.
231 *
232 * @param _name Nom du sous calque.
233 * @return Le sous calque de nom donné. <i>null</i> si aucun sous calque ne
234 * porte ce nom.
235 * @deprecated
236 */
237 public BCalque getCalque(String _name)
238 {
239 return getCalqueParNom(_name);
240 }
241
242 /**
243 * Renvoie le premier sous-calque de ce calque de nom donné.
244 *
245 * @param _name Nom du sous calque.
246 * @return Le sous calque de nom donné. <i>null</i> si aucun sous calque ne
247 * porte ce nom.
248 */
249 public BCalque getCalqueParNom(String _name)
250 {
251 if (_name == null)
252 return null;
253
254 BCalque[] cqs = getTousCalques();
255
256 for (int i = 0; i < cqs.length; i++)
257 if (_name.equals(cqs[i].getName()))
258 return cqs[i];
259
260 return null;
261 }
262
263 /**
264 * Renvoie le premier sous-calque de ce calque de nom donné.
265 *
266 * @param _title Le titre du sous calque.
267 * @return Le sous calque de titre donné. <i>null</i> si aucun sous calque ne
268 * porte ce titre.
269 */
270 public BCalque getCalqueParTitre(String _title)
271 {
272 if (_title == null)
273 return null;
274
275 BCalque[] cqs = getTousCalques();
276
277 for (int i = 0; i < cqs.length; i++)
278 if (_title.equals(cqs[i].getTitle()))
279 return cqs[i];
280
281 return null;
282 }
283
284 // Organisation
285
286 /**
287 * Place ce calque en tete de la liste des calques fils du pere.
288 * Equivalent a pere.enPremier(this)
289 * @see #enPremier(BCalque)
290 */
291 public void enPremier()
292 {
293 Container p = getParent();
294 if (p instanceof BCalque)
295 ((BCalque) p).enPremier(this);
296 }
297
298 /**
299 * Place le calque specifie en tete de la liste des fils.
300 * @see #enPremier()
301 */
302 public void enPremier(BCalque _c)
303 {
304 add(_c, 0);
305 _c.revalidate();
306 }
307
308 /**
309 * Place ce calque en fin de la liste des calques fils du pere.
310 * Equivalent a pere.enDernier(this)
311 * @see #enDernier(BCalque)
312 */
313 public void enDernier()
314 {
315 Container p = getParent();
316 if (p instanceof BCalque)
317 ((BCalque) p).enDernier(this);
318 }
319
320 /**
321 * Place le calque specifie en fin de la liste des fils.
322 * @see #enDernier()
323 */
324 public void enDernier(BCalque _c)
325 {
326 add(_c);
327 _c.revalidate();
328 }
329
330 /**
331 * Detruit ce calque.
332 * Equivalent a pere.detruire(this)
333 * @see #detruire(BCalque)
334 */
335 public void detruire()
336 {
337 Container p = getParent();
338 if (p instanceof BCalque)
339 ((BCalque) p).detruire(this);
340 }
341
342 /**
343 * Detruit le calque specifie de la liste des fils.
344 * @see #detruire()
345 */
346 public void detruire(BCalque _c)
347 {
348 if (_c.isDestructible())
349 {
350 BCalque[] cq = _c.getCalques();
351
352 for (int i = 0; i < cq.length; i++)
353 _c.detruire(cq[i]);
354
355 Container p = this;
356 while ((p != null) && !(p instanceof BVueCalque))
357 p = p.getParent();
358
359 if (p != null)
360 {
361 if (_c instanceof MouseListener)
362 ((BVueCalque) p).removeMouseListener((MouseListener) _c);
363 if (_c instanceof MouseMotionListener)
364 ((BVueCalque) p).removeMouseMotionListener((MouseMotionListener) _c);
365 }
366
367 remove(_c);
368 revalidate();
369 }
370 }
371
372 public void paint(Graphics g)
373 {
374 // Paint (HACK: forcer le clip a cause d'un bug de 1.2 (?))
375 // System.err.println(getName()+": g.getClipBounds()="+g.getClipBounds());
376 if (g.getClipBounds() == null)
377 g.setClip(0, 0, getWidth(), getHeight());
378 super.paint(g);
379 }
380
381 public void paintComponent(Graphics g)
382 {
383 // surchargee dans chaque calque
384 }
385
386 public final boolean isValidateRoot()
387 {
388 return false;
389 }
390
391 /**
392 * Reaffichage complet du calque, plus rapide.
393 */
394 public final void quick_repaint()
395 {
396 Graphics g = getGraphics();
397 if (g != null)
398 update(g);
399 repaint(1000);
400 }
401
402 public void repaint()
403 {
404 if (isValidateRoot())
405 super.repaint();
406 else if (getParent() != null)
407 getParent().repaint();
408 }
409
410 /**
411 * repaint apres un delai.
412 * @param _tm delai en millisecondes
413 */
414 public void repaint(long _tm)
415 {
416 if (isValidateRoot())
417 super.repaint(_tm);
418 else if (getParent() != null)
419 getParent().repaint(_tm);
420 }
421
422 // Proprietes
423
424 private boolean rapide_;
425
426 /**
427 * Accesseur de la propriete ajustement. Elle est envoyee par les
428 * beans de controle de repere comme BTransformationGlissiere
429 * pour preciser que l'evenement repere associe est intermediaire.
430 * Ceci permet de passer en mode rapide pour l'affichage des calques
431 * lors des rafales d'evenements repere.
432 */
433 public boolean isRapide()
434 {
435 return rapide_;
436 }
437
438 /**
439 * Affectation de la propriete ajustement.
440 * Cette affectation est appliquee aux calques fils.
441 */
442 public void setRapide(boolean _v)
443 {
444 if (rapide_ != _v)
445 {
446 boolean vp = rapide_;
447 rapide_ = _v;
448
449 BCalque[] c = getCalques();
450 for (int i = 0; i < c.length; i++)
451 c[i].setRapide(_v);
452
453 firePropertyChange("ajustement", vp, rapide_);
454 }
455 }
456
457
458 private boolean destructible_;
459
460 /**
461 * Indique si un calque peut etre detruit par l'utilisateur.
462 * Faux par defaut.
463 * @return vrai si destructible
464 */
465 public boolean isDestructible()
466 {
467 boolean r = destructible_;
468 BCalque[] c = getCalques();
469
470 for (int i = 0; i < c.length; i++)
471 r &= c[i].isDestructible();
472
473 return r;
474 }
475
476 public void setDestructible(boolean _v)
477 {
478 if (destructible_ != _v)
479 {
480 boolean vp = destructible_;
481 destructible_ = _v;
482 firePropertyChange("destructible", vp, destructible_);
483 }
484 }
485
486 /**
487 * Renvoie le domaine (l'etendue) du contenu du calque.
488 * null si non significatif.
489 * @return domaine en coordonnees reelles
490 */
491 public GrBoite getDomaine()
492 {
493 GrBoite r = null;
494
495 if (isVisible())
496 {
497 BCalque[] c = getCalques();
498 for (int i = 0; i < c.length; i++)
499 {
500 GrBoite d = c[i].getDomaine();
501 if (d != null)
502 {
503 if (r == null)
504 r = (GrBoite) d.clone();
505 else
506 r = r.union(d);
507 }
508 }
509 }
510
511 return r;
512 }
513
514 private GrMorphisme versEcran_;
515
516 /**
517 * Accesseur de la propriete versEcran. Elle est la matrice de
518 * transformation a appliquer lors de l'affichage du calque.
519 */
520 public GrMorphisme getVersEcran()
521 {
522 return versEcran_;
523 }
524
525 /**
526 * Affectation de la propriete versEcran.
527 * Cette affectation est appliquee aux calques fils.
528 */
529 public void setVersEcran(GrMorphisme _v)
530 {
531 if (versEcran_ != _v)
532 {
533 GrMorphisme vp = versEcran_;
534 versEcran_ = _v;
535
536 BCalque[] c = getCalques();
537 for (int i = 0; i < c.length; i++)
538 c[i].setVersEcran(_v);
539
540 firePropertyChange("versEcran", vp, versEcran_);
541 }
542 }
543
544 private GrMorphisme versReel_;
545
546 /**
547 * Accesseur de la propriete versReel. Elle est la matrice
548 * de transformation a appliquer lors de la lecture d'un evenement
549 * souris par exemple.
550 */
551 public GrMorphisme getVersReel()
552 {
553 return versReel_;
554 }
555
556 /**
557 * Affectation de la propriete versReel.
558 * Cette affectation est appliquee aux calques fils.
559 */
560 public void setVersReel(GrMorphisme _v)
561 {
562 if (versReel_ != _v)
563 {
564 GrMorphisme vp = versReel_;
565 versReel_ = _v;
566
567 BCalque[] c = getCalques();
568 for (int i = 0; i < c.length; i++)
569 c[i].setVersReel(_v);
570
571 firePropertyChange("versReel", vp, versReel_);
572 }
573 }
574
575 /**
576 * Affectation generique de propriete.
577 * @param _name nom de la propriete a modifier
578 * @param _value nouvelle valeur
579 */
580 public void setProperty(String _name, Object _value)
581 {
582 try
583 {
584 String n =
585 "set" + _name.substring(0, 1).toUpperCase() + _name.substring(1);
586 Class z = _value.getClass();
587
588 // System.err.println("$$$ N="+n);
589
590 try
591 {
592 z = (Class) (z.getField("TYPE").get(z));
593 }
594 catch (Exception ey)
595 {
596 }
597
598 Class[] c = null;
599 Method m = null;
600
601 do
602 {
603 // System.err.println("$$$ Z="+z);
604 c = new Class[] { z };
605 try
606 {
607 m = getClass().getMethod(n, c);
608 }
609 catch (Exception ey)
610 {
611 m = null;
612 }
613
614 // System.err.println("$$$ M="+m);
615
616 z = z.getSuperclass();
617 }
618 while ((m == null) && (z != null));
619
620 Object[] o = new Object[] { _value };
621
622 // System.err.println("$$$ O="+o);
623
624 m.invoke(this, o);
625 }
626 catch (Exception ex)
627 {
628 if (!_name.equals("ancestor"))
629 System.err.println(
630 "Propriété "
631 + _name
632 + " non disponible en écriture dans "
633 + getClass().getName()
634 + ".");
635 }
636 }
637
638 /**
639 * Accesseur generique de propriete.
640 * @param _name nom de la propriete a lire
641 * @return valeur de la propriete
642 */
643 public Object getProperty(String _name)
644 {
645 Object r = null;
646
647 try
648 {
649 String n =
650 "get" + _name.substring(0, 1).toUpperCase() + _name.substring(1);
651 Class[] c = new Class[0];
652 Method m = getClass().getMethod(n, c);
653 Object[] o = new Object[0];
654 r = m.invoke(this, o);
655 }
656 catch (Exception ex)
657 {
658 if (!_name.equals("ancestor"))
659 System.err.println(
660 "Propriété "
661 + _name
662 + " non disponible en lecture dans "
663 + getClass().getName()
664 + ".");
665 }
666
667 return r;
668 }
669
670 /**
671 * Renvoie les actions a activer pour ce calque.
672 * Cette methode est utilisee, par exemple, par la <code>ZEbliFilleCalque</code>.
673 * Si la valeur <code>null</code> est renvoyee, toutes les actions seront desactivees.
674 * @return String[] les actions a activer. Par defaut renvoie <code>null</code>.
675 */
676 public String[] getEnabledActions()
677 {
678 return enabledActions_;
679 }
680
681 /**
682 * Affecte et trie le tableau des actions a activer.
683 * @param enabledSpecificTools les nouvelles actions.
684 */
685 public void setEnabledActions(String[] enabledSpecificTools)
686 {
687 Arrays.sort(enabledSpecificTools);
688 enabledActions_ = enabledSpecificTools;
689 }
690
691 }