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 }