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