]> git.lyx.org Git - lyx.git/blob - src/text2.C
two additional fixes, one of them is really suspect...
[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         // clear 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.
1871
1872            As do redo Asger's example above (with | beeing the cursor in the
1873            result after cutting.):
1874            
1875            Example: "This is our text."
1876            Using " our " as selection, cutting will give "This is|text.".
1877            Using "our"   as selection, cutting will give "This is | text.".
1878            Using " our"  as selection, cutting will give "This is| text.".
1879            Using "our "  as selection, cutting will give "This is |text.".
1880
1881            (Lgb)
1882         */
1883
1884 #ifndef FIX_DOUBLE_SPACE
1885         bool space_wrapped =
1886                 sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos);
1887         if (sel_end_cursor.pos > 0
1888             && sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos - 1)) {
1889                 // please break before a space at the end
1890                 sel_end_cursor.pos--;
1891                 space_wrapped = true;
1892         }
1893         // cut behind a space if there is one
1894         while (sel_start_cursor.par->Last() > sel_start_cursor.pos
1895                && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
1896                && (sel_start_cursor.par != sel_end_cursor.par
1897                    || sel_start_cursor.pos < sel_end_cursor.pos))
1898                 sel_start_cursor.pos++; 
1899 #endif
1900         // there are two cases: cut only within one paragraph or
1901         // more than one paragraph
1902    
1903         if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos) 
1904             == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
1905                 // only within one paragraph
1906                 simple_cut_buffer = new LyXParagraph;
1907                 LyXParagraph::size_type i =
1908                         sel_start_cursor.pos;
1909                 for (; i < sel_end_cursor.pos; ++i) {
1910                         /* table stuff -- begin */
1911                         if (sel_start_cursor.par->table
1912                             && sel_start_cursor.par->IsNewline(sel_start_cursor.pos)) {
1913                                 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
1914                                 sel_start_cursor.pos++;
1915                         } else {
1916                                 /* table stuff -- end */
1917                                 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
1918                                 sel_start_cursor.par->Erase(sel_start_cursor.pos);
1919                         }
1920                         simple_cut_buffer->InsertFromMinibuffer(simple_cut_buffer->Last());
1921                 }
1922 #ifndef FIX_DOUBLE_SPACE
1923                 // check for double spaces
1924                 if (sel_start_cursor.pos &&
1925                     sel_start_cursor.par->Last() > sel_start_cursor.pos
1926                     && sel_start_cursor.par
1927                     ->IsLineSeparator(sel_start_cursor.pos - 1)
1928                     && sel_start_cursor.par
1929                     ->IsLineSeparator(sel_start_cursor.pos)) {
1930                         sel_start_cursor.par->Erase(sel_start_cursor.pos);
1931                 }
1932                 if (space_wrapped)
1933                         simple_cut_buffer->InsertChar(i - sel_start_cursor.pos,
1934                                                       ' ');
1935 #endif
1936                 endpar = sel_end_cursor.par->Next();
1937         } else {
1938                 // cut more than one paragraph
1939    
1940                 sel_end_cursor.par
1941                         ->BreakParagraphConservative(sel_end_cursor.pos);
1942 #ifndef FIX_DOUBLE_SPACE
1943                 // insert a space at the end if there was one
1944                 if (space_wrapped)
1945                         sel_end_cursor.par
1946                                 ->InsertChar(sel_end_cursor.par->Last(), ' ');
1947 #endif
1948                 sel_end_cursor.par = sel_end_cursor.par->Next();
1949                 sel_end_cursor.pos = 0;
1950    
1951                 cursor = sel_end_cursor;
1952
1953 #ifndef FIX_DOUBLE_SPACE
1954                 // please break behind a space, if there is one.
1955                 // The space should be copied too
1956                 if (sel_start_cursor.par
1957                     ->IsLineSeparator(sel_start_cursor.pos))
1958                         sel_start_cursor.pos++;
1959 #endif   
1960                 sel_start_cursor.par
1961                         ->BreakParagraphConservative(sel_start_cursor.pos);
1962 #ifndef FIX_DOUBLE_SPACE
1963                 if (!sel_start_cursor.pos
1964                     || sel_start_cursor.par
1965                     ->IsLineSeparator(sel_start_cursor.pos - 1)
1966                     || sel_start_cursor.par
1967                     ->IsNewline(sel_start_cursor.pos - 1)) {
1968                         sel_start_cursor.par->Next()->InsertChar(0, ' ');
1969                 }
1970 #endif
1971                 // store the endparagraph for redoing later
1972                 endpar = sel_end_cursor.par->Next(); /* needed because
1973                                                         the sel_end_
1974                                                         cursor.par
1975                                                         will be pasted! */
1976    
1977                 // store the selection
1978                 simple_cut_buffer = sel_start_cursor.par
1979                         ->ParFromPos(sel_start_cursor.pos)->next;
1980                 simple_cut_buffer->previous = 0;
1981                 sel_end_cursor.par->previous->next = 0;
1982
1983                 // cut the selection
1984                 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->next 
1985                         = sel_end_cursor.par;
1986    
1987                 sel_end_cursor.par->previous 
1988                         = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
1989
1990                 // care about footnotes
1991                 if (simple_cut_buffer->footnoteflag) {
1992                         LyXParagraph * tmppar = simple_cut_buffer;
1993                         while (tmppar){
1994                                 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1995                                 tmppar = tmppar->next;
1996                         }
1997                 }
1998
1999                 // the cut selection should begin with standard layout
2000                 simple_cut_buffer->Clear(); 
2001    
2002                 // paste the paragraphs again, if possible
2003                 if (doclear)
2004                         sel_start_cursor.par->Next()->ClearParagraph();
2005                 if (sel_start_cursor.par->FirstPhysicalPar()->HasSameLayout(sel_start_cursor.par->Next())
2006                     || 
2007                     !sel_start_cursor.par->Next()->Last())
2008                         sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->PasteParagraph();
2009
2010 #ifndef FIX_DOUBLE_SPACE
2011                 // maybe a forgotten blank
2012                 if (sel_start_cursor.pos 
2013                     && sel_start_cursor.par
2014                     ->IsLineSeparator(sel_start_cursor.pos)
2015                     && sel_start_cursor.par
2016                     ->IsLineSeparator(sel_start_cursor.pos - 1)) {
2017                         sel_start_cursor.par->Erase(sel_start_cursor.pos);
2018                 }
2019 #endif
2020         }
2021
2022         // sometimes necessary
2023         if (doclear)
2024                 sel_start_cursor.par->ClearParagraph();
2025
2026         RedoParagraphs(sel_start_cursor, endpar);
2027    
2028         ClearSelection();
2029         cursor = sel_start_cursor;
2030         SetCursor(cursor.par, cursor.pos);
2031         sel_cursor = cursor;
2032         UpdateCounters(cursor.row);
2033 }
2034
2035     
2036 void LyXText::CopySelection()
2037 {
2038         // this doesnt make sense, if there is no selection
2039         if (!selection)
2040                 return;
2041
2042         // ok we have a selection. This is always between sel_start_cursor
2043         // and sel_end cursor
2044         LyXParagraph * tmppar;
2045    
2046         /* check wether there are half footnotes in the selection */
2047         if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2048             || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2049                 tmppar = sel_start_cursor.par;
2050                 while (tmppar != sel_end_cursor.par) {
2051                         if (tmppar->footnoteflag !=
2052                             sel_end_cursor.par->footnoteflag) {
2053                                 WriteAlert(_("Impossible operation"),
2054                                            _("Don't know what to do"
2055                                              " with half floats."),
2056                                            _("sorry."));
2057                                 return;
2058                         }
2059                         tmppar = tmppar->Next();
2060                 }
2061         }
2062
2063         /* table stuff -- begin */
2064         if (sel_start_cursor.par->table || sel_end_cursor.par->table){
2065                 if ( sel_start_cursor.par != sel_end_cursor.par){
2066                         WriteAlert(_("Impossible operation"),
2067                                    _("Don't know what to do with half tables."),
2068                                    _("sorry."));
2069                         return;
2070                 }
2071         }
2072         /* table stuff -- end */
2073    
2074         // delete the simple_cut_buffer
2075         DeleteSimpleCutBuffer();
2076
2077         // set the textclass
2078         simple_cut_buffer_textclass = parameters->textclass;
2079
2080 #ifdef FIX_DOUBLE_SPACE
2081         // copy behind a space if there is one
2082         while (sel_start_cursor.par->Last() > sel_start_cursor.pos
2083                && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
2084                && (sel_start_cursor.par != sel_end_cursor.par
2085                    || sel_start_cursor.pos < sel_end_cursor.pos))
2086                 sel_start_cursor.pos++; 
2087 #endif
2088         // there are two cases: copy only within one paragraph
2089         // or more than one paragraph
2090         if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos) 
2091             == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2092                 // only within one paragraph
2093                 simple_cut_buffer = new LyXParagraph;
2094                 LyXParagraph::size_type i = 0;
2095                 for (i = sel_start_cursor.pos; i < sel_end_cursor.pos; ++i){
2096                         sel_start_cursor.par->CopyIntoMinibuffer(i);
2097                         simple_cut_buffer->InsertFromMinibuffer(i - sel_start_cursor.pos);
2098                 }
2099         } else {
2100                 // copy more than one paragraph
2101                 // clone the paragraphs within the selection
2102                 tmppar =
2103                         sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
2104                 simple_cut_buffer = tmppar->Clone();
2105                 LyXParagraph *tmppar2 = simple_cut_buffer;
2106      
2107                 while (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)
2108                        && tmppar->next) {
2109                         tmppar = tmppar->next;
2110                         tmppar2->next = tmppar->Clone();
2111                         tmppar2->next->previous = tmppar2;
2112                         tmppar2 = tmppar2->next;
2113                 }
2114                 tmppar2->next = 0;
2115
2116                 // care about footnotes
2117                 if (simple_cut_buffer->footnoteflag) {
2118                         tmppar = simple_cut_buffer;
2119                         while (tmppar){
2120                                 tmppar->footnoteflag =
2121                                         LyXParagraph::NO_FOOTNOTE;
2122                                 tmppar = tmppar->next;
2123                         }
2124                 }
2125                 
2126                 // the simple_cut_buffer paragraph is too big
2127                 LyXParagraph::size_type tmpi2 =
2128                         sel_start_cursor.par->PositionInParFromPos(sel_start_cursor.pos);
2129                 for (; tmpi2; --tmpi2)
2130                         simple_cut_buffer->Erase(0);
2131                 
2132                 // now tmppar 2 is too big, delete all after sel_end_cursor.pos
2133      
2134                 tmpi2 = sel_end_cursor.par->PositionInParFromPos(sel_end_cursor.pos);
2135                 while (tmppar2->size() > tmpi2) {
2136                         tmppar2->Erase(tmppar2->text.size() - 1);
2137                 }
2138         }
2139 }
2140           
2141
2142 void LyXText::PasteSelection()
2143 {
2144         // this does not make sense, if there is nothing to paste
2145         if (!simple_cut_buffer)
2146                 return;
2147
2148         LyXParagraph * tmppar;
2149         LyXParagraph * endpar;
2150
2151         LyXCursor tmpcursor;
2152
2153         // be carefull with footnotes in footnotes
2154         if (cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2155       
2156                 // check whether the cut_buffer includes a footnote
2157                 tmppar = simple_cut_buffer;
2158                 while (tmppar
2159                        && tmppar->footnoteflag == LyXParagraph::NO_FOOTNOTE)
2160                         tmppar = tmppar->next;
2161       
2162                 if (tmppar) {
2163                         WriteAlert(_("Impossible operation"),
2164                                    _("Can't paste float into float!"),
2165                                    _("Sorry."));
2166                         return;
2167                 }
2168         }
2169
2170         /* table stuff -- begin */
2171         if (cursor.par->table) {
2172                 if (simple_cut_buffer->next) {
2173                         WriteAlert(_("Impossible operation"),
2174                                    _("Table cell cannot include more than one paragraph!"),
2175                                    _("Sorry."));
2176                         return;
2177                 }
2178         }
2179         /* table stuff -- end */
2180    
2181         SetUndo(Undo::INSERT, 
2182                 cursor.par->ParFromPos(cursor.pos)->previous, 
2183                 cursor.par->ParFromPos(cursor.pos)->next); 
2184
2185         tmpcursor = cursor;
2186
2187         // There are two cases: cutbuffer only one paragraph or many
2188         if (!simple_cut_buffer->next) {
2189                 // only within a paragraph
2190
2191 #ifndef FIX_DOUBLE_SPACE
2192                 // please break behind a space, if there is one
2193                 while (tmpcursor.par->Last() > tmpcursor.pos
2194                        && tmpcursor.par->IsLineSeparator(tmpcursor.pos))
2195                         tmpcursor.pos++; 
2196 #endif
2197                 tmppar = simple_cut_buffer->Clone();
2198                 /* table stuff -- begin */
2199                 bool table_too_small = false;
2200                 if (tmpcursor.par->table) {
2201                         while (simple_cut_buffer->text.size()
2202                                && !table_too_small) {
2203                                 if (simple_cut_buffer->IsNewline(0)){
2204                                         while(tmpcursor.pos < tmpcursor.par->Last() && !tmpcursor.par->IsNewline(tmpcursor.pos))
2205                                                 tmpcursor.pos++;
2206                                         simple_cut_buffer->Erase(0);
2207                                         if (tmpcursor.pos < tmpcursor.par->Last())
2208                                                 tmpcursor.pos++;
2209                                         else
2210                                                 table_too_small = true;
2211                                 } else {
2212 #ifdef FIX_DOUBLE_SPACE
2213                                         // This is an attempt to fix the
2214                                         // "never insert a space at the
2215                                         // beginning of a paragraph" problem.
2216                                         if (tmpcursor.pos == 0
2217                                             && simple_cut_buffer->IsLineSeparator(0)) {
2218                                                 simple_cut_buffer->Erase(0);
2219                                         } else {
2220                                                 simple_cut_buffer->CutIntoMinibuffer(0);
2221                                                 simple_cut_buffer->Erase(0);
2222                                                 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2223                                                 tmpcursor.pos++;
2224                                         }
2225 #else
2226                                         simple_cut_buffer->CutIntoMinibuffer(0);
2227                                         simple_cut_buffer->Erase(0);
2228                                         tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2229                                         tmpcursor.pos++;
2230 #endif
2231                                 }
2232                         }
2233                 } else {
2234                         /* table stuff -- end */
2235                         // Some provisions should be done here for checking
2236                         // if we are inserting at the beginning of a
2237                         // paragraph. If there are a space at the beginning
2238                         // of the text to insert and we are inserting at
2239                         // the beginning of the paragraph the space should
2240                         // be removed.
2241                         while (simple_cut_buffer->text.size()) {
2242 #ifdef FIX_DOUBLE_SPACE
2243                                 // This is an attempt to fix the
2244                                 // "never insert a space at the
2245                                 // beginning of a paragraph" problem.
2246                                 if (tmpcursor.pos == 0
2247                                     && simple_cut_buffer->IsLineSeparator(0)) {
2248                                         simple_cut_buffer->Erase(0);
2249                                 } else {
2250                                         simple_cut_buffer->CutIntoMinibuffer(0);
2251                                         simple_cut_buffer->Erase(0);
2252                                         tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2253                                         tmpcursor.pos++;
2254                                 }
2255 #else
2256                                 simple_cut_buffer->CutIntoMinibuffer(0);
2257                                 simple_cut_buffer->Erase(0);
2258                                 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2259                                 tmpcursor.pos++;
2260 #endif
2261                         }
2262                 }
2263                 delete simple_cut_buffer;
2264                 simple_cut_buffer = tmppar;
2265                 endpar = tmpcursor.par->Next();
2266         } else {
2267                 // many paragraphs
2268
2269                 // make a copy of the simple cut_buffer
2270                 tmppar = simple_cut_buffer;
2271                 LyXParagraph * simple_cut_clone = tmppar->Clone();
2272                 LyXParagraph * tmppar2 = simple_cut_clone;
2273                 if (cursor.par->footnoteflag){
2274                         tmppar->footnoteflag = cursor.par->footnoteflag;
2275                         tmppar->footnotekind = cursor.par->footnotekind;
2276                 }
2277                 while (tmppar->next) {
2278                         tmppar = tmppar->next;
2279                         tmppar2->next = tmppar->Clone();
2280                         tmppar2->next->previous = tmppar2;
2281                         tmppar2 = tmppar2->next;
2282                         if (cursor.par->footnoteflag){
2283                                 tmppar->footnoteflag = cursor.par->footnoteflag;
2284                                 tmppar->footnotekind = cursor.par->footnotekind;
2285                         }
2286                 }
2287      
2288                 // make sure there is no class difference
2289                 SwitchLayoutsBetweenClasses(simple_cut_buffer_textclass,
2290                                             parameters->textclass,
2291                                             simple_cut_buffer);
2292      
2293                 // make the simple_cut_buffer exactly the same layout than
2294                 // the cursor paragraph
2295                 simple_cut_buffer->MakeSameLayout(cursor.par);
2296      
2297                 // find the end of the buffer
2298                 LyXParagraph * lastbuffer = simple_cut_buffer;
2299                 while (lastbuffer->Next())
2300                         lastbuffer = lastbuffer->Next();
2301      
2302                 // find the physical end of the buffer
2303 #ifdef WITH_WARNINGS
2304 #warning Explain this please.
2305 #endif
2306 #if 0
2307                 // Can someone explain to be why this is done a second time?
2308                 // (Lgb)
2309                 lastbuffer = simple_cut_buffer;
2310                 while (lastbuffer->Next())
2311                         lastbuffer = lastbuffer->Next();
2312 #endif 
2313 #ifndef FIX_DOUBLE_SPACE
2314                 // Please break behind a space, if there is one. The space 
2315                 // should be copied too.
2316                 if (cursor.par->Last() > cursor.pos
2317                     && cursor.par->IsLineSeparator(cursor.pos))
2318                         cursor.pos++; 
2319 #endif
2320                 bool paste_the_end = false;
2321
2322                 // open the paragraph for inserting the simple_cut_buffer
2323                 // if necessary
2324                 if (cursor.par->Last() > cursor.pos || !cursor.par->Next()){
2325                         cursor.par->BreakParagraphConservative(cursor.pos);
2326                         paste_the_end = true;
2327                 }
2328
2329 #ifndef FIX_DOUBLE_SPACE
2330                 // be careful with double spaces
2331                 if ((!cursor.par->Last()
2332                      || cursor.par->IsLineSeparator(cursor.pos - 1)
2333                      || cursor.par->IsNewline(cursor.pos - 1))
2334                     && simple_cut_buffer->text.size()
2335                     && simple_cut_buffer->IsLineSeparator(0))
2336                         simple_cut_buffer->Erase(0);
2337 #endif
2338                 // set the end for redoing later
2339                 endpar = cursor.par->ParFromPos(cursor.pos)->next->Next();
2340      
2341                 // paste it!
2342                 lastbuffer->ParFromPos(lastbuffer->Last())->next =
2343                         cursor.par->ParFromPos(cursor.pos)->next;
2344                 cursor.par->ParFromPos(cursor.pos)->next->previous =
2345                         lastbuffer->ParFromPos(lastbuffer->Last());
2346      
2347                 cursor.par->ParFromPos(cursor.pos)->next = simple_cut_buffer;
2348                 simple_cut_buffer->previous =
2349                         cursor.par->ParFromPos(cursor.pos);
2350    
2351                 if (cursor.par->ParFromPos(cursor.pos)->Next() == lastbuffer)
2352                         lastbuffer = cursor.par;
2353      
2354                 cursor.par->ParFromPos(cursor.pos)->PasteParagraph();
2355      
2356                 // store the new cursor position
2357                 tmpcursor.par = lastbuffer;
2358                 tmpcursor.pos = lastbuffer->Last();
2359      
2360                 // maybe some pasting
2361                 if (lastbuffer->Next() && paste_the_end) {
2362                         if (lastbuffer->Next()->HasSameLayout(lastbuffer)) {
2363 #ifndef FIX_DOUBLE_SPACE
2364                                 // be careful with double spaces
2365                                 if ((!lastbuffer->Last()
2366                                      || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2367                                      || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2368                                     && lastbuffer->Next()->Last()
2369                                     && lastbuffer->Next()->IsLineSeparator(0))
2370                                         lastbuffer->Next()->Erase(0);
2371 #endif
2372                                 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2373          
2374                         } else if (!lastbuffer->Next()->Last()) {
2375                                 lastbuffer->Next()->MakeSameLayout(lastbuffer);
2376 #ifndef FIX_DOUBLE_SPACE
2377                                 // be careful witth double spaces
2378                                 if ((!lastbuffer->Last()
2379                                      || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2380                                      || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2381                                     && lastbuffer->Next()->Last()
2382                                     && lastbuffer->Next()->IsLineSeparator(0))
2383                                         lastbuffer->Next()->Erase(0);
2384 #endif
2385                                 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2386          
2387                         } else if (!lastbuffer->Last()) {
2388                                 lastbuffer->MakeSameLayout(lastbuffer->next);
2389 #ifndef FIX_DOUBLE_SPACE
2390                                 // be careful witth double spaces
2391                                 if ((!lastbuffer->Last()
2392                                      || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2393                                      || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2394                                     && lastbuffer->Next()->Last()
2395                                     && lastbuffer->Next()->IsLineSeparator(0))
2396                                         lastbuffer->Next()->Erase(0);
2397 #endif
2398                                 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2399          
2400                         } else
2401                                 lastbuffer->Next()->ClearParagraph();
2402                 }
2403
2404                 // restore the simple cut buffer
2405                 simple_cut_buffer = simple_cut_clone;
2406         }
2407
2408         RedoParagraphs(cursor, endpar);
2409     
2410         SetCursor(cursor.par, cursor.pos);
2411         ClearSelection();
2412    
2413         sel_cursor = cursor;
2414         SetCursor(tmpcursor.par, tmpcursor.pos);
2415         SetSelection();
2416         UpdateCounters(cursor.row);
2417 }
2418    
2419
2420 // returns a pointer to the very first LyXParagraph
2421 LyXParagraph * LyXText::FirstParagraph() const
2422 {
2423         return params->paragraph;
2424 }
2425
2426
2427 // returns true if the specified string is at the specified position
2428 bool LyXText::IsStringInText(LyXParagraph * par,
2429                              LyXParagraph::size_type pos,
2430                              char const * str) const
2431 {
2432         if (par) {
2433                 int i = 0;
2434                 while (pos + i < par->Last() && str[i] && 
2435                        str[i] == par->GetChar(pos + i)) {
2436                         ++i;
2437                 }
2438                 if (!str[i])
2439                         return true;
2440         }
2441         return false;
2442 }
2443
2444
2445 // sets the selection over the number of characters of string, no check!!
2446 void LyXText::SetSelectionOverString(char const * string)
2447 {
2448         sel_cursor = cursor;
2449         for (int i = 0; string[i]; ++i)
2450                 CursorRight();
2451         SetSelection();
2452 }
2453
2454
2455 // simple replacing. The font of the first selected character is used
2456 void LyXText::ReplaceSelectionWithString(char const * str)
2457 {
2458         SetCursorParUndo();
2459         FreezeUndo();
2460
2461         if (!selection) { // create a dummy selection
2462                 sel_end_cursor = cursor;
2463                 sel_start_cursor = cursor;
2464         }
2465
2466         // Get font setting before we cut
2467         LyXParagraph::size_type pos = sel_end_cursor.pos;
2468         LyXFont font = sel_start_cursor.par->GetFontSettings(sel_start_cursor.pos);
2469
2470         // Insert the new string
2471         for (int i = 0; str[i]; ++i) {
2472                 sel_end_cursor.par->InsertChar(pos, str[i]);
2473                 sel_end_cursor.par->SetFont(pos, font);
2474                 ++pos;
2475         }
2476
2477         // Cut the selection
2478         CutSelection();
2479
2480         UnFreezeUndo();
2481 }
2482
2483
2484 // if the string can be found: return true and set the cursor to
2485 // the new position
2486 bool LyXText::SearchForward(char const * str) const
2487 {
2488         LyXParagraph * par = cursor.par;
2489         LyXParagraph::size_type pos = cursor.pos;
2490         while (par && !IsStringInText(par, pos, str)) {
2491                 if (pos < par->Last() - 1)
2492                         ++pos;
2493                 else {
2494                         pos = 0;
2495                         par = par->Next();
2496                 }
2497         }
2498         if (par) {
2499                 SetCursor(par, pos);
2500                 return true;
2501         }
2502         else
2503                 return false;
2504 }
2505
2506
2507 bool LyXText::SearchBackward(char const * string) const
2508 {
2509         LyXParagraph * par = cursor.par;
2510         int pos = cursor.pos;
2511
2512         do {
2513                 if (pos > 0)
2514                         --pos;
2515                 else {
2516                         // We skip empty paragraphs (Asger)
2517                         do {
2518                                 par = par->Previous();
2519                                 if (par)
2520                                         pos = par->Last() - 1;
2521                         } while (par && pos < 0);
2522                 }
2523         } while (par && !IsStringInText(par, pos, string));
2524   
2525         if (par) {
2526                 SetCursor(par, pos);
2527                 return true;
2528         } else
2529                 return false;
2530 }
2531
2532
2533 void LyXText::InsertStringA(LyXParagraph::TextContainer const & text)
2534 {
2535         char * str = new char[text.size() + 1];
2536         copy(text.begin(), text.end(), str);
2537         str[text.size()] = '\0';
2538         InsertStringA(str);
2539         delete [] str;
2540 }
2541
2542
2543 // needed to insert the selection
2544 void LyXText::InsertStringA(char const * s)
2545 {
2546         string str(s);
2547         LyXParagraph * par = cursor.par;
2548         LyXParagraph::size_type pos = cursor.pos;
2549         LyXParagraph::size_type a = 0;
2550         int cell = 0;
2551         LyXParagraph * endpar = cursor.par->Next();
2552         
2553         SetCursorParUndo();
2554         
2555         char flag =
2556                 textclasslist.Style(parameters->textclass, 
2557                                     cursor.par->GetLayout()).isEnvironment();
2558         // only to be sure, should not be neccessary
2559         ClearSelection();
2560         
2561         // insert the string, don't insert doublespace
2562         string::size_type i = 0;
2563         while (i < str.length()) {
2564                 if (str[i] != '\n') {
2565                         if (str[i] == ' ' 
2566                             && i + 1 < str.length() && str[i + 1] != ' '
2567                             && pos && par->GetChar(pos - 1)!= ' ') {
2568                                 par->InsertChar(pos,' ');
2569                                 ++pos;
2570                         } else if (par->table) {
2571                                 if (str[i] == '\t') {
2572                                         while((pos < par->size()) &&
2573                                               (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2574                                                 ++pos;
2575                                         if (pos < par->size())
2576                                                 ++pos;
2577                                         else // no more fields to fill skip the rest
2578                                                 break;
2579                                 } else if ((str[i] != 13) &&
2580                                            ((str[i] & 127) >= ' ')) {
2581                                         par->InsertChar(pos, str[i]);
2582                                         ++pos;
2583                                 }
2584                         } else if (str[i] == ' ') {
2585                                 par->InsertChar(pos, LyXParagraph::META_PROTECTED_SEPARATOR);
2586                                 ++pos;
2587                         } else if (str[i] == '\t') {
2588                                 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2589                                         par->InsertChar(a, LyXParagraph::META_PROTECTED_SEPARATOR);
2590                                 }
2591                                 pos = a;
2592                         } else if (str[i]!= 13 && 
2593                                    // Ignore unprintables
2594                                    (str[i] & 127) >= ' ') {
2595                                 par->InsertChar(pos, str[i]);
2596                                 ++pos;
2597                         }
2598                 } else {
2599                         if (par->table) {
2600                                 if (i + 1 >= str.length()) {
2601                                         ++pos;
2602                                         break;
2603                                 }
2604                                 while((pos < par->size()) &&
2605                                       (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2606                                         ++pos;
2607                                 ++pos;
2608                                 cell = NumberOfCell(par, pos);
2609                                 while((pos < par->size()) &&
2610                                       !(par->table->IsFirstCell(cell))) {
2611                                         while((pos < par->size()) &&
2612                                               (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2613                                                 ++pos;
2614                                         ++pos;
2615                                         cell = NumberOfCell(par, pos);
2616                                 }
2617                                 if (pos >= par->size())
2618                                         // no more fields to fill skip the rest
2619                                         break;
2620                         } else {
2621                                 if (!par->text.size()) {
2622                                         par->InsertChar(pos, LyXParagraph::META_PROTECTED_SEPARATOR);
2623                                         ++pos;
2624                                 }
2625                                 par->BreakParagraph(pos, flag);
2626                                 par = par->Next();
2627                                 pos = 0;
2628                         }
2629                 }
2630                 ++i;
2631         }
2632         
2633         RedoParagraphs(cursor, endpar);
2634         SetCursor(cursor.par, cursor.pos);
2635         sel_cursor = cursor;
2636         SetCursor(par, pos);
2637         SetSelection();
2638 }
2639
2640
2641 void LyXText::InsertStringB(LyXParagraph::TextContainer const & text)
2642 {
2643         char * str = new char[text.size() + 1];
2644         copy(text.begin(), text.end(), str);
2645         str[text.size()] = '\0';
2646         InsertStringB(str);
2647         delete [] str;
2648 }
2649
2650
2651 /* turns double-CR to single CR, others where converted into one blank and 13s 
2652  * that are ignored .Double spaces are also converted into one. Spaces at
2653  * the beginning of a paragraph are forbidden. tabs are converted into one
2654  * space. then InsertStringA is called */ 
2655 void LyXText::InsertStringB(char const * s)
2656 {
2657         string str(s);
2658         LyXParagraph * par = cursor.par;
2659         string::size_type i = 1;
2660         while (i < str.length()) {
2661                 if (str[i] == '\t' && !par->table)
2662                         str[i] = ' ';
2663                 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2664                         str[i] = 13;
2665                 if (str[i] == '\n' && i + 1 < str.length() && !par->table){
2666                         if (str[i + 1] != '\n') {
2667                                 if (str[i - 1] != ' ')
2668                                         str[i] = ' ';
2669                                 else
2670                                         str[i] = 13;
2671                         }
2672                         while (i + 1 < str.length() 
2673                                && (str[i + 1] == ' ' 
2674                                    || str[i + 1] == '\t'
2675                                    || str[i + 1] == '\n' 
2676                                    || str[i + 1] == 13)) {
2677                                 str[i + 1] = 13;
2678                                 ++i;
2679                         }
2680                 }
2681                 ++i;
2682         }
2683         InsertStringA(str.c_str());
2684 }
2685
2686
2687 bool LyXText::GotoNextError() const
2688 {
2689         LyXCursor res = cursor;
2690         do {
2691                 if (res.pos < res.par->Last() - 1) {
2692                         res.pos++;
2693                 }
2694                 else  {
2695                         res.par = res.par->Next();
2696                         res.pos = 0;
2697                 }
2698       
2699         } while (res.par && 
2700                  !(res.par->GetChar(res.pos) == LyXParagraph::META_INSET
2701                    && res.par->GetInset(res.pos)->AutoDelete()));
2702    
2703         if (res.par) {
2704                 SetCursor(res.par, res.pos);
2705                 return true;
2706         }
2707         return false;
2708 }
2709
2710
2711 bool LyXText::GotoNextNote() const
2712 {
2713         LyXCursor res = cursor;
2714         do {
2715                 if (res.pos < res.par->Last() - 1) {
2716                         res.pos++;
2717                 } else  {
2718                         res.par = res.par->Next();
2719                         res.pos = 0;
2720                 }
2721       
2722         } while (res.par && 
2723                  !(res.par->GetChar(res.pos) == LyXParagraph::META_INSET
2724                    && res.par->GetInset(res.pos)->LyxCode() == Inset::IGNORE_CODE));
2725    
2726         if (res.par) {
2727                 SetCursor(res.par, res.pos);
2728                 return true;
2729         }
2730         return false;
2731 }
2732
2733
2734 int LyXText::SwitchLayoutsBetweenClasses(char class1, char class2,
2735                                          LyXParagraph * par)
2736 {
2737         int ret = 0;
2738         if (!par || class1 == class2)
2739                 return ret;
2740         par = par->FirstPhysicalPar();
2741         while (par) {
2742                 string name = textclasslist.NameOfLayout(class1, par->layout);
2743                 int lay = 0;
2744                 pair<bool, LyXTextClass::LayoutList::size_type> pp =
2745                         textclasslist.NumberOfLayout(class2, name);
2746                 if (pp.first) {
2747                         lay = pp.second;
2748                 } else { // layout not found
2749                         // use default layout "Standard" (0)
2750                         lay = 0;
2751                 }
2752                 par->layout = lay;
2753       
2754                 if (name != textclasslist.NameOfLayout(class2, par->layout)) {
2755                         ++ret;
2756                         string s = "Layout had to be changed from\n"
2757                                 + name + " to " + textclasslist.NameOfLayout(class2, par->layout)
2758                                 + "\nbecause of class conversion from\n"
2759                                 + textclasslist.NameOfClass(class1) + " to "
2760                                 + textclasslist.NameOfClass(class2);
2761                         InsetError * new_inset = new InsetError(s);
2762                         par->InsertChar(0, LyXParagraph::META_INSET);
2763                         par->InsertInset(0, new_inset);
2764                 }
2765       
2766                 par = par->next;
2767         }
2768         return ret;
2769 }
2770
2771
2772 void LyXText::CheckParagraph(LyXParagraph * par,
2773                              LyXParagraph::size_type pos)
2774 {
2775   
2776         LyXCursor tmpcursor;
2777
2778         /* table stuff -- begin*/
2779    
2780         if (par->table) {
2781                 CheckParagraphInTable(par, pos);
2782         }
2783         else {
2784                 /* table stuff -- end*/
2785      
2786                 long y = 0;
2787                 LyXParagraph::size_type z;
2788                 Row * row = GetRow(par, pos, y);
2789      
2790                 // is there a break one row above
2791                 if (row->previous && row->previous->par == row->par) {
2792                         z = NextBreakPoint(row->previous, paperwidth);
2793                         if ( z >= row->pos) {
2794                                 // set the dimensions of the row above
2795                                 y -= row->previous->height;
2796                                 refresh_y = y;
2797                                 refresh_row = row->previous;
2798                                 status = LyXText::NEED_MORE_REFRESH;
2799        
2800                                 BreakAgain(row->previous);
2801
2802                                 // set the cursor again. Otherwise
2803                                 // dangling pointers are possible
2804                                 SetCursor(cursor.par, cursor.pos);
2805                                 sel_cursor = cursor;
2806                                 return;
2807                         }
2808                 }
2809
2810                 int tmpheight = row->height;
2811                 LyXParagraph::size_type tmplast = RowLast(row);
2812                 refresh_y = y;
2813                 refresh_row = row;
2814
2815                 BreakAgain(row);
2816                 if (row->height == tmpheight && RowLast(row) == tmplast)
2817                         status = LyXText::NEED_VERY_LITTLE_REFRESH;
2818                 else
2819                         status = LyXText::NEED_MORE_REFRESH; 
2820    
2821                 // check the special right address boxes
2822                 if (textclasslist.Style(parameters->textclass,
2823                                         par->GetLayout()).margintype
2824                     == MARGIN_RIGHT_ADDRESS_BOX) {
2825                         tmpcursor.par = par;
2826                         tmpcursor.row = row;
2827                         tmpcursor.y = y;
2828                         tmpcursor.x = 0;
2829                         tmpcursor.x_fix = 0;
2830                         tmpcursor.pos = pos;
2831                         RedoDrawingOfParagraph(tmpcursor); 
2832                 }
2833    
2834         }
2835
2836         // set the cursor again. Otherwise dangling pointers are possible
2837         // also set the selection
2838    
2839         if (selection) {
2840                 tmpcursor = cursor;
2841                 SetCursorIntern(sel_cursor.par, sel_cursor.pos);
2842                 sel_cursor = cursor; 
2843                 SetCursorIntern(sel_start_cursor.par, sel_start_cursor.pos);
2844                 sel_start_cursor = cursor; 
2845                 SetCursorIntern(sel_end_cursor.par, sel_end_cursor.pos);
2846                 sel_end_cursor = cursor; 
2847                 SetCursorIntern(last_sel_cursor.par, last_sel_cursor.pos);
2848                 last_sel_cursor = cursor; 
2849                 cursor = tmpcursor;
2850         }
2851         SetCursorIntern(cursor.par, cursor.pos);
2852 }
2853
2854
2855 // returns 0 if inset wasn't found
2856 int LyXText::UpdateInset(Inset * inset)
2857 {
2858         // first check the current paragraph
2859         int pos = cursor.par->GetPositionOfInset(inset);
2860         if (pos != -1){
2861                 CheckParagraph(cursor.par, pos);
2862                 return 1;
2863         }
2864   
2865         // check every paragraph
2866   
2867         LyXParagraph * par = FirstParagraph();
2868         do {
2869                 // make sure the paragraph is open
2870                 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2871                         pos = par->GetPositionOfInset(inset);
2872                         if (pos != -1){
2873                                 CheckParagraph(par, pos);
2874                                 return 1;
2875                         }
2876                 }
2877                 par = par->Next();
2878         } while (par);
2879   
2880         return 0;
2881 }
2882
2883
2884 void LyXText::SetCursor(LyXParagraph * par,
2885                         LyXParagraph::size_type pos) const
2886 {
2887         LyXCursor old_cursor = cursor;
2888         SetCursorIntern(par, pos);
2889         DeleteEmptyParagraphMechanism(old_cursor);
2890 }
2891
2892
2893 void LyXText::SetCursorIntern(LyXParagraph * par,
2894                               LyXParagraph::size_type pos) const
2895 {
2896         long y;
2897         Row * row;
2898         int left_margin;
2899         LyXParagraph * tmppar;
2900    
2901         // correct the cursor position if impossible
2902         if (pos > par->Last()){
2903                 tmppar = par->ParFromPos(pos);
2904                 pos = par->PositionInParFromPos(pos);
2905                 par = tmppar;
2906         }
2907         if (par->IsDummy() && par->previous &&
2908             par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2909                 while (par->previous &&
2910                        ((par->previous->IsDummy() && par->previous->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) ||
2911                         (par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE))) {
2912                         par = par->previous ;
2913                         if (par->IsDummy() &&
2914                             par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
2915                                 pos += par->text.size() + 1;
2916                 }
2917                 if (par->previous) {
2918                         par = par->previous;
2919                 }
2920                 pos += par->text.size() + 1;
2921         }
2922
2923         cursor.par = par;
2924         cursor.pos = pos;
2925
2926         /* get the cursor y position in text  */
2927         row = GetRow(par, pos, y);
2928         /* y is now the beginning of the cursor row */ 
2929         y += row->baseline;
2930         /* y is now the cursor baseline */ 
2931         cursor.y = y;
2932    
2933         /* now get the cursors x position */
2934    
2935         float x;
2936         float fill_separator, fill_hfill, fill_label_hfill;
2937         left_margin = LabelEnd(row);
2938         PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
2939         LyXParagraph::size_type main_body =
2940                 BeginningOfMainBody(row->par);
2941         /* table stuff -- begin*/
2942         if (row->par->table) {
2943                 int cell = NumberOfCell(row->par, row->pos);
2944                 float x_old = x;
2945                 x += row->par->table->GetBeginningOfTextInCell(cell);
2946                 for (pos = row->pos; pos < cursor.pos; ++pos)  {
2947                         if (row->par->IsNewline(pos)) {
2948                                 x = x_old + row->par->table->WidthOfColumn(cell);
2949                                 x_old = x;
2950                                 ++cell;
2951                                 x += row->par->table->GetBeginningOfTextInCell(cell);
2952                         } else {
2953                                 x += SingleWidth(row->par, pos);
2954                         }
2955                 }
2956         } else
2957                 /* table stuff -- end*/
2958
2959                 for (pos = row->pos; pos < cursor.pos; ++pos)  {
2960                         if (pos && pos == main_body
2961                             && !row->par->IsLineSeparator(pos - 1)) {
2962                                 x += GetFont(row->par, -2).stringWidth(
2963                                                     textclasslist.Style(parameters->textclass, row->par->GetLayout()).labelsep);
2964                                 if (x < left_margin)
2965                                         x = left_margin;
2966                         }
2967       
2968                         x += SingleWidth(row->par, pos);
2969                         if (HfillExpansion(row, pos)) {
2970                                 if (pos >= main_body)
2971                                         x += fill_hfill;
2972                                 else 
2973                                         x += fill_label_hfill;
2974                         }
2975                         else if (pos >= main_body && row->par->IsSeparator(pos)) {
2976                                 x+= fill_separator;
2977                         }
2978       
2979                         if (pos + 1 == main_body
2980                             && row->par->IsLineSeparator(pos)) {
2981                                 x += GetFont(row->par, -2).stringWidth(
2982                                                     textclasslist.Style(parameters->textclass, row->par->GetLayout()).labelsep);
2983                                 if (row->par->IsLineSeparator(pos))
2984                                         x -= SingleWidth(row->par, pos);
2985                                 if (x < left_margin)
2986                                         x = left_margin;
2987                         }
2988                 }
2989    
2990         cursor.x = int(x);
2991    
2992         cursor.x_fix = cursor.x;
2993         cursor.row = row;
2994    
2995         if (cursor.pos && 
2996             (cursor.pos == cursor.par->Last() || cursor.par->IsSeparator(cursor.pos)
2997              || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
2998                  && !cursor.par->IsSeparator(cursor.pos))
2999                     )) {
3000                 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
3001                 real_current_font = GetFont(cursor.par, cursor.pos - 1);
3002         } else {
3003                 current_font = cursor.par->GetFontSettings(cursor.pos);
3004                 real_current_font = GetFont(cursor.par, cursor.pos);
3005         }
3006 }
3007
3008
3009 void LyXText::SetCursorFromCoordinates(int x, long y) const
3010 {
3011         LyXCursor old_cursor = cursor;
3012    
3013         /* get the row first */ 
3014    
3015         Row * row = GetRowNearY(y);
3016    
3017         cursor.par = row->par;
3018    
3019         int column = GetColumnNearX(row, x);
3020         cursor.pos = row->pos + column;
3021         cursor.x = x;
3022         cursor.y = y + row->baseline;
3023    
3024         cursor.row = row;
3025     
3026         if (cursor.pos && 
3027             (cursor.pos == cursor.par->Last()
3028              || cursor.par->IsSeparator(cursor.pos)
3029              || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
3030                  && !cursor.par->IsSeparator(cursor.pos))
3031                     )) {
3032                 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
3033                 real_current_font = GetFont(cursor.par, cursor.pos - 1);
3034         } else {
3035                 current_font = cursor.par->GetFontSettings(cursor.pos);
3036                 real_current_font = GetFont(cursor.par, cursor.pos);
3037         }
3038         DeleteEmptyParagraphMechanism(old_cursor);
3039 }
3040
3041
3042 void LyXText::CursorLeft() const
3043 {
3044         CursorLeftIntern();
3045         if (cursor.par->table) {
3046                 int cell = NumberOfCell(cursor.par, cursor.pos);
3047                 if (cursor.par->table->IsContRow(cell) &&
3048                     cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3049                         CursorUp();
3050                 }
3051         }
3052 }
3053
3054
3055 void LyXText::CursorLeftIntern() const
3056 {
3057         if (cursor.pos > 0) {
3058                 SetCursor(cursor.par, cursor.pos - 1);
3059         }
3060         else if (cursor.par->Previous()) {
3061                 SetCursor(cursor.par->Previous(), cursor.par->Previous()->Last());
3062         }
3063 }
3064
3065
3066 void LyXText::CursorRight() const
3067 {
3068         CursorRightIntern();
3069         if (cursor.par->table) {
3070                 int cell = NumberOfCell(cursor.par, cursor.pos);
3071                 if (cursor.par->table->IsContRow(cell) &&
3072                     cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3073                         CursorUp();
3074                 }
3075         }
3076 }
3077
3078
3079 void LyXText::CursorRightIntern() const
3080 {
3081         if (cursor.pos < cursor.par->Last()) {
3082                 SetCursor(cursor.par, cursor.pos + 1);
3083         }
3084         else if (cursor.par->Next()) {
3085                 SetCursor(cursor.par->Next(), 0);
3086         }
3087 }
3088
3089
3090 void LyXText::CursorUp() const
3091 {
3092         SetCursorFromCoordinates(cursor.x_fix, 
3093                                  cursor.y - cursor.row->baseline - 1);
3094         if (cursor.par->table) {
3095                 int cell = NumberOfCell(cursor.par, cursor.pos);
3096                 if (cursor.par->table->IsContRow(cell) &&
3097                     cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3098                         CursorUp();
3099                 }
3100         }
3101 }
3102
3103
3104 void LyXText::CursorDown() const
3105 {
3106         if (cursor.par->table &&
3107             cursor.par->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par, cursor.pos)) &&
3108             !cursor.par->next)
3109                 return;
3110         SetCursorFromCoordinates(cursor.x_fix, 
3111                                  cursor.y - cursor.row->baseline
3112                                  + cursor.row->height + 1);
3113         if (cursor.par->table) {
3114                 int cell = NumberOfCell(cursor.par, cursor.pos);
3115                 int cell_above = cursor.par->table->GetCellAbove(cell);
3116                 while(cursor.par->table &&
3117                       cursor.par->table->IsContRow(cell) &&
3118                       (cursor.par->table->CellHasContRow(cell_above)<0)) {
3119                     SetCursorFromCoordinates(cursor.x_fix, 
3120                                              cursor.y - cursor.row->baseline
3121                                              + cursor.row->height + 1);
3122                     if (cursor.par->table) {
3123                         cell = NumberOfCell(cursor.par, cursor.pos);
3124                         cell_above = cursor.par->table->GetCellAbove(cell);
3125                     }
3126                 }
3127         }
3128 }
3129
3130
3131 void LyXText::CursorUpParagraph() const
3132 {
3133         if (cursor.pos > 0) {
3134                 SetCursor(cursor.par, 0);
3135         }
3136         else if (cursor.par->Previous()) {
3137                 SetCursor(cursor.par->Previous(), 0);
3138         }
3139 }
3140
3141
3142 void LyXText::CursorDownParagraph() const
3143 {
3144         if (cursor.par->Next()) {
3145                 SetCursor(cursor.par->Next(), 0);
3146         } else {
3147                 SetCursor(cursor.par, cursor.par->Last());
3148         }
3149 }
3150
3151
3152
3153 void LyXText::DeleteEmptyParagraphMechanism(LyXCursor const & old_cursor) const
3154 {
3155         bool deleted = false;
3156         
3157         // this is the delete-empty-paragraph-mechanism.
3158         if (selection) return;
3159
3160 #ifdef FIX_DOUBLE_SPACE
3161         /* Ok I'll put some comments here about what is missing.
3162            I have fixed BackSpace (and thus Delete) to not delete
3163            double-spaces automagically. I have also changed Cut,
3164            Copy and Paste to hopefully do some sensible things.
3165            There are still some small problems that can lead to
3166            double spaces stored in the document file or space at
3167            the beginning of paragraphs. This happens if you have
3168            the cursor betwenn to spaces and then save. Or if you
3169            cut and paste and the selection have a space at the
3170            beginning and then save right after the paste. I am
3171            sure none of these are very hard to fix, but I will
3172            put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3173            that I can get some feedback. (Lgb)
3174         */
3175
3176         // If old_cursor.pos == 0 and old_cursor.pos(1) == LineSeparator
3177         // delete the LineSeparator.
3178         // MISSING
3179
3180         // If old_cursor.pos == 1 and old_cursor.pos(0) == LineSeparator
3181         // delete the LineSeparator.
3182         // MISSING
3183
3184         // If the pos around the old_cursor were spaces, delete one of them.
3185         if (!(old_cursor.par == cursor.par && old_cursor.pos == cursor.pos)
3186             && old_cursor.pos > 0
3187             && old_cursor.pos < old_cursor.par->Last()
3188             && old_cursor.par->IsLineSeparator(old_cursor.pos)
3189             && old_cursor.par->IsLineSeparator(old_cursor.pos - 1)) {
3190                 old_cursor.par->Erase(old_cursor.pos - 1);
3191                 RedoParagraphs(old_cursor, old_cursor.par->Next());
3192                 // or RedoDrawingOfParagraph(old_cursor);
3193                 // correct cursor
3194                 if (old_cursor.par == cursor.par &&
3195                     cursor.pos > old_cursor.pos)
3196                         SetCursor(cursor.par, cursor.pos - 1);
3197                 else
3198                         SetCursor(cursor.par, cursor.pos);
3199                 return;
3200         }
3201 #endif
3202         //
3203         // Paragraph should not be deleted if empty
3204         if ((textclasslist.Style(parameters->textclass,
3205                                  old_cursor.par->GetLayout())).keepempty)
3206                 return;
3207
3208         LyXCursor tmpcursor;
3209
3210         if (old_cursor.par != cursor.par) {
3211                 if ( (old_cursor.par->Last() == 0
3212                       || (old_cursor.par->Last() == 1
3213                           && (old_cursor.par->IsLineSeparator(0))))
3214                      && old_cursor.par->FirstPhysicalPar()
3215                      == old_cursor.par->LastPhysicalPar()) {
3216                         
3217                         // ok, we will delete anything
3218                         
3219                         // make sure that you do not delete any environments
3220                         if ((old_cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3221                              !(old_cursor.row->previous 
3222                                && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3223                              && !(old_cursor.row->next 
3224                                   && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3225                             || 
3226                             (old_cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE &&
3227                              ((old_cursor.row->previous 
3228                                && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3229                               || 
3230                               (old_cursor.row->next
3231                                && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3232                                     )) {
3233                                 status = LyXText::NEED_MORE_REFRESH;
3234                                 deleted = true;
3235                                 
3236                                 if (old_cursor.row->previous) {
3237                                         refresh_row = old_cursor.row->previous;
3238                                         refresh_y = old_cursor.y - old_cursor.row->baseline - refresh_row->height;
3239                                         tmpcursor = cursor;
3240                                         cursor = old_cursor; // that undo can restore the right cursor position
3241                                         LyXParagraph * endpar = old_cursor.par->next;
3242                                         if (endpar && endpar->GetDepth()) {
3243                                                 while (endpar && endpar->GetDepth()) {
3244                                                         endpar = endpar->LastPhysicalPar()->Next();
3245                                                 }
3246                                         }
3247                                         SetUndo(Undo::DELETE,
3248                                                 old_cursor.par->previous,
3249                                                 endpar);
3250                                         cursor = tmpcursor;
3251
3252                                         // delete old row
3253                                         RemoveRow(old_cursor.row);
3254                                         if (params->paragraph == old_cursor.par) {
3255                                                 params->paragraph = params->paragraph->next;
3256                                         }
3257                                         // delete old par
3258                                         delete old_cursor.par;
3259                                         
3260                                         /* Breakagain the next par. Needed
3261                                          * because of the parindent that
3262                                          * can occur or dissappear. The
3263                                          * next row can change its height,
3264                                          * if there is another layout before */
3265                                         if (refresh_row->next) {
3266                                                 BreakAgain(refresh_row->next);
3267                                                 UpdateCounters(refresh_row);
3268                                         }
3269                                         SetHeightOfRow(refresh_row);
3270                                 } else {
3271                                         refresh_row = old_cursor.row->next;
3272                                         refresh_y = old_cursor.y - old_cursor.row->baseline;
3273                                         
3274                                         tmpcursor = cursor;
3275                                         cursor = old_cursor; // that undo can restore the right cursor position
3276                                         LyXParagraph *endpar = old_cursor.par->next;
3277                                         if (endpar && endpar->GetDepth()) {
3278                                                 while (endpar && endpar->GetDepth()) {
3279                                                         endpar = endpar->LastPhysicalPar()->Next();
3280                                                 }
3281                                         }
3282                                         SetUndo(Undo::DELETE,
3283                                                 old_cursor.par->previous,
3284                                                 endpar);
3285                                         cursor = tmpcursor;
3286
3287                                         // delete old row
3288                                         RemoveRow(old_cursor.row);
3289                                         // delete old par
3290                                         if (params->paragraph == old_cursor.par) {
3291                                                 params->paragraph = params->paragraph->next;
3292                                         }
3293                                         delete old_cursor.par;
3294                                         
3295                                         /* Breakagain the next par. Needed
3296                                            because of the parindent that can
3297                                            occur or dissappear.
3298                                            The next row can change its height,
3299                                            if there is another layout before
3300                                         */ 
3301                                         if (refresh_row) {
3302                                                 BreakAgain(refresh_row);
3303                                                 UpdateCounters(refresh_row->previous);
3304                                         }
3305                                 }
3306                                 
3307                                 // correct cursor y
3308                                 SetCursor(cursor.par, cursor.pos);
3309                                 
3310                                 /* if (cursor.y > old_cursor.y)
3311                                    cursor.y -= old_cursor.row->height; */ 
3312          
3313                                 if (sel_cursor.par  == old_cursor.par
3314                                     && sel_cursor.pos == sel_cursor.pos) {
3315                                         // correct selection
3316                                         sel_cursor = cursor;
3317                                 }
3318                         }
3319                 }
3320                 if (!deleted) {
3321                         if (old_cursor.par->ClearParagraph()){
3322                                 RedoParagraphs(old_cursor, old_cursor.par->Next());
3323                                 // correct cursor y
3324                                 SetCursor(cursor.par, cursor.pos);
3325                                 sel_cursor = cursor;
3326                         }
3327                 }
3328         }
3329 #if 0
3330         else if (cursor.par->table && (cursor.row != old_cursor.row)) {
3331                 int cell = NumberOfCell(old_cursor.par, old_cursor.pos);
3332                 if (old_cursor.par->table->IsContRow(cell) &&
3333                     IsEmptyTableRow(old_cursor)) {
3334                         RemoveTableRow(const_cast<LyXCursor*>(&old_cursor));
3335                         RedoParagraph();
3336                 }
3337         }
3338 #endif
3339 }
3340
3341
3342 LyXParagraph * LyXText::GetParFromID(int id)
3343 {
3344         LyXParagraph * result = FirstParagraph();
3345         while (result && result->id() != id)
3346                 result = result->next;
3347         return result;
3348 }
3349
3350
3351 // undo functions
3352 bool LyXText::TextUndo()
3353 {
3354         // returns false if no undo possible
3355         Undo * undo = params->undostack.pop();
3356         if (undo) {
3357                 FinishUndo();
3358                 if (!undo_frozen)
3359                         params->redostack
3360                                 .push(CreateUndo(undo->kind, 
3361                                                  GetParFromID(undo->number_of_before_par),
3362                                                  GetParFromID(undo->number_of_behind_par)));
3363         }
3364         return TextHandleUndo(undo);
3365 }
3366
3367
3368 bool LyXText::TextRedo()
3369 {
3370         // returns false if no redo possible
3371         Undo * undo = params->redostack.pop();
3372         if (undo) {
3373                 FinishUndo();
3374                 if (!undo_frozen)
3375                         params->undostack
3376                                 .push(CreateUndo(undo->kind, 
3377                                                  GetParFromID(undo->number_of_before_par),
3378                                                  GetParFromID(undo->number_of_behind_par)));
3379         }
3380         return TextHandleUndo(undo);
3381 }
3382
3383
3384 bool LyXText::TextHandleUndo(Undo * undo)
3385 {
3386         // returns false if no undo possible
3387         bool result = false;
3388         if (undo) {
3389                 LyXParagraph * before =
3390                         GetParFromID(undo->number_of_before_par); 
3391                 LyXParagraph * behind =
3392                         GetParFromID(undo->number_of_behind_par); 
3393                 LyXParagraph * tmppar;
3394                 LyXParagraph * tmppar2;
3395                 LyXParagraph * tmppar3;
3396                 LyXParagraph * tmppar4;
3397                 LyXParagraph * endpar;
3398                 LyXParagraph * tmppar5;
3399     
3400                 // if there's no before take the beginning
3401                 // of the document for redoing
3402                 if (!before)
3403                         SetCursorIntern(FirstParagraph(), 0);
3404
3405                 // replace the paragraphs with the undo informations
3406
3407                 tmppar3 = undo->par;
3408                 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3409                 tmppar4 = tmppar3;
3410                 if (tmppar4){
3411                         while (tmppar4->next)
3412                                 tmppar4 = tmppar4->next;
3413                 } // get last undo par
3414     
3415                 // now remove the old text if there is any
3416                 if (before != behind || (!behind && !before)){
3417                         if (before)
3418                                 tmppar5 = before->next;
3419                         else
3420                                 tmppar5 = params->paragraph;
3421                         tmppar2 = tmppar3;
3422                         while (tmppar5 && tmppar5 != behind){
3423                                 tmppar = tmppar5;
3424                                 tmppar5 = tmppar5->next;
3425                                 // a memory optimization for edit: Only layout information
3426                                 // is stored in the undo. So restore the text informations.
3427                                 if (undo->kind == Undo::EDIT){
3428                                         tmppar2->text = tmppar->text;
3429                                         tmppar->text.clear();
3430                                         tmppar2 = tmppar2->next;
3431                                 }
3432                                 if ( currentrow && currentrow->par == tmppar )
3433                                         currentrow = currentrow -> previous;
3434                                 // Commenting out this might remove the error
3435                                 // reported by Purify, but it might also
3436                                 // introduce a memory leak. We need to
3437                                 // check this (Lgb)
3438                                 //delete tmppar;
3439                         }
3440                 }
3441     
3442                 // put the new stuff in the list if there is one
3443                 if (tmppar3){
3444                         if (before)
3445                                 before->next = tmppar3;
3446                         else
3447                                 params->paragraph = tmppar3;
3448                         tmppar3->previous = before;
3449                 }
3450                 else {
3451                         if (!before)
3452                                 params->paragraph = behind;
3453                 }
3454                 if (tmppar4) {
3455                         tmppar4->next = behind;
3456                         if (behind)
3457                                 behind->previous = tmppar4;
3458                 }
3459     
3460     
3461                 // Set the cursor for redoing
3462                 if (before){
3463                         SetCursorIntern(before->FirstSelfrowPar(), 0);
3464                         // check wether before points to a closed float and open it if necessary
3465                         if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3466                             && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3467                                 tmppar4 = before;
3468                                 while (tmppar4->previous && 
3469                                        tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3470                                         tmppar4 = tmppar4->previous;
3471                                 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3472                                         tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3473                                         tmppar4 = tmppar4->next;
3474                                 }
3475                         }
3476                 }
3477     
3478                 // open a cosed footnote at the end if necessary
3479                 if (behind && behind->previous && 
3480                     behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3481                     behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3482                         while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3483                                 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3484                                 behind = behind->next;
3485                         }
3486                 }
3487     
3488                 // calculate the endpar for redoing the paragraphs.
3489                 if (behind){
3490                         if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3491                                 endpar = behind->LastPhysicalPar()->Next();
3492                         else
3493                                 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3494                 }
3495                 else
3496                         endpar = behind;
3497     
3498                 tmppar = GetParFromID(undo->number_of_cursor_par);
3499                 RedoParagraphs(cursor, endpar); 
3500                 if (tmppar){
3501                         SetCursorIntern(tmppar, undo->cursor_pos);
3502                         UpdateCounters(cursor.row);
3503                 }
3504                 result = true;
3505                 delete undo;
3506         }
3507         FinishUndo();
3508         return result;
3509 }
3510
3511
3512 void LyXText::FinishUndo()
3513 {
3514         // makes sure the next operation will be stored
3515         undo_finished = True;
3516 }
3517
3518
3519 void LyXText::FreezeUndo()
3520 {
3521         // this is dangerous and for internal use only
3522         undo_frozen = True;
3523 }
3524
3525
3526 void LyXText::UnFreezeUndo()
3527 {
3528         // this is dangerous and for internal use only
3529         undo_frozen = false;
3530 }
3531
3532
3533 void LyXText::SetUndo(Undo::undo_kind kind, LyXParagraph const * before,
3534                       LyXParagraph const * behind) const
3535 {
3536         if (!undo_frozen)
3537                 params->undostack.push(CreateUndo(kind, before, behind));
3538         params->redostack.clear();
3539 }
3540
3541
3542 void LyXText::SetRedo(Undo::undo_kind kind, LyXParagraph const * before,
3543                       LyXParagraph const * behind)
3544 {
3545         params->redostack.push(CreateUndo(kind, before, behind));
3546 }
3547
3548
3549 Undo * LyXText::CreateUndo(Undo::undo_kind kind, LyXParagraph const * before,
3550                           LyXParagraph const * behind) const
3551 {
3552         int before_number = -1;
3553         int behind_number = -1;
3554         if (before)
3555                 before_number = before->id();
3556         if (behind)
3557                 behind_number = behind->id();
3558         // Undo::EDIT  and Undo::FINISH are
3559         // always finished. (no overlapping there)
3560         // overlapping only with insert and delete inside one paragraph: 
3561         // Nobody wants all removed  character
3562         // appear one by one when undoing. 
3563         // EDIT is special since only layout information, not the
3564         // contents of a paragaph are stored.
3565         if (!undo_finished && kind != Undo::EDIT && 
3566             kind != Undo::FINISH){
3567                 // check wether storing is needed
3568                 if (!params->undostack.empty() && 
3569                     params->undostack.top()->kind == kind &&
3570                     params->undostack.top()->number_of_before_par ==  before_number &&
3571                     params->undostack.top()->number_of_behind_par ==  behind_number ){
3572                         // no undo needed
3573                         return 0;
3574                 }
3575         }
3576         // create a new Undo
3577         LyXParagraph * undopar;
3578         LyXParagraph * tmppar;
3579         LyXParagraph * tmppar2;
3580
3581         LyXParagraph * start = 0;
3582         LyXParagraph * end = 0;
3583   
3584         if (before)
3585                 start = before->next;
3586         else
3587                 start = FirstParagraph();
3588         if (behind)
3589                 end = behind->previous;
3590         else {
3591                 end = FirstParagraph();
3592                 while (end->next)
3593                         end = end->next;
3594         }
3595
3596         if (start && end
3597             && start != end->next
3598             && (before != behind || (!before && !behind))) {
3599                 tmppar = start;
3600                 tmppar2 = tmppar->Clone();
3601                 tmppar2->id(tmppar->id());
3602
3603                 // a memory optimization: Just store the layout information
3604                 // when only edit
3605                 if (kind == Undo::EDIT){
3606                         tmppar2->text.clear();
3607                 }
3608
3609                 undopar = tmppar2;
3610   
3611                 while (tmppar != end && tmppar->next) {
3612                         tmppar = tmppar->next;
3613                         tmppar2->next = tmppar->Clone();
3614                         tmppar2->next->id(tmppar->id());
3615                         // a memory optimization: Just store the layout
3616                         // information when only edit
3617                         if (kind == Undo::EDIT){
3618                                 tmppar2->next->text.clear();
3619                         }
3620                         tmppar2->next->previous = tmppar2;
3621                         tmppar2 = tmppar2->next;
3622                 }
3623                 tmppar2->next = 0;
3624         } else
3625                 undopar = 0; // nothing to replace (undo of delete maybe)
3626   
3627         int cursor_par = cursor.par->ParFromPos(cursor.pos)->id();
3628         int cursor_pos =  cursor.par->PositionInParFromPos(cursor.pos);
3629
3630         Undo * undo = new Undo(kind, 
3631                                before_number, behind_number,  
3632                                cursor_par, cursor_pos, 
3633                                undopar);
3634   
3635         undo_finished = false;
3636         return undo;
3637 }
3638
3639
3640 void LyXText::SetCursorParUndo()
3641 {
3642         SetUndo(Undo::FINISH, 
3643                 cursor.par->ParFromPos(cursor.pos)->previous, 
3644                 cursor.par->ParFromPos(cursor.pos)->next); 
3645 }
3646
3647
3648 void LyXText::RemoveTableRow(LyXCursor * cur) const
3649 {
3650         int cell = -1;
3651         int cell_org = 0;
3652         int ocell = 0;
3653     
3654         // move to the previous row
3655         int cell_act = NumberOfCell(cur->par, cur->pos);
3656         if (cell < 0)
3657                 cell = cell_act;
3658         while (cur->pos && !cur->par->IsNewline(cur->pos - 1))
3659                 cur->pos--;
3660         while (cur->pos && 
3661                !cur->par->table->IsFirstCell(cell_act)) {
3662                 cur->pos--;
3663                 while (cur->pos && !cur->par->IsNewline(cur->pos - 1))
3664                         cur->pos--;
3665                 --cell;
3666                 --cell_act;
3667         }
3668         // now we have to pay attention if the actual table is the
3669         //   main row of TableContRows and if yes to delete all of them
3670         if (!cell_org)
3671                 cell_org = cell;
3672         do {
3673                 ocell = cell;
3674                 // delete up to the next row
3675                 while (cur->pos < cur->par->Last() && 
3676                        (cell_act == ocell
3677                         || !cur->par->table->IsFirstCell(cell_act))) {
3678                         while (cur->pos < cur->par->Last() &&
3679                                !cur->par->IsNewline(cur->pos))
3680                                 cur->par->Erase(cur->pos);
3681                         ++cell;
3682                         ++cell_act;
3683                         if (cur->pos < cur->par->Last())
3684                                 cur->par->Erase(cur->pos);
3685                 }
3686                 if (cur->pos && cur->pos == cur->par->Last()) {
3687                         cur->pos--;
3688                         cur->par->Erase(cur->pos); // no newline at very end!
3689                 }
3690         } while (((cell + 1) < cur->par->table->GetNumberOfCells()) &&
3691                  !cur->par->table->IsContRow(cell_org) &&
3692                  cur->par->table->IsContRow(cell));
3693         cur->par->table->DeleteRow(cell_org);
3694         return;
3695 }
3696
3697
3698 #if 0
3699 bool LyXText::IsEmptyTableRow(LyXCursor const & old_cursor) const
3700 {
3701         if (!old_cursor.par->table)
3702                 return false;
3703 #ifdef I_DONT_KNOW_IF_I_SHOULD_DO_THIS
3704         int pos = old_cursor.pos;
3705         int cell = NumberOfCell(old_cursor.par, pos);
3706         
3707         // search first charater of this table row
3708         while (pos && !old_cursor.par->table->IsFirstCell(cell)) {
3709                 --pos;
3710                 while (pos && !old_cursor.par->IsNewline(pos-1))
3711                         --pos;
3712                 --cell;
3713         }
3714         if (!old_cursor.par->IsNewline(pos))
3715                 return false;
3716         ++cell;
3717         ++pos;
3718         while ((pos < old_cursor.par->Last()) &&
3719                !old_cursor.par->table->IsFirstCell(cell)) {
3720                 if (!old_cursor.par->IsNewline(pos))
3721                         return false;
3722                 ++pos;
3723                 ++cell;
3724         }
3725         return true;
3726 #endif
3727         return false;
3728 }
3729 #endif
3730
3731
3732 bool LyXText::IsEmptyTableCell() const
3733 {
3734         LyXParagraph::size_type pos = cursor.pos - 1;
3735         while (pos >= 0 && pos < cursor.par->Last()
3736                && !cursor.par->IsNewline(pos))
3737                 --pos;
3738         return cursor.par->IsNewline(pos + 1);
3739 }
3740
3741
3742 void LyXText::toggleAppendix(){
3743         LyXParagraph * par = cursor.par->FirstPhysicalPar();
3744         bool start = !par->start_of_appendix;
3745
3746         // ensure that we have only one start_of_appendix in this document
3747         LyXParagraph * tmp = FirstParagraph();
3748         for (; tmp; tmp = tmp->next)
3749                 tmp->start_of_appendix = 0;
3750         par->start_of_appendix = start;
3751
3752         // we can set the refreshing parameters now
3753         status = LyXText::NEED_MORE_REFRESH;
3754         refresh_y = 0;
3755         refresh_row = 0; // not needed for full update
3756         UpdateCounters(0);
3757         SetCursor(cursor.par, cursor.pos);
3758 }
3759