]> git.lyx.org Git - lyx.git/blob - src/text2.C
Added clean CutAndPaste handling with it's own class. Various updates for
[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         parameters = &p->params;
59         params = 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(parameters->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(parameters->textclass,
178                                               par->GetLayout()).font);
179                         par_depth = par->GetDepth();
180                 }
181         }
182
183         tmpfont.realize(textclasslist.TextClass(parameters->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(parameters->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(parameters->textclass,
226                                                       tp->GetLayout()).font);
227                 }
228         }
229
230         layoutfont.realize(textclasslist.TextClass(parameters->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(parameters->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(parameters->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(parameters->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(parameters->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, parameters->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, parameters->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(parameters->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(parameters->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(parameters->textclass,
1264                                                cursor.par->GetLayout()).align;
1265                         if (align & textclasslist
1266                             .Style(parameters->textclass,
1267                                    cursor.par->GetLayout()).alignpossible) {
1268                                 if (align == textclasslist
1269                                     .Style(parameters->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(parameters->textclass, 
1407                                                        par->GetLayout());
1408
1409         LyXTextClass const & textclass =
1410                 textclasslist.TextClass(parameters->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(parameters->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(parameters->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(parameters->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<= parameters->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->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1586                                                 s << alphaCounter(par->getCounter(i));
1587                                         else
1588                                                 s << hebrewCounter(par->getCounter(i));
1589                                         break;
1590                                 case LABEL_COUNTER_SECTION:
1591                                         if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1592                                                 s << alphaCounter(par->getCounter(i - 1));
1593                                         else
1594                                                 s << hebrewCounter(par->getCounter(i - 1));
1595
1596                                         s << '.'
1597                                           << par->getCounter(i);
1598
1599                                         break;
1600                                 case LABEL_COUNTER_SUBSECTION:
1601                                         if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1602                                                 s << alphaCounter(par->getCounter(i - 2));
1603                                         else
1604                                                 s << hebrewCounter(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->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1613                                                 s << alphaCounter(par->getCounter(i-3));
1614                                         else
1615                                                 s << hebrewCounter(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->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1625                                                 s << alphaCounter(par->getCounter(i-4));
1626                                         else
1627                                                 s << hebrewCounter(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->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1638                                                 s << alphaCounter(par->getCounter(i-5));
1639                                         else
1640                                                 s << hebrewCounter(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->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1691                                         s << '('
1692                                           << loweralphaCounter(number)
1693                                           << ')';
1694                                 else
1695                                         s << '('
1696                                           << hebrewCounter(number)
1697                                           << ')';
1698                                 break;
1699                         case 2:
1700                                 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1701                                         s << romanCounter(number) << '.';
1702                                 else
1703                                         s << '.' << romanCounter(number);
1704                                 break;
1705                         case 3:
1706                                 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1707                                         s << alphaCounter(number)
1708                                           << '.';
1709                                 else
1710                                         s << '.'
1711                                           << alphaCounter(number);
1712                                 break;
1713                         default:
1714                                 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
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                                 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1754                                         s = "Figure:";
1755                                 else
1756                                         s = ":øåéà";
1757                         else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1758                                  && (par->footnotekind == LyXParagraph::TAB
1759                                      || par->footnotekind == LyXParagraph::WIDE_TAB))
1760                                 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1761                                         s = "Table:";
1762                                 else
1763                                         s = ":äìáè";
1764                         else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1765                                  && par->footnotekind == LyXParagraph::ALGORITHM)
1766                                 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1767                                         s = "Algorithm:";
1768                                 else
1769                                         s = ":íúéøåâìà";
1770                         else {
1771                                 /* par->SetLayout(0); 
1772                                    s = layout->labelstring;  */
1773                                 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1774                                         s = "Senseless: ";
1775                                 else
1776                                         s = " :úåòîùî Ã¸Ã±Ã§";
1777            
1778                         }
1779                 }
1780                 par->labelstring = s;
1781                 
1782                 /* reset the enumeration counter. They are always resetted
1783                  * when there is any other layout between */ 
1784                 for (int i = 6 + par->enumdepth; i < 10; ++i)
1785                         par->setCounter(i, 0);
1786         }
1787 }
1788
1789
1790 /* Updates all counters BEHIND the row. Changed paragraphs
1791 * with a dynamic left margin will be rebroken. */ 
1792 void LyXText::UpdateCounters(Row * row) const
1793 {
1794         LyXParagraph * par;
1795         if (!row) {
1796                 row = firstrow;
1797                 par = row->par;
1798         }
1799         else {
1800                 if (row->par->next
1801                     && row->par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
1802                         par = row->par->LastPhysicalPar()->Next();
1803                 } else {
1804                         par = row->par->next;
1805                 }
1806         }
1807
1808         while (par) {
1809                 while (row->par != par)
1810                         row = row->next;
1811                 
1812                 SetCounter(par);
1813                 
1814                 /* now  check for the headline layouts. remember that they
1815                  * have a dynamic left margin */ 
1816                 if (!par->IsDummy()
1817                     && ( textclasslist.Style(parameters->textclass, par->layout).margintype == MARGIN_DYNAMIC
1818                          || textclasslist.Style(parameters->textclass, par->layout).labeltype == LABEL_SENSITIVE)
1819                         ){
1820          
1821                         /* Rebreak the paragraph */ 
1822                         RemoveParagraph(row);
1823                         AppendParagraph(row);
1824        
1825                         /* think about the damned open footnotes! */ 
1826                         while (par->Next() &&
1827                                (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1828                                 || par->Next()->IsDummy())){
1829                                 par = par->Next();
1830                                 if (par->IsDummy()) {
1831                                         while (row->par != par)
1832                                                 row = row->next;
1833                                         RemoveParagraph(row);
1834                                         AppendParagraph(row);
1835                                 }
1836                         }
1837                 }
1838      
1839                 par = par->LastPhysicalPar()->Next();
1840      
1841         }
1842 }
1843
1844
1845 /* insets an inset. */ 
1846 void LyXText::InsertInset(Inset *inset)
1847 {
1848         if (!cursor.par->InsertInsetAllowed(inset))
1849                 return;
1850         SetUndo(Undo::INSERT, 
1851                 cursor.par->ParFromPos(cursor.pos)->previous, 
1852                 cursor.par->ParFromPos(cursor.pos)->next);
1853         cursor.par->InsertChar(cursor.pos, LyXParagraph::META_INSET);
1854         cursor.par->InsertInset(cursor.pos, inset);
1855         InsertChar(LyXParagraph::META_INSET);  /* just to rebreak and refresh correctly.
1856                                       * The character will not be inserted a
1857                                       * second time */
1858 }
1859
1860
1861 #ifdef USE_OLD_CUT_AND_PASTE
1862 // this is for the simple cut and paste mechanism
1863 static LyXParagraph * simple_cut_buffer = 0;
1864 static char simple_cut_buffer_textclass = 0;
1865
1866 void DeleteSimpleCutBuffer()
1867 {
1868         if (!simple_cut_buffer)
1869                 return;
1870         LyXParagraph * tmppar;
1871
1872         while (simple_cut_buffer) {
1873                 tmppar =  simple_cut_buffer;
1874                 simple_cut_buffer = simple_cut_buffer->next;
1875                 delete tmppar;
1876         }
1877         simple_cut_buffer = 0;
1878 }
1879 #endif
1880
1881 void LyXText::copyEnvironmentType()
1882 {
1883         copylayouttype = cursor.par->GetLayout();
1884 }
1885
1886
1887 void LyXText::pasteEnvironmentType()
1888 {
1889         SetLayout(copylayouttype);
1890 }
1891
1892 #ifdef USE_OLD_CUT_AND_PASTE
1893 void LyXText::CutSelection(bool doclear)
1894 {
1895         // This doesn't make sense, if there is no selection
1896         if (!selection)
1897                 return;
1898    
1899         // OK, we have a selection. This is always between sel_start_cursor
1900         // and sel_end cursor
1901         LyXParagraph * tmppar;
1902    
1903         // Check whether there are half footnotes in the selection
1904         if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1905             || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
1906                 tmppar = sel_start_cursor.par;
1907                 while (tmppar != sel_end_cursor.par){
1908                         if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag) {
1909                                 WriteAlert(_("Impossible operation"),
1910                                            _("Don't know what to do with half floats."),
1911                                            _("sorry."));
1912                                 return;
1913                         }
1914                         tmppar = tmppar->Next();
1915                 }
1916         }
1917
1918         /* table stuff -- begin */
1919         if (sel_start_cursor.par->table || sel_end_cursor.par->table) {
1920                 if ( sel_start_cursor.par != sel_end_cursor.par) {
1921                         WriteAlert(_("Impossible operation"),
1922                                    _("Don't know what to do with half tables."),
1923                                    _("sorry."));
1924                         return;
1925                 }
1926                 sel_start_cursor.par->table->Reinit();
1927         }
1928         /* table stuff -- end */
1929
1930         // make sure that the depth behind the selection are restored, too
1931         LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1932         LyXParagraph * undoendpar = endpar;
1933
1934         if (endpar && endpar->GetDepth()) {
1935                 while (endpar && endpar->GetDepth()) {
1936                         endpar = endpar->LastPhysicalPar()->Next();
1937                         undoendpar = endpar;
1938                 }
1939         } else if (endpar) {
1940                 endpar = endpar->Next(); // because of parindents etc.
1941         }
1942    
1943         SetUndo(Undo::DELETE, 
1944                 sel_start_cursor
1945                 .par->ParFromPos(sel_start_cursor.pos)->previous, 
1946                 undoendpar);
1947    
1948         // clear the simple_cut_buffer
1949         DeleteSimpleCutBuffer();
1950    
1951         // set the textclass
1952         simple_cut_buffer_textclass = parameters->textclass;
1953
1954 #ifdef WITH_WARNINGS
1955 #warning Asger: Make cut more intelligent here.
1956 #endif
1957         /* 
1958            White paper for "intelligent" cutting:
1959            
1960            Example: "This is our text."
1961            Using " our " as selection, cutting will give "This istext.".
1962            Using "our" as selection, cutting will give "This is text.".
1963            Using " our" as selection, cutting will give "This is text.".
1964            Using "our " as selection, cutting will give "This is text.".
1965            
1966            All those four selections will (however) paste identically:
1967            Pasting with the cursor right after the "is" will give the
1968            original text with all four selections.
1969            
1970            The rationale is to be intelligent such that words are copied,
1971            cut and pasted in a functional manner.
1972            
1973            This is not implemented yet. (Asger)
1974
1975            The changes below sees to do a lot of what you want. However
1976            I have not verified that all cases work as they should:
1977                      - cut in single row
1978                      - cut in multiple row
1979                      - cut with insets
1980                      - cut across footnotes and paragraph
1981            My simplistic tests show that the idea are basically sound but
1982            there are some items to fix up...we only need to find them
1983            first.
1984
1985            As do redo Asger's example above (with | beeing the cursor in the
1986            result after cutting.):
1987            
1988            Example: "This is our text."
1989            Using " our " as selection, cutting will give "This is|text.".
1990            Using "our"   as selection, cutting will give "This is | text.".
1991            Using " our"  as selection, cutting will give "This is| text.".
1992            Using "our "  as selection, cutting will give "This is |text.".
1993
1994            (Lgb)
1995         */
1996
1997 #ifndef FIX_DOUBLE_SPACE
1998         bool space_wrapped =
1999                 sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos);
2000         if (sel_end_cursor.pos > 0
2001             && sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos - 1)) {
2002                 // please break before a space at the end
2003                 sel_end_cursor.pos--;
2004                 space_wrapped = true;
2005         }
2006         // cut behind a space if there is one
2007         while (sel_start_cursor.par->Last() > sel_start_cursor.pos
2008                && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
2009                && (sel_start_cursor.par != sel_end_cursor.par
2010                    || sel_start_cursor.pos < sel_end_cursor.pos))
2011                 sel_start_cursor.pos++; 
2012 #endif
2013         // there are two cases: cut only within one paragraph or
2014         // more than one paragraph
2015    
2016         if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos) 
2017             == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2018                 // only within one paragraph
2019                 simple_cut_buffer = new LyXParagraph;
2020                 LyXParagraph::size_type i =
2021                         sel_start_cursor.pos;
2022                 for (; i < sel_end_cursor.pos; ++i) {
2023                         /* table stuff -- begin */
2024                         if (sel_start_cursor.par->table
2025                             && sel_start_cursor.par->IsNewline(sel_start_cursor.pos)) {
2026                                 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
2027                                 sel_start_cursor.pos++;
2028                         } else {
2029                                 /* table stuff -- end */
2030                                 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
2031                                 sel_start_cursor.par->Erase(sel_start_cursor.pos);
2032                         }
2033                         simple_cut_buffer->InsertFromMinibuffer(simple_cut_buffer->Last());
2034                 }
2035 #ifndef FIX_DOUBLE_SPACE
2036                 // check for double spaces
2037                 if (sel_start_cursor.pos &&
2038                     sel_start_cursor.par->Last() > sel_start_cursor.pos
2039                     && sel_start_cursor.par
2040                     ->IsLineSeparator(sel_start_cursor.pos - 1)
2041                     && sel_start_cursor.par
2042                     ->IsLineSeparator(sel_start_cursor.pos)) {
2043                         sel_start_cursor.par->Erase(sel_start_cursor.pos);
2044                 }
2045                 if (space_wrapped)
2046                         simple_cut_buffer->InsertChar(i - sel_start_cursor.pos,
2047                                                       ' ');
2048 #endif
2049                 endpar = sel_end_cursor.par->Next();
2050         } else {
2051                 // cut more than one paragraph
2052    
2053                 sel_end_cursor.par
2054                         ->BreakParagraphConservative(sel_end_cursor.pos);
2055 #ifndef FIX_DOUBLE_SPACE
2056                 // insert a space at the end if there was one
2057                 if (space_wrapped)
2058                         sel_end_cursor.par
2059                                 ->InsertChar(sel_end_cursor.par->Last(), ' ');
2060 #endif
2061                 sel_end_cursor.par = sel_end_cursor.par->Next();
2062                 sel_end_cursor.pos = 0;
2063    
2064                 cursor = sel_end_cursor;
2065
2066 #ifndef FIX_DOUBLE_SPACE
2067                 // please break behind a space, if there is one.
2068                 // The space should be copied too
2069                 if (sel_start_cursor.par
2070                     ->IsLineSeparator(sel_start_cursor.pos))
2071                         sel_start_cursor.pos++;
2072 #endif   
2073                 sel_start_cursor.par
2074                         ->BreakParagraphConservative(sel_start_cursor.pos);
2075 #ifndef FIX_DOUBLE_SPACE
2076                 if (!sel_start_cursor.pos
2077                     || sel_start_cursor.par
2078                     ->IsLineSeparator(sel_start_cursor.pos - 1)
2079                     || sel_start_cursor.par
2080                     ->IsNewline(sel_start_cursor.pos - 1)) {
2081                         sel_start_cursor.par->Next()->InsertChar(0, ' ');
2082                 }
2083 #endif
2084                 // store the endparagraph for redoing later
2085                 endpar = sel_end_cursor.par->Next(); /* needed because
2086                                                         the sel_end_
2087                                                         cursor.par
2088                                                         will be pasted! */
2089    
2090                 // store the selection
2091                 simple_cut_buffer = sel_start_cursor.par
2092                         ->ParFromPos(sel_start_cursor.pos)->next;
2093                 simple_cut_buffer->previous = 0;
2094                 sel_end_cursor.par->previous->next = 0;
2095
2096                 // cut the selection
2097                 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->next 
2098                         = sel_end_cursor.par;
2099    
2100                 sel_end_cursor.par->previous 
2101                         = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
2102
2103                 // care about footnotes
2104                 if (simple_cut_buffer->footnoteflag) {
2105                         LyXParagraph * tmppar = simple_cut_buffer;
2106                         while (tmppar){
2107                                 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
2108                                 tmppar = tmppar->next;
2109                         }
2110                 }
2111
2112                 // the cut selection should begin with standard layout
2113                 simple_cut_buffer->Clear(); 
2114    
2115                 // paste the paragraphs again, if possible
2116                 if (doclear)
2117                         sel_start_cursor.par->Next()->ClearParagraph();
2118                 if (sel_start_cursor.par->FirstPhysicalPar()->HasSameLayout(sel_start_cursor.par->Next())
2119                     || 
2120                     !sel_start_cursor.par->Next()->Last())
2121                         sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->PasteParagraph();
2122
2123 #ifndef FIX_DOUBLE_SPACE
2124                 // maybe a forgotten blank
2125                 if (sel_start_cursor.pos 
2126                     && sel_start_cursor.par
2127                     ->IsLineSeparator(sel_start_cursor.pos)
2128                     && sel_start_cursor.par
2129                     ->IsLineSeparator(sel_start_cursor.pos - 1)) {
2130                         sel_start_cursor.par->Erase(sel_start_cursor.pos);
2131                 }
2132 #endif
2133         }
2134
2135         // sometimes necessary
2136         if (doclear)
2137                 sel_start_cursor.par->ClearParagraph();
2138
2139         RedoParagraphs(sel_start_cursor, endpar);
2140    
2141         ClearSelection();
2142         cursor = sel_start_cursor;
2143         SetCursor(cursor.par, cursor.pos);
2144         sel_cursor = cursor;
2145         UpdateCounters(cursor.row);
2146 }
2147
2148 #else ///////////////////////////////////////////////////////////////////
2149
2150 void LyXText::CutSelection(bool doclear)
2151 {
2152     // This doesn't make sense, if there is no selection
2153     if (!selection)
2154         return;
2155    
2156     // OK, we have a selection. This is always between sel_start_cursor
2157     // and sel_end cursor
2158     LyXParagraph * tmppar;
2159     
2160     // Check whether there are half footnotes in the selection
2161     if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2162         || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2163         tmppar = sel_start_cursor.par;
2164         while (tmppar != sel_end_cursor.par){
2165             if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag) {
2166                 WriteAlert(_("Impossible operation"),
2167                            _("Don't know what to do with half floats."),
2168                            _("sorry."));
2169                 return;
2170                         }
2171             tmppar = tmppar->Next();
2172         }
2173     }
2174     
2175     /* table stuff -- begin */
2176     if (sel_start_cursor.par->table || sel_end_cursor.par->table) {
2177         if ( sel_start_cursor.par != sel_end_cursor.par) {
2178             WriteAlert(_("Impossible operation"),
2179                        _("Don't know what to do with half tables."),
2180                        _("sorry."));
2181             return;
2182         }
2183         sel_start_cursor.par->table->Reinit();
2184     }
2185     /* table stuff -- end */
2186     
2187     // make sure that the depth behind the selection are restored, too
2188     LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
2189     LyXParagraph * undoendpar = endpar;
2190     
2191     if (endpar && endpar->GetDepth()) {
2192         while (endpar && endpar->GetDepth()) {
2193             endpar = endpar->LastPhysicalPar()->Next();
2194             undoendpar = endpar;
2195         }
2196     } else if (endpar) {
2197         endpar = endpar->Next(); // because of parindents etc.
2198     }
2199     
2200     SetUndo(Undo::DELETE, sel_start_cursor
2201             .par->ParFromPos(sel_start_cursor.pos)->previous, undoendpar);
2202     
2203     CutAndPaste cap;
2204
2205     // there are two cases: cut only within one paragraph or
2206     // more than one paragraph
2207     if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos) 
2208         == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2209         // only within one paragraph
2210         endpar = sel_start_cursor.par;
2211         cap.cutSelection(sel_start_cursor.par, &endpar,
2212                          sel_start_cursor.pos, sel_end_cursor.pos,
2213                          parameters->textclass, doclear);
2214     } else {
2215         endpar = sel_end_cursor.par;
2216
2217         cap.cutSelection(sel_start_cursor.par, &endpar,
2218                          sel_start_cursor.pos, sel_end_cursor.pos,
2219                          parameters->textclass, doclear);
2220         cursor.par = sel_end_cursor.par = endpar;
2221         cursor.pos = sel_end_cursor.pos;
2222     }
2223     endpar = sel_end_cursor.par->Next();
2224
2225     // sometimes necessary
2226     if (doclear)
2227         sel_start_cursor.par->ClearParagraph();
2228
2229     RedoParagraphs(sel_start_cursor, endpar);
2230    
2231     ClearSelection();
2232     cursor = sel_start_cursor;
2233     SetCursor(cursor.par, cursor.pos);
2234     sel_cursor = cursor;
2235     UpdateCounters(cursor.row);
2236 }
2237 #endif
2238     
2239 #ifdef USE_OLD_CUT_AND_PASTE
2240 void LyXText::CopySelection()
2241 {
2242         // this doesnt make sense, if there is no selection
2243         if (!selection)
2244                 return;
2245
2246         // ok we have a selection. This is always between sel_start_cursor
2247         // and sel_end cursor
2248         LyXParagraph * tmppar;
2249    
2250         /* check wether there are half footnotes in the selection */
2251         if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2252             || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2253                 tmppar = sel_start_cursor.par;
2254                 while (tmppar != sel_end_cursor.par) {
2255                         if (tmppar->footnoteflag !=
2256                             sel_end_cursor.par->footnoteflag) {
2257                                 WriteAlert(_("Impossible operation"),
2258                                            _("Don't know what to do"
2259                                              " with half floats."),
2260                                            _("sorry."));
2261                                 return;
2262                         }
2263                         tmppar = tmppar->Next();
2264                 }
2265         }
2266
2267         /* table stuff -- begin */
2268         if (sel_start_cursor.par->table || sel_end_cursor.par->table){
2269                 if ( sel_start_cursor.par != sel_end_cursor.par){
2270                         WriteAlert(_("Impossible operation"),
2271                                    _("Don't know what to do with half tables."),
2272                                    _("sorry."));
2273                         return;
2274                 }
2275         }
2276         /* table stuff -- end */
2277    
2278         // delete the simple_cut_buffer
2279         DeleteSimpleCutBuffer();
2280
2281         // set the textclass
2282         simple_cut_buffer_textclass = parameters->textclass;
2283
2284 #ifdef FIX_DOUBLE_SPACE
2285         // copy behind a space if there is one
2286         while (sel_start_cursor.par->Last() > sel_start_cursor.pos
2287                && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
2288                && (sel_start_cursor.par != sel_end_cursor.par
2289                    || sel_start_cursor.pos < sel_end_cursor.pos))
2290                 sel_start_cursor.pos++; 
2291 #endif
2292         // there are two cases: copy only within one paragraph
2293         // or more than one paragraph
2294         if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos) 
2295             == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2296                 // only within one paragraph
2297                 simple_cut_buffer = new LyXParagraph;
2298                 LyXParagraph::size_type i = 0;
2299                 for (i = sel_start_cursor.pos; i < sel_end_cursor.pos; ++i){
2300                         sel_start_cursor.par->CopyIntoMinibuffer(i);
2301                         simple_cut_buffer->InsertFromMinibuffer(i - sel_start_cursor.pos);
2302                 }
2303         } else {
2304                 // copy more than one paragraph
2305                 // clone the paragraphs within the selection
2306                 tmppar =
2307                         sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
2308                 simple_cut_buffer = tmppar->Clone();
2309                 LyXParagraph *tmppar2 = simple_cut_buffer;
2310      
2311                 while (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)
2312                        && tmppar->next) {
2313                         tmppar = tmppar->next;
2314                         tmppar2->next = tmppar->Clone();
2315                         tmppar2->next->previous = tmppar2;
2316                         tmppar2 = tmppar2->next;
2317                 }
2318                 tmppar2->next = 0;
2319
2320                 // care about footnotes
2321                 if (simple_cut_buffer->footnoteflag) {
2322                         tmppar = simple_cut_buffer;
2323                         while (tmppar){
2324                                 tmppar->footnoteflag =
2325                                         LyXParagraph::NO_FOOTNOTE;
2326                                 tmppar = tmppar->next;
2327                         }
2328                 }
2329                 
2330                 // the simple_cut_buffer paragraph is too big
2331                 LyXParagraph::size_type tmpi2 =
2332                         sel_start_cursor.par->PositionInParFromPos(sel_start_cursor.pos);
2333                 for (; tmpi2; --tmpi2)
2334                         simple_cut_buffer->Erase(0);
2335                 
2336                 // now tmppar 2 is too big, delete all after sel_end_cursor.pos
2337      
2338                 tmpi2 = sel_end_cursor.par->PositionInParFromPos(sel_end_cursor.pos);
2339                 while (tmppar2->size() > tmpi2) {
2340                         tmppar2->Erase(tmppar2->size() - 1);
2341                 }
2342         }
2343 }
2344
2345 #else //////////////////////////////////////////////////////////////////////
2346
2347 void LyXText::CopySelection()
2348 {
2349         // this doesnt make sense, if there is no selection
2350         if (!selection)
2351                 return;
2352
2353         // ok we have a selection. This is always between sel_start_cursor
2354         // and sel_end cursor
2355         LyXParagraph * tmppar;
2356    
2357         /* check wether there are half footnotes in the selection */
2358         if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2359             || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2360                 tmppar = sel_start_cursor.par;
2361                 while (tmppar != sel_end_cursor.par) {
2362                         if (tmppar->footnoteflag !=
2363                             sel_end_cursor.par->footnoteflag) {
2364                                 WriteAlert(_("Impossible operation"),
2365                                            _("Don't know what to do"
2366                                              " with half floats."),
2367                                            _("sorry."));
2368                                 return;
2369                         }
2370                         tmppar = tmppar->Next();
2371                 }
2372         }
2373
2374         /* table stuff -- begin */
2375         if (sel_start_cursor.par->table || sel_end_cursor.par->table){
2376                 if ( sel_start_cursor.par != sel_end_cursor.par){
2377                         WriteAlert(_("Impossible operation"),
2378                                    _("Don't know what to do with half tables."),
2379                                    _("sorry."));
2380                         return;
2381                 }
2382         }
2383         /* table stuff -- end */
2384    
2385 #ifdef FIX_DOUBLE_SPACE
2386         // copy behind a space if there is one
2387         while (sel_start_cursor.par->Last() > sel_start_cursor.pos
2388                && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
2389                && (sel_start_cursor.par != sel_end_cursor.par
2390                    || sel_start_cursor.pos < sel_end_cursor.pos))
2391                 sel_start_cursor.pos++; 
2392 #endif
2393
2394         CutAndPaste cap;
2395
2396         cap.copySelection(sel_start_cursor.par, sel_end_cursor.par,
2397                           sel_start_cursor.pos, sel_end_cursor.pos,
2398                           parameters->textclass);
2399 }
2400 #endif          
2401
2402 #ifdef USE_OLD_CUT_AND_PASTE
2403 void LyXText::PasteSelection()
2404 {
2405         // this does not make sense, if there is nothing to paste
2406         if (!simple_cut_buffer)
2407                 return;
2408
2409         LyXParagraph * tmppar;
2410         LyXParagraph * endpar;
2411
2412         LyXCursor tmpcursor;
2413
2414         // be carefull with footnotes in footnotes
2415         if (cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2416       
2417                 // check whether the cut_buffer includes a footnote
2418                 tmppar = simple_cut_buffer;
2419                 while (tmppar
2420                        && tmppar->footnoteflag == LyXParagraph::NO_FOOTNOTE)
2421                         tmppar = tmppar->next;
2422       
2423                 if (tmppar) {
2424                         WriteAlert(_("Impossible operation"),
2425                                    _("Can't paste float into float!"),
2426                                    _("Sorry."));
2427                         return;
2428                 }
2429         }
2430
2431         /* table stuff -- begin */
2432         if (cursor.par->table) {
2433                 if (simple_cut_buffer->next) {
2434                         WriteAlert(_("Impossible operation"),
2435                                    _("Table cell cannot include more than one paragraph!"),
2436                                    _("Sorry."));
2437                         return;
2438                 }
2439         }
2440         /* table stuff -- end */
2441    
2442         SetUndo(Undo::INSERT, 
2443                 cursor.par->ParFromPos(cursor.pos)->previous, 
2444                 cursor.par->ParFromPos(cursor.pos)->next); 
2445
2446         tmpcursor = cursor;
2447
2448         // There are two cases: cutbuffer only one paragraph or many
2449         if (!simple_cut_buffer->next) {
2450                 // only within a paragraph
2451
2452 #ifndef FIX_DOUBLE_SPACE
2453                 // please break behind a space, if there is one
2454                 while (tmpcursor.par->Last() > tmpcursor.pos
2455                        && tmpcursor.par->IsLineSeparator(tmpcursor.pos))
2456                         tmpcursor.pos++; 
2457 #endif
2458                 tmppar = simple_cut_buffer->Clone();
2459                 /* table stuff -- begin */
2460                 bool table_too_small = false;
2461                 if (tmpcursor.par->table) {
2462                         while (simple_cut_buffer->size()
2463                                && !table_too_small) {
2464                                 if (simple_cut_buffer->IsNewline(0)){
2465                                         while(tmpcursor.pos < tmpcursor.par->Last() && !tmpcursor.par->IsNewline(tmpcursor.pos))
2466                                                 tmpcursor.pos++;
2467                                         simple_cut_buffer->Erase(0);
2468                                         if (tmpcursor.pos < tmpcursor.par->Last())
2469                                                 tmpcursor.pos++;
2470                                         else
2471                                                 table_too_small = true;
2472                                 } else {
2473 #ifdef FIX_DOUBLE_SPACE
2474                                         // This is an attempt to fix the
2475                                         // "never insert a space at the
2476                                         // beginning of a paragraph" problem.
2477                                         if (tmpcursor.pos == 0
2478                                             && simple_cut_buffer->IsLineSeparator(0)) {
2479                                                 simple_cut_buffer->Erase(0);
2480                                         } else {
2481                                                 simple_cut_buffer->CutIntoMinibuffer(0);
2482                                                 simple_cut_buffer->Erase(0);
2483                                                 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2484                                                 tmpcursor.pos++;
2485                                         }
2486 #else
2487                                         simple_cut_buffer->CutIntoMinibuffer(0);
2488                                         simple_cut_buffer->Erase(0);
2489                                         tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2490                                         tmpcursor.pos++;
2491 #endif
2492                                 }
2493                         }
2494                 } else {
2495                         /* table stuff -- end */
2496                         // Some provisions should be done here for checking
2497                         // if we are inserting at the beginning of a
2498                         // paragraph. If there are a space at the beginning
2499                         // of the text to insert and we are inserting at
2500                         // the beginning of the paragraph the space should
2501                         // be removed.
2502                         while (simple_cut_buffer->size()) {
2503 #ifdef FIX_DOUBLE_SPACE
2504                                 // This is an attempt to fix the
2505                                 // "never insert a space at the
2506                                 // beginning of a paragraph" problem.
2507                                 if (tmpcursor.pos == 0
2508                                     && simple_cut_buffer->IsLineSeparator(0)) {
2509                                         simple_cut_buffer->Erase(0);
2510                                 } else {
2511                                         simple_cut_buffer->CutIntoMinibuffer(0);
2512                                         simple_cut_buffer->Erase(0);
2513                                         tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2514                                         tmpcursor.pos++;
2515                                 }
2516 #else
2517                                 simple_cut_buffer->CutIntoMinibuffer(0);
2518                                 simple_cut_buffer->Erase(0);
2519                                 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2520                                 tmpcursor.pos++;
2521 #endif
2522                         }
2523                 }
2524                 delete simple_cut_buffer;
2525                 simple_cut_buffer = tmppar;
2526                 endpar = tmpcursor.par->Next();
2527         } else {
2528                 // many paragraphs
2529                 CutAndPaste cap;
2530
2531                 // make a copy of the simple cut_buffer
2532                 tmppar = simple_cut_buffer;
2533                 LyXParagraph * simple_cut_clone = tmppar->Clone();
2534                 LyXParagraph * tmppar2 = simple_cut_clone;
2535                 if (cursor.par->footnoteflag){
2536                         tmppar->footnoteflag = cursor.par->footnoteflag;
2537                         tmppar->footnotekind = cursor.par->footnotekind;
2538                 }
2539                 while (tmppar->next) {
2540                         tmppar = tmppar->next;
2541                         tmppar2->next = tmppar->Clone();
2542                         tmppar2->next->previous = tmppar2;
2543                         tmppar2 = tmppar2->next;
2544                         if (cursor.par->footnoteflag){
2545                                 tmppar->footnoteflag = cursor.par->footnoteflag;
2546                                 tmppar->footnotekind = cursor.par->footnotekind;
2547                         }
2548                 }
2549      
2550                 // make sure there is no class difference
2551                 cap.SwitchLayoutsBetweenClasses(simple_cut_buffer_textclass,
2552                                                 parameters->textclass,
2553                                                 simple_cut_buffer);
2554      
2555                 // make the simple_cut_buffer exactly the same layout than
2556                 // the cursor paragraph
2557                 simple_cut_buffer->MakeSameLayout(cursor.par);
2558      
2559                 // find the end of the buffer
2560                 LyXParagraph * lastbuffer = simple_cut_buffer;
2561                 while (lastbuffer->Next())
2562                         lastbuffer = lastbuffer->Next();
2563      
2564 #ifndef FIX_DOUBLE_SPACE
2565                 // Please break behind a space, if there is one. The space 
2566                 // should be copied too.
2567                 if (cursor.par->Last() > cursor.pos
2568                     && cursor.par->IsLineSeparator(cursor.pos))
2569                         cursor.pos++; 
2570 #endif
2571                 bool paste_the_end = false;
2572
2573                 // open the paragraph for inserting the simple_cut_buffer
2574                 // if necessary
2575                 if (cursor.par->Last() > cursor.pos || !cursor.par->Next()){
2576                         cursor.par->BreakParagraphConservative(cursor.pos);
2577                         paste_the_end = true;
2578                 }
2579
2580 #ifndef FIX_DOUBLE_SPACE
2581                 // be careful with double spaces
2582                 if ((!cursor.par->Last()
2583                      || cursor.par->IsLineSeparator(cursor.pos - 1)
2584                      || cursor.par->IsNewline(cursor.pos - 1))
2585                     && simple_cut_buffer->text.size()
2586                     && simple_cut_buffer->IsLineSeparator(0))
2587                         simple_cut_buffer->Erase(0);
2588 #endif
2589                 // set the end for redoing later
2590                 endpar = cursor.par->ParFromPos(cursor.pos)->next->Next();
2591      
2592                 // paste it!
2593                 lastbuffer->ParFromPos(lastbuffer->Last())->next =
2594                         cursor.par->ParFromPos(cursor.pos)->next;
2595                 cursor.par->ParFromPos(cursor.pos)->next->previous =
2596                         lastbuffer->ParFromPos(lastbuffer->Last());
2597      
2598                 cursor.par->ParFromPos(cursor.pos)->next = simple_cut_buffer;
2599                 simple_cut_buffer->previous =
2600                         cursor.par->ParFromPos(cursor.pos);
2601    
2602                 if (cursor.par->ParFromPos(cursor.pos)->Next() == lastbuffer)
2603                         lastbuffer = cursor.par;
2604      
2605                 cursor.par->ParFromPos(cursor.pos)->PasteParagraph();
2606      
2607                 // store the new cursor position
2608                 tmpcursor.par = lastbuffer;
2609                 tmpcursor.pos = lastbuffer->Last();
2610      
2611                 // maybe some pasting
2612                 if (lastbuffer->Next() && paste_the_end) {
2613                         if (lastbuffer->Next()->HasSameLayout(lastbuffer)) {
2614 #ifndef FIX_DOUBLE_SPACE
2615                                 // be careful with double spaces
2616                                 if ((!lastbuffer->Last()
2617                                      || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2618                                      || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2619                                     && lastbuffer->Next()->Last()
2620                                     && lastbuffer->Next()->IsLineSeparator(0))
2621                                         lastbuffer->Next()->Erase(0);
2622 #endif
2623                                 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2624          
2625                         } else if (!lastbuffer->Next()->Last()) {
2626                                 lastbuffer->Next()->MakeSameLayout(lastbuffer);
2627 #ifndef FIX_DOUBLE_SPACE
2628                                 // be careful witth double spaces
2629                                 if ((!lastbuffer->Last()
2630                                      || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2631                                      || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2632                                     && lastbuffer->Next()->Last()
2633                                     && lastbuffer->Next()->IsLineSeparator(0))
2634                                         lastbuffer->Next()->Erase(0);
2635 #endif
2636                                 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2637          
2638                         } else if (!lastbuffer->Last()) {
2639                                 lastbuffer->MakeSameLayout(lastbuffer->next);
2640 #ifndef FIX_DOUBLE_SPACE
2641                                 // be careful witth double spaces
2642                                 if ((!lastbuffer->Last()
2643                                      || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2644                                      || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2645                                     && lastbuffer->Next()->Last()
2646                                     && lastbuffer->Next()->IsLineSeparator(0))
2647                                         lastbuffer->Next()->Erase(0);
2648 #endif
2649                                 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2650          
2651                         } else
2652                                 lastbuffer->Next()->ClearParagraph();
2653                 }
2654
2655                 // restore the simple cut buffer
2656                 simple_cut_buffer = simple_cut_clone;
2657         }
2658
2659         RedoParagraphs(cursor, endpar);
2660     
2661         SetCursor(cursor.par, cursor.pos);
2662         ClearSelection();
2663    
2664         sel_cursor = cursor;
2665         SetCursor(tmpcursor.par, tmpcursor.pos);
2666         SetSelection();
2667         UpdateCounters(cursor.row);
2668 }
2669
2670 #else ////////////////////////////////////////////////////////////////////
2671
2672 void LyXText::PasteSelection()
2673 {
2674     CutAndPaste cap;
2675
2676     // this does not make sense, if there is nothing to paste
2677     if (!cap.checkPastePossible(cursor.par, cursor.pos))
2678         return;
2679
2680     SetUndo(Undo::INSERT, 
2681             cursor.par->ParFromPos(cursor.pos)->previous, 
2682             cursor.par->ParFromPos(cursor.pos)->next); 
2683
2684     LyXParagraph *endpar;
2685     LyXParagraph *actpar = cursor.par;
2686     int endpos = cursor.pos;
2687
2688     cap.pasteSelection(&actpar, &endpar, endpos, parameters->textclass);
2689
2690     RedoParagraphs(cursor, endpar);
2691     
2692     SetCursor(cursor.par, cursor.pos);
2693     ClearSelection();
2694    
2695     sel_cursor = cursor;
2696     SetCursor(actpar, endpos);
2697     SetSelection();
2698     UpdateCounters(cursor.row);
2699 }
2700 #endif   
2701
2702 // returns a pointer to the very first LyXParagraph
2703 LyXParagraph * LyXText::FirstParagraph() const
2704 {
2705         return params->paragraph;
2706 }
2707
2708
2709 // returns true if the specified string is at the specified position
2710 bool LyXText::IsStringInText(LyXParagraph * par,
2711                              LyXParagraph::size_type pos,
2712                              char const * str) const
2713 {
2714         if (par) {
2715                 int i = 0;
2716                 while (pos + i < par->Last() && str[i] && 
2717                        str[i] == par->GetChar(pos + i)) {
2718                         ++i;
2719                 }
2720                 if (!str[i])
2721                         return true;
2722         }
2723         return false;
2724 }
2725
2726
2727 // sets the selection over the number of characters of string, no check!!
2728 void LyXText::SetSelectionOverString(char const * string)
2729 {
2730         sel_cursor = cursor;
2731         for (int i = 0; string[i]; ++i)
2732                 CursorRight();
2733         SetSelection();
2734 }
2735
2736
2737 // simple replacing. The font of the first selected character is used
2738 void LyXText::ReplaceSelectionWithString(char const * str)
2739 {
2740         SetCursorParUndo();
2741         FreezeUndo();
2742
2743         if (!selection) { // create a dummy selection
2744                 sel_end_cursor = cursor;
2745                 sel_start_cursor = cursor;
2746         }
2747
2748         // Get font setting before we cut
2749         LyXParagraph::size_type pos = sel_end_cursor.pos;
2750         LyXFont font = sel_start_cursor.par->GetFontSettings(sel_start_cursor.pos);
2751
2752         // Insert the new string
2753         for (int i = 0; str[i]; ++i) {
2754                 sel_end_cursor.par->InsertChar(pos, str[i]);
2755                 sel_end_cursor.par->SetFont(pos, font);
2756                 ++pos;
2757         }
2758
2759         // Cut the selection
2760         CutSelection();
2761
2762         UnFreezeUndo();
2763 }
2764
2765
2766 // if the string can be found: return true and set the cursor to
2767 // the new position
2768 bool LyXText::SearchForward(char const * str) const
2769 {
2770         LyXParagraph * par = cursor.par;
2771         LyXParagraph::size_type pos = cursor.pos;
2772         while (par && !IsStringInText(par, pos, str)) {
2773                 if (pos < par->Last() - 1)
2774                         ++pos;
2775                 else {
2776                         pos = 0;
2777                         par = par->Next();
2778                 }
2779         }
2780         if (par) {
2781                 SetCursor(par, pos);
2782                 return true;
2783         }
2784         else
2785                 return false;
2786 }
2787
2788
2789 bool LyXText::SearchBackward(char const * string) const
2790 {
2791         LyXParagraph * par = cursor.par;
2792         int pos = cursor.pos;
2793
2794         do {
2795                 if (pos > 0)
2796                         --pos;
2797                 else {
2798                         // We skip empty paragraphs (Asger)
2799                         do {
2800                                 par = par->Previous();
2801                                 if (par)
2802                                         pos = par->Last() - 1;
2803                         } while (par && pos < 0);
2804                 }
2805         } while (par && !IsStringInText(par, pos, string));
2806   
2807         if (par) {
2808                 SetCursor(par, pos);
2809                 return true;
2810         } else
2811                 return false;
2812 }
2813
2814
2815 // needed to insert the selection
2816 void LyXText::InsertStringA(string const & str)
2817 {
2818         LyXParagraph * par = cursor.par;
2819         LyXParagraph::size_type pos = cursor.pos;
2820         LyXParagraph::size_type a = 0;
2821         int cell = 0;
2822         LyXParagraph * endpar = cursor.par->Next();
2823         
2824         SetCursorParUndo();
2825         
2826         bool flag =
2827                 textclasslist.Style(parameters->textclass, 
2828                                     cursor.par->GetLayout()).isEnvironment();
2829         // only to be sure, should not be neccessary
2830         ClearSelection();
2831         
2832         // insert the string, don't insert doublespace
2833         string::size_type i = 0;
2834         while (i < str.length()) {
2835                 if (str[i] != '\n') {
2836                         if (str[i] == ' ' 
2837                             && i + 1 < str.length() && str[i + 1] != ' '
2838                             && pos && par->GetChar(pos - 1)!= ' ') {
2839                                 par->InsertChar(pos,' ');
2840                                 par->SetFont(pos, current_font);
2841                                 ++pos;
2842                         } else if (par->table) {
2843                                 if (str[i] == '\t') {
2844                                         while((pos < par->size()) &&
2845                                               (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2846                                                 ++pos;
2847                                         if (pos < par->size())
2848                                                 ++pos;
2849                                         else // no more fields to fill skip the rest
2850                                                 break;
2851                                 } else if ((str[i] != 13) &&
2852                                            ((str[i] & 127) >= ' ')) {
2853                                         par->InsertChar(pos, str[i]);
2854                                         par->SetFont(pos, current_font);
2855                                         ++pos;
2856                                 }
2857                         } else if (str[i] == ' ') {
2858 #if 1
2859                                 InsetSpecialChar * new_inset =
2860                                         new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2861                                 if (par->InsertInsetAllowed(new_inset)) {
2862                                         par->InsertChar(pos, LyXParagraph::META_INSET);
2863                                         par->SetFont(pos, current_font);
2864                                         par->InsertInset(pos, new_inset);
2865                                 } else {
2866                                         delete new_inset;
2867                                 }
2868 #else
2869                                 par->InsertChar(pos, LyXParagraph::META_PROTECTED_SEPARATOR);
2870                                 par->SetFont(pos, current_font);
2871 #endif
2872                                 ++pos;
2873                         } else if (str[i] == '\t') {
2874                                 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2875 #if 1
2876                                 InsetSpecialChar * new_inset =
2877                                         new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2878                                 if (par->InsertInsetAllowed(new_inset)) {
2879                                         par->InsertChar(pos, LyXParagraph::META_INSET);
2880                                         par->SetFont(pos, current_font);
2881                                         par->InsertInset(pos, new_inset);
2882                                 } else {
2883                                         delete new_inset;
2884                                 }
2885 #else
2886                                         par->InsertChar(a, LyXParagraph::META_PROTECTED_SEPARATOR);
2887                                         par->SetFont(a, current_font);
2888 #endif
2889                                 }
2890                                 pos = a;
2891                         } else if (str[i] != 13 && 
2892                                    // Ignore unprintables
2893                                    (str[i] & 127) >= ' ') {
2894                                 par->InsertChar(pos, str[i]);
2895                                 par->SetFont(pos, current_font);
2896                                 ++pos;
2897                         }
2898                 } else {
2899                         if (par->table) {
2900                                 if (i + 1 >= str.length()) {
2901                                         ++pos;
2902                                         break;
2903                                 }
2904                                 while((pos < par->size()) &&
2905                                       (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2906                                         ++pos;
2907                                 ++pos;
2908                                 cell = NumberOfCell(par, pos);
2909                                 while((pos < par->size()) &&
2910                                       !(par->table->IsFirstCell(cell))) {
2911
2912                                         while((pos < par->size()) &&
2913                                               (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2914                                                 ++pos;
2915                                         ++pos;
2916                                         cell = NumberOfCell(par, pos);
2917                                 }
2918                                 if (pos >= par->size())
2919                                         // no more fields to fill skip the rest
2920                                         break;
2921                         } else {
2922                                 if (!par->size()) { // par is empty
2923 #if 1
2924                                         InsetSpecialChar * new_inset =
2925                                                 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2926                                         if (par->InsertInsetAllowed(new_inset)) {
2927                                                 par->InsertChar(pos, LyXParagraph::META_INSET);
2928                                                 par->SetFont(pos, current_font);
2929                                                 par->InsertInset(pos, new_inset);
2930                                         } else {
2931                                                 delete new_inset;
2932                                         }
2933 #else
2934                                         par->InsertChar(pos, LyXParagraph::META_PROTECTED_SEPARATOR);
2935                                         par->SetFont(pos, current_font);
2936 #endif
2937                                         ++pos;
2938                                 }
2939                                 par->BreakParagraph(pos, flag);
2940                                 par = par->Next();
2941                                 pos = 0;
2942                         }
2943                 }
2944                 ++i;
2945         }
2946         
2947         RedoParagraphs(cursor, endpar);
2948         SetCursor(cursor.par, cursor.pos);
2949         sel_cursor = cursor;
2950         SetCursor(par, pos);
2951         SetSelection();
2952 }
2953
2954
2955 /* turns double-CR to single CR, others where converted into one blank and 13s 
2956  * that are ignored .Double spaces are also converted into one. Spaces at
2957  * the beginning of a paragraph are forbidden. tabs are converted into one
2958  * space. then InsertStringA is called */ 
2959 void LyXText::InsertStringB(string const & s)
2960 {
2961         string str(s);
2962         LyXParagraph * par = cursor.par;
2963         string::size_type i = 1;
2964         while (i < str.length()) {
2965                 if (str[i] == '\t' && !par->table)
2966                         str[i] = ' ';
2967                 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2968                         str[i] = 13;
2969                 if (str[i] == '\n' && i + 1 < str.length() && !par->table){
2970                         if (str[i + 1] != '\n') {
2971                                 if (str[i - 1] != ' ')
2972                                         str[i] = ' ';
2973                                 else
2974                                         str[i] = 13;
2975                         }
2976                         while (i + 1 < str.length() 
2977                                && (str[i + 1] == ' ' 
2978                                    || str[i + 1] == '\t'
2979                                    || str[i + 1] == '\n' 
2980                                    || str[i + 1] == 13)) {
2981                                 str[i + 1] = 13;
2982                                 ++i;
2983                         }
2984                 }
2985                 ++i;
2986         }
2987         InsertStringA(str);
2988 }
2989
2990
2991 bool LyXText::GotoNextError() const
2992 {
2993         LyXCursor res = cursor;
2994         do {
2995                 if (res.pos < res.par->Last() - 1) {
2996                         res.pos++;
2997                 }
2998                 else  {
2999                         res.par = res.par->Next();
3000                         res.pos = 0;
3001                 }
3002       
3003         } while (res.par && 
3004                  !(res.par->GetChar(res.pos) == LyXParagraph::META_INSET
3005                    && res.par->GetInset(res.pos)->AutoDelete()));
3006    
3007         if (res.par) {
3008                 SetCursor(res.par, res.pos);
3009                 return true;
3010         }
3011         return false;
3012 }
3013
3014
3015 bool LyXText::GotoNextNote() const
3016 {
3017         LyXCursor res = cursor;
3018         do {
3019                 if (res.pos < res.par->Last() - 1) {
3020                         res.pos++;
3021                 } else  {
3022                         res.par = res.par->Next();
3023                         res.pos = 0;
3024                 }
3025       
3026         } while (res.par && 
3027                  !(res.par->GetChar(res.pos) == LyXParagraph::META_INSET
3028                    && res.par->GetInset(res.pos)->LyxCode() == Inset::IGNORE_CODE));
3029    
3030         if (res.par) {
3031                 SetCursor(res.par, res.pos);
3032                 return true;
3033         }
3034         return false;
3035 }
3036
3037
3038 void LyXText::CheckParagraph(LyXParagraph * par,
3039                              LyXParagraph::size_type pos)
3040 {
3041   
3042         LyXCursor tmpcursor;
3043
3044         /* table stuff -- begin*/
3045    
3046         if (par->table) {
3047                 CheckParagraphInTable(par, pos);
3048         }
3049         else {
3050                 /* table stuff -- end*/
3051      
3052                 long y = 0;
3053                 LyXParagraph::size_type z;
3054                 Row * row = GetRow(par, pos, y);
3055      
3056                 // is there a break one row above
3057                 if (row->previous && row->previous->par == row->par) {
3058                         z = NextBreakPoint(row->previous, paperwidth);
3059                         if ( z >= row->pos) {
3060                                 // set the dimensions of the row above
3061                                 y -= row->previous->height;
3062                                 refresh_y = y;
3063                                 refresh_row = row->previous;
3064                                 status = LyXText::NEED_MORE_REFRESH;
3065        
3066                                 BreakAgain(row->previous);
3067
3068                                 // set the cursor again. Otherwise
3069                                 // dangling pointers are possible
3070                                 SetCursor(cursor.par, cursor.pos);
3071                                 sel_cursor = cursor;
3072                                 return;
3073                         }
3074                 }
3075
3076                 int tmpheight = row->height;
3077                 LyXParagraph::size_type tmplast = RowLast(row);
3078                 refresh_y = y;
3079                 refresh_row = row;
3080
3081                 BreakAgain(row);
3082                 if (row->height == tmpheight && RowLast(row) == tmplast)
3083                         status = LyXText::NEED_VERY_LITTLE_REFRESH;
3084                 else
3085                         status = LyXText::NEED_MORE_REFRESH; 
3086    
3087                 // check the special right address boxes
3088                 if (textclasslist.Style(parameters->textclass,
3089                                         par->GetLayout()).margintype
3090                     == MARGIN_RIGHT_ADDRESS_BOX) {
3091                         tmpcursor.par = par;
3092                         tmpcursor.row = row;
3093                         tmpcursor.y = y;
3094                         tmpcursor.x = 0;
3095                         tmpcursor.x_fix = 0;
3096                         tmpcursor.pos = pos;
3097                         RedoDrawingOfParagraph(tmpcursor); 
3098                 }
3099    
3100         }
3101
3102         // set the cursor again. Otherwise dangling pointers are possible
3103         // also set the selection
3104    
3105         if (selection) {
3106                 tmpcursor = cursor;
3107                 SetCursorIntern(sel_cursor.par, sel_cursor.pos);
3108                 sel_cursor = cursor; 
3109                 SetCursorIntern(sel_start_cursor.par, sel_start_cursor.pos);
3110                 sel_start_cursor = cursor; 
3111                 SetCursorIntern(sel_end_cursor.par, sel_end_cursor.pos);
3112                 sel_end_cursor = cursor; 
3113                 SetCursorIntern(last_sel_cursor.par, last_sel_cursor.pos);
3114                 last_sel_cursor = cursor; 
3115                 cursor = tmpcursor;
3116         }
3117         SetCursorIntern(cursor.par, cursor.pos);
3118 }
3119
3120
3121 // returns 0 if inset wasn't found
3122 int LyXText::UpdateInset(Inset * inset)
3123 {
3124         // first check the current paragraph
3125         int pos = cursor.par->GetPositionOfInset(inset);
3126         if (pos != -1){
3127                 CheckParagraph(cursor.par, pos);
3128                 return 1;
3129         }
3130   
3131         // check every paragraph
3132   
3133         LyXParagraph * par = FirstParagraph();
3134         do {
3135                 // make sure the paragraph is open
3136                 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
3137                         pos = par->GetPositionOfInset(inset);
3138                         if (pos != -1){
3139                                 CheckParagraph(par, pos);
3140                                 return 1;
3141                         }
3142                 }
3143                 par = par->Next();
3144         } while (par);
3145   
3146         return 0;
3147 }
3148
3149
3150 void LyXText::SetCursor(LyXParagraph * par,
3151                         LyXParagraph::size_type pos, bool setfont) const
3152 {
3153         LyXCursor old_cursor = cursor;
3154         SetCursorIntern(par, pos, setfont);
3155         DeleteEmptyParagraphMechanism(old_cursor);
3156 }
3157
3158
3159 void LyXText::SetCursorIntern(LyXParagraph * par,
3160                               LyXParagraph::size_type pos, bool setfont) const
3161 {
3162         // correct the cursor position if impossible
3163         if (pos > par->Last()){
3164                 LyXParagraph * tmppar = par->ParFromPos(pos);
3165                 pos = par->PositionInParFromPos(pos);
3166                 par = tmppar;
3167         }
3168         if (par->IsDummy() && par->previous &&
3169             par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
3170                 while (par->previous &&
3171                        ((par->previous->IsDummy() && par->previous->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) ||
3172                         (par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE))) {
3173                         par = par->previous ;
3174                         if (par->IsDummy() &&
3175                             par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3176                                 pos += par->size() + 1;
3177                 }
3178                 if (par->previous) {
3179                         par = par->previous;
3180                 }
3181                 pos += par->size() + 1;
3182         }
3183
3184         cursor.par = par;
3185         cursor.pos = pos;
3186
3187         if (setfont)
3188                 if (cursor.pos && 
3189                     (cursor.pos == cursor.par->Last() || cursor.par->IsSeparator(cursor.pos)
3190                      || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
3191                          && !cursor.par->IsSeparator(cursor.pos))
3192                      || (cursor.par->table && cursor.par->IsNewline(cursor.pos))
3193                      )) {
3194                         current_font = cursor.par->GetFontSettings(cursor.pos - 1);
3195                         real_current_font = GetFont(cursor.par, cursor.pos - 1);
3196                 } else {
3197                         current_font = cursor.par->GetFontSettings(cursor.pos);
3198                         real_current_font = GetFont(cursor.par, cursor.pos);
3199                 }
3200
3201         /* get the cursor y position in text  */
3202         long y = 0;
3203         Row * row = GetRow(par, pos, y);
3204         /* y is now the beginning of the cursor row */ 
3205         y += row->baseline;
3206         /* y is now the cursor baseline */ 
3207         cursor.y = y;
3208    
3209         /* now get the cursors x position */
3210         float x;
3211         float fill_separator, fill_hfill, fill_label_hfill;
3212         PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
3213         LyXParagraph::size_type cursor_vpos;
3214         LyXParagraph::size_type last = RowLast(row);
3215         if (row->pos > last)
3216                 cursor_vpos = 0;
3217         else if (pos > last)
3218                 cursor_vpos = (row->par->getLetterDirection(last) == LYX_DIR_LEFT_TO_RIGHT)
3219                         ? log2vis(last)+1 : log2vis(last);
3220         else {      
3221                 LyXDirection letter_direction =
3222                         row->par->getLetterDirection(pos);
3223                 LyXDirection font_direction =
3224                         (real_current_font.isVisibleRightToLeft())
3225                         ?  LYX_DIR_RIGHT_TO_LEFT : LYX_DIR_LEFT_TO_RIGHT;
3226                 if (letter_direction == font_direction
3227                     || pos <= row->pos
3228                     || (row->par->table && row->par->IsNewline(pos-1)))
3229                         cursor_vpos = (letter_direction == LYX_DIR_LEFT_TO_RIGHT)
3230                                 ? log2vis(pos) : log2vis(pos) + 1;
3231                 else
3232                         cursor_vpos = (font_direction == LYX_DIR_LEFT_TO_RIGHT)
3233                                 ? log2vis(pos-1) + 1 : log2vis(pos - 1);
3234         }
3235         
3236         /* table stuff -- begin*/
3237         if (row->par->table) {
3238                 int cell = NumberOfCell(row->par, row->pos);
3239                 float x_old = x;
3240                 x += row->par->table->GetBeginningOfTextInCell(cell);
3241                 for (LyXParagraph::size_type vpos = row->pos; vpos < cursor_vpos; ++vpos)  {
3242                         pos = vis2log(vpos);
3243                         if (row->par->IsNewline(pos)) {
3244                                 x = x_old + row->par->table->WidthOfColumn(cell);
3245                                 x_old = x;
3246                                 ++cell;
3247                                 x += row->par->table->GetBeginningOfTextInCell(cell);
3248                         } else {
3249                                 x += SingleWidth(row->par, pos);
3250                         }
3251                 }
3252         } else {
3253                 /* table stuff -- end*/
3254                 LyXParagraph::size_type main_body =
3255                         BeginningOfMainBody(row->par);
3256                 if (main_body > 0 &&
3257                     (main_body-1 > last || 
3258                      !row->par->IsLineSeparator(main_body-1)))
3259                         main_body = 0;
3260
3261                 for (LyXParagraph::size_type vpos = row->pos; vpos < cursor_vpos; ++vpos)  {
3262                         pos = vis2log(vpos);
3263                         if (main_body > 0 && pos == main_body-1) {
3264                                 x += fill_label_hfill +
3265                                         lyxfont::width(textclasslist
3266                                                        .Style(parameters->textclass,
3267                                                               row->par->GetLayout())
3268                                                        .labelsep,
3269                                                        GetFont(row->par, -2));
3270                                 if (row->par->IsLineSeparator(main_body-1))
3271                                         x -= SingleWidth(row->par, main_body-1);
3272                         }
3273                         if (HfillExpansion(row, pos)) {
3274                                 x += SingleWidth(row->par, pos);
3275                                 if (pos >= main_body)
3276                                         x += fill_hfill;
3277                                 else 
3278                                         x += fill_label_hfill;
3279                         }
3280                         else if (row->par->IsSeparator(pos)) {
3281                                 if (pos != last ||
3282                                     !row->next ||
3283                                     row->next->par != row->par ||
3284                                     row->par->getParDirection() ==
3285                                     row->par->getLetterDirection(last)) {
3286                                         x += SingleWidth(row->par, pos);
3287                                         if (pos >= main_body)
3288                                                 x += fill_separator;
3289                                 }
3290                         } else
3291                                 x += SingleWidth(row->par, pos);
3292                 }
3293         }
3294    
3295         cursor.x = int(x);
3296    
3297         cursor.x_fix = cursor.x;
3298         cursor.row = row;
3299 }
3300
3301
3302 void LyXText::SetCursorFromCoordinates(int x, long y) const
3303 {
3304         LyXCursor old_cursor = cursor;
3305    
3306         /* get the row first */ 
3307    
3308         Row * row = GetRowNearY(y);
3309    
3310         cursor.par = row->par;
3311    
3312         int column = GetColumnNearX(row, x);
3313         cursor.pos = row->pos + column;
3314         cursor.x = x;
3315         cursor.y = y + row->baseline;
3316    
3317         cursor.row = row;
3318     
3319         if (cursor.pos && 
3320             (cursor.pos == cursor.par->Last()
3321              || cursor.par->IsSeparator(cursor.pos)
3322              || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
3323                  && !cursor.par->IsSeparator(cursor.pos))
3324              || (cursor.par->table && cursor.par->IsNewline(cursor.pos))
3325                     )) {
3326                 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
3327                 real_current_font = GetFont(cursor.par, cursor.pos - 1);
3328         } else {
3329                 current_font = cursor.par->GetFontSettings(cursor.pos);
3330                 real_current_font = GetFont(cursor.par, cursor.pos);
3331         }
3332         DeleteEmptyParagraphMechanism(old_cursor);
3333 }
3334
3335 void LyXText::SetCursorFromCoordinates(LyXCursor & cur, int x, long y) const
3336 {
3337         /* get the row first */ 
3338    
3339         Row * row = GetRowNearY(y);
3340         int column = GetColumnNearX(row, x);
3341    
3342         cur.par = row->par;
3343         cur.pos = row->pos + column;
3344         cur.x = x;
3345         cur.y = y + row->baseline;
3346         cur.row = row;
3347 }
3348
3349
3350 void LyXText::CursorLeft() const
3351 {
3352         CursorLeftIntern();
3353         if (cursor.par->table) {
3354                 int cell = NumberOfCell(cursor.par, cursor.pos);
3355                 if (cursor.par->table->IsContRow(cell) &&
3356                     cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell)) < 0) {
3357                         CursorUp();
3358                 }
3359         }
3360 }
3361
3362
3363 void LyXText::CursorLeftIntern() const
3364 {
3365         if (cursor.pos > 0) {
3366                 SetCursor(cursor.par, cursor.pos - 1);
3367         }
3368         else if (cursor.par->Previous()) { // steps into the above paragraph.
3369                 SetCursor(cursor.par->Previous(), cursor.par->Previous()->Last());
3370         }
3371 }
3372
3373
3374 void LyXText::CursorRight() const
3375 {
3376         CursorRightIntern();
3377         if (cursor.par->table) {
3378                 int cell = NumberOfCell(cursor.par, cursor.pos);
3379                 if (cursor.par->table->IsContRow(cell) &&
3380                     cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3381                         CursorUp();
3382                 }
3383         }
3384 }
3385
3386
3387 void LyXText::CursorRightIntern() const
3388 {
3389         if (cursor.pos < cursor.par->Last()) {
3390                 SetCursor(cursor.par, cursor.pos + 1);
3391         }
3392         else if (cursor.par->Next()) {
3393                 SetCursor(cursor.par->Next(), 0);
3394         }
3395 }
3396
3397
3398 void LyXText::CursorUp() const
3399 {
3400         SetCursorFromCoordinates(cursor.x_fix, 
3401                                  cursor.y - cursor.row->baseline - 1);
3402         if (cursor.par->table) {
3403                 int cell = NumberOfCell(cursor.par, cursor.pos);
3404                 if (cursor.par->table->IsContRow(cell) &&
3405                     cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3406                         CursorUp();
3407                 }
3408         }
3409 }
3410
3411
3412 void LyXText::CursorDown() const
3413 {
3414         if (cursor.par->table &&
3415             cursor.par->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par, cursor.pos)) &&
3416             !cursor.par->next)
3417                 return;
3418         SetCursorFromCoordinates(cursor.x_fix, 
3419                                  cursor.y - cursor.row->baseline
3420                                  + cursor.row->height + 1);
3421         if (cursor.par->table) {
3422                 int cell = NumberOfCell(cursor.par, cursor.pos);
3423                 int cell_above = cursor.par->table->GetCellAbove(cell);
3424                 while(cursor.par->table &&
3425                       cursor.par->table->IsContRow(cell) &&
3426                       (cursor.par->table->CellHasContRow(cell_above)<0)) {
3427                     SetCursorFromCoordinates(cursor.x_fix, 
3428                                              cursor.y - cursor.row->baseline
3429                                              + cursor.row->height + 1);
3430                     if (cursor.par->table) {
3431                         cell = NumberOfCell(cursor.par, cursor.pos);
3432                         cell_above = cursor.par->table->GetCellAbove(cell);
3433                     }
3434                 }
3435         }
3436 }
3437
3438
3439 void LyXText::CursorUpParagraph() const
3440 {
3441         if (cursor.pos > 0) {
3442                 SetCursor(cursor.par, 0);
3443         }
3444         else if (cursor.par->Previous()) {
3445                 SetCursor(cursor.par->Previous(), 0);
3446         }
3447 }
3448
3449
3450 void LyXText::CursorDownParagraph() const
3451 {
3452         if (cursor.par->Next()) {
3453                 SetCursor(cursor.par->Next(), 0);
3454         } else {
3455                 SetCursor(cursor.par, cursor.par->Last());
3456         }
3457 }
3458
3459
3460
3461 void LyXText::DeleteEmptyParagraphMechanism(LyXCursor const & old_cursor) const
3462 {
3463         // Would be wrong to delete anything if we have a selection.
3464         if (selection) return;
3465
3466         // We allow all kinds of "mumbo-jumbo" when freespacing.
3467         if (textclasslist.Style(parameters->textclass,
3468                                 old_cursor.par->GetLayout()).free_spacing)
3469                 return;
3470
3471         bool deleted = false;
3472         
3473 #ifdef FIX_DOUBLE_SPACE
3474         /* Ok I'll put some comments here about what is missing.
3475            I have fixed BackSpace (and thus Delete) to not delete
3476            double-spaces automagically. I have also changed Cut,
3477            Copy and Paste to hopefully do some sensible things.
3478            There are still some small problems that can lead to
3479            double spaces stored in the document file or space at
3480            the beginning of paragraphs. This happens if you have
3481            the cursor betwenn to spaces and then save. Or if you
3482            cut and paste and the selection have a space at the
3483            beginning and then save right after the paste. I am
3484            sure none of these are very hard to fix, but I will
3485            put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3486            that I can get some feedback. (Lgb)
3487         */
3488
3489         // If old_cursor.pos == 0 and old_cursor.pos(1) == LineSeparator
3490         // delete the LineSeparator.
3491         // MISSING
3492
3493         // If old_cursor.pos == 1 and old_cursor.pos(0) == LineSeparator
3494         // delete the LineSeparator.
3495         // MISSING
3496
3497         // If the pos around the old_cursor were spaces, delete one of them.
3498         if (old_cursor.par != cursor.par || old_cursor.pos != cursor.pos) { // Only if the cursor has really moved
3499                 
3500                 if (old_cursor.pos > 0
3501                     && old_cursor.pos < old_cursor.par->Last()
3502                     && old_cursor.par->IsLineSeparator(old_cursor.pos)
3503                     && old_cursor.par->IsLineSeparator(old_cursor.pos - 1)) {
3504                         old_cursor.par->Erase(old_cursor.pos - 1);
3505                         status = LyXText::NEED_MORE_REFRESH;
3506                         // correct cursor
3507                         if (old_cursor.par == cursor.par &&
3508                             cursor.pos > old_cursor.pos) {
3509                                 SetCursorIntern(cursor.par, cursor.pos - 1);
3510                         }
3511                         return;
3512                 }
3513         }
3514 #endif
3515 #if 1
3516         // Do not delete empty paragraphs with keepempty set.
3517         if ((textclasslist.Style(parameters->textclass,
3518                                  old_cursor.par->GetLayout())).keepempty)
3519                 return;
3520
3521         LyXCursor tmpcursor;
3522
3523         if (old_cursor.par != cursor.par) {
3524                 if ( (old_cursor.par->Last() == 0
3525                       || (old_cursor.par->Last() == 1
3526                           && old_cursor.par->IsLineSeparator(0)))
3527                      && old_cursor.par->FirstPhysicalPar()
3528                      == old_cursor.par->LastPhysicalPar()) {
3529                         // ok, we will delete anything
3530                         
3531                         // make sure that you do not delete any environments
3532                         if ((old_cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3533                              !(old_cursor.row->previous 
3534                                && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3535                              && !(old_cursor.row->next 
3536                                   && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3537                             || (old_cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3538                                 && ((old_cursor.row->previous 
3539                                      && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3540                                     || (old_cursor.row->next
3541                                         && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3542                                     )) {
3543                                 status = LyXText::NEED_MORE_REFRESH;
3544                                 deleted = true;
3545                                 
3546                                 if (old_cursor.row->previous) {
3547                                         refresh_row = old_cursor.row->previous;
3548                                         refresh_y = old_cursor.y - old_cursor.row->baseline - refresh_row->height;
3549                                         tmpcursor = cursor;
3550                                         cursor = old_cursor; // that undo can restore the right cursor position
3551                                         LyXParagraph * endpar = old_cursor.par->next;
3552                                         if (endpar && endpar->GetDepth()) {
3553                                                 while (endpar && endpar->GetDepth()) {
3554                                                         endpar = endpar->LastPhysicalPar()->Next();
3555                                                 }
3556                                         }
3557                                         SetUndo(Undo::DELETE,
3558                                                 old_cursor.par->previous,
3559                                                 endpar);
3560                                         cursor = tmpcursor;
3561
3562                                         // delete old row
3563                                         RemoveRow(old_cursor.row);
3564                                         if (params->paragraph == old_cursor.par) {
3565                                                 params->paragraph = params->paragraph->next;
3566                                         }
3567                                         // delete old par
3568                                         delete old_cursor.par;
3569                                         
3570                                         /* Breakagain the next par. Needed
3571                                          * because of the parindent that
3572                                          * can occur or dissappear. The
3573                                          * next row can change its height,
3574                                          * if there is another layout before */
3575                                         if (refresh_row->next) {
3576                                                 BreakAgain(refresh_row->next);
3577                                                 UpdateCounters(refresh_row);
3578                                         }
3579                                         SetHeightOfRow(refresh_row);
3580                                 } else {
3581                                         refresh_row = old_cursor.row->next;
3582                                         refresh_y = old_cursor.y - old_cursor.row->baseline;
3583                                         
3584                                         tmpcursor = cursor;
3585                                         cursor = old_cursor; // that undo can restore the right cursor position
3586                                         LyXParagraph *endpar = old_cursor.par->next;
3587                                         if (endpar && endpar->GetDepth()) {
3588                                                 while (endpar && endpar->GetDepth()) {
3589                                                         endpar = endpar->LastPhysicalPar()->Next();
3590                                                 }
3591                                         }
3592                                         SetUndo(Undo::DELETE,
3593                                                 old_cursor.par->previous,
3594                                                 endpar);
3595                                         cursor = tmpcursor;
3596
3597                                         // delete old row
3598                                         RemoveRow(old_cursor.row);
3599                                         // delete old par
3600                                         if (params->paragraph == old_cursor.par) {
3601                                                 params->paragraph = params->paragraph->next;
3602                                         }
3603                                         delete old_cursor.par;
3604                                         
3605                                         /* Breakagain the next par. Needed
3606                                            because of the parindent that can
3607                                            occur or dissappear.
3608                                            The next row can change its height,
3609                                            if there is another layout before
3610                                         */ 
3611                                         if (refresh_row) {
3612                                                 BreakAgain(refresh_row);
3613                                                 UpdateCounters(refresh_row->previous);
3614                                         }
3615                                 }
3616                                 
3617                                 // correct cursor y
3618 #if 1
3619                                 SetCursorIntern(cursor.par, cursor.pos);
3620 #else
3621                                 SetCursor(cursor.par, cursor.pos);
3622 #endif                  
3623                                 /* if (cursor.y > old_cursor.y)
3624                                    cursor.y -= old_cursor.row->height; */ 
3625          
3626                                 if (sel_cursor.par  == old_cursor.par
3627                                     && sel_cursor.pos == sel_cursor.pos) {
3628                                         // correct selection
3629                                         sel_cursor = cursor;
3630                                 }
3631                         }
3632                 }
3633                 if (!deleted) {
3634                         if (old_cursor.par->ClearParagraph()) {
3635                                 RedoParagraphs(old_cursor, old_cursor.par->Next());
3636                                 // correct cursor y
3637 #if 1
3638                                 SetCursorIntern(cursor.par, cursor.pos);
3639 #else
3640                                 SetCursor(cursor.par, cursor.pos);
3641 #endif
3642                                 sel_cursor = cursor;
3643                         }
3644                 }
3645         }
3646 #endif
3647 }
3648
3649
3650 LyXParagraph * LyXText::GetParFromID(int id)
3651 {
3652         LyXParagraph * result = FirstParagraph();
3653         while (result && result->id() != id)
3654                 result = result->next;
3655         return result;
3656 }
3657
3658
3659 // undo functions
3660 bool LyXText::TextUndo()
3661 {
3662         // returns false if no undo possible
3663         Undo * undo = params->undostack.pop();
3664         if (undo) {
3665                 FinishUndo();
3666                 if (!undo_frozen)
3667                         params->redostack
3668                                 .push(CreateUndo(undo->kind, 
3669                                                  GetParFromID(undo->number_of_before_par),
3670                                                  GetParFromID(undo->number_of_behind_par)));
3671         }
3672         return TextHandleUndo(undo);
3673 }
3674
3675
3676 bool LyXText::TextRedo()
3677 {
3678         // returns false if no redo possible
3679         Undo * undo = params->redostack.pop();
3680         if (undo) {
3681                 FinishUndo();
3682                 if (!undo_frozen)
3683                         params->undostack
3684                                 .push(CreateUndo(undo->kind, 
3685                                                  GetParFromID(undo->number_of_before_par),
3686                                                  GetParFromID(undo->number_of_behind_par)));
3687         }
3688         return TextHandleUndo(undo);
3689 }
3690
3691
3692 bool LyXText::TextHandleUndo(Undo * undo)
3693 {
3694         // returns false if no undo possible
3695         bool result = false;
3696         if (undo) {
3697                 LyXParagraph * before =
3698                         GetParFromID(undo->number_of_before_par); 
3699                 LyXParagraph * behind =
3700                         GetParFromID(undo->number_of_behind_par); 
3701                 LyXParagraph * tmppar;
3702                 LyXParagraph * tmppar2;
3703                 LyXParagraph * endpar;
3704                 LyXParagraph * tmppar5;
3705     
3706                 // if there's no before take the beginning
3707                 // of the document for redoing
3708                 if (!before)
3709                         SetCursorIntern(FirstParagraph(), 0);
3710
3711                 // replace the paragraphs with the undo informations
3712
3713                 LyXParagraph * tmppar3 = undo->par;
3714                 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3715                 LyXParagraph * tmppar4 = tmppar3;
3716                 if (tmppar4){
3717                         while (tmppar4->next)
3718                                 tmppar4 = tmppar4->next;
3719                 } // get last undo par
3720     
3721                 // now remove the old text if there is any
3722                 if (before != behind || (!behind && !before)){
3723                         if (before)
3724                                 tmppar5 = before->next;
3725                         else
3726                                 tmppar5 = params->paragraph;
3727                         tmppar2 = tmppar3;
3728                         while (tmppar5 && tmppar5 != behind){
3729                                 tmppar = tmppar5;
3730                                 tmppar5 = tmppar5->next;
3731                                 // a memory optimization for edit: Only layout information
3732                                 // is stored in the undo. So restore the text informations.
3733                                 if (undo->kind == Undo::EDIT) {
3734                                         tmppar2->setContentsFromPar(tmppar);
3735                                         tmppar->clearContents();
3736                                         //tmppar2->text = tmppar->text;
3737                                         //tmppar->text.clear();
3738                                         tmppar2 = tmppar2->next;
3739                                 }
3740                                 if ( currentrow && currentrow->par == tmppar )
3741                                         currentrow = currentrow -> previous;
3742                                 // Commenting out this might remove the error
3743                                 // reported by Purify, but it might also
3744                                 // introduce a memory leak. We need to
3745                                 // check this (Lgb)
3746                                 //delete tmppar;
3747                         }
3748                 }
3749     
3750                 // put the new stuff in the list if there is one
3751                 if (tmppar3){
3752                         if (before)
3753                                 before->next = tmppar3;
3754                         else
3755                                 params->paragraph = tmppar3;
3756                         tmppar3->previous = before;
3757                 }
3758                 else {
3759                         if (!before)
3760                                 params->paragraph = behind;
3761                 }
3762                 if (tmppar4) {
3763                         tmppar4->next = behind;
3764                         if (behind)
3765                                 behind->previous = tmppar4;
3766                 }
3767     
3768     
3769                 // Set the cursor for redoing
3770                 if (before) {
3771                         SetCursorIntern(before->FirstSelfrowPar(), 0);
3772                         // check wether before points to a closed float and open it if necessary
3773                         if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3774                             && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3775                                 tmppar4 = before;
3776                                 while (tmppar4->previous && 
3777                                        tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3778                                         tmppar4 = tmppar4->previous;
3779                                 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3780                                         tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3781                                         tmppar4 = tmppar4->next;
3782                                 }
3783                         }
3784                 }
3785     
3786                 // open a cosed footnote at the end if necessary
3787                 if (behind && behind->previous && 
3788                     behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3789                     behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3790                         while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3791                                 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3792                                 behind = behind->next;
3793                         }
3794                 }
3795     
3796                 // calculate the endpar for redoing the paragraphs.
3797                 if (behind){
3798                         if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3799                                 endpar = behind->LastPhysicalPar()->Next();
3800                         else
3801                                 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3802                 }
3803                 else
3804                         endpar = behind;
3805     
3806                 tmppar = GetParFromID(undo->number_of_cursor_par);
3807                 RedoParagraphs(cursor, endpar); 
3808                 if (tmppar){
3809                         SetCursorIntern(tmppar, undo->cursor_pos);
3810                         UpdateCounters(cursor.row);
3811                 }
3812                 result = true;
3813                 delete undo;
3814         }
3815         FinishUndo();
3816         return result;
3817 }
3818
3819
3820 void LyXText::FinishUndo()
3821 {
3822         // makes sure the next operation will be stored
3823         undo_finished = True;
3824 }
3825
3826
3827 void LyXText::FreezeUndo()
3828 {
3829         // this is dangerous and for internal use only
3830         undo_frozen = True;
3831 }
3832
3833
3834 void LyXText::UnFreezeUndo()
3835 {
3836         // this is dangerous and for internal use only
3837         undo_frozen = false;
3838 }
3839
3840
3841 void LyXText::SetUndo(Undo::undo_kind kind, LyXParagraph const * before,
3842                       LyXParagraph const * behind) const
3843 {
3844         if (!undo_frozen)
3845                 params->undostack.push(CreateUndo(kind, before, behind));
3846         params->redostack.clear();
3847 }
3848
3849
3850 void LyXText::SetRedo(Undo::undo_kind kind, LyXParagraph const * before,
3851                       LyXParagraph const * behind)
3852 {
3853         params->redostack.push(CreateUndo(kind, before, behind));
3854 }
3855
3856
3857 Undo * LyXText::CreateUndo(Undo::undo_kind kind, LyXParagraph const * before,
3858                           LyXParagraph const * behind) const
3859 {
3860         int before_number = -1;
3861         int behind_number = -1;
3862         if (before)
3863                 before_number = before->id();
3864         if (behind)
3865                 behind_number = behind->id();
3866         // Undo::EDIT  and Undo::FINISH are
3867         // always finished. (no overlapping there)
3868         // overlapping only with insert and delete inside one paragraph: 
3869         // Nobody wants all removed  character
3870         // appear one by one when undoing. 
3871         // EDIT is special since only layout information, not the
3872         // contents of a paragaph are stored.
3873         if (!undo_finished && kind != Undo::EDIT && 
3874             kind != Undo::FINISH){
3875                 // check wether storing is needed
3876                 if (!params->undostack.empty() && 
3877                     params->undostack.top()->kind == kind &&
3878                     params->undostack.top()->number_of_before_par ==  before_number &&
3879                     params->undostack.top()->number_of_behind_par ==  behind_number ){
3880                         // no undo needed
3881                         return 0;
3882                 }
3883         }
3884         // create a new Undo
3885         LyXParagraph * undopar;
3886         LyXParagraph * tmppar;
3887         LyXParagraph * tmppar2;
3888
3889         LyXParagraph * start = 0;
3890         LyXParagraph * end = 0;
3891   
3892         if (before)
3893                 start = before->next;
3894         else
3895                 start = FirstParagraph();
3896         if (behind)
3897                 end = behind->previous;
3898         else {
3899                 end = FirstParagraph();
3900                 while (end->next)
3901                         end = end->next;
3902         }
3903
3904         if (start && end
3905             && start != end->next
3906             && (before != behind || (!before && !behind))) {
3907                 tmppar = start;
3908                 tmppar2 = tmppar->Clone();
3909                 tmppar2->id(tmppar->id());
3910
3911                 // a memory optimization: Just store the layout information
3912                 // when only edit
3913                 if (kind == Undo::EDIT){
3914                         //tmppar2->text.clear();
3915                         tmppar2->clearContents();
3916                 }
3917
3918                 undopar = tmppar2;
3919   
3920                 while (tmppar != end && tmppar->next) {
3921                         tmppar = tmppar->next;
3922                         tmppar2->next = tmppar->Clone();
3923                         tmppar2->next->id(tmppar->id());
3924                         // a memory optimization: Just store the layout
3925                         // information when only edit
3926                         if (kind == Undo::EDIT){
3927                                 //tmppar2->next->text.clear();
3928                                 tmppar2->clearContents();
3929                         }
3930                         tmppar2->next->previous = tmppar2;
3931                         tmppar2 = tmppar2->next;
3932                 }
3933                 tmppar2->next = 0;
3934         } else
3935                 undopar = 0; // nothing to replace (undo of delete maybe)
3936   
3937         int cursor_par = cursor.par->ParFromPos(cursor.pos)->id();
3938         int cursor_pos =  cursor.par->PositionInParFromPos(cursor.pos);
3939
3940         Undo * undo = new Undo(kind, 
3941                                before_number, behind_number,  
3942                                cursor_par, cursor_pos, 
3943                                undopar);
3944   
3945         undo_finished = false;
3946         return undo;
3947 }
3948
3949
3950 void LyXText::SetCursorParUndo()
3951 {
3952         SetUndo(Undo::FINISH, 
3953                 cursor.par->ParFromPos(cursor.pos)->previous, 
3954                 cursor.par->ParFromPos(cursor.pos)->next); 
3955 }
3956
3957
3958 void LyXText::RemoveTableRow(LyXCursor * cur) const
3959 {
3960         int cell = -1;
3961         int cell_org = 0;
3962         int ocell = 0;
3963     
3964         // move to the previous row
3965         int cell_act = NumberOfCell(cur->par, cur->pos);
3966         if (cell < 0)
3967                 cell = cell_act;
3968         while (cur->pos && !cur->par->IsNewline(cur->pos - 1))
3969                 cur->pos--;
3970         while (cur->pos && 
3971                !cur->par->table->IsFirstCell(cell_act)) {
3972                 cur->pos--;
3973                 while (cur->pos && !cur->par->IsNewline(cur->pos - 1))
3974                         cur->pos--;
3975                 --cell;
3976                 --cell_act;
3977         }
3978         // now we have to pay attention if the actual table is the
3979         //   main row of TableContRows and if yes to delete all of them
3980         if (!cell_org)
3981                 cell_org = cell;
3982         do {
3983                 ocell = cell;
3984                 // delete up to the next row
3985                 while (cur->pos < cur->par->Last() && 
3986                        (cell_act == ocell
3987                         || !cur->par->table->IsFirstCell(cell_act))) {
3988                         while (cur->pos < cur->par->Last() &&
3989                                !cur->par->IsNewline(cur->pos))
3990                                 cur->par->Erase(cur->pos);
3991                         ++cell;
3992                         ++cell_act;
3993                         if (cur->pos < cur->par->Last())
3994                                 cur->par->Erase(cur->pos);
3995                 }
3996                 if (cur->pos && cur->pos == cur->par->Last()) {
3997                         cur->pos--;
3998                         cur->par->Erase(cur->pos); // no newline at very end!
3999                 }
4000         } while (((cell + 1) < cur->par->table->GetNumberOfCells()) &&
4001                  !cur->par->table->IsContRow(cell_org) &&
4002                  cur->par->table->IsContRow(cell));
4003         cur->par->table->DeleteRow(cell_org);
4004         return;
4005 }
4006
4007
4008 bool LyXText::IsEmptyTableCell() const
4009 {
4010         LyXParagraph::size_type pos = cursor.pos - 1;
4011         while (pos >= 0 && pos < cursor.par->Last()
4012                && !cursor.par->IsNewline(pos))
4013                 --pos;
4014         return cursor.par->IsNewline(pos + 1);
4015 }
4016
4017
4018 void LyXText::toggleAppendix(){
4019         LyXParagraph * par = cursor.par->FirstPhysicalPar();
4020         bool start = !par->start_of_appendix;
4021
4022         // ensure that we have only one start_of_appendix in this document
4023         LyXParagraph * tmp = FirstParagraph();
4024         for (; tmp; tmp = tmp->next)
4025                 tmp->start_of_appendix = 0;
4026         par->start_of_appendix = start;
4027
4028         // we can set the refreshing parameters now
4029         status = LyXText::NEED_MORE_REFRESH;
4030         refresh_y = 0;
4031         refresh_row = 0; // not needed for full update
4032         UpdateCounters(0);
4033         SetCursor(cursor.par, cursor.pos);
4034 }
4035