View Javadoc

1   package fr.ove.openmath.jome.ctrlview.bidim;
2   
3   import java.awt.*;
4   import fr.ove.openmath.jome.ctrlview.bidim.*;
5   import fr.ove.openmath.jome.ctrlview.bidim.selection.events.SelectionEvent;
6   import fr.ove.openmath.jome.model.*;
7   import fr.ove.openmath.jome.behaviour.*;
8   
9   /***
10  * A layout manager that lays components to be displayed between something.<BR>
11  * Obviously, what is called something will be parenthesis, braces, ....
12  *
13  * @author © 1999 DIRAT Laurent
14  * @version 2.0  13/12/1999
15  */
16  public abstract class EnclosingLayout extends HorizontalLayout {
17      /***
18      * The opening of the enclosure
19      */
20      private SymbolDisplay opening;
21      
22      /***
23      * The closing of the enclosure
24      */
25      private SymbolDisplay closing;
26      
27      /***
28      * Returns the opening
29      */
30      public SymbolDisplay getOpening() {
31          return opening;
32      }
33      
34      /***
35      * Returns the closing
36      */
37      public SymbolDisplay getClosing() {
38          return closing;
39      }
40      
41      /***
42      * According to the operator, the layout manager has to add some components (e.g. brackets, ...)
43      * or has to perform some "re-oganisation" before rendering.<BR>
44      * As soon as the layout manager is set to the display, this mehtod MUST be called with the display laid out
45      * as parameter. This method serves as well as a registering method. So all sub-classes of the instance MUST
46      * call super.initDisplay(displayToLay).
47      * @param displayToLay the display laid by the instance
48      */
49      public void initDisplay(Display displayToLay) {
50          super.initDisplay(displayToLay);
51          
52          FormulaTreeStructure fts = (FormulaTreeStructure) displayToLay.getListener();
53          if (((Maskable) fts).isVisible()) {
54              opening = createOpening();
55  
56              // On met un listener ? l'opening
57              // En fait, il n'y en a pas besoin, dans le sens o? il n'y a pas spÈcifiquement de fts qui
58              // Ècoute le comportement de ce display. NÈanmoins, il s'avËre nÈcessaire qu'il en ait
59              // un, par exemple lors de l'iconification, car c'est le display qui reÁoit la demande
60              // d'iconification qui envoie l'ÈvÈnement correspondant ? la FTS. Or si ce display n'a pas
61              // d'Ècouteur, alors pb. Par cohÈrence, l'Ècouteur du display d'opÈrateur, est le fts qui
62              // reprÈsente cette opÈration. Par contre, la fts en question, n'Ècoute pas le display
63              // d'opÈrateur.
64              opening.addControlListener(fts);
65              this.displayToLay.add(opening);
66              
67              closing = createClosing();
68              closing.addControlListener(fts);
69              this.displayToLay.add(closing);
70          }
71      }
72      
73      /***
74      * Checks the validity of the selection.
75      */
76      public void validateSelection() {
77          SelectionEvent selEvt = new SelectionEvent(displayToLay);
78  
79          if (((Maskable) displayToLay.getListener()).isVisible()) {
80              // La validitÈ de la sÈlection est triviale.
81              // Si l'une ou l'autre des parenthËse est sÈlectionnÈe, alors on sÈlectionne
82              // tout.
83              if (opening.isSelected() || closing.isSelected()) {
84                  // SÈlectionne le display.
85                  displayToLay.select();
86                  // On purge la liste des ÈlÈments sÈlectionnÈs.
87                  selEvt.setAction(SelectionEvent.PURGE, null);
88                  displayToLay.fireSelectionEvent(selEvt);
89                  // On y ajoute nos parenthËses
90                  selEvt.setAction(SelectionEvent.ADD, displayToLay);
91                  displayToLay.fireSelectionEvent(selEvt);
92              }
93          }
94  
95          // On a vÈrifiÈ la validitÈ de la sÈlection de la puissance. On doit maitenant
96          // la contrÙler au niveau supÈrieur, au niveau du pËre.
97          Display display = displayToLay;
98          if (displayToLay.getParent() instanceof Display) {
99              display = (Display) displayToLay.getParent();
100             FormulaTreeStructure fts = (FormulaTreeStructure) display.getListener();
101             if (fts.getFather() != null)
102                 ((DisplayLayout) display.getLayout()).validateSelection();
103         }
104 
105         // On met ? jour l'affichage.
106         display.repaint();
107     }
108 
109     /***
110     * Checks the validity of the deselection.
111     * @param display the display to deselect.
112     */
113     public void validateDeselection(Display display) {
114         Display father = displayToLay;
115         Display tmp;
116         SelectionEvent selEvt = new SelectionEvent(displayToLay);
117 
118         // Si les parenthËses sont sÈlectionnÈes, alors il faut les dÈselectionner.
119         if (father.isSelected()) {
120             father.setNotSelected();
121             // On enlËve le display pËre de la liste des display sÈlectionnÈs.
122             selEvt.setAction(SelectionEvent.REMOVE, father);
123             father.fireSelectionEvent(selEvt);
124 
125             if (((Maskable) displayToLay.getListener()).isVisible()) {
126                 if (display == opening)
127                     closing.setNotSelected();
128                 else
129                     opening.setNotSelected();
130                     
131                 // L'opÈrande est mis dans la liste des sÈlectionnÈs
132                 selEvt.setAction(SelectionEvent.ADD, (Display) father.getComponent(2));
133                 father.fireSelectionEvent(selEvt);
134             }
135 
136             // Comme pour la sÈlection, on contrÙle la validitÈ de la dÈsÈlection.
137             if (father.getParent() instanceof Display) {
138                 father = (Display) father.getParent();
139                 FormulaTreeStructure fts = (FormulaTreeStructure) father.getListener();
140                 if (fts.getFather() != null)
141                     ((DisplayLayout) father.getLayout()).validateDeselection(displayToLay);
142             }
143 
144             // HÈ oui, on contrÙle la validitÈ de la sÈlection... dans une dÈsÈlection.
145             // Toujours le mÍme pb, est-ce que le nouvel Ètat de la sÈlection (aprËs
146             // dÈsÈlection donc) est syntaxiquement cohÈrent ?
147             validateSelection();
148 
149             // On met ? jour l'affichage.
150             father.repaint();
151         }
152 
153     }
154 
155     /***
156     * Computes the size of the display according to its children size (if any),
157     * and its different attributes.
158     * @return the size of the display.
159     */
160     public Dimension computeAttributes() {
161         Display display = null;
162 
163         if (((Maskable) displayToLay.getListener()).isVisible()) {
164             Displayable openingSymbol = opening.getSymbol();
165             Displayable closingSymbol = closing.getSymbol();
166             
167             // On met la hauteur ? 0, pour que dans tous les cas, le super.computeAttributes() ne soit pas
168             // biaisÈe par une Èventuelle nouvelle taille des ÈlÈments qui composent la liste.
169             // Comme c'est plus loin qu'on leur fixe la taille....
170             openingSymbol.setHeight(0);
171             opening.setHeight(0);
172             closingSymbol.setHeight(0);
173             closing.setHeight(0);
174             
175             // mÍme remarque que ci-dessus
176             opening.setAttributes(0, 0, 0, 0);
177             closing.setAttributes(0, 0, 0, 0);
178             ((Display) displayToLay.getComponent(2)).setShiftX(0);
179             
180             Dimension dim = super.computeAttributes();
181             
182             // Par contre, par rapport ? comment est calculÈe la taille display, dim comprend
183             // dÈj? la largeur de opening et closing
184             
185             openingSymbol.setAscent(displayToLay.getAscent());
186             openingSymbol.setDescent(displayToLay.getDescent());
187             openingSymbol.setHeight(displayToLay.getHeight());
188             opening.setComputeAttributes(true);
189             opening.invalidate();
190             opening.setSize(opening.getPreferredSize());
191 
192             closingSymbol.setAscent(displayToLay.getAscent());
193             closingSymbol.setDescent(displayToLay.getDescent());
194             closingSymbol.setHeight(displayToLay.getHeight());
195             closing.setComputeAttributes(true);
196             closing.invalidate();
197             closing.setSize(closing.getPreferredSize());
198             
199             // Cette taille l? correspond au dÈcalage qu'il faut appliquer ? closing
200             closing.setShiftX(dim.width - 2*closing.getWidth());
201             // Mais il faut l'enlever au display du milieu qui doit Ítre contre l'opening (because HonrizontalLayout)
202             ((Display) displayToLay.getComponent(2)).setShiftX(-closing.getShiftX() - closing.getWidth());
203             
204             return dim;
205         }
206         else
207             return super.computeAttributes();
208     }
209 
210     /***
211     * The display needs to be rebuilt. We do this.
212     */
213     public void rebuildDisplay() {
214         // La taille des displays est probablement diffÈrente de ceux qui Ètaient
215         // prÈcÈdemment. On demande alors le recalcul des display ancÍtres.
216         displayToLay.computeAncestorsAttributes();
217     }
218         
219     // ############################################
220     // ### Les diffÈrentes mÈthodes abstraites  ###
221     // ############################################
222     
223     /***
224     * Returns the opening
225     */
226     public abstract SymbolDisplay createOpening();
227     
228     /***
229     * Returns the closing
230     */
231     public abstract SymbolDisplay createClosing();
232 }