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