View Javadoc

1   /*
2   $Id: Display.java 721 2005-03-28 17:59:40Z guest $
3   */
4   
5   
6   /*
7   Copyright (C) 2001-2002 Mainline Project (I3S - ESSI - CNRS -UNSA)
8   
9   This library is free software; you can redistribute it and/or
10  modify it under the terms of the GNU Lesser General Public
11  License as published by the Free Software Foundation; either
12  version 2.1 of the License, or (at your option) any later version.
13  
14  This library is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  Lesser General Public License for more details.
18  
19  You should have received a copy of the GNU Lesser General Public
20  License along with this library; if not, write to the Free Software
21  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  
23  For further information on the GNU Lesser General Public License,
24  see: http://www.gnu.org/copyleft/lesser.html
25  For further information on this library, contact: mainline@essi.fr
26  */
27  
28  
29  package fr.ove.openmath.jome.ctrlview.bidim;
30  
31  import java.awt.*;
32  import java.awt.event.*;
33  import java.util.*;
34  import fr.ove.openmath.jome.model.*;
35  import fr.ove.openmath.jome.model.events.*;
36  import fr.ove.openmath.jome.behaviour.*;
37  import fr.ove.openmath.jome.ctrlview.events.*;
38  import fr.ove.openmath.jome.ctrlview.bidim.*;
39  import fr.ove.openmath.jome.ctrlview.bidim.selection.*;
40  import fr.ove.openmath.jome.ctrlview.bidim.selection.events.*;
41  
42  /***
43  * The display elements of the formula.
44  *
45  * @author © 1999 DIRAT Laurent
46  * @version 2.0  27/06/1999
47  */
48  public abstract class Display extends Container implements Displayable, Colorizable, Selectable, Iconifiable, ModelListenerController {
49      /***
50      * Distance between the top of the bounding box of the element to display
51      * and its baseline.
52      */
53      private int ascent;
54  
55      /***
56      * Distance between the bottom of the bounding box of the element to display
57      * and its baseline.
58      */
59      private int descent;
60  
61      /***
62      * An horizontal shift.
63      */
64      private int shiftX = 0;
65  
66      /***
67      * A vertical shift.
68      */
69      private int shiftY = 0;
70  
71      /***
72      * Indicates whether the symbol is selected or not.
73      */
74      protected boolean isSelected = false;
75      
76      /***
77      * Indicates the level of reduction for the font.
78      * (Usefull for superscripts, underscripts, ....)
79      */
80      private int level = 0;
81      
82      /***
83      * Indicates if the level needs to be updated.
84      */
85      private boolean updateLevel = true;
86      
87      /***
88      * Indicates if we draw the bounds of the display or not.
89      */
90      private boolean weDrawBounds = false;
91      
92      /***
93      * The graphic context of the display.
94      */
95      private GraphicContext graphicContext;
96      
97      /***
98      * Indicates if the display need to be computed.
99      */
100     private boolean computeAttributes = true;
101     
102     /***
103     * The rank of the container in the set of children of its parent.
104     */
105     private int rank = 0;
106     
107     /***
108     * The selection manager of the display.
109     */
110     private static SelectionEventListener selectionManager = null;
111     
112     /***
113     * The list of listeners of the instance
114     */
115     private ControlListener listener;
116     
117     /***
118     * Are we in drag'n drop mode ??
119     */
120     protected boolean dragNDrop;
121     
122     /***
123     * To indicate if the instance represents the display of the symbol of an operator.<BR>
124     * For example, the display of the operator "+", display that is automatically inserted
125     * during the rendering of the formula.
126     */
127     private boolean isSymbolOperatorDisplay = false;
128     
129     /***
130     * To indicate if, when the instance is removed from its father, it has to be removed from the
131     * list of listeners it is listening to.<BR>
132     * The default is <CODE>true<CODE>. In fact, it is in special cases the value equals to <CODE>false<CODE>.
133     * These special cases are mainly moves of the instance in its father (e.g. add(comp, comp, index) calls
134     * a remove(...) method, which automatically removes the instance from the list of listeners it is listening
135     * to. And we don't want that)
136     */
137     private boolean doRemoveFromListListeners = true;
138     
139     
140     /***
141     * The display allocator for the building of the visualisation of the formula.<BR>
142     * REMINDER : Don't forget to set the right allocator in the constructor of the inherited class.
143     */
144     private static DisplayAllocator displayAllocator = null;
145     
146 	private MouseListener mouseListener = null;
147 
148     /***
149     * The constructor.
150     * @param graphicContext the graphic context of the display.
151     */
152     public Display(GraphicContext graphicContext) {
153         super();
154         
155         this.graphicContext = new GraphicContext(graphicContext);
156         setFont(graphicContext.getFont());
157         setForeground(graphicContext.getForegroundColor());
158         setBackground(graphicContext.getBackgroundColor());
159         
160         //addMouseListener(mouseListener);
161         addMouseListener( 
162             new MouseAdapter() {
163                 public void mousePressed(MouseEvent e) {
164                     SelectionEvent selEvt = new SelectionEvent(Display.this);
165                     
166                     if (e.isControlDown()) {
167                         if (!isSelected) {
168                             DisplayLayout displayLayout = (DisplayLayout) getLayout();
169                             
170                             if (displayLayout instanceof OneFormulaLayout) {
171                                 Display formulaDisplay = (Display) getComponent(0);
172                                 if (formulaDisplay.isSelected())
173                                     displayLayout.deselectDisplay();
174                                 else {
175                                     displayLayout.selectDisplay();
176                                     setCursor(new Cursor(Cursor.HAND_CURSOR));
177                                 }
178                             }
179                             else {
180                                 displayLayout.selectDisplay();
181                                 setCursor(new Cursor(Cursor.HAND_CURSOR));
182                             }
183 
184                             repaint();
185                         }
186                         else {
187                             ((DisplayLayout) getLayout()).deselectDisplay();
188                             setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
189 
190                             repaint();
191                         }
192                     }
193                     else if (e.isShiftDown())
194                         iconify();
195                     else if (e.isAltDown())
196                         uniconify();
197                     else{
198                     	isSelected = !isSelected;
199                     	FormulaTreeStructure fts = (FormulaTreeStructure) getListener();
200                     	if(fts != null){
201 	                    	fts.setCrossRef(isSelected);
202     	                	repaint();
203                     	}
204                     }
205 
206 					if ( mouseListener != null )                    
207 					   mouseListener.mousePressed(e);
208                         
209                 }
210                 
211                 public void mouseEntered(MouseEvent e) {
212                     if (isSelected) 
213                         setCursor(new Cursor(Cursor.HAND_CURSOR));
214                     else
215                         setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
216                 }
217             
218                 public void mouseReleased(MouseEvent e) {
219                     int mouseX = e.getX();
220                     
221                     if (dragNDrop) {
222                         moveSelectedDisplays(mouseX);
223                         dragNDrop = false;
224                         repaint();
225                     }
226                     
227                 }
228 
229             }
230         );
231         
232         addMouseMotionListener(
233             new MouseMotionAdapter() {
234                 public void mouseDragged(MouseEvent e) {
235                     if (isSelected) {
236                         dragNDrop = true;
237                         setCursor(new Cursor(Cursor.MOVE_CURSOR));
238                     }
239                 }
240                 
241                 public void mouseMoved(MouseEvent e) {
242                     if (isSelected) 
243                         setCursor(new Cursor(Cursor.HAND_CURSOR));
244                     else
245                         setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
246                 }
247             }
248         );
249 	}
250 	
251 	
252 	
253 	
254     // *******************
255     // Display information
256     // *******************
257     
258     
259     /***
260     * Returns <CODE>true</CODE> if the instance is a display of the specified
261     * formula tree structure. <CODE>false</CODE> otherwise.
262     */
263     public boolean isDisplay(FormulaTreeStructure fts) {
264         // On recupËre la liste de tous les listeners de fts
265         Vector listeners = fts.getListeners();
266         
267         return listeners.contains(this);
268     }
269     
270 	
271     // ***************************************
272     // About the display as one of an operator
273     // ***************************************
274     
275     /***
276     * Sets if the instance represents the display of the symbol of an operator.
277     * @param isSymbolOperatordisplay <CODE>true</CODE> if the instance represents 
278     * the display of the symbol of an operator. <CODE>false</CODE> otherwise.
279     */
280     public void setIsSymbolOperatorDisplay(boolean isSymbolOperatorDisplay) {
281         this.isSymbolOperatorDisplay = isSymbolOperatorDisplay;
282     }
283     
284     /***
285     * @return <CODE>true</CODE> if the instance represents the display of the symbol
286     * of an operator. <CODE>false</CODE> otherwise.
287     */
288     public boolean isSymbolOperatorDisplay() {
289         return isSymbolOperatorDisplay;
290     }
291     
292     
293     // *************************
294     // The bounds of the display
295     // *************************
296     
297     /***
298     * The bounds of the display have to be drawn.
299     */
300     public void drawBounds() {
301         weDrawBounds = true;
302     }
303     
304     /***
305     * The bounds of the display don't have to be drawn.
306     */
307     public void dontDrawBounds() {
308         weDrawBounds = false;
309     }
310     
311     /***
312     * Checks if the bound must be drawn or not.
313     * @return <CODE>true</CODE> if we have to draw the bounds of the 
314     * display. <CODE>false</CODE> otherwise.
315     */
316     public boolean weDrawBounds() {
317         return weDrawBounds;
318     }
319     
320     // ************************
321     // The level of the display
322     // ************************
323     
324     /***
325     * Sets the level of the display
326     * @param level the level of the display.
327     */
328     public void setLevel(int level) {
329         this.level = level;
330     }
331     
332     /***
333     * Returns the level of the display
334     */
335     public int getLevel() {
336         return level;
337     }
338 
339     /***
340     * Increments the level value.
341     */
342     public void incLevel() {
343         level++;
344     }
345     
346     /***
347     * Decrements the level value.
348     */
349     public void decLevel() {
350         level--;
351     }
352     
353     /***
354     * Sets the level to be updated.
355     * @param updateLevel <CODE>true</CODE> if the display level need to be
356     * updated. <CODE>false</CODE> otherwise.
357     */
358     public void setUpdateLevel(boolean updateLevel) {
359         this.updateLevel = updateLevel;
360         if (updateLevel) {
361             int count = getComponentCount();
362             for (int i = 0; i < count; i++)
363                 ((Display) getComponent(i)).setUpdateLevel(updateLevel);
364         }
365     }
366     
367     /***
368     * Checks if we need to update the level of the display.
369     * @return <CODE>true</CODE> if needed. <CODE>false</CODE> otherwise.
370     */
371     public boolean getUpdateLevel() {
372         return updateLevel;
373     }
374     
375     /***
376     * Recurses into the tree of the display to inform the ancestors of the instance
377     * that they need to update their level
378     */
379     public void updateAncestorsLevel() {
380         Container parent = getParent();
381         while (parent instanceof Display) {
382             ((Display) parent).setUpdateLevel(true);
383             parent = parent.getParent();
384         }
385     }
386     
387     /***
388     * Recurses into the tree of the display to inform the children of the instance
389     * that they need to update their level
390     */
391     public void updateChildrenLevel() {
392         Display childDisplay;
393         int count = getComponentCount();
394         for (int i = 0; i < count; i++) {
395             childDisplay = (Display) getComponent(i);
396             childDisplay.setUpdateLevel(true);
397             childDisplay.updateChildrenLevel();
398         }
399     }
400     
401     
402     // ************************************
403     // The management of display attributes 
404     // ************************************
405     
406     
407     /***
408     * Sets the attributes to be computed.
409     * @param computeAttributes <CODE>true</CODE> if the display attributes need to be
410     * computed. <CODE>false</CODE> otherwise.
411     */
412     public void setComputeAttributes(boolean computeAttributes) {
413         this.computeAttributes = computeAttributes;
414     }
415 
416     /***
417     * Checks if we need to compute the display.
418     * @return <CODE>true</CODE> if needed. <CODE>false</CODE> otherwise.
419     */
420     public boolean getComputeAttributes() {
421         return computeAttributes;
422     }
423     
424     /***
425     * Recurses into the tree of the display to inform the ancestors of the instance
426     * that they need to compute their attributes.
427     */
428     public void computeAncestorsAttributes() {
429         computeAttributes = true;
430         Container parent = getParent();
431         while (parent instanceof Display) {
432             ((Display) parent).setComputeAttributes(true);
433             parent = parent.getParent();
434         }
435     }
436     
437     /***
438     * Recurses into the tree of the display to inform the children of the instance
439     * that they need to compute their attributes.
440     */
441     public void computeChildrenAttributes() {
442         computeAttributes = true;
443         int count = getComponentCount();
444         for (int i = 0; i < count; i++)
445             ((Display) getComponent(i)).computeChildrenAttributes();
446     }
447     
448     
449     // ***********************
450     // The rank of the display
451     // ***********************
452     
453     
454     /***
455     * Sets the rank of the display.
456     * @param rank the rank.
457     */
458     public void setRank(int rank) {
459         this.rank = rank;
460     }
461     
462     /***
463     * Returns the rank of the display.
464     */
465     public int getRank() {
466         return rank;
467     }
468     
469     /***
470     * Adjusts the rank of its children.
471     */
472     public void adjustRank() {
473         int count = getComponentCount();
474         for (int i = 0; i < count; i++)
475             ((Display) getComponent(i)).setRank(i);
476     }
477     
478     // *********************
479     // Display manipulations
480     // *********************
481     
482     /***
483     * Removes all the displays of the instance. <BR>
484     * The fundamental difference with removeAll is in that case, the displays removed are not
485     * removed form the list of listeners of the formula tree structure they are listening to.
486     */
487     public void removeAllDisplays() {
488         Display display;
489         int count = getComponentCount();
490         for (int i = 0; i < count; ) {
491             display = (Display) getComponent(i);
492             // Si c'est le display d'un opÈrateur, alors on l'enlËve de la liste et en plus, on l'enlËve
493             // de la liste des listeners de la fts qu'il Ècoutait.
494             // Le remove surchargÈ.
495             // si ce n'est pas le cas, on ne fait que le supprimer des fils de l'instance.
496             if (display.isSymbolOperatorDisplay)
497                 //remove(display);
498                 remove(i);
499             else
500                 //super.remove(display);
501                 super.remove(i);
502                 
503             count--;
504         }
505     }
506     
507     /***
508     * Scales the display.
509     */
510     public void scaleDisplay() {
511         setTheFont(graphicContext.scaleFont(level));
512         setComputeAttributes(true);
513         
514         int count = getComponentCount();
515         for (int i = 0; i < count; i++)
516             ((Display) getComponent(i)).scaleDisplay();
517         
518         // On regarde si le display de l'instance est le display d'une icone.
519         // Si tel est le cas, il faut que l'on scale les displays iconifiÈs.
520         FormulaTreeStructure fts = (FormulaTreeStructure) getListener();
521         if ((fts != null) && fts.isIcon()) {
522             SubstitutedDisplayManager layout = (SubstitutedDisplayManager) getLayout();
523             count = layout.getNbSubstitutedDisplay();
524             for (int i = 0; i < count; i++)
525                 layout.getSubstitutedDisplay(i).scaleDisplay();
526         }
527     }
528     
529     
530     /***
531     * Moves the selected displays to the mouse position.
532     * @param mouseX the mouse position.
533     */
534     public void moveSelectedDisplays(int mouseX) {
535         SelectionEvent selectionEvent = new SelectionEvent(this);
536 
537         // On rÈcupËre la taille de la sÈlection.
538         Integer selectionSize = null;
539         selectionEvent.setAction(SelectionEvent.GET_SELECTION_SIZE, selectionSize);
540         fireSelectionEvent(selectionEvent);
541         selectionSize = (Integer) selectionEvent.getArgument();
542         // Si diffÈrente de 0, on peut faire du drag'n drop de qque chose.
543         if (selectionSize.intValue() != 0) {
544             // On rÈcupËre la sÈlection entiËre.
545             Vector selection = null;
546             selectionEvent.setAction(SelectionEvent.GET_SELECTION, selection);
547             fireSelectionEvent(selectionEvent);
548             selection = (Vector) selectionEvent.getArgument();
549             Display display = (Display) selection.elementAt(0);
550             // On rÈcupËre le fts associÈ au display.
551             FormulaTreeStructure fts = (FormulaTreeStructure) display.getListener();
552             // On rÈcupËre l'opÈrateur dont les display sont les opÈrandes.
553             fts = (FormulaTreeStructure) fts.getFather();
554             // On fonction du type de cet opÈrateur, on permet ou pas le drag'n
555             // drop.
556             if (!fts.getAreOperandsMovable())
557                 return;  // Pour ces opÈrateur l?, on ne permet pas le drag'n drop.
558 
559             // Il faut maintenant savoir o? on va dropper la sÈlection.
560             // On rÈcupËre le display de l'opÈrateur, et on cherche cette position
561             display = (Display) display.getParent();
562             
563             // On ajuste la position de la souris pour qu'on soit en coordonnÈe relative
564             // dans le repËre de display.
565             // ATTENTION : l'instance courante est celle qui a reÁu le mouseDragged. Elle
566             // a reÁu Ègalement le mouseReleased. Ce qui fait que le mouseX est une coordonnÈe
567             // relative ? l'instance. Donc, pour ramener notre coordonnÈe relativement ? display
568             // il faut rajouter la coordonnÈe de l'instance.
569             Display tmp = this;
570             while (tmp != display) {
571                 mouseX += tmp.getX();
572                 tmp = (Display) tmp.getParent();
573             }
574             
575             // On regarde si la position de la souris ainsi calculÈe est toujours contenue
576             // dans le display. Si ce n'est pas le cas, on se trouve dans un cas particulier.
577             int insertionPosition;
578             if (mouseX <= 0) {
579                 // On a droppÈ ? gauche de display, on insËre donc au dÈbut de celui-ci
580                 // Cela revient ? dropper sur le premier display de la liste.
581                 tmp = (Display) display.getComponentAt(1, display.getAscent());
582                 insertionPosition = tmp.computeInsertionPosition(1);
583             }
584             else if (mouseX >= display.getWidth()) {
585                 // On a droppÈ ? droite de display, on insËre donc ? la fin de celui-ci
586                 // Cela revient dropper sur le dernier display de la liste.
587                 tmp = (Display) display.getComponentAt(display.getWidth() - 1, display.getAscent());
588                 insertionPosition = tmp.computeInsertionPosition(display.getWidth() - 1 - tmp.getX());
589             }
590             else {
591                 // On a droppÈ qque part dans display. On rÈcupËre ce display.
592                 tmp = (Display) display.getComponentAt(mouseX, display.getAscent());
593                 insertionPosition = tmp.computeInsertionPosition(mouseX - tmp.getX());
594             }
595             
596             // On crÈÈ la liste des opÈrandes ? permuter
597             Vector operands = new Vector();
598             for (Enumeration e = selection.elements(); e.hasMoreElements(); ) {
599                 tmp = (Display) e.nextElement();
600                 // Si l'on n'a pas affaire ? un display d'operateur, alors on ajoute l'operande
601                 // dans la liste.
602                 if (!tmp.isSymbolOperatorDisplay()) {
603                     tmp.deselect();
604                     operands.addElement(tmp.getListener());
605                 }
606             }
607             
608             // On fait la permutation
609             // Faut-il rajouter l'ÈvÈnement pour rester dans la philosophie ???
610             fts.moveOperands(operands, insertionPosition);
611             
612             // On purge la liste de sÈlection
613             selectionEvent.setAction(SelectionEvent.PURGE, null);
614             fireSelectionEvent(selectionEvent);
615         }
616     }
617 
618     /***
619     * Returns the insertion position for the moving of displays.
620     * @param mouseX the mouse position.
621     */
622     public int computeInsertionPosition(int mouseX) {
623         int insertionPosition;
624         
625         // On regarde la position de la souris.
626         // Si elle est infÈrieure ? la moitiÈ de la largeur de l'instance, alors
627         // la position d'insertion est la position de l'opÈrande dont l'instance est
628         // le display. Sinon, la position d'insertion est la position de l'opÈrande 
629         // dont l'instance est le display + 1.
630         if (mouseX <= (getWidth() / 2))
631             insertionPosition = ((FormulaTreeStructure) listener).getRank();
632         else
633             insertionPosition = ((FormulaTreeStructure) listener).getRank() + 1;
634             // Pas de pb de test pour savoir si on n'est pas sur le dernier opÈrande
635             // puisqu'on est obligÈ dans ce cas de retourner le nbre rÈel + 1 pour dire
636             // effectivement que l'on insËre ? la derniËre position.
637 
638         // On retourne la position d'insertion calculÈe.
639         return insertionPosition;
640     }
641     
642     // ******************
643     // Display allocation
644     // ******************
645     
646     /***
647     * Sets the display allocator.
648     * @param displayAllocator the display allocator
649     */
650     public void setDisplayAllocator(DisplayAllocator displayAllocator) {
651         this.displayAllocator = displayAllocator;
652     }
653     
654     /***
655     * Returns the display allocator.
656     * @return the display allocator, or <CODE>null</CODE> if none has been specified.
657     */
658     public DisplayAllocator getDisplayAllocator() {
659         return displayAllocator;
660     }
661     
662     /***
663     * Builds the display of the formula tree structure.<BR>
664     * This method has to be called when a formula tree structure has been created and the 
665     * displays have not been associated yet.<BR>
666     * As a prerequesit, the instance which call this method MUST have a corresponding instance
667     * (a listener) in the formula tree structure (i.e. the formula tree structure we want to display).<BR>
668     */
669     public void buildDisplay() {
670         Display childDisplay;
671         FormulaTreeStructure fts, ftsChild;
672         int count;
673         
674         // On rÈcupËre l'ÈlÈment de la FTS donc l'instance est le display.
675         fts = (FormulaTreeStructure) getListener();
676         if (fts != null) { // Bon malgrË le prÈrequis, on fait le test quand mÍme
677             count = fts.getNbChildren();
678             
679             // On parcourre la liste des fils de la fts, pour leur associer le display qui va bien
680             for (int i = 0; i < count; i++) {
681                 ftsChild = (FormulaTreeStructure) fts.getChild(i);
682                 // Allocation du display
683                 childDisplay = displayAllocator.allocateDisplay(graphicContext, ftsChild);
684                 
685                 
686                 // Chacun Ècoute l'autre
687                 //childDisplay.addControlListener(ftsChild);
688                 //ftsChild.addModelListener(childDisplay);
689                 // On ajoute le nouveau display comme fils ? l'instance
690                 add(childDisplay);
691                 // On descend dans la fts pour poursuivre la construction des display
692                 childDisplay.buildDisplay();
693             }
694         }
695     }
696     
697     /***
698     * Builds the display of the part of the formula tree structure at the specified index.<BR>
699     * This method has to be called when a new part of the formula tree structure has been created
700     * and the displays have not been associated yet. (modification of the formula expression, and then
701     * we only ask to build displays of the new part, and only them)<BR>
702     * As a prerequesit, the instance which calls this method MUST have a corresponding instance
703     * (a listener) in the formula tree structure (i.e. the formula tree structure we want to display)
704     * @param indexFts the index of the fts which needs displays to be associated, in the list of "sub-fts"
705     * of the corresponding fts of the instance (ouf !!!).<BR>
706     * <CODE>indexFts</CODE> must be less than the number of elements of the correponding fts, and
707     * greater or equal than 0.
708     * @return  the new display created.
709     */
710     public Display buildDisplay(int indexFts) {
711         Display childDisplay = null;
712         FormulaTreeStructure fts, ftsChild;
713         int count;
714         
715         // On rÈcupËre l'ÈlÈment de la FTS donc l'instance est le display.
716         fts = (FormulaTreeStructure) getListener();
717         if (fts != null) {
718             count = fts.getNbChildren();
719             if ((indexFts >= 0) && (indexFts < count)) {
720                 ftsChild = (FormulaTreeStructure) fts.getChild(indexFts);
721                 // Allocation du display
722                 childDisplay = displayAllocator.allocateDisplay(graphicContext, ftsChild);
723                 // Le display que l'on ajoute est au mÍme niveau que celui du pËre
724                 // (rappel: niveau = nb de fois que la rÈduction de taille doit Ítre appliquÈe,
725                 // par exemple pour les exposants.) C'est le layout manager qui s'occupe de
726                 // faire la rÈduction si nÈcessaire.
727                 childDisplay.setLevel(getLevel());
728                 // Chacun Ècoute l'autre
729                 childDisplay.addControlListener(ftsChild);
730                 ftsChild.addModelListener(childDisplay);
731                 // On ajoute le nouveau display comme fils ? l'instance
732                 add(childDisplay);
733                 // On descend dans la fts pour poursuivre la construction des display
734                 childDisplay.buildDisplay();
735             }
736         }
737         
738         return childDisplay;
739     }
740     
741     // ############################
742     // ### MÈthodes surchargÈes ###
743     // ############################
744     
745     /***
746     * Adds a child display to the instance. The child is added as the last child of the
747     * set of children of the instance.
748     * @param display the display to add.
749     */
750     public void add(Display display) {
751         super.add(display, display);
752         display.setRank(getComponentCount() - 1);
753     }
754     
755     /***
756     * Removes from the instance the display at the specified index.
757     * @param index the specified index.
758     */
759     public void remove(int index) {
760         try {
761             Display display = (Display) getComponent(index);
762             
763             if (display.doRemoveFromListListeners())
764                 // On enlËve maintenant le display supprimÈ de la liste des listeners de la fts
765                 // qu'il Ècoutait
766                 display.removeFromListListeners();
767             
768             // On enlËve le display de la liste
769             super.remove(index);
770             
771             // On rÈajuste maintenant le rank des fils de l'instance
772             adjustRank();
773         }
774         catch (ArrayIndexOutOfBoundsException e) {
775             System.out.println("Trying to remove display with a wrong index");
776             e.printStackTrace();
777         }
778     }
779     
780     /***
781     * Removes the specified display to the instance.
782     * @param display the display to remove.
783     *
784     public void remove(Display display) {
785         super.remove(display);
786         // On enlËve maintenant le display supprimÈ de la liste des listeners de la fts
787         // qu'il Ècoutait
788         display.removeFromListListeners();
789         
790         // On rÈajuste maintenant le rank des fils de l'instance
791         adjustRank();
792     }
793     */
794     
795     /***
796     * Removes all the displays of the instance.
797     */
798     public void removeAll() {
799         /*
800         for (int i = 0; i < getComponentCount(); i++)
801             remove(i);
802         */
803         for (int i = 0; i < getComponentCount(); )
804             remove(i);
805             
806         computeAncestorsAttributes();
807     }
808     
809     /***
810     * Sets if during the removal of the instance from the its father, we remove it from the list of
811     * listeners it is listening to.
812     * @param doRemoveFromListListeners <CODE>true<CODE> if we remove the instance from the list of listeners.
813     * <CODE>false</CODE> otherwise.
814     */
815     protected void setDoRemoveFromListListeners(boolean doRemoveFromListListeners) {
816         this.doRemoveFromListListeners = doRemoveFromListListeners;
817     }
818     
819     /***
820     * Returns <CODE>true<CODE> if we remove the instance from the list of listeners.
821     * <CODE>false</CODE> otherwise.
822     */
823     protected boolean doRemoveFromListListeners() {
824         return doRemoveFromListListeners;
825     }
826     
827     /***
828     * Sets if during the manipulation of children of the instance, the children manipulated have to be
829     * removed from the list od listeners.
830     * @param doRemoveFromListListeners <CODE>true<CODE> if we remove the children manipulated from the list
831     * of listeners. <CODE>false</CODE> otherwise.
832     */
833     protected void removeFromListListeners(boolean doRemoveFromListListeners) {
834         int count = getComponentCount();
835         for (int i = 0; i < count; i++)
836             ((Display) getComponent(i)).doRemoveFromListListeners = doRemoveFromListListeners;
837     }
838     
839     /***
840     * Removes the instance from the list of listeners of the formula tree structure it
841     * is listening to.
842     */
843     private void removeFromListListeners() {
844         // On rÈcupËre la fts associÈe au display enlevÈ et on lui enlËve display
845         // de la liste de ses listeners. 
846         FormulaTreeStructure fts = (FormulaTreeStructure) getListener();
847         fts.removeModelListener(this);
848         removeControlListener(fts);
849         
850         // Il faut maintenant que l'on fasse la mÍme chose avec les displays fils
851         int count = getComponentCount();
852         for (int i = 0; i < count; i++)
853             ((Display) getComponent(i)).removeFromListListeners();
854     }
855     
856         
857     
858     /***
859     * Sets a new font to the context.
860     * @param font the new font.
861     */
862     public void setFont(Font font) {
863         setTheFont(font);
864         
865         graphicContext.setFont(font);
866         
867         int count = getComponentCount();
868         // On parcourre tous les displays fils et ont leur affecte la nouvelle font.
869         for (int i = 0; i < count; i++)
870             ((Display) getComponent(i)).setFont(font);
871             
872         // On calcule la taille de la nouvelle font utilisÈe en fonction du niveau
873         // du display.
874         scaleDisplay();
875             
876         // On indique au layout manager que la taille du display (container) n'est plus
877         // valide.
878         invalidate();
879         
880         // On regarde si le display de l'instance est le display d'une icone.
881         // Si tel est le cas, il faut que l'on mette la nouvelle font aux displays iconifiÈs.
882         FormulaTreeStructure fts = (FormulaTreeStructure) getListener();
883         if ((fts != null) && fts.isIcon()) {
884             SubstitutedDisplayManager layout = (SubstitutedDisplayManager) getLayout();
885             count = layout.getNbSubstitutedDisplay();
886             for (int i = 0; i < count; i++)
887                 layout.getSubstitutedDisplay(i).setFont(font);
888         }
889     }
890     
891     protected void setTheFont(Font font) {
892         super.setFont(font);
893     }
894     
895     /***
896     * Substitutes the selection by the specified friendly name.
897     * @param the name for the substitution
898     */
899     public void substitute(String name) {
900         SelectionEvent selectionEvent = new SelectionEvent(this);
901 
902         // On rÈcupËre la taille de la sÈlection.
903         Integer selectionSize = null;
904         selectionEvent.setAction(SelectionEvent.GET_SELECTION_SIZE, selectionSize);
905         fireSelectionEvent(selectionEvent);
906         selectionSize = (Integer) selectionEvent.getArgument();
907         // Si diffÈrent de 0, il y a qque chose ? substituer.
908         if (selectionSize.intValue() != 0) {
909             // On rÈcupËre la sÈlection entiËre.
910             Vector selection = null;
911             selectionEvent.setAction(SelectionEvent.GET_SELECTION, selection);
912             fireSelectionEvent(selectionEvent);
913             selection = (Vector) selectionEvent.getArgument();
914             // On crÈÈ la liste des ÈlÈments ? iconifier. (on enlËve les displays
915             // d'opÈrateurs parasites, et aux displays qui restent, on rÈcupËre
916             // la fts dont ils sont le display).
917             Display display;
918             FormulaTreeStructure fts;
919             Vector toIconify = new Vector();
920             for (int i = 0; i < selectionSize.intValue(); i++) {
921                 display = (Display) selection.elementAt(i);
922                 if (!display.isSymbolOperatorDisplay()) {
923                     // On dÈsÈlectionne le display
924                     display.deselect();
925                     // On rÈcupËre le fts associÈ au display.
926                     fts = (FormulaTreeStructure) display.getListener();
927                     // On l'ajoute ? la liste des fts ? iconifier
928                     toIconify.addElement(fts);
929                 }
930             }
931             // On purge la sÈlection
932             selectionEvent.setAction(SelectionEvent.PURGE, null);
933             fireSelectionEvent(selectionEvent);
934             
935             // On rajoute comme premier ÈlÈment ? toIconify le nom de la substitution
936             toIconify.insertElementAt(name, 0);
937             
938             // On envoie l'ÈvÈnement au modËle pour lui dire qu'il faut faire la substitution
939             ControlEvent controlEvent = new ControlEvent(this);
940             controlEvent.setAction(ControlEvent.SUBSTITUTE, toIconify);
941             fireControlEvent(controlEvent);
942         }
943     }
944     
945     
946     // #################################################
947     // ### ImplÈmentation des diffÈrentes interfaces ###
948     // #################################################
949     
950     // *************************************************
951     // *** ImplÈmentation de l'interface Displayable ***
952     
953     /***
954     * Sets the ascent.
955     * @param ascent the new ascent value.
956     */
957     public void setAscent(int ascent) {
958         this.ascent = ascent;
959     }
960 
961     /***
962     * Returns the ascent.
963     * @return the ascent.
964     */
965     public int getAscent() {
966         return ascent;
967     }
968 
969     /***
970     * Sets the descent.
971     * @param descent the new descent value.
972     */
973     public void setDescent(int descent) {
974         this.descent = descent;
975     }
976 
977     /***
978     * Returns the descent.
979     * @return the descent.
980     */
981     public int getDescent() {
982         return descent;
983     }
984     
985     /***
986     * Sets the horizontal shift.
987     * @param shift the new horizontal shift value.
988     */
989     public void setShiftX(int shiftX) {
990         this.shiftX = shiftX;
991     }
992 
993     /***
994     * Returns the horizontal shift.
995     * @return the horizontal shift.
996     */
997     public int getShiftX() {
998         return shiftX;
999     }
1000 
1001     /***
1002     * Sets the vertical shift.
1003     * @param shiftY the new vertical shift value.
1004     */
1005     public void setShiftY(int shiftY) {
1006         this.shiftY = shiftY;
1007     }
1008 
1009     /***
1010     * Returns the vertical shift.
1011     * @return the vertical shift.
1012     */
1013     public int getShiftY() {
1014         return shiftY;
1015     }
1016     
1017     /***
1018     * Sets all the attributes.
1019     * @param ascent the new ascent value.
1020     * @param descent the new descent value.
1021     * @param shiftX the new horizontal shift value.
1022     * @param shiftY the new vertical shift value.
1023     */
1024     public void setAttributes(int ascent, int descent, int shiftX, int shiftY) {
1025         this.ascent = ascent;
1026         this.descent = descent;
1027         this.shiftX = shiftX;
1028         this.shiftY = shiftY;
1029     }
1030         
1031     /***
1032     * Sets the graphic context to the display.
1033     * @param contextGraphic the graphic context.
1034     */
1035     public void setGraphicContext(GraphicContext graphicContext) {
1036         this.graphicContext = graphicContext;
1037     }
1038     
1039     /***
1040     * Returns the graphic context of the display.
1041     */
1042     public GraphicContext getGraphicContext() {
1043         return graphicContext;
1044     }
1045     
1046     // *** Fin de l'interface Displayable ***
1047     // **************************************
1048     
1049     // *************************************************
1050     // *** ImplÈmentation de l'interface Localisable ***
1051     
1052     /***
1053     * Sets the x-location of the instance.
1054     * @param x the x-location of the instance.
1055     */
1056     public void setX(int x) {
1057         setLocation(x, getLocation().y);
1058     }
1059     
1060     /***
1061     * Returns the x-location of the display.
1062     */
1063     public int getX() {
1064         return getLocation().x;
1065     }
1066     
1067     /***
1068     * Sets the y-location of the instance.
1069     * @param y the y-location of the instance.
1070     */
1071     public void setY(int y) {
1072         setLocation(getLocation().x, y);
1073     }
1074     
1075     /***
1076     * Returns the y-location of the display.
1077     */
1078     public int getY() {
1079         return getLocation().y;
1080     }
1081     
1082     // *** Fin de l'interface Localisable ***
1083     // **************************************
1084     
1085     // *********************************************
1086     // *** ImplÈmentation de l'interface Sizable ***
1087     
1088     /***
1089     * Sets the width of the instance.
1090     * @param width the width of the instance
1091     */
1092     public void setWidth(int width) {
1093         setSize(width, getSize().height);
1094     }
1095     
1096     /***
1097     * Returns the width of the display.
1098     */
1099     public int getWidth() {
1100         return getSize().width;
1101     }
1102     
1103     /***
1104     * Sets the height of the instance.
1105     * @param height the height of the instance
1106     */
1107     public void setHeight(int height) {
1108         setSize(getSize().width, height);
1109     }
1110     
1111     /***
1112     * Returns the height of the display.
1113     */
1114     public int getHeight() {
1115         return getSize().height;
1116     }
1117     
1118     // *** Fin de l'interface sizable ***
1119     // **********************************
1120     
1121     
1122     // ****************************************
1123     // ImplÈmentation de l'interface Selectable
1124     
1125     /***
1126     * Selects the display. Selects the instance and its children if any.
1127     */
1128     public void select() {
1129         if (!isSelected) {
1130             isSelected = true;
1131             int count = getComponentCount();
1132             for (int i = 0; i < count; i++)
1133                 ((Display) getComponent(i)).select();
1134         }
1135     }
1136     
1137     /***
1138     * Deselects the display. Deselects the instance and its children if any.
1139     */
1140     public void deselect() {
1141         if (isSelected) {
1142             isSelected = false;
1143             int count = getComponentCount();
1144             for (int i = 0; i < count; i++)
1145                 ((Display) getComponent(i)).deselect();
1146         }
1147     }
1148     
1149     /***
1150     * Sets the display as selected.
1151     */
1152     public void setSelected() {
1153         isSelected = true;
1154     }
1155 
1156     /***
1157     * Sets the display as not selected.
1158     */
1159     public void setNotSelected() {
1160         isSelected = false;
1161     }
1162     
1163     /***
1164     * Checks if the display is selected or not.
1165     * @return <CODE>true</CODE> if the display is selected. 
1166     * <CODE>false</CODE> otherwise.
1167     */
1168     public boolean isSelected() {
1169         return isSelected;
1170     }
1171     
1172     /***
1173     * Returns <CODE>true</CODE> if the display have components selected or is selected.<BR>
1174     * <CODE>false</CODE> otherwise.
1175     */
1176     public boolean gotSelectedElements() {
1177         if (isSelected)
1178             return true;
1179             
1180         int count = getComponentCount();
1181         for (int i = 0; i < count; i++)
1182             if (((Display) getComponent(i)).gotSelectedElements())
1183                 return true;
1184         
1185         return false;
1186     }
1187     
1188     // *** Fin de l'interface Selectable ***
1189     // *************************************
1190     
1191     // *****************************************
1192     // ImplÈmentation de l'interface Colorisable
1193     
1194     /***
1195     * Sets a new color to the context.
1196     * @param foregroundColor the new color.
1197     */
1198     public void setForegroundColor(Color foregroundColor) {
1199         graphicContext.setForegroundColor(foregroundColor);
1200     }
1201  
1202     /***
1203     * Returns the color used by the graphic context.
1204     */
1205     public Color getForegroundColor() {
1206         return graphicContext.getForegroundColor();
1207     }
1208     
1209     /***
1210     * Sets a new color to the context.
1211     * @param backgroundColor the new color.
1212     */
1213     public void setBackgroundColor(Color backgroundColor) {
1214         graphicContext.setBackgroundColor(backgroundColor);
1215     }
1216     
1217 	public void setChildrenBackground(Color backgroundColor) {
1218 		graphicContext.setBackgroundColor(backgroundColor);
1219 		Component[] comp= getComponents();
1220 		for(int i=0;i<comp.length;i++){
1221 			if(comp[i] instanceof Display){
1222 				((Display)comp[i]).setChildrenBackground(backgroundColor);
1223 			}
1224 		}
1225 		
1226 	}
1227     
1228     
1229     /***
1230     * Returns the color used by the graphic context.
1231     */
1232     public Color getBackgroundColor() {
1233         return graphicContext.getBackgroundColor();
1234     }
1235     
1236     /***
1237     * Sets a new selection color to the context.
1238     * @param selectionColor the new color.
1239     */
1240     public void setSelectionColor(Color selectionColor) {
1241         graphicContext.setSelectionColor(selectionColor);
1242     }
1243 
1244     /***
1245     * Returns the color used in the graphic context to hilight the selection.
1246     */
1247     public Color getSelectionColor() {
1248         return graphicContext.getSelectionColor();
1249     }
1250     
1251     // *** Fin de l'interface Colorisable ***
1252     // **************************************
1253     
1254     // *****************************************
1255     // ImplÈmentation de l'interface Iconifiable
1256     
1257     // MÍme si en fait ce n'est pas un display que l'on va iconifier, on implÈmente l'interface
1258     // iconifiable, parce que c'est ? partir de l? que le processus d'iconification va Ítre lancÈ,
1259     // notamment en parcourant la liste de tous les display sÈlectionnÈs, potentiellement iconifiables.
1260     
1261     /***
1262     * Associates an icon name to the instance.
1263     *
1264     * @param iconName the name of the icon
1265     */
1266     public void setIconName(String iconName) {
1267         // on ne fait rien, ce n'est pas un display que l'on va iconifier.
1268     }
1269 
1270     /***
1271     * Returns the name of the icon associated to the instance.
1272     *
1273     * @returns The name of the icon, or <CODE>null</CODE> if there is no name
1274     * associated.
1275     */
1276     public String getIconName() {
1277         return null; // ce n'est pas un display que l'on va iconifier.
1278     }
1279     
1280     /***
1281     * @return <CODE>true</CODE> if the instance is an icon. <CODE>false</CODE> otherwise.
1282     */
1283     public boolean isIcon() {
1284         return false; // ce n'est pas un display que l'on va iconifier.
1285     }
1286     
1287     /***
1288     * Iconifies all the selected elements of the formula.
1289     */
1290     public void iconify() {
1291         SelectionEvent selectionEvent = new SelectionEvent(this);
1292 
1293         // On rÈcupËre la taille de la sÈlection.
1294         Integer selectionSize = null;
1295         selectionEvent.setAction(SelectionEvent.GET_SELECTION_SIZE, selectionSize);
1296         fireSelectionEvent(selectionEvent);
1297         selectionSize = (Integer) selectionEvent.getArgument();
1298         // Si diffÈrente de 0, il y a qque chose ? iconifier.
1299         if (selectionSize.intValue() != 0) {
1300             // On rÈcupËre la sÈlection entiËre.
1301             Vector selection = null;
1302             selectionEvent.setAction(SelectionEvent.GET_SELECTION, selection);
1303             fireSelectionEvent(selectionEvent);
1304             selection = (Vector) selectionEvent.getArgument();
1305             // On crÈÈ la liste des ÈlÈments ? iconifier. (on enlËve les displays
1306             // d'opÈrateurs parasites, et aux displays qui restent, on rÈcupËre
1307             // la fts dont ils sont le display).
1308             Display display;
1309             FormulaTreeStructure fts;
1310             Vector toIconify = new Vector();
1311             for (int i = 0; i < selectionSize.intValue(); i++) {
1312                 display = (Display) selection.elementAt(i);
1313                 if (!display.isSymbolOperatorDisplay()) {
1314                     // On dÈsÈlectionne le display
1315                     display.deselect();
1316                     // On rÈcupËre le fts associÈ au display.
1317                     fts = (FormulaTreeStructure) display.getListener();
1318                     // On l'ajoute ? la liste des fts ? iconifier
1319                     toIconify.addElement(fts);
1320                 }
1321             }
1322             // On purge la sÈlection
1323             selectionEvent.setAction(SelectionEvent.PURGE, null);
1324             fireSelectionEvent(selectionEvent);
1325             // On envoie l'ÈvÈnement au modËle pour lui dire qu'il faut iconifier
1326             ControlEvent controlEvent = new ControlEvent(this);
1327             controlEvent.setAction(ControlEvent.ICONIFY, toIconify);
1328             fireControlEvent(controlEvent);
1329         }
1330     }
1331 
1332     /***
1333     * Uniconifies all the selected icons which are in the formula.
1334     */
1335     public void uniconify() {
1336         SelectionEvent selectionEvent = new SelectionEvent(this);
1337         // On rÈcupËre la taille de la sÈlection.
1338         Integer selectionSize = null;
1339         selectionEvent.setAction(SelectionEvent.GET_SELECTION_SIZE, selectionSize);
1340         fireSelectionEvent(selectionEvent);
1341         selectionSize = (Integer) selectionEvent.getArgument();
1342         // Si diffÈrente de 0, il y a Èventuellement qque chose ? dÈsiconifier.
1343         if (selectionSize.intValue() != 0) {
1344             // On rÈcupËre la sÈlection entiËre.
1345             Vector selection = null;
1346             selectionEvent.setAction(SelectionEvent.GET_SELECTION, selection);
1347             fireSelectionEvent(selectionEvent);
1348             selection = (Vector) selectionEvent.getArgument();
1349             selectionEvent.setAction(SelectionEvent.PURGE, null);
1350             fireSelectionEvent(selectionEvent);
1351             // On parcourt la liste de sÈlection, et si l'on a affaire ? une icone
1352             // on la dÈsiconifie.
1353             Display display = null;
1354             FormulaTreeStructure fts = null;
1355             for (int i = 0; i < selectionSize.intValue(); i++) {
1356                 display = (Display) selection.elementAt(i);
1357                 // On dÈsÈlectionne le display.
1358                 display.deselect();
1359                 // On rÈcupËre le fts associÈ au display.
1360                 fts = (FormulaTreeStructure) display.getListener();
1361                 if (fts.isIcon()) {
1362                     display.computeAncestorsAttributes();
1363                     // On envoie un ÈvÈnement pour dire au modËle qu'il doit
1364                     // dÈisconifier fts.
1365                     ControlEvent controlEvent = new ControlEvent(this);
1366                     controlEvent.setAction(ControlEvent.UNICONIFY, fts);
1367                     fireControlEvent(controlEvent);
1368                 }
1369             }
1370         }
1371     }
1372     
1373     /***
1374     * Uniconifies all the selected icons.<BR>
1375     * If the icons contains other icons, these are uniconified. There is a
1376     * recursion process.
1377     */
1378     public void uniconifyAll() {
1379         ControlEvent controlEvent = new ControlEvent(this);
1380         controlEvent.setAction(ControlEvent.UNICONIFY_ALL, null);
1381         fireControlEvent(controlEvent);
1382     }
1383     
1384     /***
1385     * Sets the istance as iconifiable.
1386     * @param isIconifiable <CODE>true</CODE> if the instance is iconifiable.
1387     * <CODE>false</CODE> otherwise.
1388     */
1389     public void setIsIconifiable(boolean isIconifiable) {
1390         // Ce n'est pas un display que l'on va iconifier
1391     }
1392     
1393     /***
1394     * Returns <CODE>true</CODE> if the instance is iconifiable.
1395     * <CODE>false</CODE> otherwise.
1396     */
1397     public boolean isIconifiable() {
1398         // Ce n'est pas un display que l'on va iconifier
1399         return false;
1400     }
1401     
1402     // *** Fin de l'interface Iconifiable ***
1403     // **************************************
1404     
1405     
1406     // *****************************************************
1407     // ImplÈmentation de l'interface ModelListenerController
1408     
1409     /***
1410     * Registers another listener to be informed of changes of the display.
1411     * @param controlListener a listener to add.
1412     */
1413     public void addControlListener(ControlListener controlListener) {
1414         listener = controlListener;
1415     }
1416 
1417     /***
1418     * Removes all the listeners.
1419     */
1420     public void removeAllControlListener() {
1421         listener = null;
1422     }
1423     
1424     /***
1425     * Removes a listener.
1426     * @param controlListener a listener to remove.
1427     */
1428     public void removeControlListener(ControlListener controlListener) {
1429         listener  = null;
1430     }
1431     
1432     /***
1433     * Fires a Control event to registered listeners.
1434     * @param controlEvent event encapsulating relevant information.
1435     */
1436     public void fireControlEvent(ControlEvent controlEvent) {
1437         listener.consumeControlEvent(controlEvent);
1438     }
1439     
1440     /***
1441     * Returns the listener of the dispay. (i.e. a fts)
1442     */
1443     public ControlListener getListener() {
1444         return listener;
1445     }
1446 
1447     // *** Fin de l'interface ModelListenerController ***
1448     // **************************************************
1449     
1450     
1451     // Selection management.
1452     
1453     /***
1454     * Registers another listener to be informed of changes of the display.
1455     * @param selectionEventListener a listener to add.
1456     */
1457     public void addSelectionEventListener(SelectionEventListener selectionEventListener) {
1458         selectionManager = selectionEventListener;
1459     }
1460     
1461     /***
1462     * Removes a listener.
1463     * @param selectionEventListener listener to remove.
1464     */
1465     public void removeSelectionEventListener(SelectionEventListener selectionEventListener) {
1466         if (selectionEventListener == selectionManager)
1467             selectionManager = null;
1468     }
1469     
1470     /***
1471     * Fires a SelectionEvent event to registered listeners.
1472     * @param selectionEvent event encapsulating relevant information.
1473     */
1474     public void fireSelectionEvent(SelectionEvent selectionEvent) {
1475         selectionManager.consumeSelectionEvent(selectionEvent);
1476     }
1477     
1478 	public void setMouseListener(MouseListener listener){
1479 		mouseListener = listener;
1480 		Component[] comp= getComponents();
1481 		for(int i=0;i<comp.length;i++){
1482 			if(comp[i] instanceof Display){
1483 				((Display)comp[i]).setMouseListener(listener);
1484 			}
1485 		}
1486 	}
1487     
1488     
1489     /***
1490     * For debugg only !!!!
1491     */
1492 
1493     public void ToString() {
1494         System.out.println(super.toString());
1495         System.out.println("\t x = " + getX() + " y = " + getY());
1496         System.out.println("\t ascent = " + ascent + " descent = " + descent);
1497         System.out.println("\t width = " + getWidth() + " height = " + getHeight());
1498     }
1499     
1500     public void whoAmI() {
1501         System.out.println("I am a " + getClass().getName() + " with the " + getLayout().getClass().getName()  + " manager");
1502         System.out.println("My level is " + level);
1503         System.out.println("My children are :");
1504         for (int i = 0; i < getComponentCount(); i++)
1505             ((Display) getComponent(i)).whoAmI();
1506     }
1507 }