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