]> git.lyx.org Git - lyx.git/blob - src/text2.C
c012715c5f2d0cf99cced906966f13df39969b32
[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         //current_view->owner()->getMiniBuffer()->Set(_("Font style changed"));
1063
1064         /* Implicit selections are cleared afterwards and cursor is set to the
1065            original position. */
1066         if (implicitSelection) {
1067                 ClearSelection();
1068                 cursor = resetCursor;
1069                 SetCursor( cursor.par, cursor.pos );
1070                 sel_cursor = cursor;
1071         }
1072 }
1073
1074
1075 LyXParagraph::size_type LyXText::BeginningOfMainBody(LyXParagraph * par) const
1076 {
1077         if (textclasslist.Style(parameters->textclass, par->GetLayout()).labeltype != LABEL_MANUAL)
1078                 return 0;
1079         else
1080                 return par->BeginningOfMainBody();
1081 }
1082
1083
1084 /* if there is a selection, reset every environment you can find
1085 * in the selection, otherwise just the environment you are in */ 
1086 void LyXText::MeltFootnoteEnvironment()
1087 {
1088         LyXParagraph * tmppar, * firsttmppar;
1089    
1090         ClearSelection();
1091    
1092         /* is is only allowed, if the cursor is IN an open footnote.
1093          * Otherwise it is too dangerous */ 
1094         if (cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1095                 return;
1096    
1097         SetUndo(Undo::FINISH, 
1098                 cursor.par->PreviousBeforeFootnote()->previous,
1099                 cursor.par->NextAfterFootnote()->next);
1100
1101         /* ok, move to the beginning of the footnote. */ 
1102         while (cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1103                 cursor.par = cursor.par->Previous();
1104    
1105         SetCursor(cursor.par, cursor.par->Last());
1106         /* this is just faster than using CursorLeft(); */ 
1107    
1108         firsttmppar = cursor.par->ParFromPos(cursor.pos);
1109         tmppar = firsttmppar;
1110         /* tmppar is now the paragraph right before the footnote */
1111
1112         char first_footnote_par_is_not_empty = tmppar->next->text.size();
1113    
1114         while (tmppar->next && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1115                 tmppar = tmppar->next;         /* I use next instead of Next(),
1116                                                 * because there cannot be any
1117                                                 * footnotes in a footnote
1118                                                 * environment */
1119                 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1120       
1121                 /* remember the captions and empty paragraphs */
1122                 if ((textclasslist.Style(parameters->textclass,
1123                                     tmppar->GetLayout()).labeltype == LABEL_SENSITIVE)
1124                     || !tmppar->Last())
1125                         tmppar->SetLayout(0);
1126         }
1127    
1128         /* now we will paste the ex-footnote, if the layouts allow it */
1129         /* first restore the layout of the paragraph right behind the footnote*/ 
1130         if (tmppar->next) 
1131                 tmppar->next->MakeSameLayout(cursor.par);
1132
1133         /* first the end */ 
1134         if ((!tmppar->GetLayout() && !tmppar->table)
1135             || (tmppar->Next() && (!tmppar->Next()->Last()
1136                                    || tmppar->Next()->HasSameLayout(tmppar)))) {
1137                 if (tmppar->Next()->Last() && tmppar->Next()->IsLineSeparator(0))
1138                         tmppar->Next()->Erase(0);
1139                 tmppar->PasteParagraph();
1140         }
1141
1142         tmppar = tmppar->Next();               /* make shure tmppar cannot be touched
1143                                                 * by the pasting of the beginning */
1144
1145         /* then the beginning */ 
1146         /* if there is no space between the text and the footnote, so we insert
1147          * a blank 
1148          * (only if the previous par and the footnotepar are not empty!) */
1149         if ((!firsttmppar->next->GetLayout() && !firsttmppar->next->table)
1150             || firsttmppar->HasSameLayout(firsttmppar->next)) {
1151                 if (firsttmppar->text.size()
1152                     && !firsttmppar->IsSeparator(firsttmppar->text.size() - 1)
1153                     && first_footnote_par_is_not_empty) {
1154                         firsttmppar->next->InsertChar(0, ' ');
1155                 }
1156                 firsttmppar->PasteParagraph();
1157         }
1158    
1159         /* now redo the paragaphs */
1160         RedoParagraphs(cursor, tmppar);
1161    
1162         SetCursor(cursor.par, cursor.pos);
1163    
1164         /* sometimes it can happen, that there is a counter change */ 
1165         Row * row = cursor.row;
1166         while (row->next && row->par != tmppar && row->next->par != tmppar)
1167                 row = row->next;
1168         UpdateCounters(row);
1169    
1170    
1171         ClearSelection();
1172 }
1173
1174
1175 /* the DTP switches for paragraphs. LyX will store them in the 
1176 * first physicla paragraph. When a paragraph is broken, the top settings 
1177 * rest, the bottom settings are given to the new one. So I can make shure, 
1178 * they do not duplicate themself and you cannnot make dirty things with 
1179 * them!  */ 
1180
1181 void LyXText::SetParagraph(bool line_top, bool line_bottom,
1182                            bool pagebreak_top, bool pagebreak_bottom,
1183                            VSpace space_top, VSpace space_bottom,
1184                            LyXAlignment align, 
1185                            string labelwidthstring,
1186                            bool noindent) 
1187 {
1188         LyXCursor tmpcursor = cursor;
1189         if (!selection) {
1190                 sel_start_cursor = cursor;
1191                 sel_end_cursor = cursor;
1192         }
1193
1194         // make sure that the depth behind the selection are restored, too
1195         LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1196         LyXParagraph * undoendpar = endpar;
1197
1198         if (endpar && endpar->GetDepth()) {
1199                 while (endpar && endpar->GetDepth()) {
1200                         endpar = endpar->LastPhysicalPar()->Next();
1201                         undoendpar = endpar;
1202                 }
1203         }
1204         else if (endpar) {
1205                 endpar = endpar->Next(); /* because of parindents etc.  */
1206         }
1207    
1208         SetUndo(Undo::EDIT, 
1209                 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous, 
1210                 undoendpar);
1211
1212         
1213         LyXParagraph * tmppar = sel_end_cursor.par;
1214         while (tmppar != sel_start_cursor.par->FirstPhysicalPar()->Previous()){
1215                 SetCursor(tmppar->FirstPhysicalPar(), 0);
1216                 status = LyXText::NEED_MORE_REFRESH;
1217                 refresh_row = cursor.row;
1218                 refresh_y = cursor.y - cursor.row->baseline;
1219                 if (cursor.par->footnoteflag ==
1220                     sel_start_cursor.par->footnoteflag) {
1221                         cursor.par->line_top = line_top;
1222                         cursor.par->line_bottom = line_bottom;
1223                         cursor.par->pagebreak_top = pagebreak_top;
1224                         cursor.par->pagebreak_bottom = pagebreak_bottom;
1225                         cursor.par->added_space_top = space_top;
1226                         cursor.par->added_space_bottom = space_bottom;
1227                                 /* does the layout allow the new alignment? */
1228                         if (align == LYX_ALIGN_LAYOUT)
1229                                 align = textclasslist
1230                                         .Style(parameters->textclass,
1231                                                cursor.par->GetLayout()).align;
1232                         if (align & textclasslist
1233                             .Style(parameters->textclass,
1234                                    cursor.par->GetLayout()).alignpossible) {
1235                                 if (align == textclasslist
1236                                     .Style(parameters->textclass,
1237                                            cursor.par->GetLayout()).align)
1238                                         cursor.par->align = LYX_ALIGN_LAYOUT;
1239                                 else
1240                                         cursor.par->align = align;
1241                         }
1242                         cursor.par->SetLabelWidthString(labelwidthstring);
1243                         cursor.par->noindent = noindent;
1244                 }
1245                 
1246                 tmppar = cursor.par->FirstPhysicalPar()->Previous();
1247         }
1248         
1249         RedoParagraphs(sel_start_cursor, endpar);
1250         
1251         ClearSelection();
1252         SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
1253         sel_cursor = cursor;
1254         SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
1255         SetSelection();
1256         SetCursor(tmpcursor.par, tmpcursor.pos);
1257 }
1258
1259
1260 void LyXText::SetParagraphExtraOpt(int type,
1261                                    char const * width,
1262                                    char const * widthp,
1263                                    int alignment, bool hfill,
1264                                    bool start_minipage)
1265 {
1266         LyXCursor tmpcursor = cursor;
1267         LyXParagraph * tmppar;
1268         if (!selection) {
1269                 sel_start_cursor = cursor;
1270                 sel_end_cursor = cursor;
1271         }
1272
1273         // make sure that the depth behind the selection are restored, too
1274         LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1275         LyXParagraph * undoendpar = endpar;
1276
1277         if (endpar && endpar->GetDepth()) {
1278                 while (endpar && endpar->GetDepth()) {
1279                         endpar = endpar->LastPhysicalPar()->Next();
1280                         undoendpar = endpar;
1281                 }
1282         }
1283         else if (endpar) {
1284                 endpar = endpar->Next(); /* because of parindents etc.  */
1285         }
1286    
1287         SetUndo(Undo::EDIT, 
1288                 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous, 
1289                 undoendpar);
1290         
1291         tmppar = sel_end_cursor.par;
1292         while(tmppar != sel_start_cursor.par->FirstPhysicalPar()->Previous()) {
1293                 SetCursor(tmppar->FirstPhysicalPar(), 0);
1294                 status = LyXText::NEED_MORE_REFRESH;
1295                 refresh_row = cursor.row;
1296                 refresh_y = cursor.y - cursor.row->baseline;
1297                 if (cursor.par->footnoteflag ==
1298                     sel_start_cursor.par->footnoteflag) {
1299                         if (type == LyXParagraph::PEXTRA_NONE) {
1300                                 if (cursor.par->pextra_type != LyXParagraph::PEXTRA_NONE) {
1301                                         cursor.par->UnsetPExtraType();
1302                                         cursor.par->pextra_type = LyXParagraph::PEXTRA_NONE;
1303                                 }
1304                         } else {
1305                                 cursor.par->SetPExtraType(type, width, widthp);
1306                                 cursor.par->pextra_hfill = hfill;
1307                                 cursor.par->pextra_start_minipage = start_minipage;
1308                                 cursor.par->pextra_alignment = alignment;
1309                         }
1310                 }
1311                 tmppar = cursor.par->FirstPhysicalPar()->Previous();
1312         }
1313         RedoParagraphs(sel_start_cursor, endpar);
1314         ClearSelection();
1315         SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
1316         sel_cursor = cursor;
1317         SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
1318         SetSelection();
1319         SetCursor(tmpcursor.par, tmpcursor.pos);
1320 }
1321
1322
1323 static char const * alphaCounter(int n){
1324   static char result[2];
1325   result[1] = 0;
1326   if (n == 0)
1327     return "";
1328   else {
1329     result[0] = 64 + n;
1330     if (n > 26)
1331       return "??";
1332   }
1333   return result;
1334 }
1335
1336
1337 /* set the counter of a paragraph. This includes the labels */ 
1338 void LyXText::SetCounter(LyXParagraph * par)
1339 {
1340         int i;
1341    
1342         /* this is only relevant for the beginning of paragraph */ 
1343         par = par->FirstPhysicalPar();
1344
1345         LyXLayout const & layout = textclasslist.Style(parameters->textclass, 
1346                                            par->GetLayout());
1347
1348         LyXTextClass const & textclass = textclasslist.TextClass(parameters->textclass);
1349
1350         /* copy the prev-counters to this one, unless this is the start of a 
1351            footnote or of a bibliography or the very first paragraph */
1352         if (par->Previous()
1353             && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE 
1354                     && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1355                     && par->footnotekind == LyXParagraph::FOOTNOTE)
1356             && !(textclasslist.Style(parameters->textclass,
1357                                 par->Previous()->GetLayout()
1358                                 ).labeltype != LABEL_BIBLIO
1359                  && layout.labeltype == LABEL_BIBLIO)) {
1360                 for (i = 0; i<10; i++) {
1361                         par->setCounter(i, par->Previous()->GetFirstCounter(i));
1362                 }
1363                 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1364                 if (!par->appendix && par->start_of_appendix){
1365                   par->appendix = true;
1366                   for (i = 0; i<10; i++) {
1367                     par->setCounter(i, 0);
1368                   }  
1369                 }
1370                 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1371                 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1372         }
1373         else {
1374                 for (i = 0; i<10; i++) {
1375                         par->setCounter(i, 0);
1376                 }  
1377                 par->appendix = par->start_of_appendix;
1378                 par->enumdepth = 0;
1379                 par->itemdepth = 0;
1380         }
1381
1382         // if this is an open marginnote and this is the first
1383         // entry in the marginnote and the enclosing
1384         // environment is an enum/item then correct for the
1385         // LaTeX behaviour (ARRae)
1386         if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1387            && par->footnotekind == LyXParagraph::MARGIN
1388            && par->Previous()
1389            && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1390            && (par->PreviousBeforeFootnote()
1391                && textclasslist.Style(parameters->textclass,
1392                                  par->PreviousBeforeFootnote()->GetLayout()
1393                                  ).labeltype >= LABEL_COUNTER_ENUMI)) {
1394                 // Any itemize or enumerate environment in a marginnote
1395                 // that is embedded in an itemize or enumerate
1396                 // paragraph is seen by LaTeX as being at a deeper
1397                 // level within that enclosing itemization/enumeration
1398                 // even if there is a "standard" layout at the start of
1399                 // the marginnote.
1400                 par->enumdepth++;
1401                 par->itemdepth++;
1402         }
1403
1404         /* Maybe we have to increment the enumeration depth.
1405          * BUT, enumeration in a footnote is considered in isolation from its
1406          *      surrounding paragraph so don't increment if this is the
1407          *      first line of the footnote
1408          * AND, bibliographies can't have their depth changed ie. they
1409          *      are always of depth 0
1410          */
1411         if (par->Previous()
1412             && par->Previous()->GetDepth() < par->GetDepth()
1413             && textclasslist.Style(parameters->textclass,
1414                               par->Previous()->GetLayout()
1415                              ).labeltype == LABEL_COUNTER_ENUMI
1416             && par->enumdepth < 3
1417             && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE 
1418                     && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1419                     && par->footnotekind == LyXParagraph::FOOTNOTE)
1420             && layout.labeltype != LABEL_BIBLIO) {
1421                 par->enumdepth++;
1422         }
1423
1424         /* Maybe we have to decrement the enumeration depth, see note above */
1425         if (par->Previous()
1426             && par->Previous()->GetDepth() > par->GetDepth()
1427             && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1428                     && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1429                     && par->footnotekind == LyXParagraph::FOOTNOTE)
1430             && layout.labeltype != LABEL_BIBLIO) {
1431                 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1432                 par->setCounter(6 + par->enumdepth,
1433                         par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1434                 /* reset the counters.
1435                  * A depth change is like a breaking layout
1436                  */
1437                 for (i = 6 + par->enumdepth + 1; i<10;i++)
1438                         par->setCounter(i, 0);
1439         }
1440    
1441         if (!par->labelstring.empty()) {
1442                 par->labelstring.clear();
1443         }
1444    
1445         if (layout.margintype == MARGIN_MANUAL) {
1446                 if (par->labelwidthstring.empty()) {
1447                         par->SetLabelWidthString(layout.labelstring());
1448                 }
1449         }
1450         else {
1451                 par->SetLabelWidthString(string());
1452         }
1453    
1454         /* is it a layout that has an automatic label ? */ 
1455         if (layout.labeltype >=  LABEL_FIRST_COUNTER) {
1456       
1457                 i = layout.labeltype - LABEL_FIRST_COUNTER;
1458                 if (i >= 0 && i<= parameters->secnumdepth) {
1459                         par->incCounter(i);     // increment the counter  
1460          
1461                         char * s = new char[50];
1462
1463                         // Is there a label? Useful for Chapter layout
1464                         if (!par->appendix){
1465                                 if (!layout.labelstring().empty())
1466                                         par->labelstring = layout.labelstring();
1467                                 else
1468                                         par->labelstring.clear();
1469                         }
1470                         else {
1471                                 if (!layout.labelstring_appendix().empty())
1472                                         par->labelstring = layout.labelstring_appendix();
1473                                 else
1474                                         par->labelstring.clear();
1475                         }
1476  
1477                         if (!par->appendix){
1478                                 switch (2 * LABEL_FIRST_COUNTER -
1479                                         textclass.maxcounter() + i) {
1480                                 case LABEL_COUNTER_CHAPTER:
1481                                         sprintf(s, "%d",
1482                                                 par->getCounter(i));
1483                                         break;
1484                                 case LABEL_COUNTER_SECTION:
1485                                         sprintf(s, "%d.%d",
1486                                                 par->getCounter(i - 1),
1487                                                 par->getCounter(i));
1488                                         break;
1489                                 case LABEL_COUNTER_SUBSECTION:
1490                                         sprintf(s, "%d.%d.%d",
1491                                                 par->getCounter(i-2),
1492                                                 par->getCounter(i-1),
1493                                                 par->getCounter(i));
1494                                         break;
1495                                 case LABEL_COUNTER_SUBSUBSECTION:
1496                                         sprintf(s, "%d.%d.%d.%d",
1497                                                 par->getCounter(i-3),
1498                                                 par->getCounter(i-2),
1499                                                 par->getCounter(i-1),
1500                                                 par->getCounter(i));
1501                                         break;
1502                                 case LABEL_COUNTER_PARAGRAPH:
1503                                         sprintf(s, "%d.%d.%d.%d.%d",
1504                                                 par->getCounter(i-4),
1505                                                 par->getCounter(i-3),
1506                                                 par->getCounter(i-2),
1507                                                 par->getCounter(i-1),
1508                                                 par->getCounter(i));
1509                                         break;
1510                                 case LABEL_COUNTER_SUBPARAGRAPH:
1511                                         sprintf(s, "%d.%d.%d.%d.%d.%d",
1512                                                 par->getCounter(i-5),
1513                                                 par->getCounter(i-4),
1514                                                 par->getCounter(i-3),
1515                                                 par->getCounter(i-2),
1516                                                 par->getCounter(i-1),
1517                                                 par->getCounter(i));
1518                                         break;
1519                                 default:
1520                                         sprintf(s, "%d.", par->getCounter(i));
1521                                         break;
1522                                 }
1523                         }
1524                         else {
1525                                 switch (2 * LABEL_FIRST_COUNTER - textclass.maxcounter() + i) {
1526                                 case LABEL_COUNTER_CHAPTER:
1527                                         sprintf(s, "%s",
1528                                                 alphaCounter(par->getCounter(i)));
1529                                         break;
1530                                 case LABEL_COUNTER_SECTION:
1531                                         sprintf(s, "%s.%d",
1532                                                 alphaCounter(par->getCounter(i - 1)),
1533                                                 par->getCounter(i));
1534                                         break;
1535                                 case LABEL_COUNTER_SUBSECTION:
1536                                         sprintf(s, "%s.%d.%d",
1537                                                 alphaCounter(par->getCounter(i-2)),
1538                                                 par->getCounter(i-1),
1539                                                 par->getCounter(i));
1540                                         break;
1541                                 case LABEL_COUNTER_SUBSUBSECTION:
1542                                         sprintf(s, "%s.%d.%d.%d",
1543                                                 alphaCounter(par->getCounter(i-3)),
1544                                                 par->getCounter(i-2),
1545                                                 par->getCounter(i-1),
1546                                                 par->getCounter(i));
1547                                         break;
1548                                 case LABEL_COUNTER_PARAGRAPH:
1549                                         sprintf(s, "%s.%d.%d.%d.%d",
1550                                                 alphaCounter(par->getCounter(i-4)),
1551                                                 par->getCounter(i-3),
1552                                                 par->getCounter(i-2),
1553                                                 par->getCounter(i-1),
1554                                                 par->getCounter(i));
1555                                         break;
1556                                 case LABEL_COUNTER_SUBPARAGRAPH:
1557                                         sprintf(s, "%s.%d.%d.%d.%d.%d",
1558                                                 alphaCounter(par->getCounter(i-5)),
1559                                                 par->getCounter(i-4),
1560                                                 par->getCounter(i-3),
1561                                                 par->getCounter(i-2),
1562                                                 par->getCounter(i-1),
1563                                                 par->getCounter(i));
1564                                         break;
1565                                 default:
1566                                         sprintf(s, "%c.", par->getCounter(i));
1567                                         break;
1568                                 }
1569                         }
1570          
1571                         par->labelstring += s;
1572                         delete[] s;
1573          
1574                         for (i++; i<10; i++) {
1575                                 /* reset the following counters  */
1576                                 par->setCounter(i, 0);
1577                         }
1578                 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1579                         for (i++; i<10; i++) {
1580                                 /* reset the following counters  */
1581                                 par->setCounter(i, 0);
1582                         }
1583                 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1584                         par->incCounter(i + par->enumdepth);
1585                         char * s = new char[25];
1586                         int number = par->getCounter(i + par->enumdepth);
1587                         switch (par->enumdepth) {
1588                         case 1:
1589                                 sprintf(s, "(%c)", (number % 27) + 'a' - 1);
1590                                 break;
1591                         case 2:
1592                                 switch (number) {
1593                                 case 1: sprintf(s, "i."); break;
1594                                 case 2: sprintf(s, "ii."); break;
1595                                 case 3: sprintf(s, "iii."); break;
1596                                 case 4: sprintf(s, "iv."); break;
1597                                 case 5: sprintf(s, "v."); break;
1598                                 case 6: sprintf(s, "vi."); break;
1599                                 case 7: sprintf(s, "vii."); break;
1600                                 case 8: sprintf(s, "viii."); break;
1601                                 case 9: sprintf(s, "ix."); break;
1602                                 case 10: sprintf(s, "x."); break;
1603                                 case 11: sprintf(s, "xi."); break;
1604                                 case 12: sprintf(s, "xii."); break;
1605                                 case 13: sprintf(s, "xiii."); break;
1606                                 default:
1607                                         sprintf(s, "\\roman{%d}.", number);
1608                                         break;
1609                                 }
1610                                 break;
1611                         case 3:
1612                                 sprintf(s, "%c.", (number % 27) + 'A' - 1);
1613                                 break;
1614                         default:
1615                                 sprintf(s, "%d.", number);
1616                                 break;
1617                         }
1618                         par->labelstring = s;
1619                         delete[] s;
1620
1621                         for (i += par->enumdepth + 1;i<10;i++)
1622                                 par->setCounter(i, 0);  /* reset the following counters  */
1623          
1624                 } 
1625         } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1626             i = LABEL_COUNTER_ENUMI - LABEL_FIRST_COUNTER + par->enumdepth;
1627             par->incCounter(i);
1628             int number = par->getCounter(i);
1629             if (!par->bibkey)
1630               par->bibkey = new InsetBibKey();
1631             par->bibkey->setCounter(number);
1632             par->labelstring = layout.labelstring();
1633             
1634             // In biblio should't be following counters but...
1635         }                                               
1636         else  {
1637                 string s = layout.labelstring();
1638       
1639                 /* the caption hack: */
1640       
1641                 if (layout.labeltype == LABEL_SENSITIVE) {
1642                         if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1643                             && (par->footnotekind == LyXParagraph::FIG
1644                             || par->footnotekind == LyXParagraph::WIDE_FIG))
1645                                 s = "Figure:";
1646                         else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1647                                  && (par->footnotekind == LyXParagraph::TAB
1648                                  || par->footnotekind == LyXParagraph::WIDE_TAB))
1649                                 s = "Table:";
1650                         else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1651                                  && par->footnotekind == LyXParagraph::ALGORITHM)
1652                                 s = "Algorithm:";
1653                         else {
1654                                 /* par->SetLayout(0); 
1655                                    s = layout->labelstring;  */
1656                                 s = "Senseless: "; 
1657            
1658                         }
1659                 }
1660                 par->labelstring = s;
1661       
1662                 /* reset the enumeration counter. They are always resetted
1663                  * when there is any other layout between */ 
1664                 for (i = 6 + par->enumdepth; i<10;i++)
1665                         par->setCounter(i, 0);
1666         }
1667 }
1668
1669
1670 /* Updates all counters BEHIND the row. Changed paragraphs
1671 * with a dynamic left margin will be rebroken. */ 
1672 void LyXText::UpdateCounters(Row * row)
1673 {
1674         LyXParagraph * par;
1675         if (!row) {
1676                 row = firstrow;
1677                 par = row->par;
1678         }
1679         else {
1680                 if (row->par->next && row->par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
1681                         par = row->par->LastPhysicalPar()->Next();
1682                 } else {
1683                         par = row->par->next;
1684                 }
1685         }
1686
1687         while (par) {
1688                 while (row->par != par)
1689                         row = row->next;
1690       
1691                 SetCounter(par);
1692       
1693                 /* now  check for the headline layouts. remember that they
1694                  * have a dynamic left margin */ 
1695                 if (!par->IsDummy()
1696                     && ( textclasslist.Style(parameters->textclass, par->layout).margintype == MARGIN_DYNAMIC
1697                          || textclasslist.Style(parameters->textclass, par->layout).labeltype == LABEL_SENSITIVE)
1698                         ){
1699          
1700                         /* Rebreak the paragraph */ 
1701                         RemoveParagraph(row);
1702                         AppendParagraph(row);
1703        
1704                         /* think about the damned open footnotes! */ 
1705                         while (par->Next() &&
1706                                (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1707                                 || par->Next()->IsDummy())){
1708                                 par = par->Next();
1709                                 if (par->IsDummy()) {
1710                                         while (row->par != par)
1711                                                 row = row->next;
1712                                         RemoveParagraph(row);
1713                                         AppendParagraph(row);
1714                                 }
1715                         }
1716                 }
1717      
1718                 par = par->LastPhysicalPar()->Next();
1719      
1720         }
1721 }
1722
1723
1724 /* insets an inset. */ 
1725 void LyXText::InsertInset(Inset *inset)
1726 {
1727         SetUndo(Undo::INSERT, 
1728                 cursor.par->ParFromPos(cursor.pos)->previous, 
1729                 cursor.par->ParFromPos(cursor.pos)->next);
1730         cursor.par->InsertChar(cursor.pos, LyXParagraph::META_INSET);
1731         cursor.par->InsertInset(cursor.pos, inset);
1732         InsertChar(LyXParagraph::META_INSET);  /* just to rebreak and refresh correctly.
1733                                       * The character will not be inserted a
1734                                       * second time */
1735 }
1736
1737
1738 /* this is for the simple cut and paste mechanism */ 
1739 static LyXParagraph * simple_cut_buffer = 0;
1740 static char simple_cut_buffer_textclass = 0;
1741
1742 void DeleteSimpleCutBuffer()
1743 {
1744         if (!simple_cut_buffer)
1745                 return;
1746         LyXParagraph *tmppar;
1747
1748         while (simple_cut_buffer) {
1749                 tmppar =  simple_cut_buffer;
1750                 simple_cut_buffer = simple_cut_buffer->next;
1751                 delete tmppar;
1752         }
1753         simple_cut_buffer = 0;
1754 }
1755
1756
1757 void LyXText::copyEnvironmentType()
1758 {
1759         copylayouttype = cursor.par->GetLayout();
1760 }
1761
1762
1763 void LyXText::pasteEnvironmentType()
1764 {
1765         SetLayout(copylayouttype);
1766 }
1767
1768
1769 void LyXText::CutSelection(bool doclear)
1770 {
1771         /* This doesn't make sense, if there is no selection */ 
1772         if (!selection) {
1773                 return;
1774         }
1775    
1776         /* OK, we have a selection. This is always between sel_start_cursor
1777          * and sel_end cursor */
1778         LyXParagraph * tmppar;
1779    
1780         /* Check whether there are half footnotes in the selection */
1781         if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1782             || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE){
1783                 tmppar = sel_start_cursor.par;
1784                 while (tmppar != sel_end_cursor.par){
1785                         if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag){
1786                                 WriteAlert(_("Impossible operation"), _("Don't know what to do with half floats."), _("sorry."));
1787                                 return;
1788                         }
1789                         tmppar = tmppar->Next();
1790                 }
1791         }
1792
1793         /* table stuff -- begin*/
1794         if (sel_start_cursor.par->table || sel_end_cursor.par->table){
1795                 if ( sel_start_cursor.par != sel_end_cursor.par){
1796                         WriteAlert(_("Impossible operation"), _("Don't know what to do with half tables."), _("sorry."));
1797                         return;
1798                 }
1799                 sel_start_cursor.par->table->Reinit();
1800         }
1801         /* table stuff -- end*/
1802
1803         // make sure that the depth behind the selection are restored, too
1804         LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1805         LyXParagraph * undoendpar = endpar;
1806
1807         if (endpar && endpar->GetDepth()) {
1808                 while (endpar && endpar->GetDepth()) {
1809                         endpar = endpar->LastPhysicalPar()->Next();
1810                         undoendpar = endpar;
1811                 }
1812         }
1813         else if (endpar) {
1814                 endpar = endpar->Next();               /* because of parindents etc.  */
1815         }
1816    
1817         SetUndo(Undo::DELETE, 
1818                 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous, 
1819                 undoendpar);
1820    
1821         /* delete the simple_cut_buffer */ 
1822         DeleteSimpleCutBuffer();
1823    
1824         /* set the textclass */
1825         simple_cut_buffer_textclass = parameters->textclass;
1826
1827 #ifdef WITH_WARNINGS
1828 #warning Asger: Make cut more intelligent here.
1829 #endif
1830 /* 
1831 White paper for "intelligent" cutting:
1832
1833 Example: "This is our text."
1834 Using " our " as selection, cutting will give "This istext.".
1835 Using "our" as selection, cutting will give "This is text.".
1836 Using " our" as selection, cutting will give "This is text.".
1837 Using "our " as selection, cutting will give "This is text.".
1838
1839 All those four selections will (however) paste identically:
1840 Pasting with the cursor right after the "is" will give the
1841 original text with all four selections.
1842
1843 The rationale is to be intelligent such that words are copied,
1844 cut and pasted in a functional manner.
1845
1846 This is not implemented yet.
1847 */
1848
1849         bool space_wrapped =
1850                 sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos);
1851         if (sel_end_cursor.pos > 0
1852             && sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos - 1)) {
1853                 sel_end_cursor.pos--;  /* please break before a space at
1854                                         * the end */
1855                 space_wrapped = true;
1856         }
1857
1858         // cut behind a space if there is one
1859         while (sel_start_cursor.par->Last() > sel_start_cursor.pos
1860                && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
1861                && (sel_start_cursor.par != sel_end_cursor.par
1862                    || sel_start_cursor.pos < sel_end_cursor.pos))
1863                 sel_start_cursor.pos++; 
1864    
1865         /* there are two cases: cut only within one paragraph or
1866          * more than one paragraph */
1867    
1868         if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos) 
1869             == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
1870                 /* only within one paragraph */
1871                 simple_cut_buffer = new LyXParagraph;
1872                 LyXParagraph::size_type i =
1873                         sel_start_cursor.pos;
1874                 for (; i< sel_end_cursor.pos; i++){
1875                         /* table stuff -- begin*/
1876                         if (sel_start_cursor.par->table
1877                             && sel_start_cursor.par->IsNewline(sel_start_cursor.pos)){
1878                                 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
1879                                 sel_start_cursor.pos++;
1880                         } else {
1881                                 /* table stuff -- end*/
1882                                 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
1883                                 sel_start_cursor.par->Erase(sel_start_cursor.pos);
1884                         }
1885                         simple_cut_buffer->InsertFromMinibuffer(simple_cut_buffer->Last());
1886                 }
1887                 /* check for double spaces */
1888                 if (sel_start_cursor.pos &&
1889                     sel_start_cursor.par->Last()>sel_start_cursor.pos &&
1890                     sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1) &&
1891                     sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)){
1892                         sel_start_cursor.par->Erase(sel_start_cursor.pos);
1893                 }
1894                 if (space_wrapped)
1895                         simple_cut_buffer->InsertChar(i - sel_start_cursor.pos, ' ');
1896                 endpar = sel_end_cursor.par->Next();
1897         }
1898         else {
1899                 /* cut more than one paragraph */ 
1900    
1901                 sel_end_cursor.par->BreakParagraphConservative(sel_end_cursor.pos);
1902                 /* insert a space at the end if there was one */
1903                 if (space_wrapped)
1904                         sel_end_cursor.par->InsertChar(sel_end_cursor.par->Last(), ' ');
1905    
1906                 sel_end_cursor.par = sel_end_cursor.par->Next();
1907                 sel_end_cursor.pos = 0;
1908    
1909                 cursor = sel_end_cursor;
1910    
1911                 /* please break behind a space, if there is one. The space should
1912                  * be copied too */ 
1913                 if (sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos))
1914                         sel_start_cursor.pos++;
1915    
1916                 sel_start_cursor.par->BreakParagraphConservative(sel_start_cursor.pos);
1917                 if (!sel_start_cursor.pos
1918                     || sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1)
1919                     || sel_start_cursor.par->IsNewline(sel_start_cursor.pos - 1)) {
1920                         sel_start_cursor.par->Next()->InsertChar(0, ' ');
1921                 }
1922    
1923                 /* store the endparagraph for redoing later */
1924                 endpar = sel_end_cursor.par->Next();   /* needed because
1925                                                         * the sel_end_
1926                                                         * cursor.par
1927                                                         * will be pasted!*/
1928    
1929                 /*store the selection */ 
1930                 simple_cut_buffer = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->next;
1931                 simple_cut_buffer->previous = 0;
1932                 sel_end_cursor.par->previous->next = 0;
1933
1934                 /* cut the selection */ 
1935                 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->next 
1936                         = sel_end_cursor.par;
1937    
1938                 sel_end_cursor.par->previous 
1939                         = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
1940
1941                 /* care about footnotes */
1942                 if (simple_cut_buffer->footnoteflag) {
1943                         LyXParagraph *tmppar = simple_cut_buffer;
1944                         while (tmppar){
1945                                 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1946                                 tmppar = tmppar->next;
1947                         }
1948                 }
1949
1950                 /* the cut selection should begin with standard layout */
1951                 simple_cut_buffer->Clear(); 
1952    
1953                 /* paste the paragraphs again, if possible  */
1954                 if (doclear)
1955                         sel_start_cursor.par->Next()->ClearParagraph();
1956                 if (sel_start_cursor.par->FirstPhysicalPar()->HasSameLayout(sel_start_cursor.par->Next())
1957                     || 
1958                     !sel_start_cursor.par->Next()->Last())
1959                         sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->PasteParagraph();
1960
1961    
1962                 /* maybe a forgotten blank */
1963                 if (sel_start_cursor.pos 
1964                     && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
1965                     && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1)) {
1966                         sel_start_cursor.par->Erase(sel_start_cursor.pos);
1967                 }
1968         }   
1969
1970
1971         /* sometimes necessary */
1972         if (doclear)
1973                 sel_start_cursor.par->ClearParagraph();
1974
1975         RedoParagraphs(sel_start_cursor, endpar);
1976    
1977         ClearSelection();
1978         cursor = sel_start_cursor;
1979         SetCursor(cursor.par, cursor.pos);
1980         sel_cursor = cursor;
1981         UpdateCounters(cursor.row);
1982 }
1983
1984     
1985 void LyXText::CopySelection()
1986 {
1987         LyXParagraph::size_type i = 0;
1988         /* this doesnt make sense, if there is no selection */ 
1989         if (!selection) {
1990                 return;
1991         }
1992
1993         /* ok we have a selection. This is always between sel_start_cursor
1994          * and sel_end cursor */
1995         LyXParagraph * tmppar;
1996    
1997         /* check wether there are half footnotes in the selection */
1998         if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1999             || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE){
2000                 tmppar = sel_start_cursor.par;
2001                 while (tmppar != sel_end_cursor.par){
2002                         if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag){
2003                                 WriteAlert(_("Impossible operation"), _("Don't know what to do with half floats."), _("sorry."));
2004                                 return;
2005                         }
2006                         tmppar = tmppar->Next();
2007                 }
2008         }
2009
2010         /* table stuff -- begin*/
2011         if (sel_start_cursor.par->table || sel_end_cursor.par->table){
2012                 if ( sel_start_cursor.par != sel_end_cursor.par){
2013                         WriteAlert(_("Impossible operation"), _("Don't know what to do with half tables."), _("sorry."));
2014                         return;
2015                 }
2016         }
2017         /* table stuff -- end*/
2018    
2019         /* delete the simple_cut_buffer */ 
2020         DeleteSimpleCutBuffer();
2021
2022         /* set the textclass */
2023         simple_cut_buffer_textclass = parameters->textclass;
2024
2025         // copy behind a space if there is one
2026         while (sel_start_cursor.par->Last() > sel_start_cursor.pos
2027                && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
2028                && (sel_start_cursor.par != sel_end_cursor.par
2029                    || sel_start_cursor.pos < sel_end_cursor.pos))
2030                 sel_start_cursor.pos++; 
2031
2032         /* there are two cases: copy only within one paragraph or more than one paragraph */
2033         if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos) 
2034             == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2035                 /* only within one paragraph */
2036                 simple_cut_buffer = new LyXParagraph;
2037                 for (i = sel_start_cursor.pos; i < sel_end_cursor.pos; ++i){
2038                         sel_start_cursor.par->CopyIntoMinibuffer(i);
2039                         simple_cut_buffer->InsertFromMinibuffer(i - sel_start_cursor.pos);
2040                 }
2041         }
2042         else {
2043                 /* copy more than one paragraph */ 
2044                 /* clone the paragraphs within the selection*/
2045                 tmppar = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
2046                 simple_cut_buffer = tmppar->Clone();
2047                 LyXParagraph *tmppar2 = simple_cut_buffer;
2048      
2049                 while (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)
2050                        && tmppar->next) {
2051                         tmppar = tmppar->next;
2052                         tmppar2->next = tmppar->Clone();
2053                         tmppar2->next->previous = tmppar2;
2054                         tmppar2 = tmppar2->next;
2055                 }
2056                 tmppar2->next = 0;
2057
2058                 /* care about footnotes */
2059                 if (simple_cut_buffer->footnoteflag) {
2060                         tmppar = simple_cut_buffer;
2061                         while (tmppar){
2062                                 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
2063                                 tmppar = tmppar->next;
2064                         }
2065                 }
2066      
2067                 /* the simple_cut_buffer paragraph is too big */
2068                 LyXParagraph::size_type tmpi2 =
2069                         sel_start_cursor.par->PositionInParFromPos(sel_start_cursor.pos);
2070                 for (;tmpi2;tmpi2--)
2071                         simple_cut_buffer->Erase(0);
2072
2073                 /* now tmppar 2 is too big, delete all after sel_end_cursor.pos */
2074      
2075                 tmpi2 = sel_end_cursor.par->PositionInParFromPos(sel_end_cursor.pos);
2076                 while (tmppar2->size() > tmpi2) {
2077                         tmppar2->Erase(tmppar2->text.size() - 1);
2078                 }
2079         }
2080 }
2081           
2082
2083 void LyXText::PasteSelection()
2084 {
2085         /* this does not make sense, if there is nothing to paste */ 
2086         if (!simple_cut_buffer)
2087                 return;
2088
2089         LyXParagraph * tmppar;
2090         LyXParagraph * endpar;
2091
2092         LyXCursor tmpcursor;
2093
2094         /* be carefull with footnotes in footnotes */ 
2095         if (cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2096       
2097                 /* check whether the cut_buffer includes a footnote */
2098                 tmppar = simple_cut_buffer;
2099                 while (tmppar && tmppar->footnoteflag == LyXParagraph::NO_FOOTNOTE)
2100                         tmppar = tmppar->next;
2101       
2102                 if (tmppar) {
2103                         WriteAlert(_("Impossible operation"),
2104                                    _("Can't paste float into float!"), _("Sorry."));
2105                         return;
2106                 }
2107         }
2108
2109         /* table stuff -- begin*/
2110         if (cursor.par->table){
2111                 if (simple_cut_buffer->next){
2112                         WriteAlert(_("Impossible operation"),
2113                                    _("Table cell cannot include more than one paragraph!"),
2114                                    _("Sorry."));
2115                         return;
2116                 }
2117         }
2118         /* table stuff -- end*/
2119    
2120         SetUndo(Undo::INSERT, 
2121                 cursor.par->ParFromPos(cursor.pos)->previous, 
2122                 cursor.par->ParFromPos(cursor.pos)->next); 
2123
2124         tmpcursor = cursor;
2125
2126         /* There are two cases: cutbuffer only one paragraph or many */
2127         if (!simple_cut_buffer->next) {
2128                 /* only within a paragraph */
2129      
2130                 /* please break behind a space, if there is one */
2131                 while (tmpcursor.par->Last() > tmpcursor.pos
2132                        && tmpcursor.par->IsLineSeparator(tmpcursor.pos))
2133                         tmpcursor.pos++; 
2134
2135                 tmppar = simple_cut_buffer->Clone();
2136                 /* table stuff -- begin*/
2137                 bool table_too_small = false;
2138                 if (tmpcursor.par->table) {
2139                         while (simple_cut_buffer->text.size()
2140                                && !table_too_small) {
2141                                 if (simple_cut_buffer->IsNewline(0)){
2142                                         while(tmpcursor.pos < tmpcursor.par->Last() && !tmpcursor.par->IsNewline(tmpcursor.pos))
2143                                                 tmpcursor.pos++;
2144                                         simple_cut_buffer->Erase(0);
2145                                         if (tmpcursor.pos < tmpcursor.par->Last())
2146                                                 tmpcursor.pos++;
2147                                         else
2148                                                 table_too_small = true;
2149                                 } else {
2150                                         simple_cut_buffer->CutIntoMinibuffer(0);
2151                                         simple_cut_buffer->Erase(0);
2152                                         tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2153                                         tmpcursor.pos++;
2154                                 }
2155                         }
2156                 } else {
2157                         /* table stuff -- end*/
2158                         while (simple_cut_buffer->text.size()){
2159                                 simple_cut_buffer->CutIntoMinibuffer(0);
2160                                 simple_cut_buffer->Erase(0);
2161                                 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2162                                 tmpcursor.pos++;
2163                         }
2164                 }
2165
2166                 delete simple_cut_buffer;
2167                 simple_cut_buffer = tmppar;
2168                 endpar = tmpcursor.par->Next();
2169         } else {
2170                 /* many paragraphs */
2171
2172                 /* make a copy of the simple cut_buffer */
2173                 tmppar = simple_cut_buffer;
2174                 LyXParagraph * simple_cut_clone = tmppar->Clone();
2175                 LyXParagraph * tmppar2 = simple_cut_clone;
2176                 if (cursor.par->footnoteflag){
2177                         tmppar->footnoteflag = cursor.par->footnoteflag;
2178                         tmppar->footnotekind = cursor.par->footnotekind;
2179                 }
2180                 while (tmppar->next) {
2181                         tmppar = tmppar->next;
2182                         tmppar2->next = tmppar->Clone();
2183                         tmppar2->next->previous = tmppar2;
2184                         tmppar2 = tmppar2->next;
2185                         if (cursor.par->footnoteflag){
2186                                 tmppar->footnoteflag = cursor.par->footnoteflag;
2187                                 tmppar->footnotekind = cursor.par->footnotekind;
2188                         }
2189                 }
2190      
2191                 /* make sure there is no class difference */ 
2192                 SwitchLayoutsBetweenClasses(simple_cut_buffer_textclass,
2193                                             parameters->textclass,
2194                                             simple_cut_buffer);
2195      
2196                 /* make the simple_cut_buffer exactly the same layout than
2197                    the cursor paragraph */
2198                 simple_cut_buffer->MakeSameLayout(cursor.par);
2199      
2200                 /* find the end of the buffer */ 
2201                 LyXParagraph *lastbuffer = simple_cut_buffer;
2202                 while (lastbuffer->Next())
2203                         lastbuffer = lastbuffer->Next();
2204      
2205                 /* find the physical end of the buffer */ 
2206                 lastbuffer = simple_cut_buffer;
2207                 while (lastbuffer->Next())
2208                         lastbuffer = lastbuffer->Next();
2209      
2210                 /* please break behind a space, if there is one. The space 
2211                  * should be copied too */
2212                 if (cursor.par->Last() > cursor.pos && cursor.par->IsLineSeparator(cursor.pos))
2213                         cursor.pos++; 
2214      
2215                 bool paste_the_end = false;
2216
2217                 /* open the paragraph for inserting the simple_cut_buffer
2218                    if necessary */
2219                 if (cursor.par->Last() > cursor.pos || !cursor.par->Next()){
2220                         cursor.par->BreakParagraphConservative(cursor.pos);
2221                         paste_the_end = true;
2222                 }
2223      
2224                 /* be careful with double spaces */ 
2225                 if ((!cursor.par->Last()
2226                      || cursor.par->IsLineSeparator(cursor.pos - 1)
2227                      || cursor.par->IsNewline(cursor.pos - 1))
2228                     && simple_cut_buffer->text.size()
2229                     && simple_cut_buffer->IsLineSeparator(0))
2230                         simple_cut_buffer->Erase(0);
2231      
2232                 /* set the end for redoing later */ 
2233                 endpar = cursor.par->ParFromPos(cursor.pos)->next->Next();
2234      
2235                 /* paste it! */ 
2236                 lastbuffer->ParFromPos(lastbuffer->Last())->next = cursor.par->ParFromPos(cursor.pos)->next;
2237                 cursor.par->ParFromPos(cursor.pos)->next->previous = lastbuffer->ParFromPos(lastbuffer->Last());
2238      
2239                 cursor.par->ParFromPos(cursor.pos)->next = simple_cut_buffer;
2240                 simple_cut_buffer->previous = cursor.par->ParFromPos(cursor.pos);
2241    
2242                 if (cursor.par->ParFromPos(cursor.pos)->Next() == lastbuffer)
2243                         lastbuffer = cursor.par;
2244      
2245                 cursor.par->ParFromPos(cursor.pos)->PasteParagraph();
2246      
2247                 /* store the new cursor position  */
2248                 tmpcursor.par = lastbuffer;
2249                 tmpcursor.pos = lastbuffer->Last();
2250      
2251                 /* maybe some pasting */ 
2252                 if (lastbuffer->Next() && paste_the_end) {
2253                         if (lastbuffer->Next()->HasSameLayout(lastbuffer)) {
2254          
2255                                 /* be careful witth double spaces */ 
2256                                 if ((!lastbuffer->Last()
2257                                      || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2258                                      || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2259                                     && lastbuffer->Next()->Last()
2260                                     && lastbuffer->Next()->IsLineSeparator(0))
2261                                         lastbuffer->Next()->Erase(0);
2262          
2263                                 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2264          
2265                         }
2266                         else if (!lastbuffer->Next()->Last()) {
2267                                 lastbuffer->Next()->MakeSameLayout(lastbuffer);
2268          
2269                                 /* be careful witth double spaces */ 
2270                                 if ((!lastbuffer->Last()
2271                                      || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2272                                      || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2273                                     && lastbuffer->Next()->Last()
2274                                     && lastbuffer->Next()->IsLineSeparator(0))
2275                                         lastbuffer->Next()->Erase(0);
2276          
2277                                 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2278          
2279                         }
2280                         else if (!lastbuffer->Last()) {
2281                                 lastbuffer->MakeSameLayout(lastbuffer->next);
2282          
2283                                 /* be careful witth double spaces */ 
2284                                 if ((!lastbuffer->Last()
2285                                      || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2286                                      || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2287                                     && lastbuffer->Next()->Last()
2288                                     && lastbuffer->Next()->IsLineSeparator(0))
2289                                         lastbuffer->Next()->Erase(0);
2290          
2291                                 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2292          
2293                         }
2294                         else lastbuffer->Next()->ClearParagraph();
2295                 }
2296
2297                 /* restore the simple cut buffer */
2298                 simple_cut_buffer = simple_cut_clone;
2299         }
2300
2301         RedoParagraphs(cursor, endpar);
2302     
2303         SetCursor(cursor.par, cursor.pos);
2304         ClearSelection();
2305    
2306         sel_cursor = cursor;
2307         SetCursor(tmpcursor.par, tmpcursor.pos);
2308         SetSelection();
2309         UpdateCounters(cursor.row);
2310 }
2311    
2312
2313 /* returns a pointer to the very first LyXParagraph */ 
2314 LyXParagraph * LyXText::FirstParagraph()
2315 {
2316         return params->paragraph;
2317 }
2318
2319
2320 /* returns true if the specified string is at the specified position */
2321 bool LyXText::IsStringInText(LyXParagraph * par,
2322                              LyXParagraph::size_type pos,
2323                              char const * str)
2324 {
2325         if (par) {
2326                 int i = 0;
2327                 while (pos + i < par->Last() && str[i] && 
2328                        str[i] == par->GetChar(pos + i)) {
2329                         ++i;
2330                 }
2331                 if (!str[i])
2332                         return true;
2333         }
2334         return false;
2335 }
2336
2337
2338 /* sets the selection over the number of characters of string, no check!! */
2339 void LyXText::SetSelectionOverString(char const * string)
2340 {
2341         sel_cursor = cursor;
2342         for (int i = 0; string[i]; ++i)
2343                 CursorRight();
2344         SetSelection();
2345 }
2346
2347
2348 /* simple replacing. The font of the first selected character is used */
2349 void LyXText::ReplaceSelectionWithString(char const * str)
2350 {
2351         SetCursorParUndo();
2352         FreezeUndo();
2353
2354         if (!selection) { /* create a dummy selection */
2355                 sel_end_cursor = cursor;
2356                 sel_start_cursor = cursor;
2357         }
2358
2359         // Get font setting before we cut
2360         LyXParagraph::size_type pos = sel_end_cursor.pos;
2361         LyXFont font = sel_start_cursor.par->GetFontSettings(sel_start_cursor.pos);
2362
2363         // Insert the new string
2364         for (int i = 0; str[i]; ++i) {
2365                 sel_end_cursor.par->InsertChar(pos, str[i]);
2366                 sel_end_cursor.par->SetFont(pos, font);
2367                 ++pos;
2368         }
2369
2370         // Cut the selection
2371         CutSelection();
2372
2373         UnFreezeUndo();
2374 }
2375
2376
2377 /* if the string can be found: return true and set the cursor to
2378  * the new position */
2379 bool LyXText::SearchForward(char const * str)
2380 {
2381         LyXParagraph * par = cursor.par;
2382         LyXParagraph::size_type pos = cursor.pos;
2383         while (par && !IsStringInText(par, pos, str)) {
2384                 if (pos < par->Last() - 1)
2385                         ++pos;
2386                 else {
2387                         pos = 0;
2388                         par = par->Next();
2389                 }
2390         }
2391         if (par) {
2392                 SetCursor(par, pos);
2393                 return true;
2394         }
2395         else
2396                 return false;
2397 }
2398
2399
2400 bool LyXText::SearchBackward(char const * string)
2401 {
2402         LyXParagraph * par = cursor.par;
2403         int pos = cursor.pos;
2404
2405         do {
2406                 if (pos>0)
2407                         pos--;
2408                 else {
2409                         // We skip empty paragraphs (Asger)
2410                         do {
2411                                 par = par->Previous();
2412                                 if (par)
2413                                         pos = par->Last()-1;
2414                         } while (par && pos<0);
2415                 }
2416         } while (par && !IsStringInText(par, pos, string));
2417   
2418         if (par) {
2419                 SetCursor(par, pos);
2420                 return true;
2421         }
2422         else
2423                 return false;
2424 }
2425
2426
2427 void LyXText::InsertStringA(LyXParagraph::TextContainer const & text)
2428 {
2429         char * str = new char[text.size() + 1];
2430         copy(text.begin(), text.end(), str);
2431         str[text.size()] = '\0';
2432         InsertStringA(str);
2433         delete [] str;
2434 }
2435
2436
2437 /* needed to insert the selection */
2438 void LyXText::InsertStringA(char const * s)
2439 {
2440         string str(s);
2441         LyXParagraph * par = cursor.par;
2442         LyXParagraph::size_type pos = cursor.pos;
2443         LyXParagraph::size_type a = 0;
2444         int cell = 0;
2445         LyXParagraph * endpar = cursor.par->Next();
2446
2447         SetCursorParUndo();
2448
2449         char flag = textclasslist.Style(parameters->textclass, 
2450                                    cursor.par->GetLayout()).isEnvironment();
2451         /* only to be sure, should not be neccessary */ 
2452         ClearSelection();
2453    
2454         /* insert the string, don't insert doublespace */ 
2455         string::size_type i = 0;
2456         while (i < str.length()) {
2457                 if (str[i] != '\n') {
2458                         if (str[i] == ' ' 
2459                             && i+1<str.length() && str[i+1]!= ' '
2460                             && pos && par->GetChar(pos-1)!= ' ') {
2461                                 par->InsertChar(pos,' ');
2462                                 pos++;
2463                         }
2464                         else if (par->table) {
2465                             if (str[i] == '\t') {
2466                                 while((pos < par->size()) &&
2467                                       (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2468                                         ++pos;
2469                                 if (pos < par->size())
2470                                         ++pos;
2471                                 else // no more fields to fill skip the rest
2472                                         break;
2473                             } else if ((str[i] != 13) &&
2474                                 ((str[i] & 127) >= ' ')) {
2475                                 par->InsertChar(pos, str[i]);
2476                                 pos++;
2477                             }
2478                         }
2479                         else if (str[i] == ' ') {
2480                                 par->InsertChar(pos, LyXParagraph::META_PROTECTED_SEPARATOR);
2481                                 pos++;
2482                         }
2483                         else if (str[i] == '\t') {
2484                                 for (a = pos; a < (pos/8 + 1) * 8 ; ++a) {
2485                                         par->InsertChar(a, LyXParagraph::META_PROTECTED_SEPARATOR);
2486                                 }
2487                                 pos = a;
2488                         }
2489                         else if (str[i]!= 13 && 
2490                                  // Ignore unprintables
2491                                  (str[i] & 127) >= ' ') {
2492                                 par->InsertChar(pos, str[i]);
2493                                 pos++;
2494                         }
2495                 } else {
2496                         if (par->table) {
2497                                 if (i+1>=str.length()) {
2498                                         pos++;
2499                                         break;
2500                                 }
2501                                 while((pos < par->size()) &&
2502                                       (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2503                                         pos++;
2504                                 pos++;
2505                                 cell = NumberOfCell(par, pos);
2506                                 while((pos < par->size()) &&
2507                                       !(par->table->IsFirstCell(cell))) {
2508                                         while((pos < par->size()) &&
2509                                               (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2510                                                 ++pos;
2511                                         ++pos;
2512                                         cell = NumberOfCell(par, pos);
2513                                 }
2514                                 if (pos >= par->size())
2515                                         // no more fields to fill skip the rest
2516                                         break;
2517                         } else {
2518                                 if (!par->text.size()) {
2519                                         par->InsertChar(pos, LyXParagraph::META_PROTECTED_SEPARATOR);
2520                                         pos++;
2521                                 }
2522                                 par->BreakParagraph(pos, flag);
2523                                 par = par->Next();
2524                                 pos = 0;
2525                         }
2526                 }
2527       
2528                 i++;
2529         }
2530    
2531         RedoParagraphs(cursor, endpar);
2532         SetCursor(cursor.par, cursor.pos);
2533         sel_cursor = cursor;
2534         SetCursor(par, pos);
2535         SetSelection();
2536 }
2537
2538
2539 void LyXText::InsertStringB(LyXParagraph::TextContainer const & text)
2540 {
2541         char * str = new char[text.size() + 1];
2542         copy(text.begin(), text.end(), str);
2543         str[text.size()] = '\0';
2544         InsertStringB(str);
2545         delete [] str;
2546 }
2547
2548
2549 /* turns double-CR to single CR, others where converted into one blank and 13s 
2550  * that are ignored .Double spaces are also converted into one. Spaces at
2551  * the beginning of a paragraph are forbidden. tabs are converted into one
2552  * space. then InsertStringA is called */ 
2553 void LyXText::InsertStringB(char const * s)
2554 {
2555         string str(s);
2556         LyXParagraph * par = cursor.par;
2557         string::size_type i = 1;
2558         while (i < str.length()) {
2559                 if (str[i] == '\t' && !par->table)
2560                         str[i] = ' ';
2561                 if (str[i] == ' ' && i+1 < str.length() && str[i + 1] == ' ')
2562                         str[i] = 13;
2563                 if (str[i] == '\n' && i+1 < str.length() && !par->table){
2564                         if (str[i + 1] != '\n') {
2565                                 if (str[i - 1] != ' ')
2566                                         str[i] = ' ';
2567                                 else
2568                                         str[i] = 13;
2569                         }
2570                         while (i+1 < str.length() 
2571                                && (str[i + 1] == ' ' 
2572                                    || str[i + 1] == '\t'
2573                                    || str[i + 1] == '\n' 
2574                                    || str[i + 1] == 13)) {
2575                                 str[i + 1] = 13;
2576                                 ++i;
2577                         }
2578                 }
2579                 ++i;
2580         }
2581         InsertStringA(str.c_str());
2582 }
2583
2584
2585 bool LyXText::GotoNextError()
2586 {
2587         LyXCursor res = cursor;
2588         do {
2589                 if (res.pos < res.par->Last() - 1) {
2590                         res.pos++;
2591                 }
2592                 else  {
2593                         res.par = res.par->Next();
2594                         res.pos = 0;
2595                 }
2596       
2597         } while (res.par && 
2598                  !(res.par->GetChar(res.pos) == LyXParagraph::META_INSET
2599                    && res.par->GetInset(res.pos)->AutoDelete()));
2600    
2601         if (res.par) {
2602                 SetCursor(res.par, res.pos);
2603                 return true;
2604         }
2605    
2606         return false;
2607 }
2608
2609
2610 bool LyXText::GotoNextNote()
2611 {
2612         LyXCursor res = cursor;
2613         do {
2614                 if (res.pos < res.par->Last()-1) {
2615                         res.pos++;
2616                 }
2617                 else  {
2618                         res.par = res.par->Next();
2619                         res.pos = 0;
2620                 }
2621       
2622         } while (res.par && 
2623                  !(res.par->GetChar(res.pos) == LyXParagraph::META_INSET
2624                    && res.par->GetInset(res.pos)->LyxCode() == Inset::IGNORE_CODE));
2625    
2626         if (res.par) {
2627                 SetCursor(res.par, res.pos);
2628                 return true;
2629         }
2630    
2631         return false;
2632 }
2633
2634
2635 int LyXText::SwitchLayoutsBetweenClasses(char class1, char class2,
2636                                          LyXParagraph * par)
2637 {
2638         int ret = 0;
2639         if (!par || class1 == class2)
2640                 return ret;
2641         par = par->FirstPhysicalPar();
2642         while (par) {
2643                 string name = textclasslist.NameOfLayout(class1, par->layout);
2644                 int lay = 0;
2645                 pair<bool, LyXTextClass::LayoutList::size_type> pp =
2646                         textclasslist.NumberOfLayout(class2, name);
2647                 if (pp.first) {
2648                         lay = pp.second;
2649                 } else { // layout not found
2650                         // use default layout "Standard" (0)
2651                         lay = 0;
2652                 }
2653                 par->layout = lay;
2654       
2655                 if (name != textclasslist.NameOfLayout(class2, par->layout)) {
2656                         ret++;
2657                         string s = "Layout had to be changed from\n"
2658                                 + name + " to " + textclasslist.NameOfLayout(class2, par->layout)
2659                                 + "\nbecause of class conversion from\n"
2660                                 + textclasslist.NameOfClass(class1) + " to "
2661                                 + textclasslist.NameOfClass(class2);
2662                         InsetError * new_inset = new InsetError(s);
2663                         par->InsertChar(0, LyXParagraph::META_INSET);
2664                         par->InsertInset(0, new_inset);
2665                 }
2666       
2667                 par = par->next;
2668         }
2669         return ret;
2670 }
2671
2672
2673 void LyXText::CheckParagraph(LyXParagraph * par,
2674                              LyXParagraph::size_type pos)
2675 {
2676   
2677         LyXCursor tmpcursor;
2678
2679         /* table stuff -- begin*/
2680    
2681         if (par->table) {
2682                 CheckParagraphInTable(par, pos);
2683         }
2684         else {
2685                 /* table stuff -- end*/
2686      
2687                 long y = 0;
2688                 LyXParagraph::size_type z;
2689                 Row * row = GetRow(par, pos, y);
2690      
2691                 /* is there a break one row above */ 
2692                 if (row->previous && row->previous->par == row->par) {
2693                         z = NextBreakPoint(row->previous, paperwidth);
2694                         if ( z >= row->pos) {
2695                                 /* set the dimensions of the row above  */ 
2696                                 y -= row->previous->height;
2697                                 refresh_y = y;
2698                                 refresh_row = row->previous;
2699                                 status = LyXText::NEED_MORE_REFRESH;
2700        
2701                                 BreakAgain(row->previous);
2702
2703                                 /* set the cursor again. Otherwise dungling pointers are possible */
2704                                 SetCursor(cursor.par, cursor.pos);
2705                                 sel_cursor = cursor;
2706                                 return;
2707                         }
2708                 }
2709
2710                 int tmpheight = row->height;
2711                 LyXParagraph::size_type tmplast = RowLast(row);
2712                 refresh_y = y;
2713                 refresh_row = row;
2714
2715                 BreakAgain(row);
2716                 if (row->height == tmpheight && RowLast(row) == tmplast)
2717                         status = LyXText::NEED_VERY_LITTLE_REFRESH;
2718                 else
2719                         status = LyXText::NEED_MORE_REFRESH; 
2720    
2721                 /* check the special right address boxes */
2722                 if (textclasslist.Style(parameters->textclass, par->GetLayout()).margintype == MARGIN_RIGHT_ADDRESS_BOX) {
2723                         tmpcursor.par = par;
2724                         tmpcursor.row = row;
2725                         tmpcursor.y = y;
2726                         tmpcursor.x = 0;
2727                         tmpcursor.x_fix = 0;
2728                         tmpcursor.pos = pos;
2729                         RedoDrawingOfParagraph(tmpcursor); 
2730                 }
2731    
2732         }
2733
2734         /* set the cursor again. Otherwise dangling pointers are possible */
2735         // also set the selection
2736    
2737         if (selection){
2738                 tmpcursor = cursor;
2739                 SetCursorIntern(sel_cursor.par, sel_cursor.pos);
2740                 sel_cursor = cursor; 
2741                 SetCursorIntern(sel_start_cursor.par, sel_start_cursor.pos);
2742                 sel_start_cursor = cursor; 
2743                 SetCursorIntern(sel_end_cursor.par, sel_end_cursor.pos);
2744                 sel_end_cursor = cursor; 
2745                 SetCursorIntern(last_sel_cursor.par, last_sel_cursor.pos);
2746                 last_sel_cursor = cursor; 
2747                 cursor = tmpcursor;
2748         }
2749         SetCursorIntern(cursor.par, cursor.pos);
2750 }
2751
2752
2753 /* returns 0 if inset wasn't found */
2754 int LyXText::UpdateInset(Inset * inset)
2755 {
2756         /* first check the current paragraph */
2757         int pos = cursor.par->GetPositionOfInset(inset);
2758         if (pos != -1){
2759                 CheckParagraph(cursor.par, pos);
2760                 return 1;
2761         }
2762   
2763         /* check every paragraph */
2764   
2765         LyXParagraph * par = FirstParagraph();
2766         do {
2767                 /* make sure the paragraph is open */
2768                 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2769                         pos = par->GetPositionOfInset(inset);
2770                         if (pos != -1){
2771                                 CheckParagraph(par, pos);
2772                                 return 1;
2773                         }
2774                 }
2775                 par = par->Next();
2776         } while (par);
2777   
2778         return 0;
2779 }
2780
2781
2782 void LyXText::SetCursor(LyXParagraph * par,
2783                         LyXParagraph::size_type pos)
2784 {
2785         LyXCursor old_cursor = cursor;
2786         SetCursorIntern(par, pos);
2787         DeleteEmptyParagraphMechanism(old_cursor);
2788 }
2789
2790
2791 void LyXText::SetCursorIntern(LyXParagraph * par, LyXParagraph::size_type pos)
2792 {
2793         long y;
2794         Row * row;
2795         int left_margin;
2796         LyXParagraph * tmppar;
2797    
2798         /* correct the cursor position if impossible */
2799         if (pos > par->Last()){
2800                 tmppar = par->ParFromPos(pos);
2801                 pos = par->PositionInParFromPos(pos);
2802                 par = tmppar;
2803         }
2804         if (par->IsDummy() && par->previous &&
2805             par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2806                 while (par->previous &&
2807                        ((par->previous->IsDummy() && par->previous->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) ||
2808                         (par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE))) {
2809                         par = par->previous ;
2810                         if (par->IsDummy() &&
2811                             par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
2812                                 pos += par->text.size() + 1;
2813                 }
2814                 if (par->previous) {
2815                         par = par->previous;
2816                 }
2817                 pos += par->text.size() + 1;
2818         }
2819
2820         cursor.par = par;
2821         cursor.pos = pos;
2822
2823         /* get the cursor y position in text  */
2824         row = GetRow(par, pos, y);
2825         /* y is now the beginning of the cursor row */ 
2826         y += row->baseline;
2827         /* y is now the cursor baseline */ 
2828         cursor.y = y;
2829    
2830         /* now get the cursors x position */
2831    
2832         float x;
2833         float fill_separator, fill_hfill, fill_label_hfill;
2834         left_margin = LabelEnd(row);
2835         PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
2836         LyXParagraph::size_type main_body =
2837                 BeginningOfMainBody(row->par);
2838         /* table stuff -- begin*/
2839         if (row->par->table) {
2840                 int cell = NumberOfCell(row->par, row->pos);
2841                 float x_old = x;
2842                 x += row->par->table->GetBeginningOfTextInCell(cell);
2843                 for (pos = row->pos; pos < cursor.pos; pos++)  {
2844                         if (row->par->IsNewline(pos)) {
2845                                 x = x_old + row->par->table->WidthOfColumn(cell);
2846                                 x_old = x;
2847                                 cell++;
2848                                 x += row->par->table->GetBeginningOfTextInCell(cell);
2849                         } else {
2850                                 x += SingleWidth(row->par, pos);
2851                         }
2852                 }
2853         } else
2854                 /* table stuff -- end*/
2855
2856                 for (pos = row->pos; pos < cursor.pos; pos++)  {
2857                         if (pos && pos == main_body
2858                             && !row->par->IsLineSeparator(pos - 1)) {
2859                                 x += GetFont(row->par, -2).stringWidth(
2860                                                     textclasslist.Style(parameters->textclass, row->par->GetLayout()).labelsep);
2861                                 if (x < left_margin)
2862                                         x = left_margin;
2863                         }
2864       
2865                         x += SingleWidth(row->par, pos);
2866                         if (HfillExpansion(row, pos)) {
2867                                 if (pos >= main_body)
2868                                         x += fill_hfill;
2869                                 else 
2870                                         x += fill_label_hfill;
2871                         }
2872                         else if (pos >= main_body && row->par->IsSeparator(pos)) {
2873                                 x+= fill_separator;
2874                         }
2875       
2876                         if (pos + 1 == main_body
2877                             && row->par->IsLineSeparator(pos)) {
2878                                 x += GetFont(row->par, -2).stringWidth(
2879                                                     textclasslist.Style(parameters->textclass, row->par->GetLayout()).labelsep);
2880                                 if (row->par->IsLineSeparator(pos))
2881                                         x -= SingleWidth(row->par, pos);
2882                                 if (x < left_margin)
2883                                         x = left_margin;
2884                         }
2885                 }
2886    
2887         cursor.x = int(x);
2888    
2889         cursor.x_fix = cursor.x;
2890         cursor.row = row;
2891    
2892         if (cursor.pos && 
2893             (cursor.pos == cursor.par->Last() || cursor.par->IsSeparator(cursor.pos)
2894              || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
2895                  && !cursor.par->IsSeparator(cursor.pos))
2896                     )) {
2897                 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
2898                 real_current_font = GetFont(cursor.par, cursor.pos - 1);
2899         } else {
2900                 current_font = cursor.par->GetFontSettings(cursor.pos);
2901                 real_current_font = GetFont(cursor.par, cursor.pos);
2902         }
2903 }
2904
2905
2906 void LyXText::SetCursorFromCoordinates(int x, long y)
2907 {
2908         LyXCursor old_cursor = cursor;
2909    
2910         /* get the row first */ 
2911    
2912         Row * row = GetRowNearY(y);
2913    
2914         cursor.par = row->par;
2915    
2916         int column = GetColumnNearX(row, x);
2917         cursor.pos = row->pos + column;
2918         cursor.x = x;
2919         cursor.y = y + row->baseline;
2920    
2921         cursor.row = row;
2922     
2923         if (cursor.pos && 
2924             (cursor.pos == cursor.par->Last()
2925              || cursor.par->IsSeparator(cursor.pos)
2926              || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
2927                  && !cursor.par->IsSeparator(cursor.pos))
2928                     )) {
2929                 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
2930                 real_current_font = GetFont(cursor.par, cursor.pos - 1);
2931         } else {
2932                 current_font = cursor.par->GetFontSettings(cursor.pos);
2933                 real_current_font = GetFont(cursor.par, cursor.pos);
2934         }
2935         DeleteEmptyParagraphMechanism(old_cursor);
2936 }
2937
2938
2939 void LyXText::CursorLeft()
2940 {
2941         CursorLeftIntern();
2942         if (cursor.par->table) {
2943                 int cell = NumberOfCell(cursor.par, cursor.pos);
2944                 if (cursor.par->table->IsContRow(cell) &&
2945                     cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
2946                         CursorUp();
2947                 }
2948         }
2949 }
2950
2951
2952 void LyXText::CursorLeftIntern()
2953 {
2954         if (cursor.pos > 0) {
2955                 SetCursor(cursor.par, cursor.pos - 1);
2956         }
2957         else if (cursor.par->Previous()) {
2958                 SetCursor(cursor.par->Previous(), cursor.par->Previous()->Last());
2959         }
2960 }
2961
2962
2963 void LyXText::CursorRight()
2964 {
2965         CursorRightIntern();
2966         if (cursor.par->table) {
2967                 int cell = NumberOfCell(cursor.par, cursor.pos);
2968                 if (cursor.par->table->IsContRow(cell) &&
2969                     cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
2970                         CursorUp();
2971                 }
2972         }
2973 }
2974
2975
2976 void LyXText::CursorRightIntern()
2977 {
2978         if (cursor.pos < cursor.par->Last()) {
2979                 SetCursor(cursor.par, cursor.pos + 1);
2980         }
2981         else if (cursor.par->Next()) {
2982                 SetCursor(cursor.par->Next(), 0);
2983         }
2984 }
2985
2986
2987 void LyXText::CursorUp()
2988 {
2989         SetCursorFromCoordinates(cursor.x_fix, 
2990                                  cursor.y - cursor.row->baseline - 1);
2991         if (cursor.par->table) {
2992                 int cell = NumberOfCell(cursor.par, cursor.pos);
2993                 if (cursor.par->table->IsContRow(cell) &&
2994                     cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
2995                         CursorUp();
2996                 }
2997         }
2998 }
2999
3000
3001 void LyXText::CursorDown()
3002 {
3003         if (cursor.par->table &&
3004             cursor.par->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par, cursor.pos)) &&
3005             !cursor.par->next)
3006                 return;
3007         SetCursorFromCoordinates(cursor.x_fix, 
3008                                  cursor.y - cursor.row->baseline
3009                                  + cursor.row->height + 1);
3010         if (cursor.par->table) {
3011                 int cell = NumberOfCell(cursor.par, cursor.pos);
3012                 int cell_above = cursor.par->table->GetCellAbove(cell);
3013                 while(cursor.par->table &&
3014                       cursor.par->table->IsContRow(cell) &&
3015                       (cursor.par->table->CellHasContRow(cell_above)<0)) {
3016                     SetCursorFromCoordinates(cursor.x_fix, 
3017                                              cursor.y - cursor.row->baseline
3018                                              + cursor.row->height + 1);
3019                     if (cursor.par->table) {
3020                         cell = NumberOfCell(cursor.par, cursor.pos);
3021                         cell_above = cursor.par->table->GetCellAbove(cell);
3022                     }
3023                 }
3024         }
3025 }
3026
3027
3028 void LyXText::CursorUpParagraph()
3029 {
3030         if (cursor.pos > 0) {
3031                 SetCursor(cursor.par, 0);
3032         }
3033         else if (cursor.par->Previous()) {
3034                 SetCursor(cursor.par->Previous(), 0);
3035         }
3036 }
3037
3038
3039 void LyXText::CursorDownParagraph()
3040 {
3041         if (cursor.par->Next()) {
3042                 SetCursor(cursor.par->Next(), 0);
3043         } else {
3044                 SetCursor(cursor.par, cursor.par->Last());
3045         }
3046 }
3047
3048
3049
3050 void LyXText::DeleteEmptyParagraphMechanism(LyXCursor old_cursor)
3051 {
3052     bool deleted = false;
3053         
3054     /* this is the delete-empty-paragraph-mechanism. */ 
3055     if (selection)
3056         return;
3057
3058     // Paragraph should not be deleted if empty
3059     if ((textclasslist.Style(parameters->textclass,
3060                         old_cursor.par->GetLayout())).keepempty)
3061         return;
3062
3063     LyXCursor tmpcursor;
3064
3065     if (old_cursor.par != cursor.par) {
3066         if ( (old_cursor.par->Last() == 0
3067               || (old_cursor.par->Last() == 1
3068                   && (old_cursor.par->IsLineSeparator(0))))
3069              && old_cursor.par->FirstPhysicalPar()
3070              == old_cursor.par->LastPhysicalPar()) {
3071                         
3072             /* ok, we will delete anything */ 
3073                         
3074             // make sure that you do not delete any environments
3075             if ((old_cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3076                  !(old_cursor.row->previous 
3077                    && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3078                  && !(old_cursor.row->next 
3079                       && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3080                 || 
3081                 (old_cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE &&
3082                  ((old_cursor.row->previous 
3083                    && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3084                   || 
3085                   (old_cursor.row->next
3086                    && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3087                  )){
3088                 status = LyXText::NEED_MORE_REFRESH;
3089                 deleted = true;
3090                                 
3091                 if (old_cursor.row->previous) {
3092                     refresh_row = old_cursor.row->previous;
3093                     refresh_y = old_cursor.y - old_cursor.row->baseline - refresh_row->height;
3094                     tmpcursor = cursor;
3095                     cursor = old_cursor; // that undo can restore the right cursor position
3096                     LyXParagraph *endpar = old_cursor.par->next;
3097                     if (endpar && endpar->GetDepth()) {
3098                         while (endpar && endpar->GetDepth()) {
3099                             endpar = endpar->LastPhysicalPar()->Next();
3100                         }
3101                     }
3102                     SetUndo(Undo::DELETE,
3103                             old_cursor.par->previous,
3104                             endpar);
3105                     cursor = tmpcursor;
3106
3107                     /* delete old row */ 
3108                     RemoveRow(old_cursor.row);
3109                     if (params->paragraph == old_cursor.par) {
3110                         params->paragraph = params->paragraph->next;
3111                     }
3112                     /* delete old par */ 
3113                     delete old_cursor.par;
3114                                         
3115                     /* Breakagain the next par. Needed
3116                      * because of the parindent that
3117                      * can occur or dissappear. The
3118                      * next row can change its height,
3119                      * if there is another layout before */
3120                     if (refresh_row->next) {
3121                         BreakAgain(refresh_row->next);
3122                         UpdateCounters(refresh_row);
3123                     }
3124                     SetHeightOfRow(refresh_row);
3125                 }
3126                 else {
3127                     refresh_row = old_cursor.row->next;
3128                     refresh_y = old_cursor.y - old_cursor.row->baseline;
3129                                         
3130                     tmpcursor = cursor;
3131                     cursor = old_cursor; // that undo can restore the right cursor position
3132                     LyXParagraph *endpar = old_cursor.par->next;
3133                     if (endpar && endpar->GetDepth()) {
3134                         while (endpar && endpar->GetDepth()) {
3135                             endpar = endpar->LastPhysicalPar()->Next();
3136                         }
3137                     }
3138                     SetUndo(Undo::DELETE,
3139                             old_cursor.par->previous,
3140                             endpar);
3141                     cursor = tmpcursor;
3142
3143                     /* delete old row */ 
3144                     RemoveRow(old_cursor.row);
3145                     /* delete old par */ 
3146                     if (params->paragraph == old_cursor.par) {
3147                         params->paragraph = params->paragraph->next;
3148                     }
3149                     delete old_cursor.par;
3150                                         
3151                     /* Breakagain the next par. Needed because of
3152                      * the parindent that can occur or dissappear.
3153                      * The next row can change its height, if there
3154                      * is another layout before */ 
3155                     if (refresh_row) {
3156                         BreakAgain(refresh_row);
3157                         UpdateCounters(refresh_row->previous);
3158                     }
3159                 }
3160                                 
3161                                 /* correct cursor y */
3162                 SetCursor(cursor.par, cursor.pos);
3163                      
3164                                 /* if (cursor.y > old_cursor.y)
3165                                    cursor.y -= old_cursor.row->height; */ 
3166          
3167                 if (sel_cursor.par  == old_cursor.par
3168                     && sel_cursor.pos == sel_cursor.pos) {
3169                     /* correct selection*/ 
3170                     sel_cursor = cursor;
3171                 }
3172             }
3173        
3174         }
3175         if (!deleted){
3176             if (old_cursor.par->ClearParagraph()){
3177                 RedoParagraphs(old_cursor, old_cursor.par->Next());
3178                                 /* correct cursor y */
3179                 SetCursor(cursor.par, cursor.pos);
3180                 sel_cursor = cursor;
3181             }
3182         }
3183     } else if (cursor.par->table && (cursor.row != old_cursor.row)) {
3184         int cell = NumberOfCell(old_cursor.par, old_cursor.pos);
3185         if (old_cursor.par->table->IsContRow(cell) &&
3186             IsEmptyTableRow(&old_cursor)) {
3187             RemoveTableRow(&old_cursor);
3188             RedoParagraph();
3189         }
3190     }
3191 }
3192
3193
3194 LyXParagraph * LyXText::GetParFromID(int id)
3195 {
3196         LyXParagraph * result = FirstParagraph();
3197         while (result && result->id() != id)
3198                 result = result->next;
3199         return result;
3200 }
3201
3202
3203 // undo functions
3204 bool  LyXText::TextUndo()
3205 { // returns false if no undo possible
3206         Undo * undo = params->undostack.pop();
3207         if (undo){
3208                 FinishUndo();
3209                 if (!undo_frozen)
3210                         params->redostack.push(CreateUndo(undo->kind, 
3211                                                           GetParFromID(undo->number_of_before_par),
3212                                                           GetParFromID(undo->number_of_behind_par)));
3213         }
3214         return TextHandleUndo(undo);
3215 }
3216
3217
3218 bool LyXText::TextRedo()
3219 { // returns false if no redo possible
3220         Undo * undo = params->redostack.pop();
3221         if (undo){
3222                 FinishUndo();
3223                 if (!undo_frozen)
3224                         params->undostack.push(CreateUndo(undo->kind, 
3225                                                           GetParFromID(undo->number_of_before_par),
3226                                                           GetParFromID(undo->number_of_behind_par)));
3227         }
3228         return TextHandleUndo(undo);
3229 }
3230
3231
3232 bool LyXText::TextHandleUndo(Undo * undo){ // returns false if no undo possible
3233         bool result = false;
3234         if (undo){
3235                 LyXParagraph * before = GetParFromID(undo->number_of_before_par); 
3236                 LyXParagraph * behind = GetParFromID(undo->number_of_behind_par); 
3237                 LyXParagraph * tmppar;
3238                 LyXParagraph * tmppar2;
3239                 LyXParagraph * tmppar3;
3240                 LyXParagraph * tmppar4;
3241                 LyXParagraph * endpar;
3242                 LyXParagraph * tmppar5;
3243     
3244                 // if there's no before take the beginning of the document for redoing
3245                 if (!before)
3246                         SetCursorIntern(FirstParagraph(), 0);
3247
3248                 // replace the paragraphs with the undo informations
3249
3250                 tmppar3 = undo->par;
3251                 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3252                 tmppar4 = tmppar3;
3253                 if (tmppar4){
3254                         while (tmppar4->next)
3255                                 tmppar4 = tmppar4->next;
3256                 } // get last undo par
3257     
3258                 // now remove the old text if there is any
3259                 if (before != behind || (!behind && !before)){
3260                         if (before)
3261                                 tmppar5 = before->next;
3262                         else
3263                                 tmppar5 = params->paragraph;
3264                         tmppar2 = tmppar3;
3265                         while (tmppar5 && tmppar5 != behind){
3266                                 tmppar = tmppar5;
3267                                 tmppar5 = tmppar5->next;
3268                                 // a memory optimization for edit: Only layout information
3269                                 // is stored in the undo. So restore the text informations.
3270                                 if (undo->kind == Undo::EDIT){
3271                                         tmppar2->text = tmppar->text;
3272                                         tmppar->text.clear();
3273                                         //tmppar->text.erase(tmppar->text.begin(),
3274                                         //                 tmppar->text.end());
3275                                         tmppar2 = tmppar2->next;
3276                                 }
3277                                 if ( currentrow && currentrow->par == tmppar )
3278                                         currentrow = currentrow -> previous;
3279                                 delete tmppar;
3280                         }
3281                 }
3282     
3283                 // put the new stuff in the list if there is one
3284                 if (tmppar3){
3285                         if (before)
3286                                 before->next = tmppar3;
3287                         else
3288                                 params->paragraph = tmppar3;
3289                         tmppar3->previous = before;
3290                 }
3291                 else {
3292                         if (!before)
3293                                 params->paragraph = behind;
3294                 }
3295                 if (tmppar4) {
3296                         tmppar4->next = behind;
3297                         if (behind)
3298                                 behind->previous = tmppar4;
3299                 }
3300     
3301     
3302                 // Set the cursor for redoing
3303                 if (before){
3304                         SetCursorIntern(before->FirstSelfrowPar(), 0);
3305                         // check wether before points to a closed float and open it if necessary
3306                         if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3307                             && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3308                                 tmppar4 = before;
3309                                 while (tmppar4->previous && 
3310                                        tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3311                                         tmppar4 = tmppar4->previous;
3312                                 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3313                                         tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3314                                         tmppar4 = tmppar4->next;
3315                                 }
3316                         }
3317                 }
3318     
3319                 // open a cosed footnote at the end if necessary
3320                 if (behind && behind->previous && 
3321                     behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3322                     behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3323                         while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3324                                 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3325                                 behind = behind->next;
3326                         }
3327                 }
3328     
3329                 // calculate the endpar for redoing the paragraphs.
3330                 if (behind){
3331                         if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3332                                 endpar = behind->LastPhysicalPar()->Next();
3333                         else
3334                                 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3335                 }
3336                 else
3337                         endpar = behind;
3338     
3339                 tmppar = GetParFromID(undo->number_of_cursor_par);
3340                 RedoParagraphs(cursor, endpar); 
3341                 if (tmppar){
3342                         SetCursorIntern(tmppar, undo->cursor_pos);
3343                         UpdateCounters(cursor.row);
3344                 }
3345                 result = true;
3346                 delete undo;
3347         }
3348         FinishUndo();
3349         return result;
3350 }
3351
3352
3353 void LyXText::FinishUndo()
3354 { // makes sure the next operation will be stored
3355         undo_finished = True;
3356 }
3357
3358
3359 void LyXText::FreezeUndo()
3360 { // this is dangerous and for internal use only
3361         undo_frozen = True;
3362 }
3363
3364
3365 void LyXText::UnFreezeUndo()
3366 { // this is dangerous and for internal use only
3367         undo_frozen = false;
3368 }
3369
3370
3371 void LyXText::SetUndo(Undo::undo_kind kind, LyXParagraph * before,
3372                       LyXParagraph * behind)
3373 {
3374         if (!undo_frozen)
3375                 params->undostack.push(CreateUndo(kind, before, behind));
3376         params->redostack.clear();
3377 }
3378
3379
3380 void LyXText::SetRedo(Undo::undo_kind kind, LyXParagraph * before,
3381                       LyXParagraph * behind)
3382 {
3383         params->redostack.push(CreateUndo(kind, before, behind));
3384 }
3385
3386
3387 Undo * LyXText::CreateUndo(Undo::undo_kind kind, LyXParagraph * before,
3388                           LyXParagraph * behind)
3389 {
3390         int before_number = -1;
3391         int behind_number = -1;
3392         if (before)
3393                 before_number = before->id();
3394         if (behind)
3395                 behind_number = behind->id();
3396         // Undo::EDIT  and Undo::FINISH are
3397         // always finished. (no overlapping there)
3398         // overlapping only with insert and delete inside one paragraph: 
3399         // Nobody wants all removed  character
3400         // appear one by one when undoing. 
3401         // EDIT is special since only layout information, not the
3402         // contents of a paragaph are stored.
3403         if (!undo_finished && kind != Undo::EDIT && 
3404             kind != Undo::FINISH){
3405                 // check wether storing is needed
3406                 if (!params->undostack.empty() && 
3407                     params->undostack.top()->kind == kind &&
3408                     params->undostack.top()->number_of_before_par ==  before_number &&
3409                     params->undostack.top()->number_of_behind_par ==  behind_number ){
3410                         // no undo needed
3411                         return 0;
3412                 }
3413         }
3414         // create a new Undo
3415         LyXParagraph * undopar;
3416         LyXParagraph * tmppar;
3417         LyXParagraph * tmppar2;
3418
3419         LyXParagraph * start = 0;
3420         LyXParagraph * end = 0;
3421   
3422         if (before)
3423                 start = before->next;
3424         else
3425                 start = FirstParagraph();
3426         if (behind)
3427                 end = behind->previous;
3428         else {
3429                 end = FirstParagraph();
3430                 while (end->next)
3431                         end = end->next;
3432         }
3433
3434         if (start && end && start != end->next && (before != behind || (!before && !behind))) {
3435                 tmppar = start;
3436                 tmppar2 = tmppar->Clone();
3437                 tmppar2->id(tmppar->id());
3438
3439                 // a memory optimization: Just store the layout information when only edit
3440                 if (kind == Undo::EDIT){
3441                         tmppar2->text.clear();
3442                         //tmppar2->text.erase(tmppar2->text.begin(),
3443                         //                  tmppar2->text.end());
3444                 }
3445
3446                 undopar = tmppar2;
3447   
3448                 while (tmppar != end && tmppar->next) {
3449                         tmppar = tmppar->next;
3450                         tmppar2->next = tmppar->Clone();
3451                         tmppar2->next->id(tmppar->id());
3452                         // a memory optimization: Just store the layout information when only edit
3453                         if (kind == Undo::EDIT){
3454                                 tmppar2->next->text.clear();
3455                                 //tmppar2->next->text.erase(tmppar2->next->text.begin(), tmppar2->next->text.end());
3456                         }
3457                         tmppar2->next->previous = tmppar2;
3458                         tmppar2 = tmppar2->next;
3459                 }
3460                 tmppar2->next = 0;
3461         }
3462         else
3463                 undopar = 0; // nothing to replace (undo of delete maybe)
3464   
3465         int cursor_par = cursor.par->ParFromPos(cursor.pos)->id();
3466         int cursor_pos =  cursor.par->PositionInParFromPos(cursor.pos);
3467
3468         Undo * undo = new Undo(kind, 
3469                               before_number, behind_number,  
3470                               cursor_par, cursor_pos, 
3471                               undopar);
3472   
3473         undo_finished = false;
3474         return undo;
3475 }
3476
3477
3478 void LyXText::SetCursorParUndo()
3479 {
3480         SetUndo(Undo::FINISH, 
3481                 cursor.par->ParFromPos(cursor.pos)->previous, 
3482                 cursor.par->ParFromPos(cursor.pos)->next); 
3483 }
3484
3485 void LyXText::RemoveTableRow(LyXCursor * cur)
3486 {
3487         int cell = -1;
3488         int cell_org = 0;
3489         int ocell = 0;
3490     
3491     /* move to the previous row */
3492     int cell_act = NumberOfCell(cur->par, cur->pos);
3493     if (cell < 0)
3494         cell = cell_act;
3495     while (cur->pos && !cur->par->IsNewline(cur->pos - 1))
3496         cur->pos--;
3497     while (cur->pos && 
3498            !cur->par->table->IsFirstCell(cell_act)) {
3499         cur->pos--;
3500         while (cur->pos && !cur->par->IsNewline(cur->pos - 1))
3501             cur->pos--;
3502             --cell;
3503             --cell_act;
3504     }
3505     /* now we have to pay attention if the actual table is the
3506        main row of TableContRows and if yes to delete all of them */
3507     if (!cell_org)
3508         cell_org = cell;
3509     do {
3510         ocell = cell;
3511         /* delete up to the next row */
3512         while (cur->pos < cur->par->Last() && 
3513                (cell_act == ocell
3514                 || !cur->par->table->IsFirstCell(cell_act))) {
3515             while (cur->pos < cur->par->Last() &&
3516                    !cur->par->IsNewline(cur->pos))
3517                 cur->par->Erase(cur->pos);
3518             ++cell;
3519             ++cell_act;
3520             if (cur->pos < cur->par->Last())
3521                 cur->par->Erase(cur->pos);
3522         }
3523         if (cur->pos && cur->pos == cur->par->Last()) {
3524             cur->pos--;
3525             cur->par->Erase(cur->pos); // no newline at the very end!
3526         }
3527     } while (((cell + 1) < cur->par->table->GetNumberOfCells()) &&
3528              !cur->par->table->IsContRow(cell_org) &&
3529              cur->par->table->IsContRow(cell));
3530     cur->par->table->DeleteRow(cell_org);
3531     return;
3532 }
3533
3534
3535 bool LyXText::IsEmptyTableRow(LyXCursor * old_cursor) const
3536 {
3537         if (!old_cursor->par->table)
3538                 return false;
3539 #ifdef I_DONT_KNOW_IF_I_SHOULD_DO_THIS
3540         int pos = old_cursor->pos;
3541         int cell = NumberOfCell(old_cursor->par, pos);
3542
3543         // search first charater of this table row
3544         while (pos && !old_cursor->par->table->IsFirstCell(cell)) {
3545                 pos--;
3546                 while (pos && !old_cursor->par->IsNewline(pos-1))
3547                         pos--;
3548                 cell--;
3549         }
3550         if (!old_cursor->par->IsNewline(pos))
3551                 return false;
3552         cell++;
3553         pos++;
3554         while ((pos < old_cursor->par->Last()) &&
3555                !old_cursor->par->table->IsFirstCell(cell)) {
3556                 if (!old_cursor->par->IsNewline(pos))
3557                         return false;
3558                 pos++;
3559                 cell++;
3560         }
3561         return true;
3562 #endif
3563         return false;
3564 }
3565
3566
3567 bool LyXText::IsEmptyTableCell() const
3568 {
3569         LyXParagraph::size_type pos = cursor.pos - 1;
3570         while (pos >= 0 && pos < cursor.par->Last()
3571                && !cursor.par->IsNewline(pos))
3572                 --pos;
3573         return cursor.par->IsNewline(pos + 1);
3574 }
3575
3576
3577 void LyXText::toggleAppendix(){
3578   LyXParagraph * par = cursor.par->FirstPhysicalPar();
3579   bool start = !par->start_of_appendix;
3580
3581   /* ensure that we have only one start_of_appendix in this document */
3582   LyXParagraph * tmp = FirstParagraph();
3583   for (;tmp;tmp = tmp->next)
3584     tmp->start_of_appendix = 0;
3585   par->start_of_appendix = start;
3586
3587   /* we can set the refreshing parameters now */
3588   status = LyXText::NEED_MORE_REFRESH;
3589   refresh_y = 0;
3590   refresh_row = 0; // not needed for full update
3591   UpdateCounters(0);
3592   SetCursor(cursor.par, cursor.pos);
3593 }
3594