]> matita.cs.unibo.it Git - helm.git/blob - helm/DEVEL/mathml_editor/src/TPushParser.cc
Added some controls for the graphical deleting of apostrophe.
[helm.git] / helm / DEVEL / mathml_editor / src / TPushParser.cc
1
2 #include "ALogger.hh"
3 #include "TPushParser.hh"
4 #include "AMathMLFactory.hh"
5
6 TPushParser::TPushParser(ALogger& l, const TDictionary& d) : APushParser(l), dictionary(d)
7 {
8   init();
9 }
10
11 TPushParser::TPushParser(ALogger& l, AMathMLFactory& f, const TDictionary& d) : APushParser(l, f), dictionary(d)
12 {
13   init();
14 }
15
16 void
17 TPushParser::init()
18 {
19   nextId = 1;
20   cursor = doc.create("cursor");
21   cursor["id"] = "I0";
22   doc.clearDirty();
23   doc.root().append(cursor);
24   logger.verbosity(ALogger::Debug);
25 }
26
27 TPushParser::~TPushParser()
28 {
29 }
30
31 std::string
32 TPushParser::PRIME() const
33 {
34   const TDictionary::Entry entry = dictionary.find("prime");
35   if (entry.cls == TDictionary::OPERATOR) return entry.value;
36   else return "?";
37 }
38
39 void
40 TPushParser::do_begin()
41 {
42   TNode parent = cursor.parent();
43   if (parent.isC() && dictionary.find(parent.nameC()).table)
44     {
45       TNode row = doc.create("row");
46       TNode cell = doc.create("cell");
47       TNode g = doc.createG();
48       row.append(cell);
49       cell.append(g);
50       g.append(cursor);
51       parent.append(row);
52     }
53   else
54     {
55       TNode g = doc.createG(nextId++);
56       cursor.replace(g);
57       g.append(cursor);
58     }
59 }
60
61 void
62 TPushParser::do_end()
63 {
64   TNode parent = cursor.parent();
65   if (parent && parent.isG() && parent.hasId())
66     {
67       // normal closing brace for an explicitly open group
68       cursor.remove();
69       advance(parent);
70     }
71   else if (parent && parent.isG() && parent.parent() && parent.parent().is("cell"))
72     {
73       assert(!frames.empty());
74       // closing brace for a structure in which & or \cr have been used
75       TNode row = parent.parent().parent();
76       assert(row && row.is("row"));
77       TNode table = row.parent();
78       assert(table);
79       advance(row);
80     }
81   else if (parent && parent.isG() && !parent.hasId() && parent.parent())
82     {
83       // closing brace for a right-open macro (like \over)
84       // It's not sure that we want to exit from a phantom group with a 
85       // '}', because, to enter in the phantom group the user didn't insert a 
86       // '{'.
87       cursor.remove();
88       advance(parent);
89     }
90   else
91     {
92       // In this case, there is a redundant '}', so I think we can ignore it and 
93       // emit an error
94       logger.error("There so no corresponding'{'");
95       //assert(0);
96     }
97 }
98
99 void
100 TPushParser::do_shift()
101 {
102   TNode parent = cursor.parent();
103   assert(parent);
104   if (parent.is("tex"))
105     {
106       TNode math = doc.create("math", nextId++);
107       TNode g = doc.createG();
108       cursor.replace(math);
109       math.append(g);
110       g.append(cursor);
111     }
112   else if (parent.isG() && !parent.hasId() && parent.parent() && parent.parent().is("math"))
113     {
114       if (cursor.prev())
115         {
116           // there is something before the cursor, hence this is the
117           // closing math shift
118           if (parent.parent()["display"] != "1")
119             {
120               // one math shift is enough to close it
121               cursor.remove();
122             }
123           else
124             {
125               // we need two closing math shifts
126               //cursor.remove(); ??
127               parent.parent().append(cursor);
128             }
129         }
130       else if (parent.parent()["display"] != "1")
131         {
132           // there is nothing before the cursor, and the math is not
133           // in display mode, so this must be a double math shift
134           parent.parent()["display"] = "1";
135         }
136       else
137         {
138           parent.parent().append(cursor);
139         }
140     }
141   else if (parent.is("math"))
142     {
143       cursor.remove();
144     }
145   else
146     {
147       // In TeX, the user can type
148       //   $a-b\over2a+b$
149       // In this case, '$' character is correct.
150       // I don't think so, if user types
151       //   $12+{a-b\over2a+b$
152       // because the group is not closed with a '}'
153       logger.error("ERROR: math shift");
154     }
155 }
156
157 void
158 TPushParser::do_align()
159 {
160   TNode parent = cursor.parent();
161   if (parent && parent.isG() && parent.hasId())
162     {
163       // alignment tab used for the first time inside a group
164       TNode row = doc.create("row");
165       TNode cell = doc.create("cell");
166       TNode g = doc.createG();
167       row.append(cell);
168       cell.append(g);
169       g.append(parent.first(), cursor);
170     }
171   else if (parent && parent.isG() && parent.parent().is("cell"))
172     {
173       // alignment tab used within a cell
174       TNode oldCell = parent.parent();
175       assert(oldCell && oldCell.is("cell"));
176       TNode row = oldCell.parent();
177       assert(row && row.is("row"));
178       TNode cell = doc.create("cell");
179       if (oldCell.next()) oldCell.next().insert(cell);
180       else row.append(cell);
181       TNode g = doc.createG();
182       cell.append(g);
183       g.append(cursor);
184     }
185   else
186     {
187       logger.error("alignment tab used outside matrix");
188     }
189 }
190
191 void
192 TPushParser::do_eol()
193 {
194   //if (cursor.parent()) cursor.remove();
195 }
196
197 void
198 TPushParser::do_parameter(const std::string& p)
199 {
200   // ???
201 }
202
203 void
204 TPushParser::do_subscript()
205 {
206   TNode parent = cursor.parent();
207   if (parent.isG())
208     {
209       TNode prev = cursor.prev();
210       if (!prev)
211         {
212           TNode elem = doc.create("sb", nextId++);
213           TNode g = doc.createG();
214           cursor.replace(elem);
215           elem.append(g);
216           elem.append(cursor);
217         }
218       else
219         {
220           TNode elem = doc.create("sb", nextId++);
221           prev.replace(elem);
222           elem.append(prev);
223           elem.append(cursor);
224         }
225     }
226   else if (parent.isSb() && cursor == parent[1])
227     {
228       if (parent["under"] == "1") logger.error("already under");
229       else parent["under"] = "1";
230     }
231 }
232
233 void
234 TPushParser::do_superscript()
235 {
236   TNode parent = cursor.parent();
237   if (parent.isG())
238     {
239       TNode prev = cursor.prev();
240       if (!prev)
241         {
242           TNode elem = doc.create("sp", nextId++);
243           TNode g = doc.createG();
244           cursor.replace(elem);
245           elem.append(g);
246           elem.append(cursor);
247         }
248       else
249         {
250           TNode elem = doc.create("sp", nextId++);
251           prev.replace(elem);
252           elem.append(prev);
253           elem.append(cursor);
254         }
255     }
256   else if (parent.isSp() && cursor == parent[1])
257     {
258       if (parent["over"] == "1") logger.error("already over");
259       else parent["over"] = "1";
260     }
261 }
262
263 void
264 TPushParser::do_space(const std::string&)
265 {
266   // ? may be used to distinguish tokens in some mode?
267 }
268
269 void
270 TPushParser::do_letter(const std::string& s)
271 {
272   //TNode parent = cursor.parent();
273   TNode elem = doc.createI(s, nextId++);
274   cursor.replace(elem);
275   advance(elem);
276 }
277
278 void
279 TPushParser::do_digit(const std::string& s)
280 {
281   TNode parent = cursor.parent();
282   TNode prev = cursor.prev();
283   if (prev && parent.isG() && prev.is("n"))
284     {
285       TNode elem = doc.createN(prev.value() + s, nextId++);
286       prev.replace(elem);
287     }
288   else
289     {
290       TNode elem = doc.createN(s, nextId++);
291       cursor.replace(elem);
292       advance(elem);
293     }
294 }
295
296 bool
297 TPushParser::isPrimes(const TNode& node) const
298 {
299   assert(node);
300   return node.isG() && node.last() && node.last().is("o") && node.last()["val"] == PRIME();
301 }
302
303 void
304 TPushParser::do_apostrophe()
305 {
306   if (cursor.parent() && cursor.parent().isG())
307     {
308       if (TNode prev = cursor.prev())
309         {
310           if (prev.isSp() && prev[1] && isPrimes(prev[1]))
311             prev[1].append(doc.createO(PRIME(), nextId++));
312           else if (prev.isSb() && prev[0] &&
313                    prev[0].isSp() && prev[0][1] &&
314                    isPrimes(prev[0][1]))
315             prev[0][1].append(doc.createO(PRIME(), nextId++));
316           else
317             {
318               TNode elem = doc.create("sp");
319               TNode g = doc.createG();
320               prev.replace(elem);
321               elem.append(prev);
322               elem.append(g);
323               g.append(doc.createO(PRIME(), nextId++));
324             }
325         }
326       else
327         {
328           // is it an error?
329           logger.error("you have to type one identifier before the  ''");
330         }
331     }
332   else
333     {
334       // error ??
335     }
336 }
337
338 void
339 TPushParser::do_other(const std::string& s)
340 {
341   switch (s[0])
342     {
343     case '\'':
344       do_apostrophe();
345       break;
346     default:
347       cout << "TPushParser::do_other " << s << endl;
348       cout << "DOCUMENT: " << static_cast<GdomeNode*>(cursor.element().get_ownerDocument()) << endl;
349       TNode elem = doc.createT("o", s, nextId++);
350       cursor.replace(elem);
351       advance(elem);  
352       break;
353     }
354 }
355
356 void
357 TPushParser::do_active(const std::string&)
358 {
359   // ??? space?
360 }
361
362 void
363 TPushParser::do_comment()
364 {
365   // ???
366 }
367
368 void
369 TPushParser::do_cr()
370 {
371   TNode parent = cursor.parent();
372   if (parent && parent.isG() &&
373       parent.parent() && parent.parent().is("cell") &&
374       parent.parent().parent() && parent.parent().parent().is("row"))
375     {
376       TNode oldRow = parent.parent().parent();
377       assert(oldRow);
378       TNode table = oldRow.parent();
379       assert(table);
380       TNode row = doc.create("row");
381       TNode cell = doc.create("cell");
382       TNode g = doc.createG();
383       if (oldRow.next()) oldRow.next().insert(row);
384       else table.append(row);
385       row.append(cell);
386       cell.append(g);
387       g.append(cursor);
388     }
389 }
390
391 void
392 TPushParser::do_control(const std::string& name)
393 {
394   if (name == "cr") do_cr();
395   else
396     {
397       TNode parent = cursor.parent();
398       const TDictionary::Entry& entry = dictionary.find(name);
399       switch (entry.cls)
400         {
401         case TDictionary::IDENTIFIER:
402           {
403             TNode t = doc.createI(entry.value, nextId++);
404             t["name"] = name;
405             cursor.replace(t);
406             advance(t);
407           }
408           break;
409         case TDictionary::OPERATOR:
410           {
411             TNode t = doc.createO(entry.value, nextId++);
412             t["name"] = name;
413             cursor.replace(t);
414             advance(t);
415           }
416           break;
417         case TDictionary::NUMBER:
418           {
419             TNode t = doc.createN(entry.value, nextId++);
420             t["name"] = name;
421             cursor.replace(t);
422             advance(t);
423           }
424           break;
425         case TDictionary::MACRO:
426           {
427             TNode m = doc.createC(name, nextId++);
428             cursor.replace(m);
429             
430             logger.debug("do_control: i have pushed a frame in the stack. Here is the pattern of the associated MACRO");
431             for (unsigned i = 0; i < entry.pattern.size(); i++)
432               logger.debug(entry.pattern[i].value);
433             
434             if (entry.leftOpen && entry.rightOpen)
435               {
436                 assert(entry.pattern.empty());
437                 assert(parent.isG());
438                 TNode g1 = doc.createG();
439                 g1["left-open"] = "1";
440                 g1.append(parent.first(), m);
441                 m.append(g1);
442                 TNode g2 = doc.createG();
443                 g2.append(cursor);
444                 m.append(g2);
445                 frames.push(Frame(entry));
446               }
447             else if (entry.leftOpen)
448               {
449                 assert(parent.isG());
450                 TNode g = doc.createG();
451                 g["left-open"] = "1";
452                 g.append(parent.first(), m);
453                 m.append(g);
454                 advance(m);
455               }
456             else if (entry.rightOpen)
457               {
458                 assert(entry.pattern.empty());
459                 assert(parent.isG());
460                 TNode g = doc.createG();
461                 g.append(cursor);
462                 m.append(g);
463                 frames.push(Frame(entry));
464               }
465             else if (!entry.pattern.empty())
466               {
467                 if (parent.isG())
468                   {
469                     frames.push(Frame(entry));
470
471                     if (entry.paramDelimited(0))
472                       {
473                         TNode g = doc.createG();
474                         m.append(g);
475                         g.append(cursor);
476                       }
477                     else
478                       m.append(cursor);
479                   }
480                 else
481                   {
482                     // error, but we could handle this very easily
483                     logger.error("error, but we could handle this easily");
484                   }
485               }
486             else advance(m);
487           }
488           break;
489         case TDictionary::UNDEFINED:
490           {
491             logger.error("ERROR: using undefined macro ` + name '");
492             TNode m = doc.createC(name, nextId++);
493             cursor.replace(m);
494             advance(m);
495           }
496           break;
497         default:
498           assert(0);
499         }
500     }
501 }
502
503 void
504 TPushParser::gdelete_prev_token()
505 {
506   assert(cursor.prev());
507   assert(cursor.parent());
508   TNode prev = cursor.prev();
509   assert(prev.is("i") || prev.is("o") || prev.is("n"));
510
511   logger.debug("gdelete_prev_token: start");
512   
513   // the control below is designed to handle the case in which val have more than one unicode character
514   DOM::UCS4String ucs4val(prev.element().getAttribute("val"));
515   if ((ucs4val.length() <= 1) || prev.element().hasAttribute("name"))
516     {
517       logger.debug("gdelete_prev_token: i have removed an element");
518       cursor.remove();
519       prev.replace(cursor);
520       
521       if (cursor.parent().isC())
522         {
523           // in this case we have removed an element of a MACRO. 
524           // we can assert that this element was a non delimited argument
525           assert(!frames.empty());
526           Frame& frame = frames.top();
527           assert(frame.pos > 0);
528
529           frame.pos--;
530           logger.debug("gdelete_prev_token: it was a MACRO's child so i have decremented the member pos of the associated frame");
531         }
532     }
533   else
534     {
535       ucs4val.erase(ucs4val.length() - 1, 1);
536       prev.element().setAttribute(DOM::GdomeString("val"), DOM::GdomeString(ucs4val));
537     }
538
539   logger.debug("gdelete_prev_token: bye...");
540 }
541
542 void
543 TPushParser::gdelete_prev_script()
544 {
545   logger.debug("gdelete_prev_script: start...");
546   // this method delete a sp or an sb preceding the cursor
547   assert(cursor.prev());
548   assert(cursor.parent());
549   TNode prev = cursor.prev();
550   assert(prev.is("sp") || prev.is("sb"));
551   cursor.remove();
552   prev.append(cursor);
553   // i can invoke the gdelet_prev, because a sp (sb) MUST have two child
554   gdelete_prev();
555   logger.debug("gdelete_prev_script: bye...");
556 }
557
558 void
559 TPushParser::gdelete_prev_group()
560 {
561   logger.debug("gdelete_prev_group: start");
562   assert(cursor.prev() && cursor.prev().isG());
563   TNode prev = cursor.prev();
564   cursor.remove();
565   prev.append(cursor);
566   logger.debug("gdelete_prev_group: i have to call the do_gdelete()");
567   
568   // a group can have no child, so the gdelete_prev is not appropriate
569   // so this method is not equivalent to the one above
570   do_gdelete();
571   
572   logger.debug("gdelete_prev_group: do_gdelete terminated");
573   logger.debug("gdelete_prev_group: bye...");
574 }
575
576 void
577 TPushParser::gdelete_prev_macro()
578 {
579   logger.debug("gdelete_prev_macro: start");
580   assert(cursor.parent());
581   assert(cursor.prev());
582   TNode prev = cursor.prev();
583   assert(prev.isC());
584   
585   const TDictionary::Entry& entry = dictionary.find(prev["name"]);
586   
587   if (!entry.defined())
588     {
589       // I assume tha the user want to completely delete the undefined macro
590       logger.debug("gdelete_prev_macro: i have to remove an undefined macro");
591       cursor.remove();
592       prev.replace(cursor);
593     }
594   else
595     {
596       logger.debug("gdelete_prev_macro: i have to start to delete a defined MACRO");
597       
598       // i start to remove a MACRO. Different actions must be taken, based on the nature 
599       // of the MACRO. In some case, we can't remove the MACRO immediately, in other
600       // case it's correct. In the first case, we have to update the stack, pushing
601       // a frame in the stack with a correct value of pos, in the 
602       // second one, we do not have to push a frame in the stack
603       
604       if (entry.rightOpen)
605         {
606           // if the control element is ightOpen, the cursor should be placed after 
607           // the last child of the control element's last child, and try to remove something
608           // A frame MUST be pushed in the stack, because we dont' know if the following actions 
609           // will remove the MACRO.
610           logger.debug("gdelte_prev_macro: i have to delete a control rightOpen, so i push an element in the stack");
611           
612           frames.push(Frame(entry));
613
614           logger.debug("gdelete_prev_macro: i control the values of the pushed frame");
615           logger.debug("gdelete_prev_macro: rightOpen");
616           cout << frames.top().entry.rightOpen << endl;
617           logger.debug("gdelete_prev_macro: leftOpen");
618           cout << frames.top().entry.leftOpen << endl;
619           logger.debug("gdelete_prev_macro: pattern.empty()");
620           cout << frames.top().entry.pattern.empty() << endl;
621
622           // Since the MACRO is rightOpen, the last child of the MACRO must be a phantom group
623           assert(prev.last().isG() && !prev.last().hasId());
624           
625           cursor.remove();
626           prev.last().append(cursor);
627           
628           // the gdelete_prev is not appropriate, because the last child of the MACRO could have no child
629           logger.debug("gdelete_prev_macro: i have to call do_gdelete_phantom_group");
630           do_gdelete_phantom_group();
631           
632           if (!frames.empty())
633             {
634               logger.debug("gdelete_prev_macro: after the do_gdelete_phantom_group, the frame in the stack has to be rightOpen");
635               cout << frames.top().entry.rightOpen  << endl;
636               logger.debug("gdelte_prev_macro: after the do_gdelete_phantom_group, the top element's pattern MUST be empty");
637               cout << frames.top().entry.pattern.empty() << endl;
638             }
639           else
640             logger.debug("gdelete_prev_macro: the do_gdelete_phantom_group has removed all frames in the stack");
641           
642         }
643       else if (entry.leftOpen)
644         {
645           logger.debug("gdelete_prev_macro: i have to delete a control element with leftOpen");
646           // the leftOpen MACRO MUST have one and only one child, which MUST be a phantom group
647           // In this case, we do not have to push a frame in the stack, because we remove the 
648           // MACRO immediately, substituting it with the content of the phantom group.
649           // At the moment, i don't remove the last child of the phantom group, but
650           // i don't know if it's the correct behavior of the graphical deleting.
651           // To delete it, just remove the comment of the last instruction 
652           assert(prev.first());
653           assert(prev.first().isG());
654           assert(prev.first() == prev.last());
655           
656           TNode g = prev.first();
657           g.remove();
658           prev.replace(g.first(), TNode());
659           //do_gdelete();
660         }
661       else if (!entry.pattern.empty())
662         {
663           // we have to start removing a MACRO which accepts arguments.
664           // a MACRO without child does not exist
665           
666           logger.debug("gdelete_prev_macro: i have to remove a MACRO with argument");
667           assert(prev.size() >= 1);
668
669           // Differnt actions should be taken, based on the nature of the last child
670           // of the MACRO. We have to distinguish the case in which it's a delimited argument
671           // frome the one in which it's a not delimited argument.
672           if (prev.last().isG() && !prev.last().hasId())
673             {
674               // the last argument of the MACRO is a delimited argumet. We ideally remove 
675               // the sequence of delimiters
676               logger.debug("gdelete_prev_macro: the last argument of the MACRO is delimited");
677               cursor.remove();
678               prev.last().append(cursor);
679               // i have to push a frame with a correct value of pos
680               assert(entry.previousParam(entry.pattern.size()) != entry.pattern.size());
681               unsigned sequence_length = entry.pattern.size() - entry.previousParam(entry.pattern.size()) - 1;
682               unsigned p = entry.pattern.size() - sequence_length - 1;
683               frames.push(Frame(entry, p));
684               logger.debug("gdelete_prev_macro: i have inserted a frame, it's pos is: ");
685               cout << frames.top().pos << endl;
686               
687             }
688           else
689             {
690               // in this case, the last child of the MACRO is not a delimited argument, so we try 
691               // to remove it, but we have to take differnt actions if the MACRO is a table with rows or not. 
692               logger.debug("gdelete_prev_macro: the last argumet of the MACRO is not delimited, so itry to remove it");
693               cursor.remove();
694               if (entry.table == 1 && prev.last().is("row"))
695                 {
696                   // in this case the cursor should be appended to the group associated to 
697                   // the last cell of the last row of the table
698                   logger.debug("gdelete_prev_macro: but it is a table with rows, so i append the cursor at the end of the table");
699                   assert(prev.last().last().is("cell") && prev.last().last().first().isG());
700                   prev.last().last().first().append(cursor);
701                 }
702               else
703                 {
704                   logger.debug("gdelete_prev_macro: i append the cursor to the MACRO");
705                   prev.append(cursor);
706                 }
707
708               frames.push(Frame(entry, entry.pattern.size()));
709
710               logger.debug("gdelete_prev_macro: i've pushed a frame in the stack, and it's value of pos is ");
711               cout << frames.top().pos << endl;
712               
713               if (cursor.prev())
714                 {
715                   logger.debug("gdelete_prev_macro: i invoke the gdelete_prev");
716                   gdelete_prev();
717                 }
718               else
719                 {
720                   logger.debug("gdelete_prev_macro: i invoke the do_gdelete");
721                   do_gdelete();
722                 }
723             } // end of the else of the if (prev.last().isG() && !prev.last().hasId())
724
725         } // end of if (!entry.pattern.empty())
726       else
727         {
728           // if we are here, the MACRO preceding the cursor, is not rightOpen, nor leftOpen,
729           // and has no pattern. It means that it has no childs.
730           // We can replace it with the cursor
731           logger.debug("gdelete_prev_macro: the MACRO is empty, i remove it");
732           assert(prev.size() == 0);
733           cursor.remove();
734           prev.replace(cursor);
735         }
736     } // end of defined MACRO
737
738   logger.debug("gdelete_prev_macro: bye...");
739 }
740
741 void
742 TPushParser::gdelete_prev()
743 {
744   // if in this function, the prev of cursor does exist, also the parent and we want a graphical deleting.
745   
746   logger.debug("gdelete_prev: start...");
747
748   assert(cursor.prev());
749   assert(cursor.parent());
750
751   TNode prev = cursor.prev();
752
753   if (prev.is("i") || prev.is("o") || prev.is("n"))
754     {
755       gdelete_prev_token();
756     }
757   else if (prev.isSp() || prev.isSb())
758     {
759       gdelete_prev_script();
760     }
761   else if (prev.isG())
762     {
763       gdelete_prev_group();
764     }
765   else if (prev.isC())
766     {
767       // here we also treat the case in which the MACRO is a table
768       gdelete_prev_macro();
769     }
770   else 
771     {
772       // not handled. Future cases...
773     }
774
775   logger.debug("gdelete_prev: bye...");
776 } // end of method
777
778 void
779 TPushParser::rgreplace_futher(void)
780 {
781   // this function MUST only be invoked, when the cursor
782   // is the only child of a group with id. This function 
783   // replace the group with the cursor. But if the new parent
784   // is a group with id and the cursor is the only child of the 
785   // group, the new parent is replaced...and so on.
786   // r stands for recursive, g stands for graphical
787   assert(cursor.parent());
788   assert(cursor.parent().isG() && cursor.parent().hasId());
789
790   TNode parent = cursor.parent();
791
792   while (parent.isG() && parent.hasId() && (parent.first() == cursor))
793     {
794       parent.replace(cursor);
795       parent = cursor.parent();
796     }
797
798   if (parent.isC())
799     {
800       // in this case we have removed a MACRO's child. 
801       // I can assert that this MACRO accepts arguments.
802       assert(!frames.empty());
803       Frame& frame = frames.top();
804       assert(frame.pos > 0);
805       frame.pos--;
806     }
807 }
808
809 void
810 TPushParser::do_gdelete_script()
811 {
812   // If we are here, the cursor is child of a script and 
813   // means that a prev MUST exist and that there is only an 
814   // element preceding the cursor. The sp's (or sb's) parent 
815   // MUST NOT be a MACRO.
816   // The element preceding the cursor is the base of the script.
817
818   logger.debug("do_gdelete_script: start...");
819
820   assert(cursor.parent() && (cursor.parent().isSp() || cursor.parent().isSb()));
821   TNode parent = cursor.parent();
822           
823   assert(parent.size() == 2);
824   assert(parent.parent() && !parent.parent().isC());
825   
826   TNode prev = cursor.prev();
827   cursor.remove();
828   if (prev.isG() /*&& !prev.hasId()*/ && (prev.size() == 0))
829     {
830       // in this case, the script's base is a group with no elements, so i think 
831       // we have to remove the entire MACRO, replacing it with the cursor
832       prev.remove();
833       parent.replace(cursor);
834       
835       // if the new parent is a group with Id and the cursor is the only 
836       // element of this group, we have to remove it. This controls are made
837       // in the method rgreplace_futher().
838       if (cursor.parent().isG() && cursor.parent().hasId()) rgreplace_futher();
839     }
840   else
841     {
842       // in this case, the prev has to replace the script, 
843       // and the curosor has to be placed after the prev. 
844       assert(prev.hasId());
845       parent.replace(prev);
846       prev.parent().append(cursor);
847       // now prev should have a preceding element
848       assert(cursor.parent().size() > 1);
849     }
850   
851  logger.debug("do_gdelete_script: bye...");
852   
853 } // end of method do_gdelet_script
854
855 void
856 TPushParser::do_gdelete_macro()
857 {
858   // If we are here, the cursor is a child of a MACRO and this means
859   // that there is an open frame for the control element
860   // and this element is closed at either side (no leftOpen no rightOpen)
861   // and the MACRO was waiting for a non delimited argument, so 
862   // we can assert that frame.entry.pattern.size() >= 1
863   assert(cursor.parent() && cursor.parent().isC());
864   TNode parent = cursor.parent();
865   
866   assert(!frames.empty());
867   Frame& frame = frames.top();
868   assert(frame.entry.pattern.size() >= 1);
869
870   // we have to take different actions, based on if a preceding element exists 
871   // or not
872   logger.debug("do_gdelete_macro:");
873   TNode prev = cursor.prev();
874   if (!prev)
875     {
876       // in this case, a prev does not exist, so the actions of deleting means 
877       // that we have to remove the MACRO. So we have to pop the stack.
878       // Being here also means that the MACRO is waiting for the first argument
879       // (which is not delimited)
880       assert(frame.pos == 0);
881       parent.replace(cursor);
882       frames.pop();
883
884       // if the new parent is a group with Id, and has no elements other than the 
885       // cursor, we could remove it...but i'm not sure
886       if (cursor.parent() && cursor.parent().isG() && cursor.parent().hasId())
887         rgreplace_futher();
888       else if (cursor.parent().isC())
889         {
890           // We have assumed that a MACRO cannot be a MACRO's child. 
891           // At the moment, this assumption is valid, but in a future 
892           // it could be false.
893           assert(!frames.empty());
894           Frame& frame = frames.top();
895           assert(frame.pos > 0);
896           frame.pos--;
897         }
898     }
899   else
900     {
901       // we have to control if prev is a delimited argument or not.
902       if (prev.isG() && !prev.hasId())
903         {
904           // in this case, prev is a delimited argument, so we have 
905           // to ideally remove the sequence of delimiters
906           Frame& frame = frames.top();
907           assert(frame.pos > 1);
908           logger.debug("do_gdelete_macro: the pos of the frame is: ");
909           cout << frame.pos << endl;
910           logger.debug("do_gdelete_macro: the pattern size of the entry is");
911           cout << frame.entry.pattern.size() << endl;
912           logger.debug("do_gdelete_macro: the prev param is at");
913           cout << frame.entry.previousParam(frame.pos) << endl;
914           cursor.remove();
915           prev.append(cursor);
916           assert(frame.entry.previousParam(frame.pos) != frame.entry.pattern.size());
917           unsigned sequence_length = frame.pos - frame.entry.previousParam(frame.pos) - 1;
918           assert(sequence_length);
919           frame.pos = frame.pos - sequence_length - 1;
920         }
921       else
922         {
923           // the prev is not a delimited argument, so we have to try to remove it. 
924           // I told "try" because the prev can be a group or something that 
925           // a simple delete cannot remove completely
926           gdelete_prev();
927         }
928     }
929
930   logger.debug("do_gdelete_macro: bye...");
931 }
932
933 void
934 TPushParser::do_gdelete_groupId()
935 {
936   // if we are here, the cursor's parent is a group with Id
937   assert(cursor.parent() && cursor.parent().isG() && cursor.parent().hasId());
938   TNode parent = cursor.parent();
939
940   // we have to take different actions based on if the cursor has a preceding 
941   // element or not
942   TNode prev = cursor.prev();
943   if (prev)
944     {
945       // the cursor has a preceding element, so we try to remoev it
946       gdelete_prev();
947
948       // We control if the group has to be removed, because the cursor 
949       // could be the only element of the group.
950       if ((parent.first() == cursor) && parent.isG() && parent.hasId())
951         rgreplace_futher();
952       
953     }
954   else
955     {
956       // the cursor has no preceding elements, so we have to remove the 
957       // group.
958       rgreplace_futher();
959       
960       // i have to re-start the process, because it' a graphical delete
961       do_gdelete();
962     }
963
964   logger.debug("do_gdelete_groupId: bye...");
965   
966 } // end of method do_gdelete_groupId()
967
968 void
969 TPushParser::do_gdelete_phantom_group()
970 {
971   // if we are here, the cursor MUST be a child of a 
972   // phantom group.
973   logger.debug("do_gdelete_phantom_group: start");
974   assert(cursor.parent() && cursor.parent().isG() && !cursor.parent().hasId());
975
976   TNode parent = cursor.parent();
977
978   // now we have to control if the cursor has a preceding element or not
979   TNode prev = cursor.prev();
980   if (prev)
981     {
982       // the cursor has a preceding element, so we try to remove it
983       logger.debug("do_gdelete_phantom_group: i have to call the gdelete_prev()");
984       gdelete_prev();
985       logger.debug("do_gdelete_phantom_group: gdelete_prev terminated");
986
987       if (parent.size() == 1 && parent.parent().isSp())
988         {
989           logger.debug("do_gdelete_phantom_group: i have to remove a phantom group which is a child of a sp");
990           // in this case the gdelete_prev has removed the only element preceding the cursor.
991           // If the phantom group is a sp's child, it means that the user has removed all \' in the 
992           // phantom group. I think, we can remove the phamtom group and the sp element.
993           cursor.remove();
994           parent.replace(cursor);
995           // now we have a sp element with two children: the first child (we don't know nothing about it)
996           // and the cursror.
997           assert(cursor.parent().size() == 2);
998           
999           // to delete the script we can invoke the do_gdelete_script(), which will do all controls we need
1000           do_gdelete_script();
1001         }
1002       else if (parent.parent().isSp())
1003         {
1004           // in this case we have to place the cursor after the sp element
1005           logger.debug("do_gdelete_phantom_group: the sequence of \' is not terminated, so i place the cursor after the sp element");
1006           cursor.remove();
1007           assert(parent.parent().parent());
1008           parent.parent().parent().append(cursor);
1009         }
1010     }
1011   else
1012     {
1013       // in this case the cursor is the only element of the phantom group,
1014       // so we have to remove it. But, a phantom group has a special role, 
1015       // so we have to control the grand futher of the cursor.
1016       TNode gfuther = parent.parent();
1017       if (!gfuther)
1018         {
1019           // If here, the TML tree is in an inconsistent state
1020           logger.error("do_gdelete_phantom: TML tree in a inconsistent state");
1021         }
1022       else if (gfuther.isC())
1023         {
1024           // in this case the phantom group is child of a MACRO.
1025           // We have to control the nature of this MACRO.
1026           logger.debug("do_gdelete_phantom_group: i have to remove a phantom group which is a child of a MACRO");
1027           assert(!frames.empty());
1028           Frame& frame = frames.top();
1029           
1030           if (frame.entry.leftOpen && frame.entry.rightOpen)
1031             {
1032               // in this case, the cursor is in the second and last child 
1033               // of the MACRO. We can assert that the grand futher has two 
1034               // children. which are both phantom group
1035               logger.debug("do_gdelete_phantom_group: the MACRO is leftOpen and rigthOpen");
1036               assert(gfuther.size() == 2);
1037               assert((gfuther.last() == parent) && (gfuther.first().isG() && !gfuther.first().hasId()));
1038               assert(frame.pos == 0);
1039               
1040               TNode ggfuther = gfuther.parent();
1041               assert(ggfuther);
1042               cursor.remove();
1043               parent.remove();
1044               // i have to replace the gfuther with the elements of its first child
1045               gfuther.replace(gfuther.first().first(), TNode());
1046               logger.debug("do_gdelete_phantom_group: i have removed the control element, and replaced it with its first child");
1047               ggfuther.append(cursor);
1048               logger.debug("do_gdelete_phantom_group: cursor appended to the grand grand futher");
1049               // now we have the situation preceding the insertion of the MACRO leftOpen and rightOpen
1050               // this MACRO no longer exists.
1051               frames.pop();
1052             }
1053           else if (frame.entry.rightOpen)
1054             {
1055               // the user has inserted a MACRO rightOpen. Since the cursor is the 
1056               // only child of the MACRO, the user want to remove it. 
1057               // We can assert that cursor's parent is the only child of the MACRO
1058               logger.debug("do_gdelete_phantom_group: the MACRO is rightOpen only");
1059               assert(gfuther.size() == 1);
1060               assert(frame.pos == 0);
1061               cursor.remove();
1062               parent.remove();
1063               gfuther.replace(cursor);
1064               
1065               // now we have the situation preceding the MACRO rightOpen, so i have to pop the frame
1066               frames.pop();
1067             }
1068           else if (frame.entry.leftOpen)
1069             {
1070               // i think this situation will never occur
1071               // but it can be recovered in some way
1072               logger.error("the parser has generated a wrong TML tree");
1073             }
1074           else if (!frame.entry.pattern.empty())
1075             {
1076               // the MACRO accepts arguments, and the phantom group in which 
1077               // the cursor is, rappresents a delimited argument
1078               // We have to control if the cursor's parent has a preceding element, 
1079               // or not.
1080               logger.debug("do_gdelete_phantom_group: the MACRO accepts arguments");
1081               logger.debug("do_gdelete_phantom_group: entry pattern has size:");
1082               cout << frame.entry.pattern.size() << endl;
1083               TNode uncle = parent.prev();
1084               if (!uncle)
1085                 {
1086                   // the parent is the only element of the MACRO. 
1087                   // we can assert that frame.pos == 0.
1088                   // In this case we can replace the MACRO with the cursor
1089                   assert(frame.pos == 0);
1090                   cursor.remove();
1091                   parent.remove();
1092                   gfuther.replace(cursor);
1093                   frames.pop();
1094                 }
1095               else
1096                 {
1097                   // the parent has a preceding element. Now we have 
1098                   // to control if the uncle is a delimited argument or not.
1099                   if (uncle.isG() && !uncle.hasId())
1100                     {
1101                       // the  uncle is a delimited argument. So we have to ideally
1102                       // remove the sequrnce of delimiters.
1103                       assert(frame.pos > 1);
1104                       unsigned sequence_length = frame.pos - frame.entry.previousParam(frame.pos) - 1;
1105                       assert(frame.entry.previousParam(frame.pos) != frame.entry.pattern.size());
1106                       assert(sequence_length);
1107                       // sequence_length is the length of the delimiters sequence which separates
1108                       // the current parameter and the previous parameter
1109                       frame.pos = frame.pos - sequence_length - 1;
1110                       cursor.remove();
1111                       parent.remove();
1112                       uncle.append(cursor);
1113                     }
1114                   else
1115                     {
1116                       // the uncle is a not delimited argument, so we try to remove it.
1117                       cursor.remove();
1118                       parent.replace(cursor);
1119                       parent = cursor.parent(); // i update the parent (it should be the MACRO)
1120                       assert(parent.isC());
1121
1122                       // now i try to remove the uncle (now it' the preceding element)
1123                       gdelete_prev();
1124                     }
1125                 } // this is the else's end, that handles the case in which an uncle exists
1126             } // end of if (!frame.entry.pattern.empty())
1127           else
1128             {
1129               // the entry has no arguments, is not rightOpen and is not leftOpen.
1130               logger.warning("do_gdelete_phantom_group: TML tree in a strange state");
1131               if (gfuther.size() == 1)
1132                 {
1133                   cursor.remove();
1134                   parent.remove();
1135                   gfuther.replace(cursor);
1136                 }
1137               else
1138                 {
1139                   logger.debug("do_gdelete_phantom_group: TML tree in a very strange state");
1140                   cursor.remove();
1141                   gfuther.replace(cursor);
1142                 }
1143             }
1144         } // end of if (gfuther.isC())
1145       else if (gfuther.is("cell"))
1146         {
1147           // we have to handle the case where cursor'grand futher is a cell element.
1148           // The tables are control sequece, so there is a frame in the stack
1149           assert(!frames.empty());
1150           assert(frames.top().pos == 1);
1151           assert(frames.top().entry.table == 1);
1152           
1153           // a cell MUST be child of row element, which in turn MUST be child of an element 
1154           // havin attribute table.
1155           assert(gfuther.parent() && gfuther.parent().is("row") && gfuther.parent().parent());
1156           TNode row = gfuther.parent();
1157           
1158           // in this case the cell has no element, so the user wants to delete this cell.
1159           TNode prev_cell = gfuther.prev();
1160           cursor.remove();
1161           parent.remove();
1162           gfuther.remove();
1163           // now the cell no longer exists
1164
1165           if (!prev_cell)
1166             {
1167               // i this case, the cell is the only cell in the row.
1168               // So, i assume that the user wants to delete the entire row.
1169               TNode table = row.parent();
1170               TNode prev_row = row.prev();
1171               row.remove();
1172               
1173               if (!prev_row)
1174                 {
1175                   // the row was the only child of the table. 
1176                   // I think have to delete the entire table
1177                   assert(table.parent());
1178                   TNode parent_table = table.parent();
1179                   table.remove();
1180                   frames.pop();
1181                   parent_table.append(cursor);
1182                 }
1183               else
1184                 {
1185                   // there are other rows (one at least)
1186                   assert(prev_row.is("row"));
1187                   assert(prev_row.last());
1188                   TNode last_cell = prev_row.last();
1189                   assert(last_cell.is("cell"));
1190                   assert(last_cell.size() == 1);
1191                   assert(last_cell.first().isG() && !last_cell.first().hasId());
1192                   last_cell.first().append(cursor);
1193                 }
1194             } // end of if (!prev_cell)
1195           else
1196             {
1197               // being here means that there is a previous cell,
1198               // so we append the cursor to group.
1199               assert(prev_cell.size() == 1);
1200               assert(prev_cell.first().isG() && !prev_cell.first().hasId());
1201               prev_cell.first().append(cursor);
1202             }
1203         } // end of if (gfuther.is("cell"))
1204       else if (gfuther.isSp())
1205         {
1206           // in this case, the user pushed a \'. So this phantom group 
1207           // contained a sequence of \'. 
1208           // Maybe in this part will never be used, because, if we delete last \' in the 
1209           // phantom group, we remove the phantom group also
1210           //
1211           // In any case, if we are here we have two choice: 
1212           //   delete the phantom group;
1213           //   delete the superscript.
1214         }
1215       else
1216         {
1217           // cursor' grand futher is undefined
1218           logger.error("do_gdelete_phantom_group: TML tree in a unknown state");
1219         }
1220     } // end of the else of the if (prev)
1221
1222   if (!frames.empty())
1223     {
1224       logger.debug("do_gdelete_phantom_group: the stack is not empty");
1225       logger.debug("do_gdelte_phanto_group: is the top element rightOpen?");
1226       cout << frames.top().entry.rightOpen << endl;
1227       logger.debug("do_gdelte_phanto_group: is the top element'pattern empty?");
1228       cout << frames.top().entry.pattern.empty()  << endl;
1229     }
1230   logger.debug("do_gdelete_phantom_group: bye...");
1231 }
1232
1233
1234 void
1235 TPushParser::do_gdelete()
1236 {
1237   logger.debug("do_gdelete: start");
1238   // we have to handle the case in wich the cursor has a parent or not
1239   if (!cursor.parent())
1240     {
1241       // it's not a good situation...at the moment we do not take actions
1242       logger.error("TML tree not well structured");
1243     }
1244   else
1245     {
1246       // a parent exists. We have to take differnt actions, based on the nature of 
1247       // the parent
1248       TNode parent = cursor.parent();
1249       if (parent.is("math"))
1250         {
1251           // we ca do two thing...remove the math mode (it implies controlling the display attribute), do nothing
1252           // At the moment, the user's will of deleting is simply ignored
1253           logger.error("TML tree not well structured");
1254         }
1255       else if (parent.isG())
1256         {
1257           // the cursor's parent is a group. We have to control if it's a phantom group or not
1258           logger.debug("do_gdelete: the cursor's parent is a group");
1259           if (parent.hasId())
1260             {
1261               logger.debug("do_gdelete: which has Id");
1262               do_gdelete_groupId();
1263             }
1264           else
1265             {
1266               logger.debug("do_gdelete: which is a phantom group");
1267               do_gdelete_phantom_group();
1268             }
1269         } // end of parent is group
1270       else if (parent.isC())
1271         {
1272           cout << "the cursor's parent is a MACRO" << endl;
1273           do_gdelete_macro();
1274         } // end of parent is a MACRO
1275       else if (parent.isSp() || parent.isSb())
1276         {
1277           cout << "the cursor's parent is a script" << endl;
1278           do_gdelete_script();
1279         } // end of parent is sp or sb
1280     } // end of the else which consider the case in which parent exists
1281   
1282   if (!cursor.parent())
1283     logger.debug("do_gdelete: the cursro has no parent -> paolo is stupid");
1284
1285   if (!frames.empty())
1286     {
1287       logger.debug("do_gdelete: the stack is not empty");
1288       logger.debug("do_gdelete: is the top element rightOpen?");
1289       cout << frames.top().entry.rightOpen << endl;
1290       logger.debug("do_gdelete: is the top element'pattern empty");
1291       cout << frames.top().entry.pattern.empty() << endl;
1292     }
1293   logger.debug("do_gdelete: bye...");
1294   
1295 } // end of method do_gdelete
1296
1297 /*
1298 void
1299 TPushParser::do_gdelete()
1300 {
1301   // this function operates a graphical deleting
1302   
1303   //if (!frames.empty())
1304   //  cout << "do_gdelete: c'e' un frame aperto e il suo pos vale: " << frames.top().pos << endl;
1305   
1306   TNode parent = cursor.parent();
1307
1308   // if no parent, do nothing
1309   if (parent)
1310     {
1311       assert(parent);
1312       if (parent.isG())
1313         {
1314           TNode prev = cursor.prev();
1315           if (prev)
1316             {
1317               // i try to delete the preceding element
1318               gdelete_prev();
1319
1320               if ((parent.first() == cursor) && parent.isG() && parent.hasId())
1321                 rgreplace_futher();
1322
1323             }
1324           else // no previous node is present
1325             {
1326               // if here, we are in a gruop whose only child is the cursor.
1327               
1328               if (!parent.hasId())
1329                 {
1330                   // the parent is a phantom group
1331                   assert(parent.parent());
1332                   if (!parent.parent().is("math"))
1333                     {
1334                       TNode gfuther = parent.parent();
1335
1336                       // if the grand futher is a group with Id, it should be removed, 
1337                       // but i don't know if it will never occur...
1338                       if (gfuther.isG() && gfuther.hasId())
1339                         {
1340                           cursor.remove();
1341                           parent.replace(cursor);
1342
1343                           // re-start the process
1344                           do_gdelete();
1345                         }
1346                       else if (gfuther.isC())
1347                         {
1348                           // the grand futher is a control element: since the parent is a phantom group, 
1349                           // the TML tree should be in a inconsistent state (once removed the parent).
1350
1351                           // being here means that there is a frame in the stack
1352                           assert(!frames.empty());
1353                           cout << "do_gdelete: i have to remove a phantom group which is a child of a MACRO" << endl;
1354                           Frame& frame = frames.top();
1355                           cout << frame.entry.leftOpen << frame.entry.rightOpen << endl;
1356                           if (frame.entry.leftOpen && frame.entry.rightOpen)
1357                             {
1358                               // in this case, the cursor is in the second and last child 
1359                               // of the MACRO. We can assert that the grand futher has two 
1360                               // children. which are both phantom group
1361                               cout << "do_gdelete: the MACRO is leftOpen and rigthOpen" << endl;
1362                               assert(gfuther.size() == 2);
1363                               assert((gfuther.last() == parent) && (gfuther.first().isG() && !gfuther.first().hasId()));
1364                               assert(frame.pos == 0);
1365                             
1366                               TNode ggfuther = gfuther.parent();
1367                               assert(ggfuther);
1368                               cursor.remove();
1369                               parent.remove();
1370                               // i have to replace the gfuther with the elements of its first child
1371                               gfuther.replace(gfuther.first().first(), TNode());
1372                               cout << "do_gdelete: i have removed the control element, and replaced it with its first child" << endl;
1373                               ggfuther.append(cursor);
1374                               cout << "do_gdelete: cursor appended to the grand grand futher" << endl;
1375
1376                               // now we have the situation preceding the insertion of the MACRO leftOpen and rightOpen
1377                               // this MACRO no longer exists.
1378                               frames.pop();
1379                             }
1380                           else if (frame.entry.rightOpen)
1381                             {
1382                               // the user has inserted a MACRO rightOpen. Since the cursor is the 
1383                               // only child of the MACRO, the user want to remove it. 
1384                               // We can assert that cursor's parent is the only child of the MACRO
1385                               cout << "do_gdelete: the MACRO is rightOpen only" << endl;
1386                               assert(gfuther.size() == 1);
1387                               assert(frame.pos == 0); // i think this assert has no sense
1388                             
1389                               cursor.remove();
1390                               parent.remove();
1391                               gfuther.replace(cursor);
1392
1393                               // now we have the situation preceding the MACRO rightOpen, so i have to pop the frame
1394                               frames.pop();
1395                             }
1396                           else if (frame.entry.leftOpen)
1397                             {
1398                               // it' s an unpredicted situation
1399                               cout << "it's a bad situation, maybe handlable, but unpredicted" << endl;
1400                             }
1401                           else if (!frame.entry.pattern.empty())
1402                             {
1403                               // the MACRO (the cursor's grand futher) accepts arguments.
1404                               // we have to control if the cursor's uncle does exist.
1405
1406                               if (parent.prev())
1407                                 {
1408                                   // in this case, we can assert that frame in the stack has 
1409                                   // pos greater than 0
1410                                   cout << "this is the assert that fails" << endl;
1411                                   assert(frame.pos > 0);
1412                                 
1413                                   // cursor's uncle does exist. we have to control 
1414                                   // its nature (is it a phantom group?)
1415                                   TNode uncle = parent.prev();
1416                                   if (uncle.isG() && !uncle.hasId())
1417                                     {
1418                                       // the cursor's uncle is a phantom group, so it was a 
1419                                       // delimited argument of the MACRO and the corrisponding sequence of 
1420                                       // delimeters is inserted. So, the action of deleting means
1421                                       // removing this sequence
1422                                       assert(frame.pos > 1);
1423                                       unsigned sequence_length = frame.pos - frame.entry.previousParam(frame.pos) - 1;
1424                                       assert(frame.entry.previousParam(frame.pos) != frame.entry.pattern.size());
1425                                       assert(sequence_length);
1426                                       // sequence_length is the length of the delimiters sequence which separates
1427                                       // the current parameter and the previous parameter
1428                                       frame.pos = frame.pos - sequence_length - 1;
1429                                       cursor.remove();
1430                                       parent.remove();
1431                                       uncle.append(cursor);
1432                                     }
1433                                   else
1434                                     {
1435                                       // the uncle was a NOT delimited argument. So i try to 
1436                                       // remove it
1437                                       cursor.remove();
1438                                       parent.replace(cursor);
1439                                   
1440                                       parent = cursor.parent(); // i update the parent (it should be the MACRO)
1441                                       assert(parent.isC());
1442                                   
1443                                       gdelete_prev();
1444
1445                                     }
1446                                 }
1447                               else
1448                                 {
1449                                   // cursor's parent is the only child of the MACRO, which accepts arguments
1450                                   // i can assert that frame.pos == 0.
1451                                   // In this case i can replace the MACRO with the cursor
1452                                   assert(frame.pos == 0);
1453
1454                                   cursor.remove();
1455                                   parent.remove();
1456                                   gfuther.replace(cursor);
1457
1458                                   frames.pop();
1459                                 }
1460                             
1461                             }
1462                         }
1463                       else if (gfuther.is("cell"))
1464                         {
1465                           // being here means that there is a frame in the stack 
1466                           // associated to the "table"
1467                           cout << "do_gdelete: i have to delete a cell" << endl;
1468                           assert(!frames.empty());
1469                           assert(frames.top().pos == 1);
1470                           assert(frames.top().entry.table == 1);
1471                           // a cell MUST be child of row element, which in turn MUST be child of an element 
1472                           // havin attribute table.
1473                           assert(gfuther.parent() && gfuther.parent().is("row") && gfuther.parent().parent());
1474                           TNode row = gfuther.parent();
1475
1476                           // in this case the cell has no element, so the user wants to delete this cell.
1477                           TNode prev_cell = gfuther.prev();
1478                           
1479                           cursor.remove();
1480                           parent.remove();
1481                           gfuther.remove();
1482                           // now the cell no longer exists
1483                           
1484                           if (!prev_cell)
1485                             {
1486                               // i this case, the cell is the only cell in the row.
1487                               // So, i assume that the user wants to delete the entire row.
1488                               TNode table = row.parent();
1489                               TNode prev_row = row.prev();
1490                               row.remove();
1491                               if (!prev_row)
1492                                 {
1493                                   // the row was the only child of the table. 
1494                                   // I think have to delete the entire table
1495                                   assert(table.parent());
1496                                   TNode parent_table = table.parent();
1497                                   table.remove();
1498                                   frames.pop();
1499                                   parent_table.append(cursor);
1500                                 }
1501                               else
1502                                 {
1503                                   // there are other rows (one at least)
1504                                   assert(prev_row.is("row"));
1505                                   assert(prev_row.last());
1506                                   TNode last_cell = prev_row.last();
1507                                   assert(last_cell.is("cell"));
1508                                   assert(last_cell.size() == 1);
1509                                   assert(last_cell.first().isG() && !last_cell.first().hasId());
1510                                   last_cell.first().append(cursor);
1511                                 }
1512                             }
1513                           else
1514                             {
1515                               // being here means that there is a previous cell,
1516                               // so we append the cursor to group.
1517                               assert(prev_cell.size() == 1);
1518                               assert(prev_cell.first().isG() && !prev_cell.first().hasId());
1519                               prev_cell.first().append(cursor);
1520                             }
1521                         }
1522                     }
1523                   else // the grand futher is math
1524                     {
1525                       // nothing to do...i think
1526                       assert(frames.empty());
1527                     }
1528                 }
1529               else
1530                 { 
1531                   // the parent is a group with id and has no elements other than cursor
1532                   // so we replace it with the cursor.
1533                   rgreplace_futher();
1534
1535                   // i have to re-start the process, because it' a graphical delete
1536                   do_gdelete();
1537                 }
1538             }
1539         }
1540       else if (parent.isC())
1541         {
1542           // being here means that there is an open frame for the control element
1543           // and this element is closed at either side (no leftOpen no rightOpen)
1544           // and the MACRO was waiting for a non delimited argument, so 
1545           // we can assert that frame.entry.pattern.size() >= 1
1546           assert(!frames.empty());
1547           Frame& frame = frames.top();
1548
1549           assert(frame.entry.pattern.size() >= 1);
1550
1551           cout << "do_gdelete: frames.top().pos = " << frames.top().pos << endl;
1552
1553           TNode prev = cursor.prev();
1554
1555           if (!prev)
1556             {
1557               // in this case we can replace the MACRO with the cursor 
1558               // and pop the stack and we can assert that frame.pos == 0
1559               assert(frame.pos == 0);
1560               cursor.remove(); // it should not be necessary, but i'm not shure
1561               parent.replace(cursor);
1562               frames.pop();
1563             }
1564           else
1565             {
1566               // in this case the cursor has a preceding element 
1567               // and there are differnt things based on the nature 
1568               // of the prev: if it's a phantom group do something,
1569               // else do something else
1570               if (prev.isG() && !prev.hasId())
1571                 {
1572                   // in this case we have to append the cursor 
1573                   // to the prev and decrement frame.pos of the length of 
1574                   // delimiters sequence that delimitates the preceding argument.
1575                   // So we ideally remove this sequence
1576                   assert(frame.pos > 1);
1577                   cursor.remove();
1578                   prev.append(cursor);
1579                   assert(frame.entry.previousParam(frame.pos) != frame.entry.pattern.size());
1580                   unsigned sequence_length = frame.pos - frame.entry.previousParam(frame.pos) - 1;
1581                   assert(sequence_length);
1582                   frame.pos = frame.pos - sequence_length - 1;
1583                 }
1584               else
1585                 {
1586                   // the prev is an non delimited argument, so we try to 
1587                   // remove it.
1588                   gdelete_prev();
1589                 }
1590             }
1591         }
1592       else if (parent.is("sp") || parent.is("sb"))
1593         {
1594           // being here means that a prev MUST exist 
1595           // and that there is only an element preceding the cursor.
1596           // The sp's (or sb's) parent MUST NOT be a MACRO
1597
1598           assert(parent.size() == 2);
1599           assert(parent.parent() && !parent.parent().isC());
1600           
1601           TNode prev = cursor.prev();
1602           cursor.remove();
1603           if (prev.isG()*/ /*&& !prev.hasId()*/ /* && (prev.size() == 0))
1604             {
1605               prev.remove();
1606               parent.replace(cursor);
1607
1608               // now, cursor should be the only parent's child
1609               assert(cursor.parent().size() == 1);
1610
1611               if (cursor.parent().isG() && cursor.parent().hasId()) rgreplace_futher();
1612             }
1613           else
1614             {
1615               assert(prev.hasId());
1616               parent.replace(prev);
1617               prev.parent().append(cursor);
1618               // now prev should have a preceding element
1619               assert(cursor.parent().size() > 1);
1620             } 
1621         }
1622       else
1623         {
1624           // not handled: no control for tables, ...
1625         }
1626     }
1627   else
1628     {
1629       // the cursor has no parent!!!
1630       // do nothing?
1631       // emit an error? and if we want to emit an error, in which way?
1632     }
1633
1634 } // end of method
1635 */
1636
1637 void
1638 TPushParser::process(const TToken& token)
1639 {
1640   switch (token.category)
1641     {
1642     case TToken::BEGIN: do_begin(); break;
1643     case TToken::END: do_end(); break;
1644     case TToken::SHIFT: do_shift(); break;
1645     case TToken::ALIGN: do_align(); break;
1646     case TToken::EOL: do_eol(); break;
1647     case TToken::PARAMETER: do_parameter(token.value); break;
1648     case TToken::SUPERSCRIPT: do_superscript(); break;
1649     case TToken::SUBSCRIPT: do_subscript(); break;
1650     case TToken::SPACE: do_space(token.value); break;
1651     case TToken::LETTER: do_letter(token.value); break;
1652     case TToken::DIGIT: do_digit(token.value); break;
1653     case TToken::OTHER: do_other(token.value); break;
1654     case TToken::ACTIVE: do_active(token.value); break;
1655     case TToken::COMMENT: do_comment(); break;
1656     case TToken::CONTROL: do_control(token.value); break;
1657     case TToken::GDELETE: do_gdelete(); break;
1658     }
1659 }
1660
1661 void
1662 TPushParser::push(const TToken& token)
1663 {
1664   logger.debug("TPushParser::push " + token.value + " (cat: ");
1665   cout << token.category << ")" << endl;
1666
1667   if (token.category == TToken::GDELETE)
1668     {
1669       logger.debug("push: i have to process a token with category member = GDELETE");
1670       process(token);
1671     }
1672   else
1673     {
1674
1675       logger.debug("push: i get the cursor's parent");
1676       TNode parent = cursor.parent();
1677       // If the cursor has no parent then it is detached from the editing
1678       // tree, which means this token will be ignored
1679
1680       if (parent)
1681         // If the parent is a phantom group and the grand-parent is a
1682         // control sequence, there are two cases:
1683         // a. we are parsing a delimited argument of a entry
1684         // b. we are parsing a side of a right- or left-open entry
1685         if (parent.isG() && !parent.hasId() && parent.parent().isC())
1686           {
1687             // There must be an open frame, for the grand-parent is a control sequence
1688             logger.debug("push: cursor'parent is a phantom group, and this group has a MACRO as parent");
1689             logger.debug("push: i assert that !frames.empty()");
1690             assert(!frames.empty());
1691             logger.debug("push: this assert is OK");
1692             logger.debug("push: now i take the top element of the stack");
1693             Frame& frame = frames.top();
1694             logger.debug("push: now i've got the top element");
1695             if (!frame.entry.pattern.empty())
1696               {
1697                 // The entry pattern is not empty. By our conventions this means
1698                 // the entry cannot be open at either end, hence we are parsing
1699                 // a delimited argument
1700                 logger.debug("push: the frame.entry accepts arguments");
1701                 assert(frame.pos + 1 < frame.entry.pattern.size());
1702                 assert(frame.entry.pattern[frame.pos + 1].category != TToken::PARAMETER);
1703                 if (frame.entry.pattern[frame.pos + 1] == token)
1704                   {
1705                     // The token matches with a delimiter of the argument, 
1706                     // so we increment the frame.pos
1707                     frame.pos++;
1708
1709                     if (frame.entry.lastDelimiter(frame.pos))
1710                       {
1711                         // this delimiter is the last one for the argumet, 
1712                         // so the argument is completed
1713                         cursor.remove();
1714                         frame.pos++;
1715
1716                         if (frame.pos == frame.entry.pattern.size())
1717                           {
1718                             // This token has completed the entry
1719                             frames.pop();
1720                             advance(parent.parent());
1721                           }
1722                         else if (frame.entry.paramDelimited(frame.pos))
1723                           {
1724                             // For the next is a delimited argument we have to place
1725                             // a suitable phantom group with the cursor inside
1726                             TNode g = doc.createG();
1727                             parent.parent().append(g);
1728                             g.append(cursor);
1729                           }
1730                         else
1731                           parent.parent().append(cursor);
1732                       }
1733                   }
1734                 else
1735                   {
1736                     // Delimiter mismatch.
1737                     if (frame.entry.pattern[frame.pos].category != TToken::PARAMETER)
1738                       {
1739                         // in this case, there is a sequence of delimiters that delimitates
1740                         // the argument, and the user correctly inserted a portion of this 
1741                         // sequence, but has inserted a wrong delimiter.
1742                         // Here, there are some possibilities:
1743                         //   - ignore the token, and wait for the correct delimiter
1744                         //   - ignore the token, wait for the correct delimiter and emit an error
1745                         // If we want to emit an error, we shlould implement a class, that handle 
1746                         // the error.
1747                         // At the moment, the error is printed to screen
1748                         cout << "push: it's not the correct delimiter...you have to type " << frame.entry.pattern[frame.pos + 1].value << endl;
1749                       }
1750                     else
1751                       {
1752                         // in this case, the sequence of delimiters is composed of one 
1753                         // delimiter. It means that we have to process the token
1754                         process(token);
1755                       }
1756                   }
1757               }
1758             else
1759               {
1760                 // The entry pattern is empty, hence we are parsing a right-open
1761                 // entry. What happens if we actually are in the left side?
1762                 // This could happen only when re-editing an entered expression
1763                 // We'll see...
1764                 logger.debug("push: the frame.entry has no arguments, so i assert that i's rightOpne");
1765                 assert(frame.entry.rightOpen);
1766                 logger.debug("push: this assert is OK, now i process the token");
1767                 process(token);
1768                 logger.debug("push: the token has been processed");
1769               }
1770           }
1771         else if (parent.isC())
1772           {
1773             // We are parsing a non-delimited argument entry
1774             // or a fixed token
1775             Frame& frame = frames.top();
1776             assert(frame.pos < frame.entry.pattern.size());
1777
1778             cout << "push: there is a frame with pos " << frame.pos <<  endl;
1779             if (frame.entry.pattern[frame.pos].category == TToken::PARAMETER)
1780               {
1781                 // As by the TeX parsing rules of undelimited parameters,
1782                 // empty spaces are ignored
1783                 if (token.category != TToken::SPACE)
1784                   {
1785                     // We need to increase the frame position here, becase inside
1786                     // process the function advance will be called. At that point
1787                     // it will be important for the parser to know that the entry
1788                     // has been completed in order to place the cursor correctly
1789                     // in the next position
1790                     logger.debug("TPushParser.push: we should be here");
1791                     frame.pos++;
1792                     process(token);
1793                   }
1794               }
1795             else if (frame.entry.pattern[frame.pos] == token)
1796               {
1797                 // The token has been accepted
1798                 frame.pos++;
1799                 if (frame.pos < frame.entry.pattern.size() &&
1800                     frame.entry.paramDelimited(frame.pos))
1801                   {
1802                     // If the next is a delimited argument we have to place
1803                     // the phantom group with the cursor inside
1804                     TNode g = doc.createG();
1805                     cursor.replace(g);
1806                     g.append(cursor);
1807                   }
1808                 else
1809                   advance(parent);
1810               }
1811             else
1812               {
1813                 // There is a mismatch. Emit an error and ignore the token?
1814                 cerr << "ERROR: token ignored: " << token.value << " (cat: " << token.category << ")" << endl;
1815               }
1816
1817           }
1818         else
1819           process(token);
1820       else
1821         {
1822           cout << "ignored token" << endl;
1823         }
1824
1825     } // this end corresponds to the else of the if (token.category == TToken::GDELETE)
1826
1827   if (factory) factory->documentModified(doc);
1828
1829   if (frames.empty()) cout << "stack vuoto" << endl;
1830   else
1831     {
1832       logger.debug("push: the stack is not empty");
1833       logger.debug("push: is the top element rightOpen?");
1834       cout << frames.top().entry.rightOpen << endl;
1835       logger.debug("push: is the pattern empty");
1836       cout << frames.top().entry.pattern.empty() << endl;
1837     }
1838 }
1839
1840 void
1841 TPushParser::advance(const TNode& node)
1842 {
1843   assert(node);
1844   TNode parent = node.parent();
1845   if (!parent)
1846     ; // nothing to do, the cursor is not in the document any more
1847   else if (parent.isG())
1848     {
1849       TNode next = node.next();
1850       if (next) next.insert(cursor);
1851       else parent.append(cursor);
1852     }
1853   else if (parent.isC())
1854     {
1855       if (node.next())
1856         ; // cursor removed
1857       else
1858         {
1859           Frame& frame = frames.top();
1860           if (frame.pos == frame.entry.pattern.size())
1861             {
1862               frames.pop();
1863               advance(parent);
1864             }
1865           else
1866             parent.append(cursor);
1867         }
1868     }
1869   else if (parent.is("math"))
1870     ; // we are done
1871   else
1872     advance(parent);
1873 }
1874
1875 void
1876 TPushParser::setCursorHint(const std::string& c)
1877 {
1878   cursor["val"] = c;
1879   if (factory) factory->documentModified(doc);
1880 }