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