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