View Javadoc

1   package fr.ove.openmath.jome.ctrlview.bidim;
2   
3   import java.awt.*;
4   import java.util.*;
5   import fr.ove.openmath.jome.ctrlview.bidim.*;
6   import fr.ove.openmath.jome.ctrlview.bidim.selection.events.*;
7   import fr.ove.openmath.jome.model.*;
8   
9   /***
10  * A layout manager for an infix operator which symbol can be rendered as a string (e.g. +, *)
11  *
12  * @author © 1999 DIRAT Laurent
13  * @version 2.0  14/12/1999
14  */
15  public class BasicStringInfixOperatorLayout extends StringInfixOperatorLayout {    
16      /***
17      * Inserts, if necessary, a display of the operator symbol that the display
18      * laid by the instance represents.
19      */
20      protected void insertOperatorDisplay() {
21          Display current, next, displayOperator;
22          FormulaTreeStructure fatherFts = (FormulaTreeStructure) displayToLay.getListener();
23          FormulaTreeStructure fts;
24          int nbComponent = displayToLay.getComponentCount();
25          
26          // On parcourre tous les components prÈsents dans le display.
27          for (int i = 1; i < nbComponent; i++) {
28              // la rÈfÈrence sur le component courant
29              current = (Display) displayToLay.getComponent(i - 1);
30              // la rÈfÈrence sur le suivant
31              next = (Display) displayToLay.getComponent(i);
32              
33              // Si le courant est un display d'opÈrateur alors on continue
34              if (current.isSymbolOperatorDisplay())
35                  continue;
36                  
37              // Si le suivant n'est pas un display d'opÈrateur alors 2 cas
38              if (!next.isSymbolOperatorDisplay()) {
39                  // La seule distinction qu'il faut faire ? ce stade l?, c'est le cas o? next
40                  // est le diplay d'un - unaire. Si c'est le cas, on n'insËre pas de display.
41                  fts = (FormulaTreeStructure) next.getListener();
42                  if (fts.isOperator()) {
43                      String ope = ((Operator) fts).getTheOperator();
44                      if (ope.equals("-"))
45                          continue;
46                  }
47                      
48                  // On ajoute un display d'opÈrateur.
49                  displayOperator = createOperatorDisplay();
50                  displayToLay.add(displayOperator, displayOperator, i);
51                  
52                  // On met un listener ? l'opÈrateur.
53                  // En fait, il n'y en a pas besoin, dans le sens o? il n'y a pas spÈcifiquement de fts qui
54                  // Ècoute le comportement de ce display. NÈanmoins, il s'avËre nÈcessaire qu'il en ait
55                  // un, par exemple lors de l'iconification, car c'est le display qui reÁoit la demande
56                  // d'iconification qui envoie l'ÈvÈnement correspondant ? la FTS. Or si ce display n'a pas
57                  // d'Ècouteur, alors pb. Par cohÈrence, l'Ècouteur du display d'opÈrateur, est le fts qui
58                  // reprÈsente cette opÈration. Par contre, la fts en question, n'Ècoute pas le display
59                  // d'opÈrateur.
60                  displayOperator.addControlListener(fatherFts);
61                  i++;
62                  nbComponent++;
63              }
64          }
65          
66          // Mise ? jour des rangs des displays
67          displayToLay.adjustRank();
68          // Mise ? jour du nombre de components prÈsents dans le display.
69          prevNbComponent = displayToLay.getComponentCount();
70          // On n'a plus besoin d'insÈrer des displays d'opÈrateur.
71          insertOperatorDisplay = false;
72          // On fait en sorte que la mise ? niveau des displays (opÈrateurs) soit faite.
73          displayToLay.setUpdateLevel(true);
74          // On a rajoutÈ un display, on demande le recalcul de tous les ancÍtres
75          // de l'instance.
76          displayToLay.computeAncestorsAttributes();
77      }
78      
79      /***
80      * Checks the validity of the selection.
81      */
82      public void validateSelection() {
83          Display childDisplay;
84          DisplayLayout childLayout;
85          SelectionEvent selEvt = new SelectionEvent(displayToLay);
86          
87          int nbChild = displayToLay.getComponentCount();
88          
89          // On parcourre la liste des displays, et on regarde sur chacun des dispays s'il faut sÈlectionner
90          // un de ses voisins.
91          for (int i = 0; i < nbChild; i++) {
92              childDisplay = (Display) displayToLay.getComponent(i);
93              childLayout = (DisplayLayout) childDisplay.getLayout();
94              
95              // On regarde ici s'il faut sÈlectionner le display ? gauche de childLayout
96              // Si ledit display n'est pas sÈlectionner, on le sÈlectionne.
97              if (childLayout.selectLeftDisplay() && (i > 0)) {
98                  childDisplay = (Display) displayToLay.getComponent(i-1);
99                  if (!childDisplay.isSelected())
100                     childDisplay.select();
101             }
102 
103             // On regarde ici s'il faut sÈlectionner le display ? droite de childLayout
104             // Si ledit display n'est pas sÈlectionner, on le sÈlectionne.
105             if (childLayout.selectRightDisplay() && (i < (nbChild - 1))) {
106                 childDisplay = (Display) displayToLay.getComponent(i+1);
107                 if (!childDisplay.isSelected())
108                     childDisplay.select();
109                 // On a sÈlectionnÈ le display ? la position i+1, donc on incrÈmente ici i,
110                 // pour que dans le for, le i soit encore incrÈmentÈ et que l'on se positionne
111                 // ainsi sur un display suivant, non sÈlectionnÈ
112                 i++;
113             }
114         }
115         
116         // On parcourre la liste des displays et on regarde si les displays ? gauche et ? droite du display
117         // courant ont des ÈlÈments sÈlectionnÈs. Si c'est le cas et que le display courant est un display
118         // d'opÈrateur et qu'il n'est pas sÈlectionnÈ, alors on sÈlectionne le display ? gauche, le displa
119         // d'opÈrateur et le display ? droite.
120         // Ex: (...) + (...), dans chacune des parenthËses, un ÈlÈment est sÈlectionnÈ, on sÈlectionne tout
121         Display prev;
122         Display next;
123         for (int i = 1; i < (nbChild - 1); i++) {
124             prev = (Display) displayToLay.getComponent(i-1);
125             childDisplay = (Display) displayToLay.getComponent(i);
126             next = (Display) displayToLay.getComponent(i+1);
127             if (prev.gotSelectedElements() && next.gotSelectedElements()) {
128                 //if ((childDisplay instanceof StringDisplay) && !childDisplay.isSelected()) {
129                 if (childDisplay.isSymbolOperatorDisplay() && !childDisplay.isSelected()) {
130                     if (!prev.isSelected())
131                         prev.select();
132                     childDisplay.select();
133                     if (!next.isSelected())
134                         next.select();
135                 }
136             }
137         }
138         
139         // On crÈÈ maintenant une liste contenant tous les displays qui ont ÈtÈ sÈlectionnÈs au cours des
140         // opÈrations prÈcÈdentes.
141         Vector list = new Vector();
142         for (int i = 0; i < nbChild; i++) {
143             childDisplay = (Display) displayToLay.getComponent(i);
144             if (childDisplay.gotSelectedElements())
145                 list.addElement(childDisplay);
146         }
147 
148         if (list.size() > 0) {
149             if ((list.size() == nbChild) && !(displayToLay.getListener() instanceof Formula) && !(displayToLay.getListener() instanceof Slot)) {
150                 selEvt.setAction(SelectionEvent.PURGE, null);
151                 displayToLay.fireSelectionEvent(selEvt);
152 
153                 displayToLay.setSelected();
154                 selEvt.setAction(SelectionEvent.ADD, displayToLay);
155                 displayToLay.fireSelectionEvent(selEvt);
156             }
157             else if (list.size() != 1) {
158                 selEvt.setAction(SelectionEvent.PURGE, null);
159                 displayToLay.fireSelectionEvent(selEvt);
160 
161                 for (Enumeration e = list.elements(); e.hasMoreElements(); ) {
162                     childDisplay = (Display) e.nextElement();
163                     if (!childDisplay.isSelected())
164                         childDisplay.select();
165                     selEvt.setAction(SelectionEvent.ADD, childDisplay);
166                     displayToLay.fireSelectionEvent(selEvt);
167                 }
168             }
169         }
170         
171         // On a une sÈlection valide dans le display layed.
172         // On demande la validation au niveau de son pËre.
173         // En principe, ? cause du test sur le fait d'avoir une Formula, pas besoin
174         // d'avoir le test juste suivant. A surveiller.
175         Display display = displayToLay;
176         if (display.getParent() instanceof Display) {
177             display = (Display) display.getParent();
178             //if (!(display.getListener() instanceof Formula))
179             FormulaTreeStructure fts = (FormulaTreeStructure) display.getListener();
180             if (fts.getFather() != null)
181                 ((DisplayLayout) display.getLayout()).validateSelection();
182         }
183         
184         display.repaint(); // faut voir, parce que autant de repaint que de display ?????????
185     }
186 
187 
188     /***
189     * Checks the validity of the deselection.
190     * @param display the display to deselect.
191     */
192     public void validateDeselection(Display display) {
193         Display father = displayToLay;
194         Display tmp;
195         SelectionEvent selEvt = new SelectionEvent(father);
196         int rank = display.getRank();
197 
198         // Premier cas: father (i.e. le display gÈrÈ par l'instance) est sÈlectionnÈ.
199         if (father.isSelected()) {
200             // On l'enlËve de la liste des displays sÈlectionnÈs.
201             father.setNotSelected();
202             selEvt.setAction(SelectionEvent.REMOVE, father);
203             father.fireSelectionEvent(selEvt);
204 
205             // Comme on arrive dans cette mÈthode par display, display a ÈtÈ dÈj? dÈsÈlectionnÈ.
206             // De plus, ce LM gËre principalement (voire que) des displays N-aires dont il s'agit
207             // la plupart du temps d'une succession de displays opÈrandes entre lesquels se trouvent
208             // des displays opÈrateur (ex: + ou *).
209             // Donc, s'ils existent, on doit alors dÈsÈlectionner le display prÈcÈdent et le display
210             // suivant... display. (d'o? rÈcupÈration du rang de display au dÈbut)
211 
212             // On s'occupe du display prÈcÈdant... display.
213             if (rank > 0) {
214                 if (!(display.getListener() instanceof UnaryMinus)) {
215                     // Il existe un display avant... display, donc on prend garde de le dÈsÈlectionner,
216                     // s'il Ètait sÈlectionnÈ.
217                     tmp = ((Display) father.getComponent(rank-1));
218                     if (tmp.isSelected()) {
219                         // On dÈsÈlectionne donc ledit display.
220                         tmp.deselect();
221 
222                         // Maintenant, on regarde s'il existe un display prÈcÈdent celui que l'on vient
223                         // de dÈsÈlectionner, qui est un display d'opÈrateur et qui est sÈlectionnÈ.
224                         // Si c'est le cas, on le dÈsÈlectionne.
225                         if (rank > 1) {
226                             tmp = ((Display) father.getComponent(rank-2));
227                             if (tmp.isSymbolOperatorDisplay() && tmp.isSelected())
228                                 tmp.deselect();
229                         }
230                     }
231                 }
232             }
233 
234             // On s'occupe du display suivant... display.
235             if (rank < (father.getComponentCount()-1)) {
236                 // Il existe un display aprËs... display, donc on prend garde de le dÈsÈlectionner,
237                 // s'il Ètait sÈlectionnÈ.
238                 tmp = ((Display) father.getComponent(rank+1));
239                 // Il faut faire attention dans le cas d'une addition o? il y aurait un opÈrateur unaire.
240                 // (Normalement seulement un UnaryMinus). Dans le cas le plus simple, une soustraction: a-b
241                 // Si a-b est sÈlectionnÈ et que l'on arrive ici parce on a dÈsÈlectionnÈ a, alors -b doit rester
242                 // sÈlectionnÈ. D'o? ce cas particulier supplÈmentaire.
243                 if (!(tmp.getListener() instanceof UnaryMinus)) {
244                     if (tmp.isSelected()) {
245                         tmp.deselect();
246 
247                         // Maintenant, on regarde s'il existe un display suivant celui que l'on vient
248                         // de dÈsÈlectionner, qui est un display d'opÈrateur et qui est sÈlectionnÈ.
249                         // Si c'est le cas, on le dÈsÈlectionne.
250                         if (rank < (father.getComponentCount()-2)) {
251                             tmp = ((Display) father.getComponent(rank+2));
252                             if (tmp.isSymbolOperatorDisplay() && tmp.isSelected())
253                                 tmp.deselect();
254                         }
255                     }
256                 }
257                 else
258                     ((LeftAssocPrefixedUnaryOperatorLayout) tmp.getLayout()).setSelectLeftDisplay(false);
259             }
260             
261             // On parcourre la liste des display de father et on ajoute dans la liste des sÈlectionnÈs,
262             // ... les sÈlectionnÈs.
263             for (int i = 0; i < father.getComponentCount(); i++) {
264                 tmp = (Display) father.getComponent(i);
265                 if (tmp.isSelected()) {
266                     selEvt.setAction(SelectionEvent.ADD, tmp);
267                     father.fireSelectionEvent(selEvt);
268                 }
269             }
270             
271             // On regarde maintenant au niveau supÈrieur, si la dÈsÈlection de father gÈnËre
272             // une dÈsÈlection qui est valide.
273             if (father.getParent() instanceof Display) {
274                 father = (Display) father.getParent();
275                 FormulaTreeStructure fts = (FormulaTreeStructure) father.getListener();
276                 if (fts.getFather() != null)
277                     ((DisplayLayout) father.getLayout()).validateDeselection(displayToLay);
278             }
279         }
280         // DeuxiËme cas: father (i.e. le display gÈrÈ par l'instance) n'est pas sÈlectionnÈ.
281         // Mais, il en a des sÈlectionnÈs, puisque display fait partie de sa descendance.
282         else {
283             // Et bien, on fait exactement la mÍme chose que prÈcÈdemment, ? la diffÈrence importante
284             // que l?, les displays sÈlectionnÈs font partie de la liste des displays sÈlectionnÈs.
285             // Il faut donc les y enlever.
286             if (rank > 0) {
287                 if (!(display.getListener() instanceof UnaryMinus)) {
288                     tmp = ((Display) father.getComponent(rank-1));
289                     if (tmp.isSelected()) {
290                         tmp.deselect();
291                         selEvt.setAction(SelectionEvent.REMOVE, tmp);
292                         father.fireSelectionEvent(selEvt);
293 
294                         if (rank > 1) {
295                             tmp = ((Display) father.getComponent(rank-2));
296                             if (tmp.isSymbolOperatorDisplay() && tmp.isSelected()) {
297                                 tmp.deselect();
298                                 selEvt.setAction(SelectionEvent.REMOVE, tmp);
299                                 father.fireSelectionEvent(selEvt);
300                             }
301                         }
302                     }
303                 }
304             }
305 
306             if (rank < (father.getComponentCount()-1)) {
307                 tmp = ((Display) father.getComponent(rank+1));
308                 // Il faut faire attention dans le cas d'une addition o? il y aurait un opÈrateur unaire.
309                 // (Normalement seulement un UnaryMinus). Dans le cas le plus simple, une soustraction: a-b
310                 // Si a-b est sÈlectionnÈ et que l'on arrive ici parce on a dÈsÈlectionnÈ a, alors -b doit rester
311                 // sÈlectionnÈ. D'o? ce cas particulier supplÈmentaire.
312                 if (!(tmp.getListener() instanceof UnaryMinus)) {
313                     if (tmp.isSelected()) {
314                         tmp.deselect();
315 
316                         // Maintenant, on regarde s'il existe un display suivant celui que l'on vient
317                         // de dÈsÈlectionner, qui est un display d'opÈrateur et qui est sÈlectionnÈ.
318                         // Si c'est le cas, on le dÈsÈlectionne.
319                         if (rank < (father.getComponentCount()-2)) {
320                             tmp = ((Display) father.getComponent(rank+2));
321                             if (tmp.isSymbolOperatorDisplay() && tmp.isSelected())
322                                 tmp.deselect();
323                         }
324                     }
325                 }
326                 else
327                     ((LeftAssocPrefixedUnaryOperatorLayout) tmp.getLayout()).setSelectLeftDisplay(false);
328             }
329         }
330 
331         // Comme toujours, on contrÙle maintenant, avec les Èventuels displays sÈlectionnÈs restant,
332         // si la sÈlection est valide.
333         validateSelection();
334         // On met ? jour le display.
335         father.repaint();
336     }
337 }