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