View Javadoc

1   /*
2   $Id: FormulaTreeStructure.java 710 2005-03-21 16:34:22Z 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.model;
30  
31  import java.util.*;
32  import fr.ove.utils.*;
33  import fr.ove.openmath.jome.behaviour.*;
34  import fr.ove.openmath.jome.model.*;
35  import fr.ove.openmath.jome.model.events.*;
36  import fr.ove.openmath.jome.ctrlview.events.*;
37  import fr.ove.openmath.jome.model.evaluation.*;
38  
39  /***
40  * @author © 2000 DIRAT Laurent
41  * @version 2.1  10/01/2000
42  */
43  public abstract class FormulaTreeStructure extends Node implements ControlListener, Iconifiable, fr.ove.utils.Comparable, Maskable, Modifiable {
44      /***
45      * To check if we consider the instance as a template or not. <BR>
46      * (usefull for the building of the formula tree structure).
47      * By default, the new intance create is not a template.
48      */
49      private boolean isTemplate = false;
50      
51      /***
52      * The priority of the instance considered as an operator.
53      */
54      private int asOperatorPriority;
55  
56      /***
57      * The priority of the instance considered as an operand.
58      */
59      private int asOperandPriority;
60      
61      /***
62      * The list of listeners of the instance
63      */
64      private Vector listeners = new Vector();
65      
66      /***
67      * Flag to set if we allow the move of the children (so operands) of the instance.<BR>
68      * In other word, says some kind of commutativity of the operator.<BR>
69      * The default is <CODE>false</CODE> because only "few" operators have this property.
70      */
71      private boolean areOperandsMovable = false;
72      
73      /***
74      * The resources manager
75      */
76      static FormulaResourcesManager resourcesManager = new FormulaResourcesManager("fr.ove.openmath.jome.model.resources2");
77      
78      /***
79      * theresource indentifier of the instance
80      */
81      private String resourceIdentifier;
82  
83  	private boolean isCrossRef = false;
84  
85  
86  	public void setCrossRef(boolean ref){
87  		isCrossRef = ref;
88  	}
89  	
90  	public boolean getCrossRef(){
91  		return isCrossRef;
92  	}
93      
94      // ***********************************
95      // Gestion des listeners de l'instance
96      
97      /***
98      * Registers another listener to be informed of changes of the FTS.
99      * @param modelListener a listener to add.
100     */
101     public void addModelListener(ModelListener modelListener) {
102         listeners.addElement(modelListener);
103     }
104     
105     /***
106     * Removes a listener.
107     * @param modelListener a listener to remove.
108     */
109     public void removeModelListener(ModelListener modelListener) {
110         listeners.removeElement(modelListener);
111     }
112 
113     /***
114     * Removes all the listeners.
115     */
116     public void removeAllModelListener() {
117         listeners.setSize(0);
118     }
119 
120     /***
121     * Fires a ModelEvent event to registered listeners.
122     * @param modelEvent event encapsulating relevant information.
123     */
124     public void fireModelEvent(ModelEvent modelEvent) {
125         for (int i = 0; i < listeners.size(); i++)
126           ((ModelListener)listeners.elementAt(i)).consumeModelEvent(modelEvent);
127     }
128     
129     /***
130     * Returns all the registered listener of the instance.
131     */
132     public Vector getListeners() {
133         return listeners;
134     }
135 
136     // **** fin de la gestion des listeners ****
137     // *****************************************
138 
139     
140     /***
141     * Sets the resource identifier of the instance.
142     * @param the resource identifier.
143     */
144     public void setResourceIdentifier(String resourceIdentifier) {
145         this.resourceIdentifier = resourceIdentifier;
146     }
147     
148     /***
149     * Returns the resource identifier of the instance.
150     */
151     public String getResourceIdentifier() {
152         return resourceIdentifier;
153     }
154     
155     /***
156     * Sets the as operator priority
157     * @param asOperatorPriority the priority
158     */
159     public void setAsOperatorPriority(int asOperatorPriority) {
160         this.asOperatorPriority = asOperatorPriority;
161     }
162     
163     /***
164     * Returns the priority of the instance viewed as an operator.
165     * @return the priority of the instance viewed as an operator.
166     */
167     public int getAsOperatorPriority() {
168         return asOperatorPriority;
169     }
170 
171     /***
172     * Sets the as operand priority
173     * @param asOperandPriority the priority
174     */
175     public void setAsOperandPriority(int asOperandPriority) {
176         this.asOperandPriority = asOperandPriority;
177     }
178     
179     /***
180     * Returns the priority of the instance viewed as an operand.
181     * @return the priority of the instance viewed as an operand.
182     */
183     public int getAsOperandPriority() {
184         return asOperandPriority;
185     }
186     
187     /***
188     * Returns <CODE>true</CODE> if it is a template.<BR>
189     * <CODE>false</CODE> otherwise.
190     */
191     public boolean isTemplate() {
192         return isTemplate;
193     }
194 
195     /***
196     * Sets the instance as a template.
197     */
198     public void setIsTemplate(boolean isTemplate) {
199         this.isTemplate = isTemplate;
200     }
201     
202     /***
203     * Returns the node (operator), which is the position in the formula tree, where the
204     * instance have to be inserted.
205     *
206     * @param current the current insert position in the formula tree.
207     * @return the insert position in the formula tree for the instance.
208     */
209     public FormulaTreeStructure findLocation(FormulaTreeStructure current) {
210         //while (this.asOperandPriority < current.asOperatorPriority)
211         while (asOperandPriority < current.getAsOperatorPriority())
212             current = (FormulaTreeStructure) current.getFather();
213 
214         return current;
215     }
216 
217     /***
218     * Returns the father of the node which, from the current instance, have the specified
219     * priority.
220     *
221     * @param priority the specified priority.
222     * @return the desired father.
223     */
224     public FormulaTreeStructure goTo(int priority) {
225         FormulaTreeStructure current = this;
226 
227         // Si le test est vrai, c'est qu'on est dÈj? sur un tel noeud.
228         // On retourne un noeud identique placÈ au-dessus dans l'arbre
229         int prio = current.asOperatorPriority;
230         if (current.asOperatorPriority == priority)
231             current = (FormulaTreeStructure) current.getFather();
232 
233         while ((current.asOperatorPriority != priority) &&
234                 (((FormulaTreeStructure)current.getFather()).asOperatorPriority != 0))
235             current = (FormulaTreeStructure) current.getFather();
236 
237         return (FormulaTreeStructure) current.getFather();
238     }
239     
240     /*
241     * Sets if we allow the move of the children (so operands) of the instance.
242     * @param areOperandsMovable <CODE>true</CODE> if the operands are movable.
243     * <CODE>false</CODE> otherwise.
244     */
245     public void setAreOperandsMovable(boolean areOperandsMovable) {
246         this.areOperandsMovable = areOperandsMovable;
247     }
248     
249     /*
250     * Returns if we allow the move of the children (so operands) of the instance.
251     * @return <CODE>true</CODE> if the operands are movable. <CODE>false</CODE> otherwise.
252     */
253     public boolean getAreOperandsMovable() {
254         return areOperandsMovable;
255     }
256     
257     /***
258     * Moves the specified list of the instance children to the specified
259     * rank. The first child in the list has its rank setted to the specified
260     * one, the second to the first+1, ...and so on.
261     * @param list the list of the instance operands to move.
262     * @param rank the specified rank.
263     */
264     public void moveOperands(Vector list, int rank) {
265         // On fait la permutation dans la FTS
266         moveChildren(list, rank);
267         
268         ModelEvent modelEvent = new ModelEvent(this);
269         // On a fait les dÈplacements nÈcÈssaires, on reconstruit le display
270         modelEvent.setAction(ModelEvent.REBUILD, null);
271         // On envoie l'ÈvÈnement.
272         fireModelEvent(modelEvent);
273         // On envoie maintenant un ÈvÈnement comme quoi il faut mettre ?
274         // jour l'affichage.
275         modelEvent.setAction(ModelEvent.UPDATE, null);
276         // On envoie l'ÈvÈnement.
277         fireModelEvent(modelEvent);
278     }
279     
280     // #################################################
281     // ### ImplÈmentation des diffÈrentes interfaces ###
282     // #################################################
283     
284     // ****************************************
285     // ImplÈmentation de l'interface Comparable
286     
287     /***
288     * Tests if the instance is equal to the specified one.
289     * @param toCompare the instance to compare with the current instance.
290     */
291     public boolean isEqual(fr.ove.utils.Comparable toCompare) {
292         // On verra plus tard
293         return false;
294     }
295     
296     /***
297     * Tests if the instance is greater than the specified one.
298     * @param toCompare the instance to compare with the current instance.
299     */
300     public boolean isGreater(fr.ove.utils.Comparable toCompare) {
301         // On s'en fout, seule l'ÈgalitÈ nous intÈresse
302         return false;
303     }
304     
305     /***
306     * Tests if the instance is greater or equal than the specified one.
307     * @param toCompare the instance to compare with the current instance.
308     */
309     public boolean isGreaterOrEqual(fr.ove.utils.Comparable toCompare) {
310         // On s'en fout, seule l'ÈgalitÈ nous intÈresse
311         return false;
312     }
313     
314     /***
315     * Tests if the instance is lesser than the specified one.
316     * @param toCompare the instance to compare with the current instance.
317     */
318     public boolean isLesser(fr.ove.utils.Comparable toCompare) {
319         // On s'en fout, seule l'ÈgalitÈ nous intÈresse
320         return false;
321     }
322     
323     /***
324     * Tests if the instance is lesser or equal than the specified one.
325     * @param toCompare the instance to compare with the current instance.
326     */
327     public boolean isLesserOrEqual(fr.ove.utils.Comparable toCompare) {
328         // On s'en fout, seule l'ÈgalitÈ nous intÈresse
329         return false;
330     }
331     
332     // *** Fin de l'interface Comparable ***
333     // *************************************
334     
335     
336     // *****************************************
337     // ImplÈmentation de l'interface Iconifiable
338     
339     /***
340     * Associates an icon name to the instance.
341     * @param iconName the name of the icon
342     */
343     public void setIconName(String iconName) {
344         // On ne fait rien, c'est dans les classes dÈrivÈes qu'on va implÈmenter getIconName().
345         // Ca Èvite de stocker une String pour pas grand chose.
346     }
347     
348     /***
349     * Returns the name of the icon associated to the instance.<BR>
350     * The icon name is the name of the ressource identifier where "_Ico" added to the end.
351     * @returns The name of the icon, or <CODE>null</CODE> if there is no name
352     * associated.
353     */
354     public String getIconName() {
355         return resourceIdentifier + "_Ico"; //resourcesManager.getIconName(resourceIdentifier);
356     }
357     
358     /***
359     * @return <CODE>true</CODE> if the instance is an icon. <CODE>false</CODE> otherwise.
360     */
361     public boolean isIcon() {
362         return false;
363     }
364     
365     /***
366     * Iconifies the instance.
367     */
368     public void iconify() {
369         if (isIconifiable()) {
370             Icon icon = new Icon(this);
371             // On ajoute l'instance ? iconifier dans Icon (<=> on iconfie l'instance)
372             icon.addIconified(this);
373             // On insËre maintenant notre icon ? la place de l'instance.
374             icon.insert(this);
375         }
376     }
377     
378     /***
379     * Uniconifies the instance.
380     */
381     public void uniconify() {
382         // Par dÈfaut on ne fait rien, on ne peut dÈsiconifier qu'une icone
383     }
384     
385     
386     /***
387     * Uniconifies all the iconified parts of the instance.
388     */
389     public void uniconifyAll() {
390         if (getNbChildren() != 0) {
391             boolean rebuildDisplay = false;
392             // On parcourre tous les enfants de l'instance et si on trouve une icone, on la
393             // dÈsiconifie
394             FormulaTreeStructure fts = null;
395             
396             /*
397             for (Enumeration e = getChildren().elements(); e.hasMoreElements(); ) {
398                 fts = (FormulaTreeStructure) e.nextElement();
399                 if (fts.isIcon()) {
400                     fts.uniconify();
401                     rebuildDisplay = true;
402                 }
403             }
404             */
405             for (int i = 0; i < getNbChildren(); i++) {
406                 fts = (FormulaTreeStructure) getChild(i);
407                 if (fts.isIcon()) {
408                     fts.uniconify();
409                     rebuildDisplay = true;
410                     i = -1; // On repart ? zÈro car la dÈsiconification a pu en refaire apparaÓtre.
411                 }
412             }
413             
414             // l'instance n'a plus de d'icone fille, on s'occupe de la descendance
415             for (Enumeration e = getChildren().elements(); e.hasMoreElements(); )
416                 ((FormulaTreeStructure) e.nextElement()).uniconifyAll();
417         
418             // Reconstruction du display que si y a eu dÈsiconification
419             if (rebuildDisplay) {
420                 // On part du principe que si l'on a une icone, c'est que l'on a le display qui lui est
421                 // associÈ, donc reconstruction du display.
422                 // Faire gaffe ? appeler le ModelEvent.UPDATE quand nÈcessaire
423                 
424                 // On envoie maintenant un ÈvÈnement comme quoi il faut reconstruire
425                 // l'affichage.
426                 ModelEvent modelEvent = new ModelEvent(this);
427                 modelEvent.setAction(ModelEvent.REBUILD, null);
428                 fireModelEvent(modelEvent);
429             }
430         }
431     }
432         
433     /***
434     * Sets the instance as iconifiable.
435     * @param isIconifiable <CODE>true</CODE> if the instance is iconifiable.
436     * <CODE>false</CODE> otherwise.
437     */
438     public void setIsIconifiable(boolean isIconifiable) {
439         // On ne fait rien, les classes hÈritiËres retourneront la valeur qui leur correspond.
440         // On Èvite de stocker un boolÈen pour pas grand chose puisque peu ne seront pas iconifiables
441     }
442     
443     /***
444     * Returns <CODE>true</CODE> if the instance is iconifiable.
445     * <CODE>false</CODE> otherwise.
446     */
447     public boolean isIconifiable() {
448         return true;  // TrËs peu ne sont pas iconifiables. Les concernÈs surchargeront cette mÈthode.
449     }
450     
451     // *** Fin de l'interface Iconifiable ***
452     // **************************************
453     
454     
455     // *********************************************
456     // ImplÈmentation de l'interface ControlListener
457     
458     
459     /***
460     * Consumes (i.e. treats) the event received.
461     * @param controlEvent the event to consume.
462     */
463     public void consumeControlEvent(ControlEvent controlEvent) {
464         ModelEvent modelEvent;
465         int action = controlEvent.getAction();
466         FormulaTreeStructure fts = null;
467         
468         switch (action) {
469             case ControlEvent.ADD :
470                 //System.out.println("ControlEvent.ADD : on ajoute un nouveau display");
471                 break;
472             case ControlEvent.REMOVE :
473                 //System.out.println("ControlEvent.REMOVE : on enleve un display");
474                 break;
475             case ControlEvent.ICONIFY :
476                 //System.out.println("ControlEvent.ICONIFY : on iconifie");
477                 Vector toIconify = (Vector) controlEvent.getArgument();
478                 Icon icon = null;
479                 if (toIconify.size() == 1) {
480                     fts = (FormulaTreeStructure) toIconify.elementAt(0);
481                     // une seule fts ? iconifier.
482                     if (fts.isIconifiable()) {
483                         // Ce n'est pas dÈj? une icone et fts est iconifiable, on peut en crÈer une.
484                         icon = new Icon(fts);
485                         // On ajoute notre fts ? iconifier dans Icon (<=> on iconfie fts)
486                         icon.addIconified(fts);
487                         // On insËre maintenant notre icon ? la place de fts.
488                         icon.insert(fts);
489                     }
490                     // fts = icon.father pour que l'on puisse ajouter le display de notre icone dans icon.father
491                     fts = (FormulaTreeStructure) icon.getFather();
492                 }
493                 else {
494                     // Plusieurs fts sont ? iconifier. Il faut donc rÈcupÈrer la fts
495                     // dont elles sont les filles, pour pouvoir crÈer l'icone adÈquate.
496                     fts = (FormulaTreeStructure) ((FormulaTreeStructure) toIconify.elementAt(0)).getFather();
497                     // On crÈe une nouvelle icone
498                     icon = new Icon(fts);
499                     // On ajoute maintenant tous les fts ? iconifier.
500                     int countToIconify = toIconify.size();
501                     for (int i = 0; i < countToIconify; i++)
502                         icon.addIconified((FormulaTreeStructure) toIconify.elementAt(i));
503                     // On insËre maintenant notre icon ? la place de la 1-Ëre fts.
504                     icon.insert(icon.getIconified(0));
505                 }
506                 
507                 // On ajoute un display pour notre icon.
508                 modelEvent = new ModelEvent(fts);
509                 modelEvent.setAction(ModelEvent.ADD, icon);
510                 fts.fireModelEvent(modelEvent);
511                 
512                 // On met ? jour l'affichage de la fts.
513                 modelEvent.setAction(ModelEvent.UPDATE, null);
514                 fts.fireModelEvent(modelEvent);
515                 
516                 break;
517                 
518             case ControlEvent.UNICONIFY :
519                 //System.out.println("ControlEvent.UNICONIFY : on desiconifie");
520                 Icon anIcon = (Icon) controlEvent.getArgument();
521                 fts = (FormulaTreeStructure) anIcon.getFather();
522                 anIcon.uniconify();
523                 
524                 // On envoie maintenant un ÈvÈnement comme quoi il faut reconstruire
525                 // l'affichage.
526                 modelEvent = new ModelEvent(fts);
527                 modelEvent.setAction(ModelEvent.REBUILD, null);
528                 fts.fireModelEvent(modelEvent);
529                 // On envoie maintenant un ÈvÈnement comme quoi il faut mettre ?
530                 // jour l'affichage.
531                 modelEvent.setAction(ModelEvent.UPDATE, null);
532                 // On envoie l'ÈvÈnement.
533                 fts.fireModelEvent(modelEvent);
534                 break;
535                 
536             case ControlEvent.UNICONIFY_ALL :
537                 // On remonte dans la FTS jusqu'? tomber sur la racine de la formule.
538                 fts = this;
539                 while (fts.getFather() != null)
540                     fts = (FormulaTreeStructure) getFather();
541                     
542                 // On est sur la racine de la formule.
543                 // A partir de l?, on demande de tout dÈsiconifier
544                 fts.uniconifyAll();
545                 
546                 // On envoie maintenant un ÈvÈnement comme quoi il faut mettre ?
547                 // jour l'affichage.
548                 modelEvent = new ModelEvent(fts);
549                 modelEvent.setAction(ModelEvent.UPDATE, null);
550                 // On envoie l'ÈvÈnement.
551                 fts.fireModelEvent(modelEvent);
552                 break;
553                 
554             case ControlEvent.SUBSTITUTE :
555                 //System.out.println("ControlEvent.ICONIFY : on iconifie");
556                 // ### ATTENTION, le premier ÈlÈment sera le nom pour la substitution
557                 Vector toSubstitute = (Vector) controlEvent.getArgument();
558                 fts = (FormulaTreeStructure) toSubstitute.elementAt(1);
559                 // On crÈe une nouvelle icone
560                 Icon substitution = new Icon((String) toSubstitute.elementAt(0));
561                 // On ajoute maintenant tous les fts ? iconifier.
562                 int countToIconify = toSubstitute.size();
563                 
564                 if ((countToIconify == 2) && !fts.isIconifiable())
565                     break;
566                 
567                 for (int i = 1; i < countToIconify; i++)
568                     substitution.addIconified((FormulaTreeStructure) toSubstitute.elementAt(i));
569 
570                 // On insËre maintenant notre icon ? la place de la 1-Ëre fts.
571                 substitution.insert(fts);
572 
573                 // fts = substitution.father pour que l'on puisse ajouter le display de notre icone
574                 // dans substitution.father
575                 fts = (FormulaTreeStructure) substitution.getFather();
576 
577                 // On ajoute un display pour notre icon.
578                 modelEvent = new ModelEvent(fts);
579                 modelEvent.setAction(ModelEvent.ADD, substitution);
580                 fts.fireModelEvent(modelEvent);
581                 // On met ? jour l'affichage de la fts.
582                 modelEvent.setAction(ModelEvent.UPDATE, null);
583                 fts.fireModelEvent(modelEvent);
584                 break;
585         }
586     }
587 
588     // *** Fin de l'interface ControlListener ***
589     // ******************************************
590     
591     // **************************************
592     // ImplÈmentation de l'interface Maskable
593     
594     /***
595     * Sets the instance as vissible or not.
596     * @param isVisible <CODE>true</CODE> if the instance is visible. <CODE>false</CODE> otherwise.
597     */
598     public void setIsVisble(boolean isVisible) {
599         // Ne fait rien par dÈfaut. Tout les opÈrateurs sont visibles ? de rares exceptions prËs.
600         // Ce sont ces exceptions qui maintiendront cette propriÈtÈ correctement en la surchargeant
601     }
602 
603     /***
604     * Checks if the instance is visible.
605     * @returns <CODE>true</CODE> if the instance is visible. <CODE>false</CODE> otherwise.
606     */
607     public boolean isVisible() {
608         // Tout les opÈrateurs sont visibles ? de rares exceptions prËs.
609         // Ce sont ces exceptions qui maintiendront cette propriÈtÈ correctement en la surchargeant
610         return true;
611     }
612     
613     // *** Fin de l'interface Maskable ***
614     // ***********************************
615     
616     
617     // *****************************************
618     // ImplÈmentation de l'interface Modifiable
619     
620     /***
621     * Sets the value.
622     */
623     public void setValue(String value) {
624     }
625     
626     /***
627     * Returns the value.
628     */
629     public String getValue() {
630         return null;
631     }
632     
633     // *** Fin de l'interface Modifiable ***
634     // *************************************
635     
636     // ############################################
637     // ### Les diffÈrentes mÈthodes abstraites  ###
638     // ############################################
639     
640     /***
641     * To check is the instance is an operator.
642     * @return <CODE>true</CODE> if it is an operator. <CODE>false</CODE> otherwise.
643     */
644     public abstract boolean isOperator();
645     
646     /***
647     * Inserts the instance in the formula tree, from the current insertion position.
648     * (checks the priorities and goes up in the tree if necessary).
649     *
650     * @param current the current insertion position.
651     * @return the new insertion position.
652     */
653     public abstract FormulaTreeStructure insert(FormulaTreeStructure current);
654     
655     /***
656     * The Creation of the corresponding linear expression of the formula.
657     */
658     public abstract String createLinear(String linear);
659 
660     /***
661     * Evaluates the instance.
662     */
663     public abstract String evaluate();
664 }