]> git.lyx.org Git - lyx.git/blob - src/text2.C
e15b93454aef4669d71eac0fca710de8ba37881d
[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 void LyXText::SetCursor(LyXCursor & cur, LyXParagraph * par,
3160                         LyXParagraph::size_type pos) const
3161 {
3162         // correct the cursor position if impossible
3163         if (pos > par->Last()){
3164                 LyXParagraph * tmppar = par->ParFromPos(pos);
3165                 pos = par->PositionInParFromPos(pos);
3166                 par = tmppar;
3167         }
3168         if (par->IsDummy() && par->previous &&
3169             par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
3170                 while (par->previous &&
3171                        ((par->previous->IsDummy() &&
3172                          (par->previous->previous->footnoteflag ==
3173                           LyXParagraph::CLOSED_FOOTNOTE)) ||
3174                         (par->previous->footnoteflag ==
3175                          LyXParagraph::CLOSED_FOOTNOTE))) {
3176                         par = par->previous ;
3177                         if (par->IsDummy() &&
3178                             (par->previous->footnoteflag ==
3179                              LyXParagraph::CLOSED_FOOTNOTE))
3180                                 pos += par->size() + 1;
3181                 }
3182                 if (par->previous) {
3183                         par = par->previous;
3184                 }
3185                 pos += par->size() + 1;
3186         }
3187
3188         cur.par = par;
3189         cur.pos = pos;
3190
3191         /* get the cursor y position in text  */
3192         long y = 0;
3193         Row * row = GetRow(par, pos, y);
3194         /* y is now the beginning of the cursor row */ 
3195         y += row->baseline;
3196         /* y is now the cursor baseline */ 
3197         cur.y = y;
3198    
3199         /* now get the cursors x position */
3200         float x;
3201         float fill_separator, fill_hfill, fill_label_hfill;
3202         PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
3203         LyXParagraph::size_type cursor_vpos;
3204         LyXParagraph::size_type last = RowLastPrintable(row);
3205
3206         if (pos > last + 1)   // This shouldn't happen.
3207                 pos = last+1;
3208
3209         if (last < row->pos)
3210                 cursor_vpos = 0;
3211         else if ((pos > last) ||
3212                  ((pos - 1 >= row->pos) &&
3213                   (row->par->IsSeparator(pos) ||
3214                    (row->par->table && row->par->IsNewline(pos)))))
3215                 /// Place cursor after char at (logical) position pos-1
3216                 cursor_vpos = !(bidi_level(pos-1) % 2)
3217                         ? log2vis(pos-1) + 1 : log2vis(pos-1);
3218         else
3219                 /// Place cursor before char at (logical) position pos
3220                 cursor_vpos = !(bidi_level(pos) % 2)
3221                         ? log2vis(pos) : log2vis(pos) + 1;
3222
3223         /* table stuff -- begin*/
3224         if (row->par->table) {
3225                 int cell = NumberOfCell(row->par, row->pos);
3226                 float x_old = x;
3227                 x += row->par->table->GetBeginningOfTextInCell(cell);
3228                 for (LyXParagraph::size_type vpos = row->pos;
3229                      vpos < cursor_vpos; ++vpos) {
3230                         pos = vis2log(vpos);
3231                         if (row->par->IsNewline(pos)) {
3232                                 x = x_old + row->par->table->WidthOfColumn(cell);
3233                                 x_old = x;
3234                                 ++cell;
3235                                 x += row->par->table->GetBeginningOfTextInCell(cell);
3236                         } else {
3237                                 x += SingleWidth(row->par, pos);
3238                         }
3239                 }
3240         } else {
3241                 /* table stuff -- end*/
3242                 LyXParagraph::size_type main_body =
3243                         BeginningOfMainBody(row->par);
3244                 if ((main_body > 0) &&
3245                     ((main_body-1 > last) || 
3246                      !row->par->IsLineSeparator(main_body-1)))
3247                         main_body = 0;
3248
3249                 for (LyXParagraph::size_type vpos = row->pos;
3250                      vpos < cursor_vpos; ++vpos) {
3251                         pos = vis2log(vpos);
3252                         if (main_body > 0 && pos == main_body-1) {
3253                                 x += fill_label_hfill +
3254                                         lyxfont::width(textclasslist.Style(
3255                                                 buffer->params.textclass,
3256                                                 row->par->GetLayout())
3257                                                        .labelsep,
3258                                                        GetFont(row->par, -2));
3259                                 if (row->par->IsLineSeparator(main_body-1))
3260                                         x -= SingleWidth(row->par,main_body-1);
3261                         }
3262                         if (HfillExpansion(row, pos)) {
3263                                 x += SingleWidth(row->par, pos);
3264                                 if (pos >= main_body)
3265                                         x += fill_hfill;
3266                                 else 
3267                                         x += fill_label_hfill;
3268                         } else if (row->par->IsSeparator(pos)) {
3269                                 x += SingleWidth(row->par, pos);
3270                                 if (pos >= main_body)
3271                                         x += fill_separator;
3272                         } else
3273                                 x += SingleWidth(row->par, pos);
3274                 }
3275         }
3276    
3277         cur.x = int(x);
3278         cur.x_fix = cur.x;
3279         cur.row = row;
3280 }
3281
3282
3283 void LyXText::SetCursorIntern(LyXParagraph * par,
3284                               LyXParagraph::size_type pos, bool setfont) const
3285 {
3286         SetCursor(cursor, par, pos);
3287 #warning Remove this when verified working (Jug 20000413)
3288 #if 0
3289         // correct the cursor position if impossible
3290         if (pos > par->Last()){
3291                 LyXParagraph * tmppar = par->ParFromPos(pos);
3292                 pos = par->PositionInParFromPos(pos);
3293                 par = tmppar;
3294         }
3295         if (par->IsDummy() && par->previous &&
3296             par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
3297                 while (par->previous &&
3298                        ((par->previous->IsDummy() && par->previous->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) ||
3299                         (par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE))) {
3300                         par = par->previous ;
3301                         if (par->IsDummy() &&
3302                             par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3303                                 pos += par->size() + 1;
3304                 }
3305                 if (par->previous) {
3306                         par = par->previous;
3307                 }
3308                 pos += par->size() + 1;
3309         }
3310
3311         cursor.par = par;
3312         cursor.pos = pos;
3313
3314         /* get the cursor y position in text  */
3315         long y = 0;
3316         Row * row = GetRow(par, pos, y);
3317         /* y is now the beginning of the cursor row */ 
3318         y += row->baseline;
3319         /* y is now the cursor baseline */ 
3320         cursor.y = y;
3321    
3322         /* now get the cursors x position */
3323         float x;
3324         float fill_separator, fill_hfill, fill_label_hfill;
3325         PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
3326         LyXParagraph::size_type cursor_vpos;
3327         LyXParagraph::size_type last = RowLastPrintable(row);
3328
3329         if (pos > last + 1)   // This shouldn't happen.
3330                 pos = last+1;
3331
3332         if (last < row->pos)
3333                 cursor_vpos = 0;
3334         else if (pos > last ||
3335             (pos - 1 >= row->pos &&
3336              (row->par->IsSeparator(pos) ||
3337               (row->par->table && row->par->IsNewline(pos))
3338               )))
3339                 /// Place cursor after char at (logical) position pos-1
3340                 cursor_vpos = (bidi_level(pos-1) % 2 == 0)
3341                         ? log2vis(pos-1) + 1 : log2vis(pos-1);
3342         else
3343                 /// Place cursor before char at (logical) position pos
3344                 cursor_vpos = (bidi_level(pos) % 2 == 0)
3345                         ? log2vis(pos) : log2vis(pos) + 1;
3346
3347         /* table stuff -- begin*/
3348         if (row->par->table) {
3349                 int cell = NumberOfCell(row->par, row->pos);
3350                 float x_old = x;
3351                 x += row->par->table->GetBeginningOfTextInCell(cell);
3352                 for (LyXParagraph::size_type vpos = row->pos; vpos < cursor_vpos; ++vpos)  {
3353                         pos = vis2log(vpos);
3354                         if (row->par->IsNewline(pos)) {
3355                                 x = x_old + row->par->table->WidthOfColumn(cell);
3356                                 x_old = x;
3357                                 ++cell;
3358                                 x += row->par->table->GetBeginningOfTextInCell(cell);
3359                         } else {
3360                                 x += SingleWidth(row->par, pos);
3361                         }
3362                 }
3363         } else {
3364                 /* table stuff -- end*/
3365                 LyXParagraph::size_type main_body =
3366                         BeginningOfMainBody(row->par);
3367                 if (main_body > 0 &&
3368                     (main_body-1 > last || 
3369                      !row->par->IsLineSeparator(main_body-1)))
3370                         main_body = 0;
3371
3372                 for (LyXParagraph::size_type vpos = row->pos; vpos < cursor_vpos; ++vpos)  {
3373                         pos = vis2log(vpos);
3374                         if (main_body > 0 && pos == main_body-1) {
3375                                 x += fill_label_hfill +
3376                                         lyxfont::width(textclasslist
3377                                                        .Style(buffer->params.textclass,
3378                                                               row->par->GetLayout())
3379                                                        .labelsep,
3380                                                        GetFont(row->par, -2));
3381                                 if (row->par->IsLineSeparator(main_body-1))
3382                                         x -= SingleWidth(row->par, main_body-1);
3383                         }
3384                         if (HfillExpansion(row, pos)) {
3385                                 x += SingleWidth(row->par, pos);
3386                                 if (pos >= main_body)
3387                                         x += fill_hfill;
3388                                 else 
3389                                         x += fill_label_hfill;
3390                         }
3391                         else if (row->par->IsSeparator(pos)) {
3392                                 x += SingleWidth(row->par, pos);
3393                                 if (pos >= main_body)
3394                                         x += fill_separator;
3395                         } else
3396                                 x += SingleWidth(row->par, pos);
3397                 }
3398         }
3399    
3400         cursor.x = int(x);
3401    
3402         cursor.x_fix = cursor.x;
3403         cursor.row = row;
3404 #endif
3405         if (setfont) {
3406                 if (cursor.pos && 
3407                     (cursor.pos == cursor.par->Last() || cursor.par->IsSeparator(cursor.pos)
3408                      || (cursor.par->table && cursor.par->IsNewline(cursor.pos))
3409                      )) {
3410                         current_font = cursor.par->GetFontSettings(cursor.pos - 1);
3411                         real_current_font = GetFont(cursor.par, cursor.pos - 1);
3412                 } else {
3413                         current_font = cursor.par->GetFontSettings(cursor.pos);
3414                         real_current_font = GetFont(cursor.par, cursor.pos);
3415                 }
3416         }
3417 }
3418
3419
3420 void LyXText::SetCursorFromCoordinates(int x, long y) const
3421 {
3422         LyXCursor old_cursor = cursor;
3423    
3424         /* get the row first */ 
3425    
3426         Row * row = GetRowNearY(y);
3427    
3428         cursor.par = row->par;
3429    
3430         int column = GetColumnNearX(row, x);
3431         cursor.pos = row->pos + column;
3432         cursor.x = x;
3433         cursor.y = y + row->baseline;
3434    
3435         cursor.row = row;
3436     
3437         if (cursor.pos && 
3438             (cursor.pos == cursor.par->Last()
3439              || cursor.par->IsSeparator(cursor.pos)
3440              || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
3441                  && !cursor.par->IsSeparator(cursor.pos))
3442              || (cursor.par->table && cursor.par->IsNewline(cursor.pos))
3443                     )) {
3444                 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
3445                 real_current_font = GetFont(cursor.par, cursor.pos - 1);
3446         } else {
3447                 current_font = cursor.par->GetFontSettings(cursor.pos);
3448                 real_current_font = GetFont(cursor.par, cursor.pos);
3449         }
3450         DeleteEmptyParagraphMechanism(old_cursor);
3451 }
3452
3453 void LyXText::SetCursorFromCoordinates(LyXCursor & cur, int x, long y) const
3454 {
3455         /* get the row first */ 
3456    
3457         Row * row = GetRowNearY(y);
3458         int column = GetColumnNearX(row, x);
3459    
3460         cur.par = row->par;
3461         cur.pos = row->pos + column;
3462         cur.x = x;
3463         cur.y = y + row->baseline;
3464         cur.row = row;
3465 }
3466
3467
3468 void LyXText::CursorLeft() const
3469 {
3470         CursorLeftIntern();
3471         if (cursor.par->table) {
3472                 int cell = NumberOfCell(cursor.par, cursor.pos);
3473                 if (cursor.par->table->IsContRow(cell) &&
3474                     cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell)) < 0) {
3475                         CursorUp();
3476                 }
3477         }
3478 }
3479
3480
3481 void LyXText::CursorLeftIntern() const
3482 {
3483         if (cursor.pos > 0) {
3484                 SetCursor(cursor.par, cursor.pos - 1);
3485         }
3486         else if (cursor.par->Previous()) { // steps into the above paragraph.
3487                 SetCursor(cursor.par->Previous(), cursor.par->Previous()->Last());
3488         }
3489 }
3490
3491
3492 void LyXText::CursorRight() const
3493 {
3494         CursorRightIntern();
3495         if (cursor.par->table) {
3496                 int cell = NumberOfCell(cursor.par, cursor.pos);
3497                 if (cursor.par->table->IsContRow(cell) &&
3498                     cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3499                         CursorUp();
3500                 }
3501         }
3502 }
3503
3504
3505 void LyXText::CursorRightIntern() const
3506 {
3507         if (cursor.pos < cursor.par->Last()) {
3508                 SetCursor(cursor.par, cursor.pos + 1);
3509         }
3510         else if (cursor.par->Next()) {
3511                 SetCursor(cursor.par->Next(), 0);
3512         }
3513 }
3514
3515
3516 void LyXText::CursorUp() const
3517 {
3518         SetCursorFromCoordinates(cursor.x_fix, 
3519                                  cursor.y - cursor.row->baseline - 1);
3520         if (cursor.par->table) {
3521                 int cell = NumberOfCell(cursor.par, cursor.pos);
3522                 if (cursor.par->table->IsContRow(cell) &&
3523                     cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3524                         CursorUp();
3525                 }
3526         }
3527 }
3528
3529
3530 void LyXText::CursorDown() const
3531 {
3532         if (cursor.par->table &&
3533             cursor.par->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par, cursor.pos)) &&
3534             !cursor.par->next)
3535                 return;
3536         SetCursorFromCoordinates(cursor.x_fix, 
3537                                  cursor.y - cursor.row->baseline
3538                                  + cursor.row->height + 1);
3539         if (cursor.par->table) {
3540                 int cell = NumberOfCell(cursor.par, cursor.pos);
3541                 int cell_above = cursor.par->table->GetCellAbove(cell);
3542                 while(cursor.par->table &&
3543                       cursor.par->table->IsContRow(cell) &&
3544                       (cursor.par->table->CellHasContRow(cell_above)<0)) {
3545                     SetCursorFromCoordinates(cursor.x_fix, 
3546                                              cursor.y - cursor.row->baseline
3547                                              + cursor.row->height + 1);
3548                     if (cursor.par->table) {
3549                         cell = NumberOfCell(cursor.par, cursor.pos);
3550                         cell_above = cursor.par->table->GetCellAbove(cell);
3551                     }
3552                 }
3553         }
3554 }
3555
3556
3557 void LyXText::CursorUpParagraph() const
3558 {
3559         if (cursor.pos > 0) {
3560                 SetCursor(cursor.par, 0);
3561         }
3562         else if (cursor.par->Previous()) {
3563                 SetCursor(cursor.par->Previous(), 0);
3564         }
3565 }
3566
3567
3568 void LyXText::CursorDownParagraph() const
3569 {
3570         if (cursor.par->Next()) {
3571                 SetCursor(cursor.par->Next(), 0);
3572         } else {
3573                 SetCursor(cursor.par, cursor.par->Last());
3574         }
3575 }
3576
3577
3578
3579 void LyXText::DeleteEmptyParagraphMechanism(LyXCursor const & old_cursor) const
3580 {
3581         // Would be wrong to delete anything if we have a selection.
3582         if (selection) return;
3583
3584         // We allow all kinds of "mumbo-jumbo" when freespacing.
3585         if (textclasslist.Style(buffer->params.textclass,
3586                                 old_cursor.par->GetLayout()).free_spacing)
3587                 return;
3588
3589         bool deleted = false;
3590         
3591 #ifdef FIX_DOUBLE_SPACE
3592         /* Ok I'll put some comments here about what is missing.
3593            I have fixed BackSpace (and thus Delete) to not delete
3594            double-spaces automagically. I have also changed Cut,
3595            Copy and Paste to hopefully do some sensible things.
3596            There are still some small problems that can lead to
3597            double spaces stored in the document file or space at
3598            the beginning of paragraphs. This happens if you have
3599            the cursor betwenn to spaces and then save. Or if you
3600            cut and paste and the selection have a space at the
3601            beginning and then save right after the paste. I am
3602            sure none of these are very hard to fix, but I will
3603            put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3604            that I can get some feedback. (Lgb)
3605         */
3606
3607         // If old_cursor.pos == 0 and old_cursor.pos(1) == LineSeparator
3608         // delete the LineSeparator.
3609         // MISSING
3610
3611         // If old_cursor.pos == 1 and old_cursor.pos(0) == LineSeparator
3612         // delete the LineSeparator.
3613         // MISSING
3614
3615         // If the pos around the old_cursor were spaces, delete one of them.
3616         if (old_cursor.par != cursor.par || old_cursor.pos != cursor.pos) { // Only if the cursor has really moved
3617                 
3618                 if (old_cursor.pos > 0
3619                     && old_cursor.pos < old_cursor.par->Last()
3620                     && old_cursor.par->IsLineSeparator(old_cursor.pos)
3621                     && old_cursor.par->IsLineSeparator(old_cursor.pos - 1)) {
3622                         old_cursor.par->Erase(old_cursor.pos - 1);
3623                         RedoParagraphs(old_cursor, old_cursor.par->Next());
3624                         // correct cursor
3625                         if (old_cursor.par == cursor.par &&
3626                             cursor.pos > old_cursor.pos) {
3627                                 SetCursorIntern(cursor.par, cursor.pos - 1);
3628                         } else
3629                                 SetCursorIntern(cursor.par, cursor.pos);
3630                         return;
3631                 }
3632         }
3633 #endif
3634 #if 1
3635         // Do not delete empty paragraphs with keepempty set.
3636         if ((textclasslist.Style(buffer->params.textclass,
3637                                  old_cursor.par->GetLayout())).keepempty)
3638                 return;
3639
3640         LyXCursor tmpcursor;
3641
3642         if (old_cursor.par != cursor.par) {
3643                 if ( (old_cursor.par->Last() == 0
3644                       || (old_cursor.par->Last() == 1
3645                           && old_cursor.par->IsLineSeparator(0)))
3646                      && old_cursor.par->FirstPhysicalPar()
3647                      == old_cursor.par->LastPhysicalPar()) {
3648                         // ok, we will delete anything
3649                         
3650                         // make sure that you do not delete any environments
3651                         if ((old_cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3652                              !(old_cursor.row->previous 
3653                                && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3654                              && !(old_cursor.row->next 
3655                                   && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3656                             || (old_cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3657                                 && ((old_cursor.row->previous 
3658                                      && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3659                                     || (old_cursor.row->next
3660                                         && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3661                                     )) {
3662                                 status = LyXText::NEED_MORE_REFRESH;
3663                                 deleted = true;
3664                                 
3665                                 if (old_cursor.row->previous) {
3666                                         refresh_row = old_cursor.row->previous;
3667                                         refresh_y = old_cursor.y - old_cursor.row->baseline - refresh_row->height;
3668                                         tmpcursor = cursor;
3669                                         cursor = old_cursor; // that undo can restore the right cursor position
3670                                         LyXParagraph * endpar = old_cursor.par->next;
3671                                         if (endpar && endpar->GetDepth()) {
3672                                                 while (endpar && endpar->GetDepth()) {
3673                                                         endpar = endpar->LastPhysicalPar()->Next();
3674                                                 }
3675                                         }
3676                                         SetUndo(Undo::DELETE,
3677                                                 old_cursor.par->previous,
3678                                                 endpar);
3679                                         cursor = tmpcursor;
3680
3681                                         // delete old row
3682                                         RemoveRow(old_cursor.row);
3683                                         if (buffer->paragraph == old_cursor.par) {
3684                                                 buffer->paragraph = buffer->paragraph->next;
3685                                         }
3686                                         // delete old par
3687                                         delete old_cursor.par;
3688                                         
3689                                         /* Breakagain the next par. Needed
3690                                          * because of the parindent that
3691                                          * can occur or dissappear. The
3692                                          * next row can change its height,
3693                                          * if there is another layout before */
3694                                         if (refresh_row->next) {
3695                                                 BreakAgain(refresh_row->next);
3696                                                 UpdateCounters(refresh_row);
3697                                         }
3698                                         SetHeightOfRow(refresh_row);
3699                                 } else {
3700                                         refresh_row = old_cursor.row->next;
3701                                         refresh_y = old_cursor.y - old_cursor.row->baseline;
3702                                         
3703                                         tmpcursor = cursor;
3704                                         cursor = old_cursor; // that undo can restore the right cursor position
3705                                         LyXParagraph *endpar = old_cursor.par->next;
3706                                         if (endpar && endpar->GetDepth()) {
3707                                                 while (endpar && endpar->GetDepth()) {
3708                                                         endpar = endpar->LastPhysicalPar()->Next();
3709                                                 }
3710                                         }
3711                                         SetUndo(Undo::DELETE,
3712                                                 old_cursor.par->previous,
3713                                                 endpar);
3714                                         cursor = tmpcursor;
3715
3716                                         // delete old row
3717                                         RemoveRow(old_cursor.row);
3718                                         // delete old par
3719                                         if (buffer->paragraph == old_cursor.par) {
3720                                                 buffer->paragraph = buffer->paragraph->next;
3721                                         }
3722                                         delete old_cursor.par;
3723                                         
3724                                         /* Breakagain the next par. Needed
3725                                            because of the parindent that can
3726                                            occur or dissappear.
3727                                            The next row can change its height,
3728                                            if there is another layout before
3729                                         */ 
3730                                         if (refresh_row) {
3731                                                 BreakAgain(refresh_row);
3732                                                 UpdateCounters(refresh_row->previous);
3733                                         }
3734                                 }
3735                                 
3736                                 // correct cursor y
3737 #if 1
3738                                 SetCursorIntern(cursor.par, cursor.pos);
3739 #else
3740                                 SetCursor(cursor.par, cursor.pos);
3741 #endif                  
3742                                 /* if (cursor.y > old_cursor.y)
3743                                    cursor.y -= old_cursor.row->height; */ 
3744          
3745                                 if (sel_cursor.par  == old_cursor.par
3746                                     && sel_cursor.pos == sel_cursor.pos) {
3747                                         // correct selection
3748                                         sel_cursor = cursor;
3749                                 }
3750                         }
3751                 }
3752                 if (!deleted) {
3753                         if (old_cursor.par->ClearParagraph()) {
3754                                 RedoParagraphs(old_cursor, old_cursor.par->Next());
3755                                 // correct cursor y
3756 #if 1
3757                                 SetCursorIntern(cursor.par, cursor.pos);
3758 #else
3759                                 SetCursor(cursor.par, cursor.pos);
3760 #endif
3761                                 sel_cursor = cursor;
3762                         }
3763                 }
3764         }
3765 #endif
3766 }
3767
3768
3769 LyXParagraph * LyXText::GetParFromID(int id)
3770 {
3771         LyXParagraph * result = FirstParagraph();
3772         while (result && result->id() != id)
3773                 result = result->next;
3774         return result;
3775 }
3776
3777
3778 // undo functions
3779 bool LyXText::TextUndo()
3780 {
3781         // returns false if no undo possible
3782         Undo * undo = buffer->undostack.pop();
3783         if (undo) {
3784                 FinishUndo();
3785                 if (!undo_frozen)
3786                         buffer->redostack
3787                                 .push(CreateUndo(undo->kind, 
3788                                                  GetParFromID(undo->number_of_before_par),
3789                                                  GetParFromID(undo->number_of_behind_par)));
3790         }
3791         return TextHandleUndo(undo);
3792 }
3793
3794
3795 bool LyXText::TextRedo()
3796 {
3797         // returns false if no redo possible
3798         Undo * undo = buffer->redostack.pop();
3799         if (undo) {
3800                 FinishUndo();
3801                 if (!undo_frozen)
3802                         buffer->undostack
3803                                 .push(CreateUndo(undo->kind, 
3804                                                  GetParFromID(undo->number_of_before_par),
3805                                                  GetParFromID(undo->number_of_behind_par)));
3806         }
3807         return TextHandleUndo(undo);
3808 }
3809
3810
3811 bool LyXText::TextHandleUndo(Undo * undo)
3812 {
3813         // returns false if no undo possible
3814         bool result = false;
3815         if (undo) {
3816                 LyXParagraph * before =
3817                         GetParFromID(undo->number_of_before_par); 
3818                 LyXParagraph * behind =
3819                         GetParFromID(undo->number_of_behind_par); 
3820                 LyXParagraph * tmppar;
3821                 LyXParagraph * tmppar2;
3822                 LyXParagraph * endpar;
3823                 LyXParagraph * tmppar5;
3824     
3825                 // if there's no before take the beginning
3826                 // of the document for redoing
3827                 if (!before)
3828                         SetCursorIntern(FirstParagraph(), 0);
3829
3830                 // replace the paragraphs with the undo informations
3831
3832                 LyXParagraph * tmppar3 = undo->par;
3833                 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3834                 LyXParagraph * tmppar4 = tmppar3;
3835                 if (tmppar4){
3836                         while (tmppar4->next)
3837                                 tmppar4 = tmppar4->next;
3838                 } // get last undo par
3839     
3840                 // now remove the old text if there is any
3841                 if (before != behind || (!behind && !before)){
3842                         if (before)
3843                                 tmppar5 = before->next;
3844                         else
3845                                 tmppar5 = buffer->paragraph;
3846                         tmppar2 = tmppar3;
3847                         while (tmppar5 && tmppar5 != behind){
3848                                 tmppar = tmppar5;
3849                                 tmppar5 = tmppar5->next;
3850                                 // a memory optimization for edit: Only layout information
3851                                 // is stored in the undo. So restore the text informations.
3852                                 if (undo->kind == Undo::EDIT) {
3853                                         tmppar2->setContentsFromPar(tmppar);
3854                                         tmppar->clearContents();
3855                                         //tmppar2->text = tmppar->text;
3856                                         //tmppar->text.clear();
3857                                         tmppar2 = tmppar2->next;
3858                                 }
3859                                 if ( currentrow && currentrow->par == tmppar )
3860                                         currentrow = currentrow -> previous;
3861                                 // Commenting out this might remove the error
3862                                 // reported by Purify, but it might also
3863                                 // introduce a memory leak. We need to
3864                                 // check this (Lgb)
3865                                 //delete tmppar;
3866                         }
3867                 }
3868     
3869                 // put the new stuff in the list if there is one
3870                 if (tmppar3){
3871                         if (before)
3872                                 before->next = tmppar3;
3873                         else
3874                                 buffer->paragraph = tmppar3;
3875                         tmppar3->previous = before;
3876                 }
3877                 else {
3878                         if (!before)
3879                                 buffer->paragraph = behind;
3880                 }
3881                 if (tmppar4) {
3882                         tmppar4->next = behind;
3883                         if (behind)
3884                                 behind->previous = tmppar4;
3885                 }
3886     
3887     
3888                 // Set the cursor for redoing
3889                 if (before) {
3890                         SetCursorIntern(before->FirstSelfrowPar(), 0);
3891                         // check wether before points to a closed float and open it if necessary
3892                         if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3893                             && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3894                                 tmppar4 = before;
3895                                 while (tmppar4->previous && 
3896                                        tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3897                                         tmppar4 = tmppar4->previous;
3898                                 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3899                                         tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3900                                         tmppar4 = tmppar4->next;
3901                                 }
3902                         }
3903                 }
3904     
3905                 // open a cosed footnote at the end if necessary
3906                 if (behind && behind->previous && 
3907                     behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3908                     behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3909                         while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3910                                 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3911                                 behind = behind->next;
3912                         }
3913                 }
3914     
3915                 // calculate the endpar for redoing the paragraphs.
3916                 if (behind){
3917                         if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3918                                 endpar = behind->LastPhysicalPar()->Next();
3919                         else
3920                                 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3921                 }
3922                 else
3923                         endpar = behind;
3924     
3925                 tmppar = GetParFromID(undo->number_of_cursor_par);
3926                 RedoParagraphs(cursor, endpar); 
3927                 if (tmppar){
3928                         SetCursorIntern(tmppar, undo->cursor_pos);
3929                         UpdateCounters(cursor.row);
3930                 }
3931                 result = true;
3932                 delete undo;
3933         }
3934         FinishUndo();
3935         return result;
3936 }
3937
3938
3939 void LyXText::FinishUndo()
3940 {
3941         // makes sure the next operation will be stored
3942         undo_finished = True;
3943 }
3944
3945
3946 void LyXText::FreezeUndo()
3947 {
3948         // this is dangerous and for internal use only
3949         undo_frozen = True;
3950 }
3951
3952
3953 void LyXText::UnFreezeUndo()
3954 {
3955         // this is dangerous and for internal use only
3956         undo_frozen = false;
3957 }
3958
3959
3960 void LyXText::SetUndo(Undo::undo_kind kind, LyXParagraph const * before,
3961                       LyXParagraph const * behind) const
3962 {
3963         if (!undo_frozen)
3964                 buffer->undostack.push(CreateUndo(kind, before, behind));
3965         buffer->redostack.clear();
3966 }
3967
3968
3969 void LyXText::SetRedo(Undo::undo_kind kind, LyXParagraph const * before,
3970                       LyXParagraph const * behind)
3971 {
3972         buffer->redostack.push(CreateUndo(kind, before, behind));
3973 }
3974
3975
3976 Undo * LyXText::CreateUndo(Undo::undo_kind kind, LyXParagraph const * before,
3977                           LyXParagraph const * behind) const
3978 {
3979         int before_number = -1;
3980         int behind_number = -1;
3981         if (before)
3982                 before_number = before->id();
3983         if (behind)
3984                 behind_number = behind->id();
3985         // Undo::EDIT  and Undo::FINISH are
3986         // always finished. (no overlapping there)
3987         // overlapping only with insert and delete inside one paragraph: 
3988         // Nobody wants all removed  character
3989         // appear one by one when undoing. 
3990         // EDIT is special since only layout information, not the
3991         // contents of a paragaph are stored.
3992         if (!undo_finished && kind != Undo::EDIT && 
3993             kind != Undo::FINISH){
3994                 // check wether storing is needed
3995                 if (!buffer->undostack.empty() && 
3996                     buffer->undostack.top()->kind == kind &&
3997                     buffer->undostack.top()->number_of_before_par ==  before_number &&
3998                     buffer->undostack.top()->number_of_behind_par ==  behind_number ){
3999                         // no undo needed
4000                         return 0;
4001                 }
4002         }
4003         // create a new Undo
4004         LyXParagraph * undopar;
4005         LyXParagraph * tmppar;
4006         LyXParagraph * tmppar2;
4007
4008         LyXParagraph * start = 0;
4009         LyXParagraph * end = 0;
4010   
4011         if (before)
4012                 start = before->next;
4013         else
4014                 start = FirstParagraph();
4015         if (behind)
4016                 end = behind->previous;
4017         else {
4018                 end = FirstParagraph();
4019                 while (end->next)
4020                         end = end->next;
4021         }
4022
4023         if (start && end
4024             && start != end->next
4025             && (before != behind || (!before && !behind))) {
4026                 tmppar = start;
4027                 tmppar2 = tmppar->Clone();
4028                 tmppar2->id(tmppar->id());
4029
4030                 // a memory optimization: Just store the layout information
4031                 // when only edit
4032                 if (kind == Undo::EDIT){
4033                         //tmppar2->text.clear();
4034                         tmppar2->clearContents();
4035                 }
4036
4037                 undopar = tmppar2;
4038   
4039                 while (tmppar != end && tmppar->next) {
4040                         tmppar = tmppar->next;
4041                         tmppar2->next = tmppar->Clone();
4042                         tmppar2->next->id(tmppar->id());
4043                         // a memory optimization: Just store the layout
4044                         // information when only edit
4045                         if (kind == Undo::EDIT){
4046                                 //tmppar2->next->text.clear();
4047                                 tmppar2->clearContents();
4048                         }
4049                         tmppar2->next->previous = tmppar2;
4050                         tmppar2 = tmppar2->next;
4051                 }
4052                 tmppar2->next = 0;
4053         } else
4054                 undopar = 0; // nothing to replace (undo of delete maybe)
4055   
4056         int cursor_par = cursor.par->ParFromPos(cursor.pos)->id();
4057         int cursor_pos =  cursor.par->PositionInParFromPos(cursor.pos);
4058
4059         Undo * undo = new Undo(kind, 
4060                                before_number, behind_number,  
4061                                cursor_par, cursor_pos, 
4062                                undopar);
4063   
4064         undo_finished = false;
4065         return undo;
4066 }
4067
4068
4069 void LyXText::SetCursorParUndo()
4070 {
4071         SetUndo(Undo::FINISH, 
4072                 cursor.par->ParFromPos(cursor.pos)->previous, 
4073                 cursor.par->ParFromPos(cursor.pos)->next); 
4074 }
4075
4076
4077 void LyXText::RemoveTableRow(LyXCursor * cur) const
4078 {
4079         int cell = -1;
4080         int cell_org = 0;
4081         int ocell = 0;
4082     
4083         // move to the previous row
4084         int cell_act = NumberOfCell(cur->par, cur->pos);
4085         if (cell < 0)
4086                 cell = cell_act;
4087         while (cur->pos && !cur->par->IsNewline(cur->pos - 1))
4088                 cur->pos--;
4089         while (cur->pos && 
4090                !cur->par->table->IsFirstCell(cell_act)) {
4091                 cur->pos--;
4092                 while (cur->pos && !cur->par->IsNewline(cur->pos - 1))
4093                         cur->pos--;
4094                 --cell;
4095                 --cell_act;
4096         }
4097         // now we have to pay attention if the actual table is the
4098         //   main row of TableContRows and if yes to delete all of them
4099         if (!cell_org)
4100                 cell_org = cell;
4101         do {
4102                 ocell = cell;
4103                 // delete up to the next row
4104                 while (cur->pos < cur->par->Last() && 
4105                        (cell_act == ocell
4106                         || !cur->par->table->IsFirstCell(cell_act))) {
4107                         while (cur->pos < cur->par->Last() &&
4108                                !cur->par->IsNewline(cur->pos))
4109                                 cur->par->Erase(cur->pos);
4110                         ++cell;
4111                         ++cell_act;
4112                         if (cur->pos < cur->par->Last())
4113                                 cur->par->Erase(cur->pos);
4114                 }
4115                 if (cur->pos && cur->pos == cur->par->Last()) {
4116                         cur->pos--;
4117                         cur->par->Erase(cur->pos); // no newline at very end!
4118                 }
4119         } while (((cell + 1) < cur->par->table->GetNumberOfCells()) &&
4120                  !cur->par->table->IsContRow(cell_org) &&
4121                  cur->par->table->IsContRow(cell));
4122         cur->par->table->DeleteRow(cell_org);
4123         return;
4124 }
4125
4126
4127 bool LyXText::IsEmptyTableCell() const
4128 {
4129         LyXParagraph::size_type pos = cursor.pos - 1;
4130         while (pos >= 0 && pos < cursor.par->Last()
4131                && !cursor.par->IsNewline(pos))
4132                 --pos;
4133         return cursor.par->IsNewline(pos + 1);
4134 }
4135
4136
4137 void LyXText::toggleAppendix(){
4138         LyXParagraph * par = cursor.par->FirstPhysicalPar();
4139         bool start = !par->start_of_appendix;
4140
4141         // ensure that we have only one start_of_appendix in this document
4142         LyXParagraph * tmp = FirstParagraph();
4143         for (; tmp; tmp = tmp->next)
4144                 tmp->start_of_appendix = 0;
4145         par->start_of_appendix = start;
4146
4147         // we can set the refreshing parameters now
4148         status = LyXText::NEED_MORE_REFRESH;
4149         refresh_y = 0;
4150         refresh_row = 0; // not needed for full update
4151         UpdateCounters(0);
4152         SetCursor(cursor.par, cursor.pos);
4153 }
4154