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