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