]> git.lyx.org Git - lyx.git/blob - src/text2.C
white-space changes, removed definitions.h several enum changes because of this,...
[lyx.git] / src / text2.C
1 /* This file is part of
2  * ======================================================
3  * 
4  *           LyX, The Document Processor
5  *       
6  *           Copyright 1995 Matthias Ettrich
7  *           Copyright 1995-1999 The LyX Team.
8  *
9  * ====================================================== */
10
11 #include <config.h>
12
13 #include <cctype>
14 #include FORMS_H_LOCATION
15
16
17 #ifdef __GNUG__
18 #pragma implementation "lyxtext.h"
19 #endif
20
21 #include "LString.h"
22 #include "lyxparagraph.h"
23 #include "insets/inseterror.h"
24 #include "layout.h"
25 #include "LyXView.h"
26 #include "support/textutils.h"
27 #include "lyx_cb.h"
28 #include "undo.h"
29 #include "minibuffer.h"
30 #include "buffer.h"
31 #include "bufferparams.h"
32 #include "lyx_gui_misc.h"
33 #include "lyxtext.h"
34 #include "gettext.h"
35
36 using std::copy;
37
38 extern MiniBuffer * minibuffer;
39
40 // Constructor
41 LyXText::LyXText(int pw, Buffer * p)
42 {
43         firstrow = 0;
44         lastrow = 0;
45         currentrow = 0;
46         currentrow_y = 0;
47         paperwidth = pw;
48         parameters = &p->params;
49         params = p;
50         number_of_rows = 0;
51         refresh_y = 0;
52         status = LyXText::UNCHANGED;
53         LyXParagraph * par = p->paragraph;
54         current_font = GetFont(par, 0);
55    
56         height = 0;
57    
58         while (par) {
59                 InsertParagraph(par, lastrow);
60                 par = par->Next();
61         }
62         /* set cursor at the very top position */
63         selection = true;                      /* these setting is necessary 
64                                                 * because of the delete-empty-
65                                                 * paragraph mechanism in
66                                                 * SetCursor */
67         SetCursor(firstrow->par, 0);
68         sel_cursor = cursor;
69         selection = false;
70         mark_set = false;
71    
72         /* no rebreak necessary */ 
73         need_break_row = 0;
74    
75         undo_finished = true;
76         undo_frozen = false;
77
78         // Default layouttype for copy environment type
79         copylayouttype = 0;
80 }
81
82
83 // Destructor
84 LyXText::~LyXText()
85 {
86         // Delete all rows, this does not touch the paragraphs!
87         Row * tmprow = firstrow;
88         while (firstrow) {
89                 tmprow = firstrow->next;
90                 delete firstrow;
91                 firstrow = tmprow;
92         }
93 }
94
95
96 // Gets the fully instantiated font at a given position in a paragraph
97 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
98 // The difference is that this one is used for displaying, and thus we
99 // are allowed to make cosmetic improvements. For instance make footnotes
100 // smaller. (Asger)
101 // If position is -1, we get the layout font of the paragraph.
102 // If position is -2, we get the font of the manual label of the paragraph.
103 LyXFont LyXText::GetFont(LyXParagraph * par,
104                          LyXParagraph::size_type pos)
105 {
106         LyXLayout const & layout = 
107                 textclasslist.Style(parameters->textclass, par->GetLayout());
108
109         char par_depth = par->GetDepth();
110         // We specialize the 95% common case:
111         if (par->footnoteflag == LyXParagraph::NO_FOOTNOTE && !par_depth) {
112                 if (pos >= 0){
113                         // 95% goes here
114                         if (layout.labeltype == LABEL_MANUAL
115                             && pos < BeginningOfMainBody(par)) {
116                                 // 1% goes here
117                                 return par->GetFontSettings(pos).
118                                                 realize(layout.reslabelfont);
119                         } else
120                                 return par->GetFontSettings(pos).
121                                                 realize(layout.resfont);
122                 } else {
123                         // 5% goes here.
124                         // process layoutfont for pos == -1 and labelfont for pos < -1
125                         if (pos == -1)
126                                 return layout.resfont;
127                         else
128                                 return layout.reslabelfont;
129                 }
130         }
131
132         // The uncommon case need not be optimized as much
133
134         LyXFont layoutfont, tmpfont;
135
136         if (pos >= 0){
137                 // 95% goes here
138                 if (pos < BeginningOfMainBody(par)) {
139                         // 1% goes here
140                         layoutfont = layout.labelfont;
141                 } else {
142                         // 99% goes here
143                         layoutfont = layout.font;
144                 }
145                 tmpfont = par->GetFontSettings(pos);
146                 tmpfont.realize(layoutfont);
147         } else {
148                 // 5% goes here.
149                 // process layoutfont for pos == -1 and labelfont for pos < -1
150                 if (pos == -1)
151                         tmpfont = layout.font;
152                 else
153                         tmpfont = layout.labelfont;
154         }
155
156         // Resolve against environment font information
157         while (par && par_depth && !tmpfont.resolved()) {
158                 par = par->DepthHook(par_depth - 1);
159                 if (par) {
160                         tmpfont.realize(textclasslist.
161                                         Style(parameters->textclass,
162                                               par->GetLayout()).font);
163                         par_depth = par->GetDepth();
164                 }
165         }
166
167         tmpfont.realize(textclasslist.TextClass(parameters->textclass).defaultfont());
168
169         // Cosmetic improvement: If this is an open footnote, make the font 
170         // smaller.
171         if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
172             && par->footnotekind == LyXParagraph::FOOTNOTE) {
173                 tmpfont.decSize();
174         }
175
176         return tmpfont;
177 }
178
179
180 void LyXText::SetCharFont(LyXParagraph * par,
181                           LyXParagraph::size_type pos,
182                           LyXFont font)
183 {
184         /* let the insets convert their font */ 
185         if (par->GetChar(pos) == LyXParagraph::META_INSET) {
186                 if (par->GetInset(pos))
187                         font = par->GetInset(pos)->ConvertFont(font);
188         }
189
190         LyXLayout const & layout = textclasslist.Style(parameters->textclass,
191                                            par->GetLayout());
192
193         // Get concrete layout font to reduce against
194         LyXFont layoutfont;
195
196         if (pos < BeginningOfMainBody(par))
197                 layoutfont = layout.labelfont;
198         else
199                 layoutfont = layout.font;
200
201         // Realize against environment font information
202         if (par->GetDepth()){
203                 LyXParagraph * tp = par;
204                 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
205                         tp = tp->DepthHook(tp->GetDepth()-1);
206                         if (tp)
207                                 layoutfont.realize(textclasslist.
208                                                 Style(parameters->textclass,
209                                                       tp->GetLayout()).font);
210                 }
211         }
212
213         layoutfont.realize(textclasslist.TextClass(parameters->textclass).defaultfont());
214
215         if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
216             && par->footnotekind == LyXParagraph::FOOTNOTE) {
217                 layoutfont.decSize();
218         }
219
220         // Now, reduce font against full layout font
221         font.reduce(layoutfont);
222
223         par->SetFont(pos, font);
224 }
225
226
227 /* inserts a new row behind the specified row, increments
228  * the touched counters */
229 void LyXText::InsertRow(Row * row, LyXParagraph * par,
230                         LyXParagraph::size_type pos)
231 {
232         Row * tmprow = new Row;
233         if (!row) {
234                 tmprow->previous = 0;
235                 tmprow->next = firstrow;
236                 firstrow = tmprow;
237         }
238         else {
239                 tmprow->previous = row;
240                 tmprow->next = row->next;
241                 row->next = tmprow;
242         }
243    
244         if (tmprow->next)
245                 tmprow->next->previous = tmprow;
246    
247         if (tmprow->previous)
248                 tmprow->previous->next = tmprow;
249    
250    
251         tmprow->par = par;
252         tmprow->pos = pos;
253    
254         if (row == lastrow)
255                 lastrow = tmprow;
256         number_of_rows++;                              /* one more row  */
257 }
258
259
260 /* removes the row and reset the touched counters */
261 void LyXText::RemoveRow(Row * row)
262 {
263         /* this must not happen before the currentrow for clear reasons.
264            so the trick is just to set the current row onto the previous
265            row of this row */
266         long unused_y;
267         GetRow(row->par, row->pos, unused_y);
268         currentrow = currentrow->previous;
269         if (currentrow)
270                 currentrow_y -= currentrow->height;
271         else
272                 currentrow_y = 0;
273    
274         if (row->next)
275                 row->next->previous = row->previous;
276         if (!row->previous) {
277                 firstrow = row->next;
278         }
279         else  {
280                 row->previous->next = row->next;
281         }
282         if (row == lastrow)
283                 lastrow = row->previous;
284    
285         height -= row->height;         /* the text becomes smaller  */
286    
287         delete row;
288         --number_of_rows;                              /* one row less  */
289 }
290
291
292 /* remove all following rows of the paragraph of the specified row. */
293 void LyXText::RemoveParagraph(Row * row)
294 {
295         Row * tmprow;
296
297         LyXParagraph * tmppar = row->par;
298         row = row->next;
299     
300         while (row && row->par == tmppar) {
301                 tmprow = row->next;
302                 RemoveRow(row);
303                 row = tmprow;
304         }
305 }
306    
307   
308 /* insert the specified paragraph behind the specified row */
309 void LyXText::InsertParagraph(LyXParagraph * par, Row * row)
310 {
311         InsertRow(row, par, 0);        /* insert a new row, starting 
312                                         * at postition 0 */
313
314         SetCounter(par);                       /* set the counters  */
315    
316         /* and now append the whole paragraph behind the new row */
317         if (!row) {
318                 firstrow->height = 0;
319                 AppendParagraph(firstrow);
320         }
321         else {
322                 row->next->height = 0;
323                 AppendParagraph(row->next);
324         }
325 }
326     
327
328 void LyXText::ToggleFootnote()
329 {
330         LyXParagraph * par = cursor.par->ParFromPos(cursor.pos);
331         if (par->next && par->next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
332                 OpenFootnote();
333                 minibuffer->Set(_("Opened float"));
334         }
335         else {
336                 minibuffer->Set(_("Closed float"));
337                 CloseFootnote();
338         }
339 }
340
341
342 void LyXText::OpenStuff()
343 {
344         if (cursor.pos == 0 && cursor.par->bibkey){
345                 cursor.par->bibkey->Edit(0, 0);
346         }
347         else if (cursor.pos < cursor.par->Last() 
348                  && cursor.par->GetChar(cursor.pos) == LyXParagraph::META_INSET
349                  && cursor.par->GetInset(cursor.pos)->Editable()) {
350                 minibuffer->Set(cursor.par->GetInset(cursor.pos)->EditMessage());
351                 if (cursor.par->GetInset(cursor.pos)->Editable() != 2)
352                         SetCursorParUndo();
353                 cursor.par->GetInset(cursor.pos)->Edit(0, 0);
354         }
355         else {
356                 ToggleFootnote();
357         }
358 }
359
360
361 void LyXText::CloseFootnote()
362 {
363         LyXParagraph * endpar, * tmppar;
364         Row * row;
365    
366         LyXParagraph * par = cursor.par->ParFromPos(cursor.pos);
367    
368         /* if the cursor is not in an open footnote, or 
369          * there is no open footnote in this paragraph, just return. */ 
370         if (cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
371       
372                 if (!par->next
373                     || par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
374                         minibuffer->Set(_("Nothing to do"));
375                         return;
376                 }
377    
378                 /* ok, move the cursor right before the footnote */ 
379  
380                 /* just a little faster than using CursorRight() */
381                 for (cursor.pos = 0; cursor.par->ParFromPos(cursor.pos)!= par; cursor.pos++);
382                 /* now the cursor is at the beginning of the physical par */
383                 SetCursor(cursor.par,
384                           cursor.pos +
385                           cursor.par->ParFromPos(cursor.pos)->text.size());
386         }
387         else  {
388                 /* we are in a footnote, so let us move at the beginning */ 
389                 /* this is just faster than using just CursorLeft() */ 
390        
391                 tmppar = cursor.par;
392                 while (tmppar->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
393                         /* just a little bit faster than movin the cursor */
394                         tmppar = tmppar->Previous();
395                 }
396                 SetCursor(tmppar, tmppar->Last());
397         }
398    
399         /* the cursor must be exactly before the footnote */ 
400         par = cursor.par->ParFromPos(cursor.pos);
401    
402         status = LyXText::NEED_MORE_REFRESH;
403         refresh_row = cursor.row;
404         refresh_y = cursor.y - cursor.row->baseline;
405    
406         tmppar = cursor.par;
407         endpar = par->NextAfterFootnote()->Next();
408         row = cursor.row;
409    
410         tmppar->CloseFootnote(cursor.pos);
411
412         while (tmppar != endpar) {
413                 RemoveRow(row->next);
414                 if (row->next)
415                         tmppar = row->next->par;
416                 else
417                         tmppar = 0;
418         }
419    
420         AppendParagraph(cursor.row);
421    
422         SetCursor(cursor.par, cursor.pos);
423         sel_cursor = cursor;
424    
425         /* just necessary */
426         if (cursor.row->next)
427                 SetHeightOfRow(cursor.row->next);
428 }
429
430
431 /* used in setlayout */
432 // Asger is not sure we want to do this...
433 void LyXText::MakeFontEntriesLayoutSpecific(LyXParagraph * par)
434 {
435         LyXFont layoutfont, tmpfont;
436    
437         LyXLayout const & layout = textclasslist.Style(parameters->textclass, par->GetLayout());
438
439         for (LyXParagraph::size_type pos = 0;
440              pos < par->Last(); ++pos) {
441                 if (pos < BeginningOfMainBody(par))
442                         layoutfont = layout.labelfont;
443                 else
444                         layoutfont = layout.font;
445       
446                 tmpfont = par->GetFontSettings(pos);
447                 tmpfont.reduce(layoutfont);
448                 par->SetFont(pos, tmpfont);
449         }
450 }
451
452
453 /* set layout over selection and make a total rebreak of those paragraphs */
454 void  LyXText::SetLayout(char layout)
455 {
456         LyXCursor tmpcursor;
457
458         /* if there is no selection just set the layout of the current paragraph  */
459         if (!selection) {
460                 sel_start_cursor = cursor;       /* dummy selection  */
461                 sel_end_cursor = cursor;
462         }
463
464         LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
465         LyXParagraph * undoendpar = endpar;
466
467         if (endpar && endpar->GetDepth()) {
468                 while (endpar && endpar->GetDepth()) {
469                         endpar = endpar->LastPhysicalPar()->Next();
470                         undoendpar = endpar;
471                 }
472         }
473         else if (endpar) {
474                 endpar = endpar->Next();               /* because of parindents etc.  */
475         }
476    
477         SetUndo(Undo::EDIT, 
478                 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous, 
479                 undoendpar);
480
481         tmpcursor = cursor;                    /* store the current cursor  */
482
483         /* ok we have a selection. This is always between sel_start_cursor
484          * and sel_end cursor */ 
485         cursor = sel_start_cursor;
486    
487         LyXLayout const & lyxlayout = textclasslist.Style(parameters->textclass, layout);
488    
489         while (cursor.par != sel_end_cursor.par) {
490                 if (cursor.par->footnoteflag ==
491                     sel_start_cursor.par->footnoteflag) {
492                         cursor.par->SetLayout(layout);
493                         MakeFontEntriesLayoutSpecific(cursor.par);
494                         LyXParagraph* fppar = cursor.par->FirstPhysicalPar();
495                         fppar->added_space_top = lyxlayout.fill_top ?
496                                 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
497                         fppar->added_space_bottom = lyxlayout.fill_bottom ? 
498                                 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE); 
499                         if (lyxlayout.margintype == MARGIN_MANUAL)
500                                 cursor.par->SetLabelWidthString(lyxlayout.labelstring());
501                         if (lyxlayout.labeltype != LABEL_BIBLIO
502                             && fppar->bibkey) {
503                                 delete fppar->bibkey;
504                                 fppar->bibkey = 0;
505                         }
506                 }
507                 cursor.par = cursor.par->Next();
508         }
509         if (cursor.par->footnoteflag ==
510             sel_start_cursor.par->footnoteflag) {
511                 cursor.par->SetLayout(layout);
512                 MakeFontEntriesLayoutSpecific(cursor.par);
513                 LyXParagraph* fppar = cursor.par->FirstPhysicalPar();
514                 fppar->added_space_top = lyxlayout.fill_top ?
515                         VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
516                 fppar->added_space_bottom = lyxlayout.fill_bottom ? 
517                         VSpace(VSpace::VFILL) : VSpace(VSpace::NONE); 
518                 if (lyxlayout.margintype == MARGIN_MANUAL)
519                         cursor.par->SetLabelWidthString(lyxlayout.labelstring());
520                 if (lyxlayout.labeltype != LABEL_BIBLIO
521                     && fppar->bibkey) {
522                         delete fppar->bibkey;
523                         fppar->bibkey = 0;
524                 }
525         }
526    
527         RedoParagraphs(sel_start_cursor, endpar);
528    
529         /* we have to reset the selection, because the
530          * geometry could have changed */ 
531         SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
532         sel_cursor = cursor;
533         SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
534         UpdateCounters(cursor.row);
535         ClearSelection();
536         SetSelection();
537         SetCursor(tmpcursor.par, tmpcursor.pos);
538 }
539
540
541 /* increment depth over selection and
542  * make a total rebreak of those paragraphs */
543 void  LyXText::IncDepth()
544 {
545         // If there is no selection, just use the current paragraph
546         if (!selection) {
547                 sel_start_cursor = cursor;       /* dummy selection */
548                 sel_end_cursor = cursor;
549         }
550
551         // We end at the next paragraph with depth 0
552         LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
553         LyXParagraph * undoendpar = endpar;
554
555         if (endpar && endpar->GetDepth()) {
556                 while (endpar && endpar->GetDepth()) {
557                         endpar = endpar->LastPhysicalPar()->Next();
558                         undoendpar = endpar;
559                 }
560         }
561         else if (endpar) {
562                 endpar = endpar->Next();               /* because of parindents etc.  */
563         }
564         
565         SetUndo(Undo::EDIT, 
566                 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous, 
567                 undoendpar);
568
569         LyXCursor tmpcursor = cursor;        /* store the current cursor  */
570
571         /* ok we have a selection. This is always between sel_start_cursor
572          * and sel_end cursor */ 
573         cursor = sel_start_cursor;
574    
575         bool anything_changed = false;
576    
577         while (true) {
578                 // NOTE: you can't change the depth of a bibliography entry
579                 if (cursor.par->footnoteflag ==
580                     sel_start_cursor.par->footnoteflag
581                     && textclasslist.Style(parameters->textclass,
582                                       cursor.par->GetLayout()
583                                      ).labeltype != LABEL_BIBLIO) {
584                         LyXParagraph * prev = cursor.par->FirstPhysicalPar()->Previous();
585                         if (prev 
586                             && (prev->GetDepth() - cursor.par->GetDepth() > 0
587                                 || (prev->GetDepth() == cursor.par->GetDepth()
588                                     && textclasslist.Style(parameters->textclass,
589                                                       prev->GetLayout()).isEnvironment()))) {
590                                 cursor.par->FirstPhysicalPar()->depth++;
591                                 anything_changed = true;
592                                 }
593                 }
594                 if (cursor.par == sel_end_cursor.par)
595                        break;
596                 cursor.par = cursor.par->Next();
597         }
598    
599         /* if nothing changed set all depth to 0 */ 
600         if (!anything_changed) {
601                 cursor = sel_start_cursor;
602                 while (cursor.par != sel_end_cursor.par) {
603                         cursor.par->FirstPhysicalPar()->depth = 0;
604                         cursor.par = cursor.par->Next();
605                 }
606                 if (cursor.par->footnoteflag == sel_start_cursor.par->footnoteflag)
607                         cursor.par->FirstPhysicalPar()->depth = 0;
608         }
609    
610         RedoParagraphs(sel_start_cursor, endpar);
611    
612         /* we have to reset the selection, because the
613          * geometry could have changed */ 
614         SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
615         sel_cursor = cursor;
616         SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
617         UpdateCounters(cursor.row);
618         ClearSelection();
619         SetSelection();
620         SetCursor(tmpcursor.par, tmpcursor.pos);
621 }
622
623
624 /* decrement depth over selection and
625  * make a total rebreak of those paragraphs */
626 void  LyXText::DecDepth()
627 {
628         /* if there is no selection just set the layout of the current paragraph  */
629         if (!selection) {
630                 sel_start_cursor = cursor;       /* dummy selection  */
631                 sel_end_cursor = cursor;
632         }
633    
634         LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
635         LyXParagraph * undoendpar = endpar;
636
637         if (endpar && endpar->GetDepth()) {
638                 while (endpar && endpar->GetDepth()) {
639                         endpar = endpar->LastPhysicalPar()->Next();
640                         undoendpar = endpar;
641                 }
642         }
643         else if (endpar) {
644                 endpar = endpar->Next();               /* because of parindents etc.  */
645         }
646    
647         SetUndo(Undo::EDIT, 
648                 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous, 
649                 undoendpar);
650
651         LyXCursor tmpcursor = cursor;                  /* store the current cursor  */
652
653         /* ok we have a selection. This is always between sel_start_cursor
654          * and sel_end cursor */ 
655         cursor = sel_start_cursor;
656
657         while (true) {
658                 if (cursor.par->footnoteflag ==
659                     sel_start_cursor.par->footnoteflag) {
660                         if (cursor.par->FirstPhysicalPar()->depth)
661                                 cursor.par->FirstPhysicalPar()->depth--;
662                 }
663                 if (cursor.par == sel_end_cursor.par)
664                         break;
665                 cursor.par = cursor.par->Next();
666         }
667
668         RedoParagraphs(sel_start_cursor, endpar);
669    
670         /* we have to reset the selection, because the
671          * geometry could have changed */ 
672         SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
673         sel_cursor = cursor;
674         SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
675         UpdateCounters(cursor.row);
676         ClearSelection();
677         SetSelection();
678         SetCursor(tmpcursor.par, tmpcursor.pos);
679 }
680
681
682 /* set font over selection and make a total rebreak of those paragraphs */
683 void  LyXText::SetFont(LyXFont font, bool toggleall)
684 {
685         /* if there is no selection just set the current_font */
686         if (!selection) {
687                 // Determine basis font
688                 LyXFont layoutfont;
689                 if (cursor.pos < BeginningOfMainBody(cursor.par))
690                         layoutfont = GetFont(cursor.par, -2);
691                 else
692                         layoutfont = GetFont(cursor.par, -1);
693                 // Update current font
694                 real_current_font.update(font, toggleall);
695
696                 // Reduce to implicit settings
697                 current_font = real_current_font;
698                 current_font.reduce(layoutfont);
699                 // And resolve it completely
700                 real_current_font.realize(layoutfont);
701                 return;
702         }
703
704         LyXCursor tmpcursor = cursor;                  /* store the current cursor  */
705    
706         /* ok we have a selection. This is always between sel_start_cursor
707          * and sel_end cursor */ 
708    
709         SetUndo(Undo::EDIT, 
710                 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous, 
711                 sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)->next); 
712         cursor = sel_start_cursor;
713         while (cursor.par != sel_end_cursor.par ||
714                (cursor.par->footnoteflag == sel_start_cursor.par->footnoteflag
715                 && cursor.pos < sel_end_cursor.pos)) 
716         {
717                 if (cursor.pos < cursor.par->Last()
718                     && cursor.par->footnoteflag
719                     == sel_start_cursor.par->footnoteflag) {   /* an open footnote
720                                                                 * should behave
721                                                                 * like a closed */
722                         LyXFont newfont = GetFont(cursor.par, cursor.pos);
723                         newfont.update(font, toggleall);
724                         SetCharFont(cursor.par, cursor.pos, newfont);
725                         cursor.pos++;
726                 } else {
727                         cursor.pos = 0;
728                         cursor.par = cursor.par->Next();
729                 }
730         }
731    
732         RedoParagraphs(sel_start_cursor, sel_end_cursor.par->Next());
733    
734         /* we have to reset the selection, because the
735          * geometry could have changed */ 
736         SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
737         sel_cursor = cursor;
738         SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
739         ClearSelection();
740         SetSelection();
741         SetCursor(tmpcursor.par, tmpcursor.pos);
742 }
743
744
745 void LyXText::RedoHeightOfParagraph(LyXCursor cursor)
746 {
747         Row * tmprow = cursor.row;
748         long y = cursor.y - tmprow->baseline;
749
750         SetHeightOfRow(tmprow);
751         LyXParagraph * first_phys_par = tmprow->par->FirstPhysicalPar();
752         /* find the first row of the paragraph */
753         if (first_phys_par != tmprow->par)
754                 while (tmprow->previous && tmprow->previous->par != first_phys_par)  {
755                         tmprow = tmprow->previous;
756                         y -= tmprow->height;
757                         SetHeightOfRow(tmprow);
758                 }
759         while (tmprow->previous && tmprow->previous->par == first_phys_par)  {
760                 tmprow = tmprow->previous;
761                 y -= tmprow->height;
762                 SetHeightOfRow(tmprow);
763         }
764    
765         /* we can set the refreshing parameters now */
766         status = LyXText::NEED_MORE_REFRESH;
767         refresh_y = y;
768         refresh_row = tmprow;
769         SetCursor(cursor.par, cursor.pos);
770 }
771
772
773 void LyXText::RedoDrawingOfParagraph(LyXCursor cursor)
774 {
775         Row * tmprow = cursor.row;
776    
777         long y = cursor.y - tmprow->baseline;
778         SetHeightOfRow(tmprow);
779         LyXParagraph * first_phys_par = tmprow->par->FirstPhysicalPar();
780         /* find the first row of the paragraph */
781         if (first_phys_par != tmprow->par)
782                 while (tmprow->previous && tmprow->previous->par != first_phys_par)  {
783                         tmprow = tmprow->previous;
784                         y -= tmprow->height;
785                 }
786         while (tmprow->previous && tmprow->previous->par == first_phys_par)  {
787                 tmprow = tmprow->previous;
788                 y -= tmprow->height;
789       
790         }
791    
792         /* we can set the refreshing parameters now */
793         if (status == LyXText::UNCHANGED || y < refresh_y) {
794                 refresh_y = y;
795                 refresh_row = tmprow;
796         }
797         status = LyXText::NEED_MORE_REFRESH;
798         SetCursor(cursor.par, cursor.pos);
799 }
800
801
802 /* deletes and inserts again all paragaphs between the cursor
803 * and the specified par 
804 * This function is needed after SetLayout and SetFont etc. */
805 void LyXText::RedoParagraphs(LyXCursor cursor, LyXParagraph * endpar)
806 {
807         Row * tmprow2;
808         LyXParagraph * tmppar, * first_phys_par;
809    
810         Row * tmprow = cursor.row;
811    
812         long y = cursor.y - tmprow->baseline;
813    
814         if (!tmprow->previous){
815                 first_phys_par = FirstParagraph();   // a trick/hack for UNDO
816         }
817         else {
818                 first_phys_par = tmprow->par->FirstPhysicalPar();
819                 /* find the first row of the paragraph */
820                 if (first_phys_par != tmprow->par)
821                         while (tmprow->previous && tmprow->previous->par != first_phys_par)  {
822                                 tmprow = tmprow->previous;
823                                 y -= tmprow->height;
824                         }
825                 while (tmprow->previous && tmprow->previous->par == first_phys_par)  {
826                         tmprow = tmprow->previous;
827                         y -= tmprow->height;
828                 }
829         }
830    
831         /* we can set the refreshing parameters now */
832         status = LyXText::NEED_MORE_REFRESH;
833         refresh_y = y;
834         refresh_row = tmprow->previous;        /* the real refresh row will
835                                                 * be deleted, so I store
836                                                 * the previous here */ 
837         /* remove it */
838         if (tmprow->next)
839                 tmppar = tmprow->next->par;
840         else
841                 tmppar = 0;
842         while (tmppar != endpar) {
843                 RemoveRow(tmprow->next);
844                 if (tmprow->next)
845                         tmppar = tmprow->next->par;
846                 else
847                         tmppar = 0;
848         }  
849    
850         /* remove the first one */
851         tmprow2 = tmprow;                      /* this is because tmprow->previous
852                                                 * can be 0 */
853         tmprow = tmprow->previous;
854         RemoveRow(tmprow2);
855    
856         tmppar = first_phys_par;
857
858         do {
859                 if (tmppar) {
860                         InsertParagraph(tmppar, tmprow);
861                         if (!tmprow)
862                                 tmprow = firstrow;
863                         while (tmprow->next && tmprow->next->par == tmppar)
864                                 tmprow = tmprow->next;
865                         tmppar = tmppar->Next();
866          
867                 }
868         }
869         while (tmppar != endpar);
870    
871         /* this is because of layout changes */ 
872         if (refresh_row) {
873                 refresh_y -= refresh_row->height;
874                 SetHeightOfRow(refresh_row);   
875         }
876         else {
877                 refresh_row = firstrow;
878                 refresh_y = 0;
879                 SetHeightOfRow(refresh_row);   
880         }
881    
882         if (tmprow && tmprow->next)
883                 SetHeightOfRow(tmprow->next);
884 }
885
886
887 int LyXText::FullRebreak()
888 {
889         if (need_break_row) {
890                 BreakAgain(need_break_row);
891                 need_break_row = 0;
892                 return 1;
893         }
894         return 0;
895 }
896
897
898 /* important for the screen */
899
900
901 /* the cursor set functions have a special mechanism. When they
902 * realize, that you left an empty paragraph, they will delete it.
903 * They also delet the corresponding row */
904    
905 /* need the selection cursor: */ 
906 void LyXText::SetSelection()
907 {
908         if (!selection) {
909                 last_sel_cursor = sel_cursor;
910                 sel_start_cursor = sel_cursor;
911                 sel_end_cursor = sel_cursor;
912         }
913    
914         selection = True;
915    
916         /* first the toggling area */ 
917         if (cursor.y < last_sel_cursor.y ||
918             (cursor.y == last_sel_cursor.y && cursor.x < last_sel_cursor.x)) {
919                 toggle_end_cursor = last_sel_cursor;
920                 toggle_cursor = cursor;
921         }
922         else {
923                 toggle_end_cursor = cursor;
924                 toggle_cursor = last_sel_cursor;
925         }
926    
927         last_sel_cursor = cursor;
928    
929         /* and now the whole selection */ 
930    
931         if (sel_cursor.y < cursor.y ||
932             (sel_cursor.y == cursor.y && sel_cursor.x < cursor.x)) {
933                 sel_end_cursor = cursor;
934                 sel_start_cursor = sel_cursor;
935         }
936         else {
937                 sel_end_cursor = sel_cursor; 
938                 sel_start_cursor = cursor;
939         }
940    
941         /* a selection with no contents is not a selection */ 
942         if (sel_start_cursor.x == sel_end_cursor.x && 
943             sel_start_cursor.y == sel_end_cursor.y)
944                 selection = false;
945 }
946
947
948 void LyXText::ClearSelection()
949 {
950         selection = false;
951         mark_set = false;
952 }
953
954
955 void  LyXText::CursorHome()
956 {
957         SetCursor(cursor.par, cursor.row->pos);
958 }
959
960
961 void  LyXText::CursorEnd()
962 {
963         if (!cursor.row->next || cursor.row->next->par != cursor.row->par)
964                 SetCursor(cursor.par, RowLast(cursor.row) + 1);
965         else {
966                 if (cursor.par->Last() && 
967                     (cursor.par->GetChar(RowLast(cursor.row)) == ' '
968                      || cursor.par->IsNewline(RowLast(cursor.row))))
969                         SetCursor(cursor.par, RowLast(cursor.row));
970                 else
971                         SetCursor(cursor.par, RowLast(cursor.row) + 1);
972         }
973         if (cursor.par->table) {
974                 int cell = NumberOfCell(cursor.par, cursor.pos);
975                 if (cursor.par->table->RowHasContRow(cell) &&
976                     cursor.par->table->CellHasContRow(cell)<0) {
977                         if (!cursor.row->next || cursor.row->next->par != cursor.row->par)
978                                 SetCursor(cursor.par, RowLast(cursor.row) + 1);
979                         else {
980                                 if (cursor.par->Last() && 
981                                     (cursor.par->GetChar(RowLast(cursor.row)) == ' '
982                                      || cursor.par->IsNewline(RowLast(cursor.row))))
983                                         SetCursor(cursor.par, RowLast(cursor.row));
984                                 else
985                                         SetCursor(cursor.par, RowLast(cursor.row) + 1);
986                         }
987                 }
988         }
989 }
990
991
992 void  LyXText::CursorTop()
993 {
994         while (cursor.par->Previous())
995                 cursor.par = cursor.par->Previous();
996         SetCursor(cursor.par, 0);
997 }
998
999
1000 void  LyXText::CursorBottom()
1001 {
1002         while (cursor.par->Next())
1003                 cursor.par = cursor.par->Next();
1004         SetCursor(cursor.par, cursor.par->Last());
1005 }
1006    
1007    
1008 /* returns a pointer to the row near the specified y-coordinate
1009 * (relative to the whole text). y is set to the real beginning
1010 * of this row */ 
1011 Row * LyXText::GetRowNearY(long & y)
1012 {
1013         Row * tmprow;
1014         long tmpy;
1015    
1016         if (currentrow){
1017                 tmprow = currentrow;
1018                 tmpy = currentrow_y;
1019         }
1020         else {
1021                 tmprow = firstrow;
1022                 tmpy = 0;
1023         }
1024
1025         if (tmpy<= y)
1026                 while (tmprow->next && tmpy + tmprow->height <= y) {
1027                         tmpy += tmprow->height;
1028                         tmprow = tmprow->next;
1029                 }
1030         else
1031                 while (tmprow->previous && tmpy > y) {
1032                         tmprow = tmprow->previous;
1033                         tmpy -= tmprow->height;
1034                 }
1035
1036         currentrow = tmprow;
1037         currentrow_y = tmpy;
1038
1039         y = tmpy;                              /* return the real y  */
1040         return tmprow;
1041 }
1042    
1043
1044 void LyXText::ToggleFree(LyXFont font, bool toggleall)
1045 {
1046         // If the mask is completely neutral, tell user
1047         if (font == LyXFont(LyXFont::ALL_IGNORE)){
1048                 // Could only happen with user style
1049                 minibuffer->Set(_("No font change defined. Use Character under"
1050                                   " the Layout menu to define font change."));
1051                 return;
1052         }
1053
1054         // Try implicit word selection
1055         LyXCursor resetCursor = cursor;
1056         int implicitSelection = SelectWordWhenUnderCursor();
1057
1058         // Set font
1059         SetFont(font, toggleall);
1060         //minibuffer->Set(_("Font style changed"));
1061
1062         /* Implicit selections are cleared afterwards and cursor is set to the
1063            original position. */
1064         if (implicitSelection) {
1065                 ClearSelection();
1066                 cursor = resetCursor;
1067                 SetCursor( cursor.par, cursor.pos );
1068                 sel_cursor = cursor;
1069         }
1070 }
1071
1072
1073 LyXParagraph::size_type LyXText::BeginningOfMainBody(LyXParagraph * par)
1074 {
1075         if (textclasslist.Style(parameters->textclass, par->GetLayout()).labeltype != LABEL_MANUAL)
1076                 return 0;
1077         else
1078                 return par->BeginningOfMainBody();
1079 }
1080
1081
1082 /* if there is a selection, reset every environment you can find
1083 * in the selection, otherwise just the environment you are in */ 
1084 void LyXText::MeltFootnoteEnvironment()
1085 {
1086         LyXParagraph * tmppar, * firsttmppar;
1087    
1088         ClearSelection();
1089    
1090         /* is is only allowed, if the cursor is IN an open footnote.
1091          * Otherwise it is too dangerous */ 
1092         if (cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1093                 return;
1094    
1095         SetUndo(Undo::FINISH, 
1096                 cursor.par->PreviousBeforeFootnote()->previous,
1097                 cursor.par->NextAfterFootnote()->next);
1098
1099         /* ok, move to the beginning of the footnote. */ 
1100         while (cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1101                 cursor.par = cursor.par->Previous();
1102    
1103         SetCursor(cursor.par, cursor.par->Last());
1104         /* this is just faster than using CursorLeft(); */ 
1105    
1106         firsttmppar = cursor.par->ParFromPos(cursor.pos);
1107         tmppar = firsttmppar;
1108         /* tmppar is now the paragraph right before the footnote */
1109
1110         char first_footnote_par_is_not_empty = tmppar->next->text.size();
1111    
1112         while (tmppar->next && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1113                 tmppar = tmppar->next;         /* I use next instead of Next(),
1114                                                 * because there cannot be any
1115                                                 * footnotes in a footnote
1116                                                 * environment */
1117                 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1118       
1119                 /* remember the captions and empty paragraphs */
1120                 if ((textclasslist.Style(parameters->textclass,
1121                                     tmppar->GetLayout()).labeltype == LABEL_SENSITIVE)
1122                     || !tmppar->Last())
1123                         tmppar->SetLayout(0);
1124         }
1125    
1126         /* now we will paste the ex-footnote, if the layouts allow it */
1127         /* first restore the layout of the paragraph right behind the footnote*/ 
1128         if (tmppar->next) 
1129                 tmppar->next->MakeSameLayout(cursor.par);
1130
1131         /* first the end */ 
1132         if ((!tmppar->GetLayout() && !tmppar->table)
1133             || (tmppar->Next() && (!tmppar->Next()->Last()
1134                                    || tmppar->Next()->HasSameLayout(tmppar)))) {
1135                 if (tmppar->Next()->Last() && tmppar->Next()->IsLineSeparator(0))
1136                         tmppar->Next()->Erase(0);
1137                 tmppar->PasteParagraph();
1138         }
1139
1140         tmppar = tmppar->Next();               /* make shure tmppar cannot be touched
1141                                                 * by the pasting of the beginning */
1142
1143         /* then the beginning */ 
1144         /* if there is no space between the text and the footnote, so we insert
1145          * a blank 
1146          * (only if the previous par and the footnotepar are not empty!) */
1147         if ((!firsttmppar->next->GetLayout() && !firsttmppar->next->table)
1148             || firsttmppar->HasSameLayout(firsttmppar->next)) {
1149                 if (firsttmppar->text.size()
1150                     && !firsttmppar->IsSeparator(firsttmppar->text.size() - 1)
1151                     && first_footnote_par_is_not_empty) {
1152                         firsttmppar->next->InsertChar(0, ' ');
1153                 }
1154                 firsttmppar->PasteParagraph();
1155         }
1156    
1157         /* now redo the paragaphs */
1158         RedoParagraphs(cursor, tmppar);
1159    
1160         SetCursor(cursor.par, cursor.pos);
1161    
1162         /* sometimes it can happen, that there is a counter change */ 
1163         Row * row = cursor.row;
1164         while (row->next && row->par != tmppar && row->next->par != tmppar)
1165                 row = row->next;
1166         UpdateCounters(row);
1167    
1168    
1169         ClearSelection();
1170 }
1171
1172
1173 /* the DTP switches for paragraphs. LyX will store them in the 
1174 * first physicla paragraph. When a paragraph is broken, the top settings 
1175 * rest, the bottom settings are given to the new one. So I can make shure, 
1176 * they do not duplicate themself and you cannnot make dirty things with 
1177 * them!  */ 
1178
1179 void LyXText::SetParagraph(bool line_top, bool line_bottom,
1180                            bool pagebreak_top, bool pagebreak_bottom,
1181                            VSpace space_top, VSpace space_bottom,
1182                            LyXAlignment align, 
1183                            string labelwidthstring,
1184                            bool noindent) 
1185 {
1186         LyXCursor tmpcursor = cursor;
1187         if (!selection) {
1188                 sel_start_cursor = cursor;
1189                 sel_end_cursor = cursor;
1190         }
1191
1192         // make sure that the depth behind the selection are restored, too
1193         LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1194         LyXParagraph * undoendpar = endpar;
1195
1196         if (endpar && endpar->GetDepth()) {
1197                 while (endpar && endpar->GetDepth()) {
1198                         endpar = endpar->LastPhysicalPar()->Next();
1199                         undoendpar = endpar;
1200                 }
1201         }
1202         else if (endpar) {
1203                 endpar = endpar->Next(); /* because of parindents etc.  */
1204         }
1205    
1206         SetUndo(Undo::EDIT, 
1207                 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous, 
1208                 undoendpar);
1209
1210         
1211         LyXParagraph * tmppar = sel_end_cursor.par;
1212         while (tmppar != sel_start_cursor.par->FirstPhysicalPar()->Previous()){
1213                 SetCursor(tmppar->FirstPhysicalPar(), 0);
1214                 status = LyXText::NEED_MORE_REFRESH;
1215                 refresh_row = cursor.row;
1216                 refresh_y = cursor.y - cursor.row->baseline;
1217                 if (cursor.par->footnoteflag ==
1218                     sel_start_cursor.par->footnoteflag) {
1219                         cursor.par->line_top = line_top;
1220                         cursor.par->line_bottom = line_bottom;
1221                         cursor.par->pagebreak_top = pagebreak_top;
1222                         cursor.par->pagebreak_bottom = pagebreak_bottom;
1223                         cursor.par->added_space_top = space_top;
1224                         cursor.par->added_space_bottom = space_bottom;
1225                                 /* does the layout allow the new alignment? */
1226                         if (align == LYX_ALIGN_LAYOUT)
1227                                 align = textclasslist
1228                                         .Style(parameters->textclass,
1229                                                cursor.par->GetLayout()).align;
1230                         if (align & textclasslist
1231                             .Style(parameters->textclass,
1232                                    cursor.par->GetLayout()).alignpossible) {
1233                                 if (align == textclasslist
1234                                     .Style(parameters->textclass,
1235                                            cursor.par->GetLayout()).align)
1236                                         cursor.par->align = LYX_ALIGN_LAYOUT;
1237                                 else
1238                                         cursor.par->align = align;
1239                         }
1240                         cursor.par->SetLabelWidthString(labelwidthstring);
1241                         cursor.par->noindent = noindent;
1242                 }
1243                 
1244                 tmppar = cursor.par->FirstPhysicalPar()->Previous();
1245         }
1246         
1247         RedoParagraphs(sel_start_cursor, endpar);
1248         
1249         ClearSelection();
1250         SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
1251         sel_cursor = cursor;
1252         SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
1253         SetSelection();
1254         SetCursor(tmpcursor.par, tmpcursor.pos);
1255 }
1256
1257
1258 void LyXText::SetParagraphExtraOpt(int type,
1259                                    char const * width,
1260                                    char const * widthp,
1261                                    int alignment, bool hfill,
1262                                    bool start_minipage)
1263 {
1264         LyXCursor tmpcursor = cursor;
1265         LyXParagraph * tmppar;
1266         if (!selection) {
1267                 sel_start_cursor = cursor;
1268                 sel_end_cursor = cursor;
1269         }
1270
1271         // make sure that the depth behind the selection are restored, too
1272         LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1273         LyXParagraph * undoendpar = endpar;
1274
1275         if (endpar && endpar->GetDepth()) {
1276                 while (endpar && endpar->GetDepth()) {
1277                         endpar = endpar->LastPhysicalPar()->Next();
1278                         undoendpar = endpar;
1279                 }
1280         }
1281         else if (endpar) {
1282                 endpar = endpar->Next(); /* because of parindents etc.  */
1283         }
1284    
1285         SetUndo(Undo::EDIT, 
1286                 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous, 
1287                 undoendpar);
1288         
1289         tmppar = sel_end_cursor.par;
1290         while(tmppar != sel_start_cursor.par->FirstPhysicalPar()->Previous()) {
1291                 SetCursor(tmppar->FirstPhysicalPar(), 0);
1292                 status = LyXText::NEED_MORE_REFRESH;
1293                 refresh_row = cursor.row;
1294                 refresh_y = cursor.y - cursor.row->baseline;
1295                 if (cursor.par->footnoteflag ==
1296                     sel_start_cursor.par->footnoteflag) {
1297                         if (type == LyXParagraph::PEXTRA_NONE) {
1298                                 if (cursor.par->pextra_type != LyXParagraph::PEXTRA_NONE) {
1299                                         cursor.par->UnsetPExtraType();
1300                                         cursor.par->pextra_type = LyXParagraph::PEXTRA_NONE;
1301                                 }
1302                         } else {
1303                                 cursor.par->SetPExtraType(type, width, widthp);
1304                                 cursor.par->pextra_hfill = hfill;
1305                                 cursor.par->pextra_start_minipage = start_minipage;
1306                                 cursor.par->pextra_alignment = alignment;
1307                         }
1308                 }
1309                 tmppar = cursor.par->FirstPhysicalPar()->Previous();
1310         }
1311         RedoParagraphs(sel_start_cursor, endpar);
1312         ClearSelection();
1313         SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
1314         sel_cursor = cursor;
1315         SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
1316         SetSelection();
1317         SetCursor(tmpcursor.par, tmpcursor.pos);
1318 }
1319
1320
1321 static char const * alphaCounter(int n){
1322   static char result[2];
1323   result[1] = 0;
1324   if (n == 0)
1325     return "";
1326   else {
1327     result[0] = 64 + n;
1328     if (n > 26)
1329       return "??";
1330   }
1331   return result;
1332 }
1333
1334
1335 /* set the counter of a paragraph. This includes the labels */ 
1336 void LyXText::SetCounter(LyXParagraph * par)
1337 {
1338         int i;
1339    
1340         /* this is only relevant for the beginning of paragraph */ 
1341         par = par->FirstPhysicalPar();
1342
1343         LyXLayout const & layout = textclasslist.Style(parameters->textclass, 
1344                                            par->GetLayout());
1345
1346         LyXTextClass const & textclass = textclasslist.TextClass(parameters->textclass);
1347
1348         /* copy the prev-counters to this one, unless this is the start of a 
1349            footnote or of a bibliography or the very first paragraph */
1350         if (par->Previous()
1351             && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE 
1352                     && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1353                     && par->footnotekind == LyXParagraph::FOOTNOTE)
1354             && !(textclasslist.Style(parameters->textclass,
1355                                 par->Previous()->GetLayout()
1356                                 ).labeltype != LABEL_BIBLIO
1357                  && layout.labeltype == LABEL_BIBLIO)) {
1358                 for (i = 0; i<10; i++) {
1359                         par->setCounter(i, par->Previous()->GetFirstCounter(i));
1360                 }
1361                 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1362                 if (!par->appendix && par->start_of_appendix){
1363                   par->appendix = true;
1364                   for (i = 0; i<10; i++) {
1365                     par->setCounter(i, 0);
1366                   }  
1367                 }
1368                 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1369                 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1370         }
1371         else {
1372                 for (i = 0; i<10; i++) {
1373                         par->setCounter(i, 0);
1374                 }  
1375                 par->appendix = par->start_of_appendix;
1376                 par->enumdepth = 0;
1377                 par->itemdepth = 0;
1378         }
1379
1380         // if this is an open marginnote and this is the first
1381         // entry in the marginnote and the enclosing
1382         // environment is an enum/item then correct for the
1383         // LaTeX behaviour (ARRae)
1384         if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1385            && par->footnotekind == LyXParagraph::MARGIN
1386            && par->Previous()
1387            && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1388            && (par->PreviousBeforeFootnote()
1389                && textclasslist.Style(parameters->textclass,
1390                                  par->PreviousBeforeFootnote()->GetLayout()
1391                                  ).labeltype >= LABEL_COUNTER_ENUMI)) {
1392                 // Any itemize or enumerate environment in a marginnote
1393                 // that is embedded in an itemize or enumerate
1394                 // paragraph is seen by LaTeX as being at a deeper
1395                 // level within that enclosing itemization/enumeration
1396                 // even if there is a "standard" layout at the start of
1397                 // the marginnote.
1398                 par->enumdepth++;
1399                 par->itemdepth++;
1400         }
1401
1402         /* Maybe we have to increment the enumeration depth.
1403          * BUT, enumeration in a footnote is considered in isolation from its
1404          *      surrounding paragraph so don't increment if this is the
1405          *      first line of the footnote
1406          * AND, bibliographies can't have their depth changed ie. they
1407          *      are always of depth 0
1408          */
1409         if (par->Previous()
1410             && par->Previous()->GetDepth() < par->GetDepth()
1411             && textclasslist.Style(parameters->textclass,
1412                               par->Previous()->GetLayout()
1413                              ).labeltype == LABEL_COUNTER_ENUMI
1414             && par->enumdepth < 3
1415             && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE 
1416                     && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1417                     && par->footnotekind == LyXParagraph::FOOTNOTE)
1418             && layout.labeltype != LABEL_BIBLIO) {
1419                 par->enumdepth++;
1420         }
1421
1422         /* Maybe we have to decrement the enumeration depth, see note above */
1423         if (par->Previous()
1424             && par->Previous()->GetDepth() > par->GetDepth()
1425             && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1426                     && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1427                     && par->footnotekind == LyXParagraph::FOOTNOTE)
1428             && layout.labeltype != LABEL_BIBLIO) {
1429                 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1430                 par->setCounter(6 + par->enumdepth,
1431                         par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1432                 /* reset the counters.
1433                  * A depth change is like a breaking layout
1434                  */
1435                 for (i = 6 + par->enumdepth + 1; i<10;i++)
1436                         par->setCounter(i, 0);
1437         }
1438    
1439         if (!par->labelstring.empty()) {
1440                 par->labelstring.clear();
1441         }
1442    
1443         if (layout.margintype == MARGIN_MANUAL) {
1444                 if (par->labelwidthstring.empty()) {
1445                         par->SetLabelWidthString(layout.labelstring());
1446                 }
1447         }
1448         else {
1449                 par->SetLabelWidthString(string());
1450         }
1451    
1452         /* is it a layout that has an automatic label ? */ 
1453         if (layout.labeltype >=  LABEL_FIRST_COUNTER) {
1454       
1455                 i = layout.labeltype - LABEL_FIRST_COUNTER;
1456                 if (i >= 0 && i<= parameters->secnumdepth) {
1457                         par->incCounter(i);     // increment the counter  
1458          
1459                         char * s = new char[50];
1460
1461                         // Is there a label? Useful for Chapter layout
1462                         if (!par->appendix){
1463                                 if (!layout.labelstring().empty())
1464                                         par->labelstring = layout.labelstring();
1465                                 else
1466                                         par->labelstring.clear();
1467                         }
1468                         else {
1469                                 if (!layout.labelstring_appendix().empty())
1470                                         par->labelstring = layout.labelstring_appendix();
1471                                 else
1472                                         par->labelstring.clear();
1473                         }
1474  
1475                         if (!par->appendix){
1476                                 switch (2 * LABEL_FIRST_COUNTER -
1477                                         textclass.maxcounter() + i) {
1478                                 case LABEL_COUNTER_CHAPTER:
1479                                         sprintf(s, "%d",
1480                                                 par->getCounter(i));
1481                                         break;
1482                                 case LABEL_COUNTER_SECTION:
1483                                         sprintf(s, "%d.%d",
1484                                                 par->getCounter(i - 1),
1485                                                 par->getCounter(i));
1486                                         break;
1487                                 case LABEL_COUNTER_SUBSECTION:
1488                                         sprintf(s, "%d.%d.%d",
1489                                                 par->getCounter(i-2),
1490                                                 par->getCounter(i-1),
1491                                                 par->getCounter(i));
1492                                         break;
1493                                 case LABEL_COUNTER_SUBSUBSECTION:
1494                                         sprintf(s, "%d.%d.%d.%d",
1495                                                 par->getCounter(i-3),
1496                                                 par->getCounter(i-2),
1497                                                 par->getCounter(i-1),
1498                                                 par->getCounter(i));
1499                                         break;
1500                                 case LABEL_COUNTER_PARAGRAPH:
1501                                         sprintf(s, "%d.%d.%d.%d.%d",
1502                                                 par->getCounter(i-4),
1503                                                 par->getCounter(i-3),
1504                                                 par->getCounter(i-2),
1505                                                 par->getCounter(i-1),
1506                                                 par->getCounter(i));
1507                                         break;
1508                                 case LABEL_COUNTER_SUBPARAGRAPH:
1509                                         sprintf(s, "%d.%d.%d.%d.%d.%d",
1510                                                 par->getCounter(i-5),
1511                                                 par->getCounter(i-4),
1512                                                 par->getCounter(i-3),
1513                                                 par->getCounter(i-2),
1514                                                 par->getCounter(i-1),
1515                                                 par->getCounter(i));
1516                                         break;
1517                                 default:
1518                                         sprintf(s, "%d.", par->getCounter(i));
1519                                         break;
1520                                 }
1521                         }
1522                         else {
1523                                 switch (2 * LABEL_FIRST_COUNTER - textclass.maxcounter() + i) {
1524                                 case LABEL_COUNTER_CHAPTER:
1525                                         sprintf(s, "%s",
1526                                                 alphaCounter(par->getCounter(i)));
1527                                         break;
1528                                 case LABEL_COUNTER_SECTION:
1529                                         sprintf(s, "%s.%d",
1530                                                 alphaCounter(par->getCounter(i - 1)),
1531                                                 par->getCounter(i));
1532                                         break;
1533                                 case LABEL_COUNTER_SUBSECTION:
1534                                         sprintf(s, "%s.%d.%d",
1535                                                 alphaCounter(par->getCounter(i-2)),
1536                                                 par->getCounter(i-1),
1537                                                 par->getCounter(i));
1538                                         break;
1539                                 case LABEL_COUNTER_SUBSUBSECTION:
1540                                         sprintf(s, "%s.%d.%d.%d",
1541                                                 alphaCounter(par->getCounter(i-3)),
1542                                                 par->getCounter(i-2),
1543                                                 par->getCounter(i-1),
1544                                                 par->getCounter(i));
1545                                         break;
1546                                 case LABEL_COUNTER_PARAGRAPH:
1547                                         sprintf(s, "%s.%d.%d.%d.%d",
1548                                                 alphaCounter(par->getCounter(i-4)),
1549                                                 par->getCounter(i-3),
1550                                                 par->getCounter(i-2),
1551                                                 par->getCounter(i-1),
1552                                                 par->getCounter(i));
1553                                         break;
1554                                 case LABEL_COUNTER_SUBPARAGRAPH:
1555                                         sprintf(s, "%s.%d.%d.%d.%d.%d",
1556                                                 alphaCounter(par->getCounter(i-5)),
1557                                                 par->getCounter(i-4),
1558                                                 par->getCounter(i-3),
1559                                                 par->getCounter(i-2),
1560                                                 par->getCounter(i-1),
1561                                                 par->getCounter(i));
1562                                         break;
1563                                 default:
1564                                         sprintf(s, "%c.", par->getCounter(i));
1565                                         break;
1566                                 }
1567                         }
1568          
1569                         par->labelstring += s;
1570                         delete[] s;
1571          
1572                         for (i++; i<10; i++) {
1573                                 /* reset the following counters  */
1574                                 par->setCounter(i, 0);
1575                         }
1576                 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1577                         for (i++; i<10; i++) {
1578                                 /* reset the following counters  */
1579                                 par->setCounter(i, 0);
1580                         }
1581                 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1582                         par->incCounter(i + par->enumdepth);
1583                         char * s = new char[25];
1584                         int number = par->getCounter(i + par->enumdepth);
1585                         switch (par->enumdepth) {
1586                         case 1:
1587                                 sprintf(s, "(%c)", (number % 27) + 'a' - 1);
1588                                 break;
1589                         case 2:
1590                                 switch (number) {
1591                                 case 1: sprintf(s, "i."); break;
1592                                 case 2: sprintf(s, "ii."); break;
1593                                 case 3: sprintf(s, "iii."); break;
1594                                 case 4: sprintf(s, "iv."); break;
1595                                 case 5: sprintf(s, "v."); break;
1596                                 case 6: sprintf(s, "vi."); break;
1597                                 case 7: sprintf(s, "vii."); break;
1598                                 case 8: sprintf(s, "viii."); break;
1599                                 case 9: sprintf(s, "ix."); break;
1600                                 case 10: sprintf(s, "x."); break;
1601                                 case 11: sprintf(s, "xi."); break;
1602                                 case 12: sprintf(s, "xii."); break;
1603                                 case 13: sprintf(s, "xiii."); break;
1604                                 default:
1605                                         sprintf(s, "\\roman{%d}.", number);
1606                                         break;
1607                                 }
1608                                 break;
1609                         case 3:
1610                                 sprintf(s, "%c.", (number % 27) + 'A' - 1);
1611                                 break;
1612                         default:
1613                                 sprintf(s, "%d.", number);
1614                                 break;
1615                         }
1616                         par->labelstring = s;
1617                         delete[] s;
1618
1619                         for (i += par->enumdepth + 1;i<10;i++)
1620                                 par->setCounter(i, 0);  /* reset the following counters  */
1621          
1622                 } 
1623         } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1624             i = LABEL_COUNTER_ENUMI - LABEL_FIRST_COUNTER + par->enumdepth;
1625             par->incCounter(i);
1626             int number = par->getCounter(i);
1627             if (!par->bibkey)
1628               par->bibkey = new InsetBibKey();
1629             par->bibkey->setCounter(number);
1630             par->labelstring = layout.labelstring();
1631             
1632             // In biblio should't be following counters but...
1633         }                                               
1634         else  {
1635                 string s = layout.labelstring();
1636       
1637                 /* the caption hack: */
1638       
1639                 if (layout.labeltype == LABEL_SENSITIVE) {
1640                         if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1641                             && (par->footnotekind == LyXParagraph::FIG
1642                             || par->footnotekind == LyXParagraph::WIDE_FIG))
1643                                 s = "Figure:";
1644                         else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1645                                  && (par->footnotekind == LyXParagraph::TAB
1646                                  || par->footnotekind == LyXParagraph::WIDE_TAB))
1647                                 s = "Table:";
1648                         else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1649                                  && par->footnotekind == LyXParagraph::ALGORITHM)
1650                                 s = "Algorithm:";
1651                         else {
1652                                 /* par->SetLayout(0); 
1653                                    s = layout->labelstring;  */
1654                                 s = "Senseless: "; 
1655            
1656                         }
1657                 }
1658                 par->labelstring = s;
1659       
1660                 /* reset the enumeration counter. They are always resetted
1661                  * when there is any other layout between */ 
1662                 for (i = 6 + par->enumdepth; i<10;i++)
1663                         par->setCounter(i, 0);
1664         }
1665 }
1666
1667
1668 /* Updates all counters BEHIND the row. Changed paragraphs
1669 * with a dynamic left margin will be rebroken. */ 
1670 void LyXText::UpdateCounters(Row * row)
1671 {
1672         LyXParagraph * par;
1673         if (!row) {
1674                 row = firstrow;
1675                 par = row->par;
1676         }
1677         else {
1678                 if (row->par->next && row->par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
1679                         par = row->par->LastPhysicalPar()->Next();
1680                 } else {
1681                         par = row->par->next;
1682                 }
1683         }
1684
1685         while (par) {
1686                 while (row->par != par)
1687                         row = row->next;
1688       
1689                 SetCounter(par);
1690       
1691                 /* now  check for the headline layouts. remember that they
1692                  * have a dynamic left margin */ 
1693                 if (!par->IsDummy()
1694                     && ( textclasslist.Style(parameters->textclass, par->layout).margintype == MARGIN_DYNAMIC
1695                          || textclasslist.Style(parameters->textclass, par->layout).labeltype == LABEL_SENSITIVE)
1696                         ){
1697          
1698                         /* Rebreak the paragraph */ 
1699                         RemoveParagraph(row);
1700                         AppendParagraph(row);
1701        
1702                         /* think about the damned open footnotes! */ 
1703                         while (par->Next() &&
1704                                (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1705                                 || par->Next()->IsDummy())){
1706                                 par = par->Next();
1707                                 if (par->IsDummy()) {
1708                                         while (row->par != par)
1709                                                 row = row->next;
1710                                         RemoveParagraph(row);
1711                                         AppendParagraph(row);
1712                                 }
1713                         }
1714                 }
1715      
1716                 par = par->LastPhysicalPar()->Next();
1717      
1718         }
1719 }
1720
1721
1722 /* insets an inset. */ 
1723 void LyXText::InsertInset(Inset *inset)
1724 {
1725         SetUndo(Undo::INSERT, 
1726                 cursor.par->ParFromPos(cursor.pos)->previous, 
1727                 cursor.par->ParFromPos(cursor.pos)->next);
1728         cursor.par->InsertChar(cursor.pos, LyXParagraph::META_INSET);
1729         cursor.par->InsertInset(cursor.pos, inset);
1730         InsertChar(LyXParagraph::META_INSET);  /* just to rebreak and refresh correctly.
1731                                       * The character will not be inserted a
1732                                       * second time */
1733 }
1734
1735
1736 /* this is for the simple cut and paste mechanism */ 
1737 static LyXParagraph * simple_cut_buffer = 0;
1738 static char simple_cut_buffer_textclass = 0;
1739
1740 void DeleteSimpleCutBuffer()
1741 {
1742         if (!simple_cut_buffer)
1743                 return;
1744         LyXParagraph *tmppar;
1745
1746         while (simple_cut_buffer) {
1747                 tmppar =  simple_cut_buffer;
1748                 simple_cut_buffer = simple_cut_buffer->next;
1749                 delete tmppar;
1750         }
1751         simple_cut_buffer = 0;
1752 }
1753
1754
1755 void LyXText::copyEnvironmentType()
1756 {
1757         copylayouttype = cursor.par->GetLayout();
1758 }
1759
1760
1761 void LyXText::pasteEnvironmentType()
1762 {
1763         SetLayout(copylayouttype);
1764 }
1765
1766
1767 void LyXText::CutSelection(bool doclear)
1768 {
1769         /* This doesn't make sense, if there is no selection */ 
1770         if (!selection) {
1771                 return;
1772         }
1773    
1774         /* OK, we have a selection. This is always between sel_start_cursor
1775          * and sel_end cursor */
1776         LyXParagraph * tmppar;
1777    
1778         /* Check whether there are half footnotes in the selection */
1779         if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1780             || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE){
1781                 tmppar = sel_start_cursor.par;
1782                 while (tmppar != sel_end_cursor.par){
1783                         if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag){
1784                                 WriteAlert(_("Impossible operation"), _("Don't know what to do with half floats."), _("sorry."));
1785                                 return;
1786                         }
1787                         tmppar = tmppar->Next();
1788                 }
1789         }
1790
1791         /* table stuff -- begin*/
1792         if (sel_start_cursor.par->table || sel_end_cursor.par->table){
1793                 if ( sel_start_cursor.par != sel_end_cursor.par){
1794                         WriteAlert(_("Impossible operation"), _("Don't know what to do with half tables."), _("sorry."));
1795                         return;
1796                 }
1797                 sel_start_cursor.par->table->Reinit();
1798         }
1799         /* table stuff -- end*/
1800
1801         // make sure that the depth behind the selection are restored, too
1802         LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1803         LyXParagraph * undoendpar = endpar;
1804
1805         if (endpar && endpar->GetDepth()) {
1806                 while (endpar && endpar->GetDepth()) {
1807                         endpar = endpar->LastPhysicalPar()->Next();
1808                         undoendpar = endpar;
1809                 }
1810         }
1811         else if (endpar) {
1812                 endpar = endpar->Next();               /* because of parindents etc.  */
1813         }
1814    
1815         SetUndo(Undo::DELETE, 
1816                 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous, 
1817                 undoendpar);
1818    
1819         /* delete the simple_cut_buffer */ 
1820         DeleteSimpleCutBuffer();
1821    
1822         /* set the textclass */
1823         simple_cut_buffer_textclass = parameters->textclass;
1824
1825 #ifdef WITH_WARNINGS
1826 #warning Asger: Make cut more intelligent here.
1827 #endif
1828 /* 
1829 White paper for "intelligent" cutting:
1830
1831 Example: "This is our text."
1832 Using " our " as selection, cutting will give "This istext.".
1833 Using "our" as selection, cutting will give "This is text.".
1834 Using " our" as selection, cutting will give "This is text.".
1835 Using "our " as selection, cutting will give "This is text.".
1836
1837 All those four selections will (however) paste identically:
1838 Pasting with the cursor right after the "is" will give the
1839 original text with all four selections.
1840
1841 The rationale is to be intelligent such that words are copied,
1842 cut and pasted in a functional manner.
1843
1844 This is not implemented yet.
1845 */
1846
1847         bool space_wrapped =
1848                 sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos);
1849         if (sel_end_cursor.pos > 0
1850             && sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos - 1)) {
1851                 sel_end_cursor.pos--;  /* please break before a space at
1852                                         * the end */
1853                 space_wrapped = true;
1854         }
1855
1856         // cut behind a space if there is one
1857         while (sel_start_cursor.par->Last() > sel_start_cursor.pos
1858                && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
1859                && (sel_start_cursor.par != sel_end_cursor.par
1860                    || sel_start_cursor.pos < sel_end_cursor.pos))
1861                 sel_start_cursor.pos++; 
1862    
1863         /* there are two cases: cut only within one paragraph or
1864          * more than one paragraph */
1865    
1866         if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos) 
1867             == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
1868                 /* only within one paragraph */
1869                 simple_cut_buffer = new LyXParagraph;
1870                 LyXParagraph::size_type i =
1871                         sel_start_cursor.pos;
1872                 for (; i< sel_end_cursor.pos; i++){
1873                         /* table stuff -- begin*/
1874                         if (sel_start_cursor.par->table
1875                             && sel_start_cursor.par->IsNewline(sel_start_cursor.pos)){
1876                                 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
1877                                 sel_start_cursor.pos++;
1878                         } else {
1879                                 /* table stuff -- end*/
1880                                 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
1881                                 sel_start_cursor.par->Erase(sel_start_cursor.pos);
1882                         }
1883                         simple_cut_buffer->InsertFromMinibuffer(simple_cut_buffer->Last());
1884                 }
1885                 /* check for double spaces */
1886                 if (sel_start_cursor.pos &&
1887                     sel_start_cursor.par->Last()>sel_start_cursor.pos &&
1888                     sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1) &&
1889                     sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)){
1890                         sel_start_cursor.par->Erase(sel_start_cursor.pos);
1891                 }
1892                 if (space_wrapped)
1893                         simple_cut_buffer->InsertChar(i - sel_start_cursor.pos, ' ');
1894                 endpar = sel_end_cursor.par->Next();
1895         }
1896         else {
1897                 /* cut more than one paragraph */ 
1898    
1899                 sel_end_cursor.par->BreakParagraphConservative(sel_end_cursor.pos);
1900                 /* insert a space at the end if there was one */
1901                 if (space_wrapped)
1902                         sel_end_cursor.par->InsertChar(sel_end_cursor.par->Last(), ' ');
1903    
1904                 sel_end_cursor.par = sel_end_cursor.par->Next();
1905                 sel_end_cursor.pos = 0;
1906    
1907                 cursor = sel_end_cursor;
1908    
1909                 /* please break behind a space, if there is one. The space should
1910                  * be copied too */ 
1911                 if (sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos))
1912                         sel_start_cursor.pos++;
1913    
1914                 sel_start_cursor.par->BreakParagraphConservative(sel_start_cursor.pos);
1915                 if (!sel_start_cursor.pos
1916                     || sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1)
1917                     || sel_start_cursor.par->IsNewline(sel_start_cursor.pos - 1)) {
1918                         sel_start_cursor.par->Next()->InsertChar(0, ' ');
1919                 }
1920    
1921                 /* store the endparagraph for redoing later */
1922                 endpar = sel_end_cursor.par->Next();   /* needed because
1923                                                         * the sel_end_
1924                                                         * cursor.par
1925                                                         * will be pasted!*/
1926    
1927                 /*store the selection */ 
1928                 simple_cut_buffer = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->next;
1929                 simple_cut_buffer->previous = 0;
1930                 sel_end_cursor.par->previous->next = 0;
1931
1932                 /* cut the selection */ 
1933                 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->next 
1934                         = sel_end_cursor.par;
1935    
1936                 sel_end_cursor.par->previous 
1937                         = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
1938
1939                 /* care about footnotes */
1940                 if (simple_cut_buffer->footnoteflag) {
1941                         LyXParagraph *tmppar = simple_cut_buffer;
1942                         while (tmppar){
1943                                 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1944                                 tmppar = tmppar->next;
1945                         }
1946                 }
1947
1948                 /* the cut selection should begin with standard layout */
1949                 simple_cut_buffer->Clear(); 
1950    
1951                 /* paste the paragraphs again, if possible  */
1952                 if (doclear)
1953                         sel_start_cursor.par->Next()->ClearParagraph();
1954                 if (sel_start_cursor.par->FirstPhysicalPar()->HasSameLayout(sel_start_cursor.par->Next())
1955                     || 
1956                     !sel_start_cursor.par->Next()->Last())
1957                         sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->PasteParagraph();
1958
1959    
1960                 /* maybe a forgotten blank */
1961                 if (sel_start_cursor.pos 
1962                     && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
1963                     && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1)) {
1964                         sel_start_cursor.par->Erase(sel_start_cursor.pos);
1965                 }
1966         }   
1967
1968
1969         /* sometimes necessary */
1970         if (doclear)
1971                 sel_start_cursor.par->ClearParagraph();
1972
1973         RedoParagraphs(sel_start_cursor, endpar);
1974    
1975         ClearSelection();
1976         cursor = sel_start_cursor;
1977         SetCursor(cursor.par, cursor.pos);
1978         sel_cursor = cursor;
1979         UpdateCounters(cursor.row);
1980 }
1981
1982     
1983 void LyXText::CopySelection()
1984 {
1985         LyXParagraph::size_type i = 0;
1986         /* this doesnt make sense, if there is no selection */ 
1987         if (!selection) {
1988                 return;
1989         }
1990
1991         /* ok we have a selection. This is always between sel_start_cursor
1992          * and sel_end cursor */
1993         LyXParagraph * tmppar;
1994    
1995         /* check wether there are half footnotes in the selection */
1996         if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1997             || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE){
1998                 tmppar = sel_start_cursor.par;
1999                 while (tmppar != sel_end_cursor.par){
2000                         if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag){
2001                                 WriteAlert(_("Impossible operation"), _("Don't know what to do with half floats."), _("sorry."));
2002                                 return;
2003                         }
2004                         tmppar = tmppar->Next();
2005                 }
2006         }
2007
2008         /* table stuff -- begin*/
2009         if (sel_start_cursor.par->table || sel_end_cursor.par->table){
2010                 if ( sel_start_cursor.par != sel_end_cursor.par){
2011                         WriteAlert(_("Impossible operation"), _("Don't know what to do with half tables."), _("sorry."));
2012                         return;
2013                 }
2014         }
2015         /* table stuff -- end*/
2016    
2017         /* delete the simple_cut_buffer */ 
2018         DeleteSimpleCutBuffer();
2019
2020         /* set the textclass */
2021         simple_cut_buffer_textclass = parameters->textclass;
2022
2023         // copy behind a space if there is one
2024         while (sel_start_cursor.par->Last() > sel_start_cursor.pos
2025                && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
2026                && (sel_start_cursor.par != sel_end_cursor.par
2027                    || sel_start_cursor.pos < sel_end_cursor.pos))
2028                 sel_start_cursor.pos++; 
2029
2030         /* there are two cases: copy only within one paragraph or more than one paragraph */
2031         if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos) 
2032             == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2033                 /* only within one paragraph */
2034                 simple_cut_buffer = new LyXParagraph;
2035                 for (i = sel_start_cursor.pos; i < sel_end_cursor.pos; ++i){
2036                         sel_start_cursor.par->CopyIntoMinibuffer(i);
2037                         simple_cut_buffer->InsertFromMinibuffer(i - sel_start_cursor.pos);
2038                 }
2039         }
2040         else {
2041                 /* copy more than one paragraph */ 
2042                 /* clone the paragraphs within the selection*/
2043                 tmppar = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
2044                 simple_cut_buffer = tmppar->Clone();
2045                 LyXParagraph *tmppar2 = simple_cut_buffer;
2046      
2047                 while (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)
2048                        && tmppar->next) {
2049                         tmppar = tmppar->next;
2050                         tmppar2->next = tmppar->Clone();
2051                         tmppar2->next->previous = tmppar2;
2052                         tmppar2 = tmppar2->next;
2053                 }
2054                 tmppar2->next = 0;
2055
2056                 /* care about footnotes */
2057                 if (simple_cut_buffer->footnoteflag) {
2058                         tmppar = simple_cut_buffer;
2059                         while (tmppar){
2060                                 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
2061                                 tmppar = tmppar->next;
2062                         }
2063                 }
2064      
2065                 /* the simple_cut_buffer paragraph is too big */
2066                 LyXParagraph::size_type tmpi2 =
2067                         sel_start_cursor.par->PositionInParFromPos(sel_start_cursor.pos);
2068                 for (;tmpi2;tmpi2--)
2069                         simple_cut_buffer->Erase(0);
2070
2071                 /* now tmppar 2 is too big, delete all after sel_end_cursor.pos */
2072      
2073                 tmpi2 = sel_end_cursor.par->PositionInParFromPos(sel_end_cursor.pos);
2074                 while (tmppar2->size() > tmpi2) {
2075                         tmppar2->Erase(tmppar2->text.size() - 1);
2076                 }
2077         }
2078 }
2079           
2080
2081 void LyXText::PasteSelection()
2082 {
2083         /* this does not make sense, if there is nothing to paste */ 
2084         if (!simple_cut_buffer)
2085                 return;
2086
2087         LyXParagraph * tmppar;
2088         LyXParagraph * endpar;
2089
2090         LyXCursor tmpcursor;
2091
2092         /* be carefull with footnotes in footnotes */ 
2093         if (cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2094       
2095                 /* check whether the cut_buffer includes a footnote */
2096                 tmppar = simple_cut_buffer;
2097                 while (tmppar && tmppar->footnoteflag == LyXParagraph::NO_FOOTNOTE)
2098                         tmppar = tmppar->next;
2099       
2100                 if (tmppar) {
2101                         WriteAlert(_("Impossible operation"),
2102                                    _("Can't paste float into float!"), _("Sorry."));
2103                         return;
2104                 }
2105         }
2106
2107         /* table stuff -- begin*/
2108         if (cursor.par->table){
2109                 if (simple_cut_buffer->next){
2110                         WriteAlert(_("Impossible operation"),
2111                                    _("Table cell cannot include more than one paragraph!"),
2112                                    _("Sorry."));
2113                         return;
2114                 }
2115         }
2116         /* table stuff -- end*/
2117    
2118         SetUndo(Undo::INSERT, 
2119                 cursor.par->ParFromPos(cursor.pos)->previous, 
2120                 cursor.par->ParFromPos(cursor.pos)->next); 
2121
2122         tmpcursor = cursor;
2123
2124         /* There are two cases: cutbuffer only one paragraph or many */
2125         if (!simple_cut_buffer->next) {
2126                 /* only within a paragraph */
2127      
2128                 /* please break behind a space, if there is one */
2129                 while (tmpcursor.par->Last() > tmpcursor.pos
2130                        && tmpcursor.par->IsLineSeparator(tmpcursor.pos))
2131                         tmpcursor.pos++; 
2132
2133                 tmppar = simple_cut_buffer->Clone();
2134                 /* table stuff -- begin*/
2135                 bool table_too_small = false;
2136                 if (tmpcursor.par->table) {
2137                         while (simple_cut_buffer->text.size()
2138                                && !table_too_small) {
2139                                 if (simple_cut_buffer->IsNewline(0)){
2140                                         while(tmpcursor.pos < tmpcursor.par->Last() && !tmpcursor.par->IsNewline(tmpcursor.pos))
2141                                                 tmpcursor.pos++;
2142                                         simple_cut_buffer->Erase(0);
2143                                         if (tmpcursor.pos < tmpcursor.par->Last())
2144                                                 tmpcursor.pos++;
2145                                         else
2146                                                 table_too_small = true;
2147                                 } else {
2148                                         simple_cut_buffer->CutIntoMinibuffer(0);
2149                                         simple_cut_buffer->Erase(0);
2150                                         tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2151                                         tmpcursor.pos++;
2152                                 }
2153                         }
2154                 } else {
2155                         /* table stuff -- end*/
2156                         while (simple_cut_buffer->text.size()){
2157                                 simple_cut_buffer->CutIntoMinibuffer(0);
2158                                 simple_cut_buffer->Erase(0);
2159                                 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2160                                 tmpcursor.pos++;
2161                         }
2162                 }
2163
2164                 delete simple_cut_buffer;
2165                 simple_cut_buffer = tmppar;
2166                 endpar = tmpcursor.par->Next();
2167         } else {
2168                 /* many paragraphs */
2169
2170                 /* make a copy of the simple cut_buffer */
2171                 tmppar = simple_cut_buffer;
2172                 LyXParagraph * simple_cut_clone = tmppar->Clone();
2173                 LyXParagraph * tmppar2 = simple_cut_clone;
2174                 if (cursor.par->footnoteflag){
2175                         tmppar->footnoteflag = cursor.par->footnoteflag;
2176                         tmppar->footnotekind = cursor.par->footnotekind;
2177                 }
2178                 while (tmppar->next) {
2179                         tmppar = tmppar->next;
2180                         tmppar2->next = tmppar->Clone();
2181                         tmppar2->next->previous = tmppar2;
2182                         tmppar2 = tmppar2->next;
2183                         if (cursor.par->footnoteflag){
2184                                 tmppar->footnoteflag = cursor.par->footnoteflag;
2185                                 tmppar->footnotekind = cursor.par->footnotekind;
2186                         }
2187                 }
2188      
2189                 /* make sure there is no class difference */ 
2190                 SwitchLayoutsBetweenClasses(simple_cut_buffer_textclass,
2191                                             parameters->textclass,
2192                                             simple_cut_buffer);
2193      
2194                 /* make the simple_cut_buffer exactly the same layout than
2195                    the cursor paragraph */
2196                 simple_cut_buffer->MakeSameLayout(cursor.par);
2197      
2198                 /* find the end of the buffer */ 
2199                 LyXParagraph *lastbuffer = simple_cut_buffer;
2200                 while (lastbuffer->Next())
2201                         lastbuffer = lastbuffer->Next();
2202      
2203                 /* find the physical end of the buffer */ 
2204                 lastbuffer = simple_cut_buffer;
2205                 while (lastbuffer->Next())
2206                         lastbuffer = lastbuffer->Next();
2207      
2208                 /* please break behind a space, if there is one. The space 
2209                  * should be copied too */
2210                 if (cursor.par->Last() > cursor.pos && cursor.par->IsLineSeparator(cursor.pos))
2211                         cursor.pos++; 
2212      
2213                 bool paste_the_end = false;
2214
2215                 /* open the paragraph for inserting the simple_cut_buffer
2216                    if necessary */
2217                 if (cursor.par->Last() > cursor.pos || !cursor.par->Next()){
2218                         cursor.par->BreakParagraphConservative(cursor.pos);
2219                         paste_the_end = true;
2220                 }
2221      
2222                 /* be careful with double spaces */ 
2223                 if ((!cursor.par->Last()
2224                      || cursor.par->IsLineSeparator(cursor.pos - 1)
2225                      || cursor.par->IsNewline(cursor.pos - 1))
2226                     && simple_cut_buffer->text.size()
2227                     && simple_cut_buffer->IsLineSeparator(0))
2228                         simple_cut_buffer->Erase(0);
2229      
2230                 /* set the end for redoing later */ 
2231                 endpar = cursor.par->ParFromPos(cursor.pos)->next->Next();
2232      
2233                 /* paste it! */ 
2234                 lastbuffer->ParFromPos(lastbuffer->Last())->next = cursor.par->ParFromPos(cursor.pos)->next;
2235                 cursor.par->ParFromPos(cursor.pos)->next->previous = lastbuffer->ParFromPos(lastbuffer->Last());
2236      
2237                 cursor.par->ParFromPos(cursor.pos)->next = simple_cut_buffer;
2238                 simple_cut_buffer->previous = cursor.par->ParFromPos(cursor.pos);
2239    
2240                 if (cursor.par->ParFromPos(cursor.pos)->Next() == lastbuffer)
2241                         lastbuffer = cursor.par;
2242      
2243                 cursor.par->ParFromPos(cursor.pos)->PasteParagraph();
2244      
2245                 /* store the new cursor position  */
2246                 tmpcursor.par = lastbuffer;
2247                 tmpcursor.pos = lastbuffer->Last();
2248      
2249                 /* maybe some pasting */ 
2250                 if (lastbuffer->Next() && paste_the_end) {
2251                         if (lastbuffer->Next()->HasSameLayout(lastbuffer)) {
2252          
2253                                 /* be careful witth double spaces */ 
2254                                 if ((!lastbuffer->Last()
2255                                      || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2256                                      || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2257                                     && lastbuffer->Next()->Last()
2258                                     && lastbuffer->Next()->IsLineSeparator(0))
2259                                         lastbuffer->Next()->Erase(0);
2260          
2261                                 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2262          
2263                         }
2264                         else if (!lastbuffer->Next()->Last()) {
2265                                 lastbuffer->Next()->MakeSameLayout(lastbuffer);
2266          
2267                                 /* be careful witth double spaces */ 
2268                                 if ((!lastbuffer->Last()
2269                                      || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2270                                      || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2271                                     && lastbuffer->Next()->Last()
2272                                     && lastbuffer->Next()->IsLineSeparator(0))
2273                                         lastbuffer->Next()->Erase(0);
2274          
2275                                 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2276          
2277                         }
2278                         else if (!lastbuffer->Last()) {
2279                                 lastbuffer->MakeSameLayout(lastbuffer->next);
2280          
2281                                 /* be careful witth double spaces */ 
2282                                 if ((!lastbuffer->Last()
2283                                      || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2284                                      || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2285                                     && lastbuffer->Next()->Last()
2286                                     && lastbuffer->Next()->IsLineSeparator(0))
2287                                         lastbuffer->Next()->Erase(0);
2288          
2289                                 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2290          
2291                         }
2292                         else lastbuffer->Next()->ClearParagraph();
2293                 }
2294
2295                 /* restore the simple cut buffer */
2296                 simple_cut_buffer = simple_cut_clone;
2297         }
2298
2299         RedoParagraphs(cursor, endpar);
2300     
2301         SetCursor(cursor.par, cursor.pos);
2302         ClearSelection();
2303    
2304         sel_cursor = cursor;
2305         SetCursor(tmpcursor.par, tmpcursor.pos);
2306         SetSelection();
2307         UpdateCounters(cursor.row);
2308 }
2309    
2310
2311 /* returns a pointer to the very first LyXParagraph */ 
2312 LyXParagraph * LyXText::FirstParagraph()
2313 {
2314         return params->paragraph;
2315 }
2316
2317
2318 /* returns true if the specified string is at the specified position */
2319 bool LyXText::IsStringInText(LyXParagraph * par,
2320                              LyXParagraph::size_type pos,
2321                              char const * str)
2322 {
2323         if (par) {
2324                 int i = 0;
2325                 while (pos + i < par->Last() && str[i] && 
2326                        str[i] == par->GetChar(pos + i)) {
2327                         ++i;
2328                 }
2329                 if (!str[i])
2330                         return true;
2331         }
2332         return false;
2333 }
2334
2335
2336 /* sets the selection over the number of characters of string, no check!! */
2337 void LyXText::SetSelectionOverString(char const * string)
2338 {
2339         sel_cursor = cursor;
2340         for (int i = 0; string[i]; ++i)
2341                 CursorRight();
2342         SetSelection();
2343 }
2344
2345
2346 /* simple replacing. The font of the first selected character is used */
2347 void LyXText::ReplaceSelectionWithString(char const * str)
2348 {
2349         SetCursorParUndo();
2350         FreezeUndo();
2351
2352         if (!selection) { /* create a dummy selection */
2353                 sel_end_cursor = cursor;
2354                 sel_start_cursor = cursor;
2355         }
2356
2357         // Get font setting before we cut
2358         LyXParagraph::size_type pos = sel_end_cursor.pos;
2359         LyXFont font = sel_start_cursor.par->GetFontSettings(sel_start_cursor.pos);
2360
2361         // Insert the new string
2362         for (int i = 0; str[i]; ++i) {
2363                 sel_end_cursor.par->InsertChar(pos, str[i]);
2364                 sel_end_cursor.par->SetFont(pos, font);
2365                 ++pos;
2366         }
2367
2368         // Cut the selection
2369         CutSelection();
2370
2371         UnFreezeUndo();
2372 }
2373
2374
2375 /* if the string can be found: return true and set the cursor to
2376  * the new position */
2377 bool LyXText::SearchForward(char const * str)
2378 {
2379         LyXParagraph * par = cursor.par;
2380         LyXParagraph::size_type pos = cursor.pos;
2381         while (par && !IsStringInText(par, pos, str)) {
2382                 if (pos < par->Last() - 1)
2383                         ++pos;
2384                 else {
2385                         pos = 0;
2386                         par = par->Next();
2387                 }
2388         }
2389         if (par) {
2390                 SetCursor(par, pos);
2391                 return true;
2392         }
2393         else
2394                 return false;
2395 }
2396
2397
2398 bool LyXText::SearchBackward(char const * string)
2399 {
2400         LyXParagraph * par = cursor.par;
2401         int pos = cursor.pos;
2402
2403         do {
2404                 if (pos>0)
2405                         pos--;
2406                 else {
2407                         // We skip empty paragraphs (Asger)
2408                         do {
2409                                 par = par->Previous();
2410                                 if (par)
2411                                         pos = par->Last()-1;
2412                         } while (par && pos<0);
2413                 }
2414         } while (par && !IsStringInText(par, pos, string));
2415   
2416         if (par) {
2417                 SetCursor(par, pos);
2418                 return true;
2419         }
2420         else
2421                 return false;
2422 }
2423
2424
2425 void LyXText::InsertStringA(LyXParagraph::TextContainer const & text)
2426 {
2427         char * str = new char[text.size() + 1];
2428         copy(text.begin(), text.end(), str);
2429         str[text.size()] = '\0';
2430         InsertStringA(str);
2431         delete [] str;
2432 }
2433
2434
2435 /* needed to insert the selection */
2436 void LyXText::InsertStringA(char const * str)
2437 {
2438         LyXParagraph * par = cursor.par;
2439         LyXParagraph::size_type pos = cursor.pos;
2440         LyXParagraph::size_type a = 0;
2441         int cell = 0;
2442         LyXParagraph * endpar = cursor.par->Next();
2443
2444         SetCursorParUndo();
2445
2446         char flag = textclasslist.Style(parameters->textclass, 
2447                                    cursor.par->GetLayout()).isEnvironment();
2448         /* only to be sure, should not be neccessary */ 
2449         ClearSelection();
2450    
2451         /* insert the string, don't insert doublespace */ 
2452         int i = 0;
2453         while (str[i]) {
2454                 if (str[i]!= '\n') {
2455                         if (str[i] == ' ' && (str[i+1]!= ' ')
2456                             && pos && par->GetChar(pos-1)!= ' ') {
2457                                 par->InsertChar(pos,' ');
2458                                 pos++;
2459                         }
2460                         else if (par->table) {
2461                             if (str[i] == '\t') {
2462                                 while((pos < par->size()) &&
2463                                       (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2464                                         ++pos;
2465                                 if (pos < par->size())
2466                                         ++pos;
2467                                 else // no more fields to fill skip the rest
2468                                         break;
2469                             } else if ((str[i] != 13) &&
2470                                 ((str[i] & 127) >= ' ')) {
2471                                 par->InsertChar(pos, str[i]);
2472                                 pos++;
2473                             }
2474                         }
2475                         else if (str[i] == ' ') {
2476                                 par->InsertChar(pos, LyXParagraph::META_PROTECTED_SEPARATOR);
2477                                 pos++;
2478                         }
2479                         else if (str[i] == '\t') {
2480                                 for (a = pos; a < (pos/8 + 1) * 8 ; ++a) {
2481                                         par->InsertChar(a, LyXParagraph::META_PROTECTED_SEPARATOR);
2482                                 }
2483                                 pos = a;
2484                         }
2485                         else if (str[i]!= 13 && 
2486                                  // Ignore unprintables
2487                                  (str[i] & 127) >= ' ') {
2488                                 par->InsertChar(pos, str[i]);
2489                                 pos++;
2490                         }
2491                 } else {
2492                         if (par->table) {
2493                                 if (!str[i+1]) {
2494                                         pos++;
2495                                         break;
2496                                 }
2497                                 while((pos < par->size()) &&
2498                                       (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2499                                         pos++;
2500                                 pos++;
2501                                 cell = NumberOfCell(par, pos);
2502                                 while((pos < par->size()) &&
2503                                       !(par->table->IsFirstCell(cell))) {
2504                                         while((pos < par->size()) &&
2505                                               (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2506                                                 ++pos;
2507                                         ++pos;
2508                                         cell = NumberOfCell(par, pos);
2509                                 }
2510                                 if (pos >= par->size())
2511                                         // no more fields to fill skip the rest
2512                                         break;
2513                         } else {
2514                                 if (!par->text.size()) {
2515                                         par->InsertChar(pos, LyXParagraph::META_PROTECTED_SEPARATOR);
2516                                         pos++;
2517                                 }
2518                                 par->BreakParagraph(pos, flag);
2519                                 par = par->Next();
2520                                 pos = 0;
2521                         }
2522                 }
2523       
2524                 i++;
2525         }
2526    
2527         RedoParagraphs(cursor, endpar);
2528         SetCursor(cursor.par, cursor.pos);
2529         sel_cursor = cursor;
2530         SetCursor(par, pos);
2531         SetSelection();
2532 }
2533
2534
2535 void LyXText::InsertStringB(LyXParagraph::TextContainer const & text)
2536 {
2537         char * str = new char[text.size() + 1];
2538         copy(text.begin(), text.end(), str);
2539         str[text.size()] = '\0';
2540         InsertStringB(str);
2541         delete [] str;
2542 }
2543
2544
2545 /* turns double-CR to single CR, others where converted into one blank and 13s 
2546  * that are ignored .Double spaces are also converted into one. Spaces at
2547  * the beginning of a paragraph are forbidden. tabs are converted into one
2548  * space. then InsertStringA is called */ 
2549 void LyXText::InsertStringB(char const * s)
2550 {
2551         string str(s);
2552         LyXParagraph * par = cursor.par;
2553         int i = 1;
2554         while (str[i]) {
2555                 if (str[i] == '\t' && !par->table)
2556                         str[i] = ' ';
2557                 if (str[i] == ' ' && str[i + 1] == ' ')
2558                         str[i] = 13;
2559                 if (str[i] == '\n' && str[i + 1] && !par->table){
2560                         if (str[i + 1] != '\n') {
2561                                 if (str[i - 1] != ' ')
2562                                         str[i] = ' ';
2563                                 else
2564                                         str[i] = 13;
2565                         }
2566                         while (str[i + 1] && (str[i + 1] == ' '
2567                                                || str[i + 1] == '\t'
2568                                                || str[i + 1] == '\n'
2569                                                || str[i + 1] == 13)) {
2570                                 str[i + 1] = 13;
2571                                 ++i;
2572                         }
2573                 }
2574                 ++i;
2575         }
2576         InsertStringA(str.c_str());
2577 }
2578
2579
2580 bool LyXText::GotoNextError()
2581 {
2582         LyXCursor res = cursor;
2583         do {
2584                 if (res.pos < res.par->Last() - 1) {
2585                         res.pos++;
2586                 }
2587                 else  {
2588                         res.par = res.par->Next();
2589                         res.pos = 0;
2590                 }
2591       
2592         } while (res.par && 
2593                  !(res.par->GetChar(res.pos) == LyXParagraph::META_INSET
2594                    && res.par->GetInset(res.pos)->AutoDelete()));
2595    
2596         if (res.par) {
2597                 SetCursor(res.par, res.pos);
2598                 return true;
2599         }
2600    
2601         return false;
2602 }
2603
2604
2605 bool LyXText::GotoNextNote()
2606 {
2607         LyXCursor res = cursor;
2608         do {
2609                 if (res.pos < res.par->Last()-1) {
2610                         res.pos++;
2611                 }
2612                 else  {
2613                         res.par = res.par->Next();
2614                         res.pos = 0;
2615                 }
2616       
2617         } while (res.par && 
2618                  !(res.par->GetChar(res.pos) == LyXParagraph::META_INSET
2619                    && res.par->GetInset(res.pos)->LyxCode() == Inset::IGNORE_CODE));
2620    
2621         if (res.par) {
2622                 SetCursor(res.par, res.pos);
2623                 return true;
2624         }
2625    
2626         return false;
2627 }
2628
2629
2630 int LyXText::SwitchLayoutsBetweenClasses(char class1, char class2,
2631                                          LyXParagraph * par)
2632 {
2633         InsetError * new_inset = 0;
2634         int ret = 0;
2635         if (!par || class1 == class2)
2636                 return ret;
2637         par = par->FirstPhysicalPar();
2638         while (par) {
2639                 string name = textclasslist.NameOfLayout(class1, par->layout);
2640                 int lay = 0;
2641                 pair<bool, LyXTextClass::LayoutList::size_type> pp =
2642                         textclasslist.NumberOfLayout(class2, name);
2643                 if (pp.first) {
2644                         lay = pp.second;
2645                 } else { // layout not found
2646                         // use default layout "Standard" (0)
2647                         lay = 0;
2648                 }
2649                 par->layout = lay;
2650       
2651                 if (name != textclasslist.NameOfLayout(class2, par->layout)) {
2652                         ret++;
2653                         string s = "Layout had to be changed from\n"
2654                                 + name + " to " + textclasslist.NameOfLayout(class2, par->layout)
2655                                 + "\nbecause of class conversion from\n"
2656                                 + textclasslist.NameOfClass(class1) + " to "
2657                                 + textclasslist.NameOfClass(class2);
2658                         new_inset = new InsetError(s);
2659                         par->InsertChar(0, LyXParagraph::META_INSET);
2660                         par->InsertInset(0, new_inset);
2661                 }
2662       
2663                 par = par->next;
2664         }
2665         return ret;
2666 }
2667
2668
2669 void LyXText::CheckParagraph(LyXParagraph * par,
2670                              LyXParagraph::size_type pos)
2671 {
2672   
2673         LyXCursor tmpcursor;
2674
2675         /* table stuff -- begin*/
2676    
2677         if (par->table) {
2678                 CheckParagraphInTable(par, pos);
2679         }
2680         else {
2681                 /* table stuff -- end*/
2682      
2683                 long y = 0;
2684                 LyXParagraph::size_type z;
2685                 Row * row = GetRow(par, pos, y);
2686      
2687                 /* is there a break one row above */ 
2688                 if (row->previous && row->previous->par == row->par) {
2689                         z = NextBreakPoint(row->previous, paperwidth);
2690                         if ( z >= row->pos) {
2691                                 /* set the dimensions of the row above  */ 
2692                                 y -= row->previous->height;
2693                                 refresh_y = y;
2694                                 refresh_row = row->previous;
2695                                 status = LyXText::NEED_MORE_REFRESH;
2696        
2697                                 BreakAgain(row->previous);
2698
2699                                 /* set the cursor again. Otherwise dungling pointers are possible */
2700                                 SetCursor(cursor.par, cursor.pos);
2701                                 sel_cursor = cursor;
2702                                 return;
2703                         }
2704                 }
2705
2706                 int tmpheight = row->height;
2707                 LyXParagraph::size_type tmplast = RowLast(row);
2708                 refresh_y = y;
2709                 refresh_row = row;
2710
2711                 BreakAgain(row);
2712                 if (row->height == tmpheight && RowLast(row) == tmplast)
2713                         status = LyXText::NEED_VERY_LITTLE_REFRESH;
2714                 else
2715                         status = LyXText::NEED_MORE_REFRESH; 
2716    
2717                 /* check the special right address boxes */
2718                 if (textclasslist.Style(parameters->textclass, par->GetLayout()).margintype == MARGIN_RIGHT_ADDRESS_BOX) {
2719                         tmpcursor.par = par;
2720                         tmpcursor.row = row;
2721                         tmpcursor.y = y;
2722                         tmpcursor.x = 0;
2723                         tmpcursor.x_fix = 0;
2724                         tmpcursor.pos = pos;
2725                         RedoDrawingOfParagraph(tmpcursor); 
2726                 }
2727    
2728         }
2729
2730         /* set the cursor again. Otherwise dangling pointers are possible */
2731         // also set the selection
2732    
2733         if (selection){
2734                 tmpcursor = cursor;
2735                 SetCursorIntern(sel_cursor.par, sel_cursor.pos);
2736                 sel_cursor = cursor; 
2737                 SetCursorIntern(sel_start_cursor.par, sel_start_cursor.pos);
2738                 sel_start_cursor = cursor; 
2739                 SetCursorIntern(sel_end_cursor.par, sel_end_cursor.pos);
2740                 sel_end_cursor = cursor; 
2741                 SetCursorIntern(last_sel_cursor.par, last_sel_cursor.pos);
2742                 last_sel_cursor = cursor; 
2743                 cursor = tmpcursor;
2744         }
2745         SetCursorIntern(cursor.par, cursor.pos);
2746 }
2747
2748
2749 /* returns 0 if inset wasn't found */
2750 int LyXText::UpdateInset(Inset * inset)
2751 {
2752         /* first check the current paragraph */
2753         int pos = cursor.par->GetPositionOfInset(inset);
2754         if (pos != -1){
2755                 CheckParagraph(cursor.par, pos);
2756                 return 1;
2757         }
2758   
2759         /* check every paragraph */
2760   
2761         LyXParagraph * par = FirstParagraph();
2762         do {
2763                 /* make sure the paragraph is open */
2764                 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2765                         pos = par->GetPositionOfInset(inset);
2766                         if (pos != -1){
2767                                 CheckParagraph(par, pos);
2768                                 return 1;
2769                         }
2770                 }
2771                 par = par->Next();
2772         } while (par);
2773   
2774         return 0;
2775 }
2776
2777
2778 void LyXText::SetCursor(LyXParagraph * par,
2779                         LyXParagraph::size_type pos)
2780 {
2781         LyXCursor old_cursor = cursor;
2782         SetCursorIntern(par, pos);
2783         DeleteEmptyParagraphMechanism(old_cursor);
2784 }
2785
2786
2787 void LyXText::SetCursorIntern(LyXParagraph * par, LyXParagraph::size_type pos)
2788 {
2789         long y;
2790         Row * row;
2791         int left_margin;
2792         LyXParagraph * tmppar;
2793    
2794         /* correct the cursor position if impossible */
2795         if (pos > par->Last()){
2796                 tmppar = par->ParFromPos(pos);
2797                 pos = par->PositionInParFromPos(pos);
2798                 par = tmppar;
2799         }
2800         if (par->IsDummy() && par->previous &&
2801             par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2802                 while (par->previous &&
2803                        ((par->previous->IsDummy() && par->previous->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) ||
2804                         (par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE))) {
2805                         par = par->previous ;
2806                         if (par->IsDummy() &&
2807                             par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
2808                                 pos += par->text.size() + 1;
2809                 }
2810                 if (par->previous) {
2811                         par = par->previous;
2812                 }
2813                 pos += par->text.size() + 1;
2814         }
2815
2816         cursor.par = par;
2817         cursor.pos = pos;
2818
2819         /* get the cursor y position in text  */
2820         row = GetRow(par, pos, y);
2821         /* y is now the beginning of the cursor row */ 
2822         y += row->baseline;
2823         /* y is now the cursor baseline */ 
2824         cursor.y = y;
2825    
2826         /* now get the cursors x position */
2827    
2828         float x;
2829         float fill_separator, fill_hfill, fill_label_hfill;
2830         left_margin = LabelEnd(row);
2831         PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
2832         LyXParagraph::size_type main_body =
2833                 BeginningOfMainBody(row->par);
2834         /* table stuff -- begin*/
2835         if (row->par->table) {
2836                 int cell = NumberOfCell(row->par, row->pos);
2837                 float x_old = x;
2838                 x += row->par->table->GetBeginningOfTextInCell(cell);
2839                 for (pos = row->pos; pos < cursor.pos; pos++)  {
2840                         if (row->par->IsNewline(pos)) {
2841                                 x = x_old + row->par->table->WidthOfColumn(cell);
2842                                 x_old = x;
2843                                 cell++;
2844                                 x += row->par->table->GetBeginningOfTextInCell(cell);
2845                         } else {
2846                                 x += SingleWidth(row->par, pos);
2847                         }
2848                 }
2849         } else
2850                 /* table stuff -- end*/
2851
2852                 for (pos = row->pos; pos < cursor.pos; pos++)  {
2853                         if (pos && pos == main_body
2854                             && !row->par->IsLineSeparator(pos - 1)) {
2855                                 x += GetFont(row->par, -2).stringWidth(
2856                                                     textclasslist.Style(parameters->textclass, row->par->GetLayout()).labelsep);
2857                                 if (x < left_margin)
2858                                         x = left_margin;
2859                         }
2860       
2861                         x += SingleWidth(row->par, pos);
2862                         if (HfillExpansion(row, pos)) {
2863                                 if (pos >= main_body)
2864                                         x += fill_hfill;
2865                                 else 
2866                                         x += fill_label_hfill;
2867                         }
2868                         else if (pos >= main_body && row->par->IsSeparator(pos)) {
2869                                 x+= fill_separator;
2870                         }
2871       
2872                         if (pos + 1 == main_body
2873                             && row->par->IsLineSeparator(pos)) {
2874                                 x += GetFont(row->par, -2).stringWidth(
2875                                                     textclasslist.Style(parameters->textclass, row->par->GetLayout()).labelsep);
2876                                 if (row->par->IsLineSeparator(pos))
2877                                         x -= SingleWidth(row->par, pos);
2878                                 if (x < left_margin)
2879                                         x = left_margin;
2880                         }
2881                 }
2882    
2883         cursor.x = int(x);
2884    
2885         cursor.x_fix = cursor.x;
2886         cursor.row = row;
2887    
2888         if (cursor.pos && 
2889             (cursor.pos == cursor.par->Last() || cursor.par->IsSeparator(cursor.pos)
2890              || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
2891                  && !cursor.par->IsSeparator(cursor.pos))
2892                     )) {
2893                 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
2894                 real_current_font = GetFont(cursor.par, cursor.pos - 1);
2895         } else {
2896                 current_font = cursor.par->GetFontSettings(cursor.pos);
2897                 real_current_font = GetFont(cursor.par, cursor.pos);
2898         }
2899 }
2900
2901
2902 void LyXText::SetCursorFromCoordinates(int x, long y)
2903 {
2904         LyXCursor old_cursor = cursor;
2905    
2906         /* get the row first */ 
2907    
2908         Row * row = GetRowNearY(y);
2909    
2910         cursor.par = row->par;
2911    
2912         int column = GetColumnNearX(row, x);
2913         cursor.pos = row->pos + column;
2914         cursor.x = x;
2915         cursor.y = y + row->baseline;
2916    
2917         cursor.row = row;
2918     
2919         if (cursor.pos && 
2920             (cursor.pos == cursor.par->Last()
2921              || cursor.par->IsSeparator(cursor.pos)
2922              || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
2923                  && !cursor.par->IsSeparator(cursor.pos))
2924                     )) {
2925                 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
2926                 real_current_font = GetFont(cursor.par, cursor.pos - 1);
2927         } else {
2928                 current_font = cursor.par->GetFontSettings(cursor.pos);
2929                 real_current_font = GetFont(cursor.par, cursor.pos);
2930         }
2931         DeleteEmptyParagraphMechanism(old_cursor);
2932 }
2933
2934
2935 void LyXText::CursorLeft()
2936 {
2937         CursorLeftIntern();
2938         if (cursor.par->table) {
2939                 int cell = NumberOfCell(cursor.par, cursor.pos);
2940                 if (cursor.par->table->IsContRow(cell) &&
2941                     cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
2942                         CursorUp();
2943                 }
2944         }
2945 }
2946
2947
2948 void LyXText::CursorLeftIntern()
2949 {
2950         if (cursor.pos > 0) {
2951                 SetCursor(cursor.par, cursor.pos - 1);
2952         }
2953         else if (cursor.par->Previous()) {
2954                 SetCursor(cursor.par->Previous(), cursor.par->Previous()->Last());
2955         }
2956 }
2957
2958
2959 void LyXText::CursorRight()
2960 {
2961         CursorRightIntern();
2962         if (cursor.par->table) {
2963                 int cell = NumberOfCell(cursor.par, cursor.pos);
2964                 if (cursor.par->table->IsContRow(cell) &&
2965                     cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
2966                         CursorUp();
2967                 }
2968         }
2969 }
2970
2971
2972 void LyXText::CursorRightIntern()
2973 {
2974         if (cursor.pos < cursor.par->Last()) {
2975                 SetCursor(cursor.par, cursor.pos + 1);
2976         }
2977         else if (cursor.par->Next()) {
2978                 SetCursor(cursor.par->Next(), 0);
2979         }
2980 }
2981
2982
2983 void LyXText::CursorUp()
2984 {
2985         SetCursorFromCoordinates(cursor.x_fix, 
2986                                  cursor.y - cursor.row->baseline - 1);
2987         if (cursor.par->table) {
2988                 int cell = NumberOfCell(cursor.par, cursor.pos);
2989                 if (cursor.par->table->IsContRow(cell) &&
2990                     cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
2991                         CursorUp();
2992                 }
2993         }
2994 }
2995
2996
2997 void LyXText::CursorDown()
2998 {
2999         if (cursor.par->table &&
3000             cursor.par->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par, cursor.pos)) &&
3001             !cursor.par->next)
3002                 return;
3003         SetCursorFromCoordinates(cursor.x_fix, 
3004                                  cursor.y - cursor.row->baseline
3005                                  + cursor.row->height + 1);
3006         if (cursor.par->table) {
3007                 int cell = NumberOfCell(cursor.par, cursor.pos);
3008                 int cell_above = cursor.par->table->GetCellAbove(cell);
3009                 while(cursor.par->table &&
3010                       cursor.par->table->IsContRow(cell) &&
3011                       (cursor.par->table->CellHasContRow(cell_above)<0)) {
3012                     SetCursorFromCoordinates(cursor.x_fix, 
3013                                              cursor.y - cursor.row->baseline
3014                                              + cursor.row->height + 1);
3015                     if (cursor.par->table) {
3016                         cell = NumberOfCell(cursor.par, cursor.pos);
3017                         cell_above = cursor.par->table->GetCellAbove(cell);
3018                     }
3019                 }
3020         }
3021 }
3022
3023
3024 void LyXText::CursorUpParagraph()
3025 {
3026         if (cursor.pos > 0) {
3027                 SetCursor(cursor.par, 0);
3028         }
3029         else if (cursor.par->Previous()) {
3030                 SetCursor(cursor.par->Previous(), 0);
3031         }
3032 }
3033
3034
3035 void LyXText::CursorDownParagraph()
3036 {
3037         if (cursor.par->Next()) {
3038                 SetCursor(cursor.par->Next(), 0);
3039         } else {
3040                 SetCursor(cursor.par, cursor.par->Last());
3041         }
3042 }
3043
3044
3045
3046 void LyXText::DeleteEmptyParagraphMechanism(LyXCursor old_cursor)
3047 {
3048     bool deleted = false;
3049         
3050     /* this is the delete-empty-paragraph-mechanism. */ 
3051     if (selection)
3052         return;
3053
3054     // Paragraph should not be deleted if empty
3055     if ((textclasslist.Style(parameters->textclass,
3056                         old_cursor.par->GetLayout())).keepempty)
3057         return;
3058
3059     LyXCursor tmpcursor;
3060
3061     if (old_cursor.par != cursor.par) {
3062         if ( (old_cursor.par->Last() == 0
3063               || (old_cursor.par->Last() == 1
3064                   && (old_cursor.par->IsLineSeparator(0))))
3065              && old_cursor.par->FirstPhysicalPar()
3066              == old_cursor.par->LastPhysicalPar()) {
3067                         
3068             /* ok, we will delete anything */ 
3069                         
3070             // make sure that you do not delete any environments
3071             if ((old_cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3072                  !(old_cursor.row->previous 
3073                    && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3074                  && !(old_cursor.row->next 
3075                       && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3076                 || 
3077                 (old_cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE &&
3078                  ((old_cursor.row->previous 
3079                    && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3080                   || 
3081                   (old_cursor.row->next
3082                    && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3083                  )){
3084                 status = LyXText::NEED_MORE_REFRESH;
3085                 deleted = true;
3086                                 
3087                 if (old_cursor.row->previous) {
3088                     refresh_row = old_cursor.row->previous;
3089                     refresh_y = old_cursor.y - old_cursor.row->baseline - refresh_row->height;
3090                     tmpcursor = cursor;
3091                     cursor = old_cursor; // that undo can restore the right cursor position
3092                     LyXParagraph *endpar = old_cursor.par->next;
3093                     if (endpar && endpar->GetDepth()) {
3094                         while (endpar && endpar->GetDepth()) {
3095                             endpar = endpar->LastPhysicalPar()->Next();
3096                         }
3097                     }
3098                     SetUndo(Undo::DELETE,
3099                             old_cursor.par->previous,
3100                             endpar);
3101                     cursor = tmpcursor;
3102
3103                     /* delete old row */ 
3104                     RemoveRow(old_cursor.row);
3105                     if (params->paragraph == old_cursor.par) {
3106                         params->paragraph = params->paragraph->next;
3107                     }
3108                     /* delete old par */ 
3109                     delete old_cursor.par;
3110                                         
3111                     /* Breakagain the next par. Needed
3112                      * because of the parindent that
3113                      * can occur or dissappear. The
3114                      * next row can change its height,
3115                      * if there is another layout before */
3116                     if (refresh_row->next) {
3117                         BreakAgain(refresh_row->next);
3118                         UpdateCounters(refresh_row);
3119                     }
3120                     SetHeightOfRow(refresh_row);
3121                 }
3122                 else {
3123                     refresh_row = old_cursor.row->next;
3124                     refresh_y = old_cursor.y - old_cursor.row->baseline;
3125                                         
3126                     tmpcursor = cursor;
3127                     cursor = old_cursor; // that undo can restore the right cursor position
3128                     LyXParagraph *endpar = old_cursor.par->next;
3129                     if (endpar && endpar->GetDepth()) {
3130                         while (endpar && endpar->GetDepth()) {
3131                             endpar = endpar->LastPhysicalPar()->Next();
3132                         }
3133                     }
3134                     SetUndo(Undo::DELETE,
3135                             old_cursor.par->previous,
3136                             endpar);
3137                     cursor = tmpcursor;
3138
3139                     /* delete old row */ 
3140                     RemoveRow(old_cursor.row);
3141                     /* delete old par */ 
3142                     if (params->paragraph == old_cursor.par) {
3143                         params->paragraph = params->paragraph->next;
3144                     }
3145                     delete old_cursor.par;
3146                                         
3147                     /* Breakagain the next par. Needed because of
3148                      * the parindent that can occur or dissappear.
3149                      * The next row can change its height, if there
3150                      * is another layout before */ 
3151                     if (refresh_row) {
3152                         BreakAgain(refresh_row);
3153                         UpdateCounters(refresh_row->previous);
3154                     }
3155                 }
3156                                 
3157                                 /* correct cursor y */
3158                 SetCursor(cursor.par, cursor.pos);
3159                      
3160                                 /* if (cursor.y > old_cursor.y)
3161                                    cursor.y -= old_cursor.row->height; */ 
3162          
3163                 if (sel_cursor.par  == old_cursor.par
3164                     && sel_cursor.pos == sel_cursor.pos) {
3165                     /* correct selection*/ 
3166                     sel_cursor = cursor;
3167                 }
3168             }
3169        
3170         }
3171         if (!deleted){
3172             if (old_cursor.par->ClearParagraph()){
3173                 RedoParagraphs(old_cursor, old_cursor.par->Next());
3174                                 /* correct cursor y */
3175                 SetCursor(cursor.par, cursor.pos);
3176                 sel_cursor = cursor;
3177             }
3178         }
3179     } else if (cursor.par->table && (cursor.row != old_cursor.row)) {
3180         int cell = NumberOfCell(old_cursor.par, old_cursor.pos);
3181         if (old_cursor.par->table->IsContRow(cell) &&
3182             IsEmptyTableRow(&old_cursor)) {
3183             RemoveTableRow(&old_cursor);
3184             RedoParagraph();
3185         }
3186     }
3187 }
3188
3189
3190 LyXParagraph * LyXText::GetParFromID(int id)
3191 {
3192         LyXParagraph * result = FirstParagraph();
3193         while (result && result->GetID() != id)
3194                 result = result->next;
3195         return result;
3196 }
3197
3198
3199 // undo functions
3200 bool  LyXText::TextUndo()
3201 { // returns false if no undo possible
3202         Undo * undo = params->undostack.Pop();
3203         if (undo){
3204                 FinishUndo();
3205                 if (!undo_frozen)
3206                         params->redostack.Push(CreateUndo(undo->kind, 
3207                                                           GetParFromID(undo->number_of_before_par),
3208                                                           GetParFromID(undo->number_of_behind_par)));
3209         }
3210         return TextHandleUndo(undo);
3211 }
3212
3213
3214 bool LyXText::TextRedo()
3215 { // returns false if no redo possible
3216         Undo * undo = params->redostack.Pop();
3217         if (undo){
3218                 FinishUndo();
3219                 if (!undo_frozen)
3220                         params->undostack.Push(CreateUndo(undo->kind, 
3221                                                           GetParFromID(undo->number_of_before_par),
3222                                                           GetParFromID(undo->number_of_behind_par)));
3223         }
3224         return TextHandleUndo(undo);
3225 }
3226
3227
3228 bool LyXText::TextHandleUndo(Undo * undo){ // returns false if no undo possible
3229         bool result = false;
3230         if (undo){
3231                 LyXParagraph * before = GetParFromID(undo->number_of_before_par); 
3232                 LyXParagraph * behind = GetParFromID(undo->number_of_behind_par); 
3233                 LyXParagraph * tmppar;
3234                 LyXParagraph * tmppar2;
3235                 LyXParagraph * tmppar3;
3236                 LyXParagraph * tmppar4;
3237                 LyXParagraph * endpar;
3238                 LyXParagraph * tmppar5;
3239     
3240                 // if there's no before take the beginning of the document for redoing
3241                 if (!before)
3242                         SetCursorIntern(FirstParagraph(), 0);
3243
3244                 // replace the paragraphs with the undo informations
3245
3246                 tmppar3 = undo->par;
3247                 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3248                 tmppar4 = tmppar3;
3249                 if (tmppar4){
3250                         while (tmppar4->next)
3251                                 tmppar4 = tmppar4->next;
3252                 } // get last undo par
3253     
3254                 // now remove the old text if there is any
3255                 if (before != behind || (!behind && !before)){
3256                         if (before)
3257                                 tmppar5 = before->next;
3258                         else
3259                                 tmppar5 = params->paragraph;
3260                         tmppar2 = tmppar3;
3261                         while (tmppar5 && tmppar5 != behind){
3262                                 tmppar = tmppar5;
3263                                 tmppar5 = tmppar5->next;
3264                                 // a memory optimization for edit: Only layout information
3265                                 // is stored in the undo. So restore the text informations.
3266                                 if (undo->kind == Undo::EDIT){
3267                                         tmppar2->text = tmppar->text;
3268                                         tmppar->text.clear();
3269                                         //tmppar->text.erase(tmppar->text.begin(),
3270                                         //                 tmppar->text.end());
3271                                         tmppar2 = tmppar2->next;
3272                                 }
3273                                 if ( currentrow && currentrow->par == tmppar )
3274                                         currentrow = currentrow -> previous;
3275                                 delete tmppar;
3276                         }
3277                 }
3278     
3279                 // put the new stuff in the list if there is one
3280                 if (tmppar3){
3281                         if (before)
3282                                 before->next = tmppar3;
3283                         else
3284                                 params->paragraph = tmppar3;
3285                         tmppar3->previous = before;
3286                 }
3287                 else {
3288                         if (!before)
3289                                 params->paragraph = behind;
3290                 }
3291                 if (tmppar4) {
3292                         tmppar4->next = behind;
3293                         if (behind)
3294                                 behind->previous = tmppar4;
3295                 }
3296     
3297     
3298                 // Set the cursor for redoing
3299                 if (before){
3300                         SetCursorIntern(before->FirstSelfrowPar(), 0);
3301                         // check wether before points to a closed float and open it if necessary
3302                         if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3303                             && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3304                                 tmppar4 = before;
3305                                 while (tmppar4->previous && 
3306                                        tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3307                                         tmppar4 = tmppar4->previous;
3308                                 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3309                                         tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3310                                         tmppar4 = tmppar4->next;
3311                                 }
3312                         }
3313                 }
3314     
3315                 // open a cosed footnote at the end if necessary
3316                 if (behind && behind->previous && 
3317                     behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3318                     behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3319                         while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3320                                 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3321                                 behind = behind->next;
3322                         }
3323                 }
3324     
3325                 // calculate the endpar for redoing the paragraphs.
3326                 if (behind){
3327                         if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3328                                 endpar = behind->LastPhysicalPar()->Next();
3329                         else
3330                                 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3331                 }
3332                 else
3333                         endpar = behind;
3334     
3335                 tmppar = GetParFromID(undo->number_of_cursor_par);
3336                 RedoParagraphs(cursor, endpar); 
3337                 if (tmppar){
3338                         SetCursorIntern(tmppar, undo->cursor_pos);
3339                         UpdateCounters(cursor.row);
3340                 }
3341                 result = true;
3342                 delete undo;
3343         }
3344         FinishUndo();
3345         return result;
3346 }
3347
3348
3349 void LyXText::FinishUndo()
3350 { // makes sure the next operation will be stored
3351         undo_finished = True;
3352 }
3353
3354
3355 void LyXText::FreezeUndo()
3356 { // this is dangerous and for internal use only
3357         undo_frozen = True;
3358 }
3359
3360
3361 void LyXText::UnFreezeUndo()
3362 { // this is dangerous and for internal use only
3363         undo_frozen = false;
3364 }
3365
3366
3367 void LyXText::SetUndo(Undo::undo_kind kind, LyXParagraph * before,
3368                       LyXParagraph * behind)
3369 {
3370         if (!undo_frozen)
3371                 params->undostack.Push(CreateUndo(kind, before, behind));
3372         params->redostack.Clear();
3373 }
3374
3375
3376 void LyXText::SetRedo(Undo::undo_kind kind, LyXParagraph * before,
3377                       LyXParagraph * behind)
3378 {
3379         params->redostack.Push(CreateUndo(kind, before, behind));
3380 }
3381
3382
3383 Undo * LyXText::CreateUndo(Undo::undo_kind kind, LyXParagraph * before,
3384                           LyXParagraph * behind)
3385 {
3386         int before_number = -1;
3387         int behind_number = -1;
3388         if (before)
3389                 before_number = before->GetID();
3390         if (behind)
3391                 behind_number = behind->GetID();
3392         // Undo::EDIT  and Undo::FINISH are
3393         // always finished. (no overlapping there)
3394         // overlapping only with insert and delete inside one paragraph: 
3395         // Nobody wants all removed  character
3396         // appear one by one when undoing. 
3397         // EDIT is special since only layout information, not the
3398         // contents of a paragaph are stored.
3399         if (!undo_finished && kind != Undo::EDIT && 
3400             kind != Undo::FINISH){
3401                 // check wether storing is needed
3402                 if (params->undostack.Top() && 
3403                     params->undostack.Top()->kind == kind &&
3404                     params->undostack.Top()->number_of_before_par ==  before_number &&
3405                     params->undostack.Top()->number_of_behind_par ==  behind_number ){
3406                         // no undo needed
3407                         return 0;
3408                 }
3409         }
3410         // create a new Undo
3411         LyXParagraph * undopar;
3412         LyXParagraph * tmppar;
3413         LyXParagraph * tmppar2;
3414
3415         LyXParagraph * start = 0;
3416         LyXParagraph * end = 0;
3417   
3418         if (before)
3419                 start = before->next;
3420         else
3421                 start = FirstParagraph();
3422         if (behind)
3423                 end = behind->previous;
3424         else {
3425                 end = FirstParagraph();
3426                 while (end->next)
3427                         end = end->next;
3428         }
3429
3430         if (start && end && start != end->next && (before != behind || (!before && !behind))) {
3431                 tmppar = start;
3432                 tmppar2 = tmppar->Clone();
3433                 tmppar2->SetID(tmppar->GetID());
3434
3435                 // a memory optimization: Just store the layout information when only edit
3436                 if (kind == Undo::EDIT){
3437                         tmppar2->text.clear();
3438                         //tmppar2->text.erase(tmppar2->text.begin(),
3439                         //                  tmppar2->text.end());
3440                 }
3441
3442                 undopar = tmppar2;
3443   
3444                 while (tmppar != end && tmppar->next) {
3445                         tmppar = tmppar->next;
3446                         tmppar2->next = tmppar->Clone();
3447                         tmppar2->next->SetID(tmppar->GetID());
3448                         // a memory optimization: Just store the layout information when only edit
3449                         if (kind == Undo::EDIT){
3450                                 tmppar2->next->text.clear();
3451                                 //tmppar2->next->text.erase(tmppar2->next->text.begin(), tmppar2->next->text.end());
3452                         }
3453                         tmppar2->next->previous = tmppar2;
3454                         tmppar2 = tmppar2->next;
3455                 }
3456                 tmppar2->next = 0;
3457         }
3458         else
3459                 undopar = 0; // nothing to replace (undo of delete maybe)
3460   
3461         int cursor_par = cursor.par->ParFromPos(cursor.pos)->GetID();
3462         int cursor_pos =  cursor.par->PositionInParFromPos(cursor.pos);
3463
3464         Undo * undo = new Undo(kind, 
3465                               before_number, behind_number,  
3466                               cursor_par, cursor_pos, 
3467                               undopar);
3468   
3469         undo_finished = false;
3470         return undo;
3471 }
3472
3473
3474 void LyXText::SetCursorParUndo()
3475 {
3476         SetUndo(Undo::FINISH, 
3477                 cursor.par->ParFromPos(cursor.pos)->previous, 
3478                 cursor.par->ParFromPos(cursor.pos)->next); 
3479 }
3480
3481 void LyXText::RemoveTableRow(LyXCursor * cursor)
3482 {
3483     int
3484         cell_act,
3485         cell = -1,
3486         cell_org = 0,
3487         ocell = 0;
3488     
3489     /* move to the previous row */
3490     cell_act = NumberOfCell(cursor->par, cursor->pos);
3491     if (cell < 0)
3492         cell = cell_act;
3493     while (cursor->pos && !cursor->par->IsNewline(cursor->pos-1))
3494         cursor->pos--;
3495     while (cursor->pos && 
3496            !cursor->par->table->IsFirstCell(cell_act)){
3497         cursor->pos--;
3498         while (cursor->pos && !cursor->par->IsNewline(cursor->pos-1))
3499             cursor->pos--;
3500             cell--;
3501             cell_act--;
3502     }
3503     /* now we have to pay attention if the actual table is the
3504        main row of TableContRows and if yes to delete all of them */
3505     if (!cell_org)
3506         cell_org = cell;
3507     do {
3508         ocell = cell;
3509         /* delete up to the next row */
3510         while (cursor->pos < cursor->par->Last() && 
3511                (cell_act == ocell
3512                 || !cursor->par->table->IsFirstCell(cell_act))){
3513             while (cursor->pos < cursor->par->Last() &&
3514                    !cursor->par->IsNewline(cursor->pos))
3515                 cursor->par->Erase(cursor->pos);
3516             cell++;
3517             cell_act++;
3518             if (cursor->pos < cursor->par->Last())
3519                 cursor->par-> Erase(cursor->pos);
3520         }
3521         if (cursor->pos && cursor->pos == cursor->par->Last()){
3522             cursor->pos--;
3523             cursor->par->Erase(cursor->pos); // no newline at the very end!
3524         }
3525     } while (((cell+1) < cursor->par->table->GetNumberOfCells()) &&
3526              !cursor->par->table->IsContRow(cell_org) &&
3527              cursor->par->table->IsContRow(cell));
3528     cursor->par->table->DeleteRow(cell_org);
3529     return;
3530 }
3531
3532
3533 bool LyXText::IsEmptyTableRow(LyXCursor * old_cursor)
3534 {
3535         if (!old_cursor->par->table)
3536                 return false;
3537 #ifdef I_DONT_KNOW_IF_I_SHOULD_DO_THIS
3538         int
3539                 pos = old_cursor->pos,
3540                 cell = NumberOfCell(old_cursor->par, pos);
3541
3542         // search first charater of this table row
3543         while (pos && !old_cursor->par->table->IsFirstCell(cell)) {
3544                 pos--;
3545                 while (pos && !old_cursor->par->IsNewline(pos-1))
3546                         pos--;
3547                 cell--;
3548         }
3549         if (!old_cursor->par->IsNewline(pos))
3550                 return false;
3551         cell++;
3552         pos++;
3553         while ((pos < old_cursor->par->Last()) &&
3554                !old_cursor->par->table->IsFirstCell(cell)) {
3555                 if (!old_cursor->par->IsNewline(pos))
3556                         return false;
3557                 pos++;
3558                 cell++;
3559         }
3560         return true;
3561 #endif
3562         return false;
3563 }
3564
3565
3566 bool LyXText::IsEmptyTableCell()
3567 {
3568         LyXParagraph::size_type pos = cursor.pos - 1;
3569         while (pos >= 0 && pos < cursor.par->Last()
3570                && !cursor.par->IsNewline(pos))
3571                 --pos;
3572         return cursor.par->IsNewline(pos + 1);
3573 }
3574
3575
3576 void LyXText::toggleAppendix(){
3577   LyXParagraph * par = cursor.par->FirstPhysicalPar();
3578   bool start = !par->start_of_appendix;
3579
3580   /* ensure that we have only one start_of_appendix in this document */
3581   LyXParagraph * tmp = FirstParagraph();
3582   for (;tmp;tmp = tmp->next)
3583     tmp->start_of_appendix = 0;
3584   par->start_of_appendix = start;
3585
3586   /* we can set the refreshing parameters now */
3587   status = LyXText::NEED_MORE_REFRESH;
3588   refresh_y = 0;
3589   refresh_row = 0; // not needed for full update
3590   UpdateCounters(0);
3591   SetCursor(cursor.par, cursor.pos);
3592 }
3593