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   
8   /***
9   * Layout manager that lays the display of an operator whose symbol is located between its 2 operands.<BR>
10  * Rendering is done vertically, the first operand on top, the symbol in the middle and the second operand
11  * under the 2 previous.
12  *
13  * @author © 1999 DIRAT Laurent
14  * @version 2.0 15/12/1999
15  */
16  public abstract class BetweenOperatorLayout extends VerticalCenteredLayout implements OperatorDisplayCreator {
17      /***
18      * According to the operator, the layout manager has to add some components (e.g. brackets, ...)
19      * or has to perform some "re-oganisation" before rendering.<BR>
20      * As soon as the layout manager is set to the display, this mehtod MUST be called with the display laid out
21      * as parameter. This method serves as well as a registering method. So all sub-classes of the instance MUST
22      * call super.initDisplay(displayToLay).
23      * @param displayToLay the display laid by the instance
24      */
25      public void initDisplay(Display displayToLay) {
26          super.initDisplay(displayToLay);
27          Display operatorDisplay = createOperatorDisplay();
28  
29          // On met un listener au display de l'opÈrateur
30          // En fait, il n'y en a pas besoin, dans le sens o? il n'y a pas spÈcifiquement de fts qui
31          // Ècoute le comportement de ce display. NÈanmoins, il s'avËre nÈcessaire qu'il en ait
32          // un, par exemple lors de l'iconification, car c'est le display qui reÁoit la demande
33          // d'iconification qui envoie l'ÈvÈnement correspondant ? la FTS. Or si ce display n'a pas
34          // d'Ècouteur, alors pb. Par cohÈrence, l'Ècouteur du display d'opÈrateur, est le fts qui
35          // reprÈsente cette opÈration. Par contre, la fts en question, n'Ècoute pas le display
36          // d'opÈrateur.
37          operatorDisplay.addControlListener((FormulaTreeStructure) displayToLay.getListener());
38          this.displayToLay.add(operatorDisplay);
39      }
40      
41      /***
42      * Checks the validity of the selection.
43      */
44      public void validateSelection() {
45          SelectionEvent selEvt = new SelectionEvent(displayToLay);
46  
47          // La validitÈ de la sÈlection est triviale.
48          // Si les 2 opÈrandes sont sÈlectionnÈs, ou si le symbole de l'opÈrateur est sÈlectionnÈ,
49          // alors on sÈlectionne tout.
50          Display operatorDisplay = (Display) displayToLay.getComponent(0);
51          Display operand1 = (Display) displayToLay.getComponent(1);
52          Display operand2 = (Display) displayToLay.getComponent(2);
53          if ((operand1.gotSelectedElements() && operand2.gotSelectedElements()) ||
54              (operatorDisplay.isSelected())) {
55              // SÈlectionne le display.
56              displayToLay.select();
57              // On purge la liste des ÈlÈments sÈlectionnÈs.
58              selEvt.setAction(SelectionEvent.PURGE, null);
59              displayToLay.fireSelectionEvent(selEvt);
60              // On y ajoute os parenthËses
61              selEvt.setAction(SelectionEvent.ADD, displayToLay);
62              displayToLay.fireSelectionEvent(selEvt);
63          }
64  
65          // On a vÈrifiÈ la validitÈ de la sÈlection de la puissance. On doit maitenant
66          // la contrÙler au niveau supÈrieur, au niveau du pËre.
67          Display display = displayToLay;
68          if (display.getParent() instanceof Display) {
69              display = (Display) display.getParent();
70              FormulaTreeStructure fts = (FormulaTreeStructure) display.getListener();
71              if (fts.getFather() != null)
72                  ((DisplayLayout) display.getLayout()).validateSelection();
73          }
74  
75          // On met ? jour l'affichage.
76          display.repaint();
77      }
78      
79      /***
80      * Checks the validity of the deselection.
81      * @param display the display to deselect.
82      */
83      public void validateDeselection(Display display) {
84          Display father = displayToLay;
85          SelectionEvent selEvt = new SelectionEvent(father);
86          
87          // Si la fraction est sÈlectionnÈe, alors il faut la dÈselectionner.
88          if (father.isSelected()) {
89              father.setNotSelected();
90              // On enlËve le display pËre de la liste des display sÈlectionnÈs.
91              selEvt.setAction(SelectionEvent.REMOVE, father);
92              father.fireSelectionEvent(selEvt);
93              
94              Display operatorDisplay = (Display) father.getComponent(0);
95              Display operand1 = (Display) father.getComponent(1);
96              Display operand2 = (Display) father.getComponent(2);
97              
98              if (display == operand1) {
99                  operatorDisplay.setNotSelected();
100                 selEvt.setAction(SelectionEvent.ADD, operand2);
101                 father.fireSelectionEvent(selEvt);
102             }
103             else if (display == operand2) {
104                 operatorDisplay.setNotSelected();
105                 selEvt.setAction(SelectionEvent.ADD, operand1);
106                 father.fireSelectionEvent(selEvt);
107             }
108             else {
109                 operand1.deselect();
110                 operatorDisplay.setNotSelected();
111                 operand2.deselect();
112             }
113 
114             // Comme pour la sÈlection, on contrÙle la validitÈ de la dÈsÈlection.
115             if (father.getParent() instanceof Display) {
116                 father = (Display) father.getParent();
117                 FormulaTreeStructure fts = (FormulaTreeStructure) father.getListener();
118                 if (fts.getFather() != null)
119                     ((DisplayLayout) father.getLayout()).validateDeselection(displayToLay);
120             }
121             
122             // HÈ oui, on contrÙle la validitÈ de la sÈlection... dans une dÈsÈlection.
123             // Toujours le mÍme pb, est-ce que le nouvel Ètat de la sÈlection (aprËs
124             // dÈsÈlection donc) est syntaxiquement cohÈrent ?
125             validateSelection();
126             
127             // On met ? jour l'affichage.
128             father.repaint();
129         }        
130     }
131     
132     /***
133     * Computes the size of the display according to its children size (if any),
134     * and its different attributes.
135     * @return the size of the display.
136     */
137     public Dimension computeAttributes() {
138         Display displayOperator = (Display) displayToLay.getComponent(0);
139         Display topOperand = (Display) displayToLay.getComponent(1);
140         Display bottomOperand = (Display) displayToLay.getComponent(2);
141         // Initialisation de ces paramËtres pour annuler les (Èventuelles) prÈcÈdentes valeurs prises.
142         displayOperator.setShiftY(0);
143         topOperand.setShiftY(0);
144         bottomOperand.setShiftY(0);
145 
146         // On calcule les attributs des display enfants comme si on avait affaire ? un VerticalCenteredLayout.
147         // La diffÈrece rÈside dans le fait qu'il faut faire en sorte que le display de l'opÈrateur soit affichÈ
148         // entre les opÈrandes
149         Dimension dim = super.computeAttributes(); 
150         
151 
152         // Cette taille l? correspond au dÈcalage qu'il faut appliquer ? la barre de fraction
153         displayOperator.setShiftY(topOperand.getHeight());
154         // Mais il faut l'enlever au display du numÈrateur
155         topOperand.setShiftY(-displayOperator.getShiftY() - displayOperator.getHeight());
156         bottomOperand.setShiftY(displayOperator.getHeight());
157         
158         // On met la baseline de la fraction sur celle de la barre de fraction + qque broutilles qui
159         // correspondent ? o? se trouve la barre horizontale du +
160         int ascent = displayToLay.getFontMetrics(displayToLay.getFont()).getAscent();
161         ascent = (int) Math.round(((float) ascent)*0.388f);
162         
163         ascent += topOperand.getShiftY() + topOperand.getHeight() + 
164                  displayOperator.getShiftY() + displayOperator.getAscent();
165         
166         displayToLay.setAscent(ascent);
167         displayToLay.setDescent(dim.height - ascent);
168         
169         displayToLay.setComputeAttributes(false);
170         
171         return dim;
172     }
173     
174     /***
175     * The display needs to be rebuilt. We do this.
176     */
177     public void rebuildDisplay() {
178         Display tmp;
179         Display listDisplay[] = new Display[2];
180         
181         for (int i = 1; i <= 2; i++) {
182             tmp = (Display) displayToLay.getComponent(i);
183             tmp.setLocation(0,0);
184             listDisplay[((FormulaTreeStructure) tmp.getListener()).getRank()] = tmp;
185         }
186         
187         // On garde un rÈfÈrence sur le display du symbole l'opÈrateur
188         tmp = (Display) displayToLay.getComponent(0);
189         // On fait en sorte que temporairement ce display ne soit pas considÈrÈ comme un
190         // display d'opÈrateur, sinon il serait supprimÈ de la liste des listeners de la fts,
191         // chose qu'on ne veut pas puisque qu'on va le remettre ? sa place.
192         tmp.setIsSymbolOperatorDisplay(false);
193         
194         // ATTENTION : ici, on enlËve les displays fils de display, mais on ne les enlËve pas de la liste
195         // des listeners de la fts qu'il sont en train d'Ècouter.
196         displayToLay.removeAllDisplays();
197         
198         // On remet tmp comme Ètant un display d'opÈrateur
199         tmp.setIsSymbolOperatorDisplay(true);
200         // On le rajoute dans displayToLay ? sa position (la premiËre)
201         displayToLay.add(tmp);
202                 
203         for (int i = 0; i < 2; i++)
204             displayToLay.add(listDisplay[i]);
205         
206         // La taille des displays est probablement diffÈrente de ceux qui Ètaient
207         // prÈcÈdemment. On demande alors le recalcul des display ancÍtres.
208         displayToLay.computeAncestorsAttributes();
209     }
210 }