]> git.lyx.org Git - lyx.git/blob - src/text2.C
apply the ostream changes to mathed, some other small related things
[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
1352 char const * alphaCounter(int n) {
1353         static char result[2];
1354         result[1] = 0;
1355         if (n == 0)
1356                 return "";
1357         else {
1358                 result[0] = 'A' + n;
1359                 if (n > 'Z')
1360                         return "??";
1361         }
1362         return result;
1363 }
1364
1365
1366 // set the counter of a paragraph. This includes the labels
1367 void LyXText::SetCounter(LyXParagraph * par) const
1368 {
1369         // this is only relevant for the beginning of paragraph
1370         par = par->FirstPhysicalPar();
1371
1372         LyXLayout const & layout = textclasslist.Style(parameters->textclass, 
1373                                                        par->GetLayout());
1374
1375         LyXTextClass const & textclass =
1376                 textclasslist.TextClass(parameters->textclass);
1377
1378         /* copy the prev-counters to this one, unless this is the start of a 
1379            footnote or of a bibliography or the very first paragraph */
1380         if (par->Previous()
1381             && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE 
1382                     && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1383                     && par->footnotekind == LyXParagraph::FOOTNOTE)
1384             && !(textclasslist.Style(parameters->textclass,
1385                                 par->Previous()->GetLayout()
1386                                 ).labeltype != LABEL_BIBLIO
1387                  && layout.labeltype == LABEL_BIBLIO)) {
1388                 for (int i = 0; i < 10; ++i) {
1389                         par->setCounter(i, par->Previous()->GetFirstCounter(i));
1390                 }
1391                 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1392                 if (!par->appendix && par->start_of_appendix){
1393                   par->appendix = true;
1394                   for (int i = 0; i < 10; ++i) {
1395                     par->setCounter(i, 0);
1396                   }  
1397                 }
1398                 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1399                 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1400         }
1401         else {
1402                 for (int i = 0; i < 10; ++i) {
1403                         par->setCounter(i, 0);
1404                 }  
1405                 par->appendix = par->start_of_appendix;
1406                 par->enumdepth = 0;
1407                 par->itemdepth = 0;
1408         }
1409
1410         // if this is an open marginnote and this is the first
1411         // entry in the marginnote and the enclosing
1412         // environment is an enum/item then correct for the
1413         // LaTeX behaviour (ARRae)
1414         if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1415            && par->footnotekind == LyXParagraph::MARGIN
1416            && par->Previous()
1417            && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1418            && (par->PreviousBeforeFootnote()
1419                && textclasslist.Style(parameters->textclass,
1420                                  par->PreviousBeforeFootnote()->GetLayout()
1421                                  ).labeltype >= LABEL_COUNTER_ENUMI)) {
1422                 // Any itemize or enumerate environment in a marginnote
1423                 // that is embedded in an itemize or enumerate
1424                 // paragraph is seen by LaTeX as being at a deeper
1425                 // level within that enclosing itemization/enumeration
1426                 // even if there is a "standard" layout at the start of
1427                 // the marginnote.
1428                 par->enumdepth++;
1429                 par->itemdepth++;
1430         }
1431
1432         /* Maybe we have to increment the enumeration depth.
1433          * BUT, enumeration in a footnote is considered in isolation from its
1434          *      surrounding paragraph so don't increment if this is the
1435          *      first line of the footnote
1436          * AND, bibliographies can't have their depth changed ie. they
1437          *      are always of depth 0
1438          */
1439         if (par->Previous()
1440             && par->Previous()->GetDepth() < par->GetDepth()
1441             && textclasslist.Style(parameters->textclass,
1442                               par->Previous()->GetLayout()
1443                              ).labeltype == LABEL_COUNTER_ENUMI
1444             && par->enumdepth < 3
1445             && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE 
1446                     && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1447                     && par->footnotekind == LyXParagraph::FOOTNOTE)
1448             && layout.labeltype != LABEL_BIBLIO) {
1449                 par->enumdepth++;
1450         }
1451
1452         /* Maybe we have to decrement the enumeration depth, see note above */
1453         if (par->Previous()
1454             && par->Previous()->GetDepth() > par->GetDepth()
1455             && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1456                     && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1457                     && par->footnotekind == LyXParagraph::FOOTNOTE)
1458             && layout.labeltype != LABEL_BIBLIO) {
1459                 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1460                 par->setCounter(6 + par->enumdepth,
1461                         par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1462                 /* reset the counters.
1463                  * A depth change is like a breaking layout
1464                  */
1465                 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1466                         par->setCounter(i, 0);
1467         }
1468    
1469         if (!par->labelstring.empty()) {
1470                 par->labelstring.clear();
1471         }
1472    
1473         if (layout.margintype == MARGIN_MANUAL) {
1474                 if (par->labelwidthstring.empty()) {
1475                         par->SetLabelWidthString(layout.labelstring());
1476                 }
1477         } else {
1478                 par->SetLabelWidthString(string());
1479         }
1480    
1481         /* is it a layout that has an automatic label ? */ 
1482         if (layout.labeltype >=  LABEL_FIRST_COUNTER) {
1483       
1484                 int i = layout.labeltype - LABEL_FIRST_COUNTER;
1485                 if (i >= 0 && i<= parameters->secnumdepth) {
1486                         par->incCounter(i);     // increment the counter  
1487          
1488                         char * s = new char[50];
1489
1490                         // Is there a label? Useful for Chapter layout
1491                         if (!par->appendix){
1492                                 if (!layout.labelstring().empty())
1493                                         par->labelstring = layout.labelstring();
1494                                 else
1495                                         par->labelstring.clear();
1496                         } else {
1497                                 if (!layout.labelstring_appendix().empty())
1498                                         par->labelstring = layout.labelstring_appendix();
1499                                 else
1500                                         par->labelstring.clear();
1501                         }
1502  
1503                         if (!par->appendix){
1504                                 switch (2 * LABEL_FIRST_COUNTER -
1505                                         textclass.maxcounter() + i) {
1506                                 case LABEL_COUNTER_CHAPTER:
1507                                         sprintf(s, "%d",
1508                                                 par->getCounter(i));
1509                                         break;
1510                                 case LABEL_COUNTER_SECTION:
1511                                         sprintf(s, "%d.%d",
1512                                                 par->getCounter(i - 1),
1513                                                 par->getCounter(i));
1514                                         break;
1515                                 case LABEL_COUNTER_SUBSECTION:
1516                                         sprintf(s, "%d.%d.%d",
1517                                                 par->getCounter(i-2),
1518                                                 par->getCounter(i-1),
1519                                                 par->getCounter(i));
1520                                         break;
1521                                 case LABEL_COUNTER_SUBSUBSECTION:
1522                                         sprintf(s, "%d.%d.%d.%d",
1523                                                 par->getCounter(i-3),
1524                                                 par->getCounter(i-2),
1525                                                 par->getCounter(i-1),
1526                                                 par->getCounter(i));
1527                                         break;
1528                                 case LABEL_COUNTER_PARAGRAPH:
1529                                         sprintf(s, "%d.%d.%d.%d.%d",
1530                                                 par->getCounter(i-4),
1531                                                 par->getCounter(i-3),
1532                                                 par->getCounter(i-2),
1533                                                 par->getCounter(i-1),
1534                                                 par->getCounter(i));
1535                                         break;
1536                                 case LABEL_COUNTER_SUBPARAGRAPH:
1537                                         sprintf(s, "%d.%d.%d.%d.%d.%d",
1538                                                 par->getCounter(i-5),
1539                                                 par->getCounter(i-4),
1540                                                 par->getCounter(i-3),
1541                                                 par->getCounter(i-2),
1542                                                 par->getCounter(i-1),
1543                                                 par->getCounter(i));
1544                                         break;
1545                                 default:
1546                                         sprintf(s, "%d.", par->getCounter(i));
1547                                         break;
1548                                 }
1549                         } else {
1550                                 switch (2 * LABEL_FIRST_COUNTER - textclass.maxcounter() + i) {
1551                                 case LABEL_COUNTER_CHAPTER:
1552                                         sprintf(s, "%s",
1553                                                 alphaCounter(par->getCounter(i)));
1554                                         break;
1555                                 case LABEL_COUNTER_SECTION:
1556                                         sprintf(s, "%s.%d",
1557                                                 alphaCounter(par->getCounter(i - 1)),
1558                                                 par->getCounter(i));
1559                                         break;
1560                                 case LABEL_COUNTER_SUBSECTION:
1561                                         sprintf(s, "%s.%d.%d",
1562                                                 alphaCounter(par->getCounter(i-2)),
1563                                                 par->getCounter(i-1),
1564                                                 par->getCounter(i));
1565                                         break;
1566                                 case LABEL_COUNTER_SUBSUBSECTION:
1567                                         sprintf(s, "%s.%d.%d.%d",
1568                                                 alphaCounter(par->getCounter(i-3)),
1569                                                 par->getCounter(i-2),
1570                                                 par->getCounter(i-1),
1571                                                 par->getCounter(i));
1572                                         break;
1573                                 case LABEL_COUNTER_PARAGRAPH:
1574                                         sprintf(s, "%s.%d.%d.%d.%d",
1575                                                 alphaCounter(par->getCounter(i-4)),
1576                                                 par->getCounter(i-3),
1577                                                 par->getCounter(i-2),
1578                                                 par->getCounter(i-1),
1579                                                 par->getCounter(i));
1580                                         break;
1581                                 case LABEL_COUNTER_SUBPARAGRAPH:
1582                                         sprintf(s, "%s.%d.%d.%d.%d.%d",
1583                                                 alphaCounter(par->getCounter(i-5)),
1584                                                 par->getCounter(i-4),
1585                                                 par->getCounter(i-3),
1586                                                 par->getCounter(i-2),
1587                                                 par->getCounter(i-1),
1588                                                 par->getCounter(i));
1589                                         break;
1590                                 default:
1591                                         sprintf(s, "%c.", par->getCounter(i));
1592                                         break;
1593                                 }
1594                         }
1595          
1596                         par->labelstring += s;
1597                         delete[] s;
1598          
1599                         for (i++; i < 10; ++i) {
1600                                 // reset the following counters
1601                                 par->setCounter(i, 0);
1602                         }
1603                 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1604                         for (i++; i < 10; ++i) {
1605                                 // reset the following counters
1606                                 par->setCounter(i, 0);
1607                         }
1608                 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1609                         par->incCounter(i + par->enumdepth);
1610                         char * s = new char[25];
1611                         int number = par->getCounter(i + par->enumdepth);
1612
1613                         static const char *roman[20] = {
1614                                 "i",   "ii",  "iii", "iv", "v",
1615                                 "vi",  "vii", "viii", "ix", "x",
1616                                 "xi",  "xii", "xiii", "xiv", "xv",
1617                                 "xvi", "xvii", "xviii", "xix", "xx"
1618                         };
1619                         static const char hebrew[22] = {
1620                                 'à', 'á', 'â', 'ã', 'ä', 'Ã¥', 'æ', 'ç', 'è',
1621                                 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö', 
1622                                 '÷', 'ø', 'ù', 'ú'
1623                         };
1624
1625                         switch (par->enumdepth) {
1626                         case 1:
1627                                 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1628                                         sprintf(s, "(%c)", ((number-1) % 26) + 'a');
1629                                 else
1630                                         sprintf(s, "(%c)", hebrew[(number-1) % 22]);
1631                                 break;
1632                         case 2:
1633                                 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1634                                         sprintf(s, "%s.", roman[(number-1) % 20]);
1635                                 else
1636                                         sprintf(s, ".%s", roman[(number-1) % 20]);
1637                                 break;
1638                         case 3:
1639                                 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1640                                         sprintf(s, "%c.", ((number-1) % 26) + 'A');
1641                                 else
1642                                         sprintf(s, ".%c", ((number-1) % 26) + 'A');
1643                                 break;
1644                         default:
1645                                 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1646                                         sprintf(s, "%d.", number);
1647                                 else
1648                                         sprintf(s, ".%d", number);      
1649                                 break;
1650                         }
1651                         par->labelstring = s;
1652                         delete[] s;
1653
1654                         for (i += par->enumdepth + 1; i < 10; ++i)
1655                                 par->setCounter(i, 0);  /* reset the following counters  */
1656          
1657                 } 
1658         } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1659                 int i = LABEL_COUNTER_ENUMI - LABEL_FIRST_COUNTER + par->enumdepth;
1660                 par->incCounter(i);
1661                 int number = par->getCounter(i);
1662                 if (!par->bibkey)
1663                         par->bibkey = new InsetBibKey();
1664                 par->bibkey->setCounter(number);
1665                 par->labelstring = layout.labelstring();
1666                 
1667                 // In biblio should't be following counters but...
1668         } else {
1669                 string s = layout.labelstring();
1670                 
1671                 // the caption hack:
1672       
1673                 if (layout.labeltype == LABEL_SENSITIVE) {
1674                         if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1675                             && (par->footnotekind == LyXParagraph::FIG
1676                                 || par->footnotekind == LyXParagraph::WIDE_FIG))
1677                                 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1678                                         s = "Figure:";
1679                                 else
1680                                         s = ":øåéà";
1681                         else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1682                                  && (par->footnotekind == LyXParagraph::TAB
1683                                      || par->footnotekind == LyXParagraph::WIDE_TAB))
1684                                 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1685                                         s = "Table:";
1686                                 else
1687                                         s = ":äìáè";
1688                         else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1689                                  && par->footnotekind == LyXParagraph::ALGORITHM)
1690                                 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1691                                         s = "Algorithm:";
1692                                 else
1693                                         s = ":íúéøåâìà";
1694                         else {
1695                                 /* par->SetLayout(0); 
1696                                    s = layout->labelstring;  */
1697                                 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1698                                         s = "Senseless: ";
1699                                 else
1700                                         s = " :úåòîùî Ã¸Ã±Ã§";
1701            
1702                         }
1703                 }
1704                 par->labelstring = s;
1705                 
1706                 /* reset the enumeration counter. They are always resetted
1707                  * when there is any other layout between */ 
1708                 for (int i = 6 + par->enumdepth; i < 10; ++i)
1709                         par->setCounter(i, 0);
1710         }
1711 }
1712
1713
1714 /* Updates all counters BEHIND the row. Changed paragraphs
1715 * with a dynamic left margin will be rebroken. */ 
1716 void LyXText::UpdateCounters(Row * row) const
1717 {
1718         LyXParagraph * par;
1719         if (!row) {
1720                 row = firstrow;
1721                 par = row->par;
1722         }
1723         else {
1724                 if (row->par->next
1725                     && row->par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
1726                         par = row->par->LastPhysicalPar()->Next();
1727                 } else {
1728                         par = row->par->next;
1729                 }
1730         }
1731
1732         while (par) {
1733                 while (row->par != par)
1734                         row = row->next;
1735                 
1736                 SetCounter(par);
1737                 
1738                 /* now  check for the headline layouts. remember that they
1739                  * have a dynamic left margin */ 
1740                 if (!par->IsDummy()
1741                     && ( textclasslist.Style(parameters->textclass, par->layout).margintype == MARGIN_DYNAMIC
1742                          || textclasslist.Style(parameters->textclass, par->layout).labeltype == LABEL_SENSITIVE)
1743                         ){
1744          
1745                         /* Rebreak the paragraph */ 
1746                         RemoveParagraph(row);
1747                         AppendParagraph(row);
1748        
1749                         /* think about the damned open footnotes! */ 
1750                         while (par->Next() &&
1751                                (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1752                                 || par->Next()->IsDummy())){
1753                                 par = par->Next();
1754                                 if (par->IsDummy()) {
1755                                         while (row->par != par)
1756                                                 row = row->next;
1757                                         RemoveParagraph(row);
1758                                         AppendParagraph(row);
1759                                 }
1760                         }
1761                 }
1762      
1763                 par = par->LastPhysicalPar()->Next();
1764      
1765         }
1766 }
1767
1768
1769 /* insets an inset. */ 
1770 void LyXText::InsertInset(Inset *inset)
1771 {
1772         SetUndo(Undo::INSERT, 
1773                 cursor.par->ParFromPos(cursor.pos)->previous, 
1774                 cursor.par->ParFromPos(cursor.pos)->next);
1775         cursor.par->InsertChar(cursor.pos, LyXParagraph::META_INSET);
1776         cursor.par->InsertInset(cursor.pos, inset);
1777         InsertChar(LyXParagraph::META_INSET);  /* just to rebreak and refresh correctly.
1778                                       * The character will not be inserted a
1779                                       * second time */
1780 }
1781
1782
1783 // this is for the simple cut and paste mechanism
1784 static LyXParagraph * simple_cut_buffer = 0;
1785 static char simple_cut_buffer_textclass = 0;
1786
1787 void DeleteSimpleCutBuffer()
1788 {
1789         if (!simple_cut_buffer)
1790                 return;
1791         LyXParagraph * tmppar;
1792
1793         while (simple_cut_buffer) {
1794                 tmppar =  simple_cut_buffer;
1795                 simple_cut_buffer = simple_cut_buffer->next;
1796                 delete tmppar;
1797         }
1798         simple_cut_buffer = 0;
1799 }
1800
1801
1802 void LyXText::copyEnvironmentType()
1803 {
1804         copylayouttype = cursor.par->GetLayout();
1805 }
1806
1807
1808 void LyXText::pasteEnvironmentType()
1809 {
1810         SetLayout(copylayouttype);
1811 }
1812
1813
1814 void LyXText::CutSelection(bool doclear)
1815 {
1816         // This doesn't make sense, if there is no selection
1817         if (!selection)
1818                 return;
1819    
1820         // OK, we have a selection. This is always between sel_start_cursor
1821         // and sel_end cursor
1822         LyXParagraph * tmppar;
1823    
1824         // Check whether there are half footnotes in the selection
1825         if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1826             || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
1827                 tmppar = sel_start_cursor.par;
1828                 while (tmppar != sel_end_cursor.par){
1829                         if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag) {
1830                                 WriteAlert(_("Impossible operation"),
1831                                            _("Don't know what to do with half floats."),
1832                                            _("sorry."));
1833                                 return;
1834                         }
1835                         tmppar = tmppar->Next();
1836                 }
1837         }
1838
1839         /* table stuff -- begin */
1840         if (sel_start_cursor.par->table || sel_end_cursor.par->table) {
1841                 if ( sel_start_cursor.par != sel_end_cursor.par) {
1842                         WriteAlert(_("Impossible operation"),
1843                                    _("Don't know what to do with half tables."),
1844                                    _("sorry."));
1845                         return;
1846                 }
1847                 sel_start_cursor.par->table->Reinit();
1848         }
1849         /* table stuff -- end */
1850
1851         // make sure that the depth behind the selection are restored, too
1852         LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1853         LyXParagraph * undoendpar = endpar;
1854
1855         if (endpar && endpar->GetDepth()) {
1856                 while (endpar && endpar->GetDepth()) {
1857                         endpar = endpar->LastPhysicalPar()->Next();
1858                         undoendpar = endpar;
1859                 }
1860         } else if (endpar) {
1861                 endpar = endpar->Next(); // because of parindents etc.
1862         }
1863    
1864         SetUndo(Undo::DELETE, 
1865                 sel_start_cursor
1866                 .par->ParFromPos(sel_start_cursor.pos)->previous, 
1867                 undoendpar);
1868    
1869         // clear the simple_cut_buffer
1870         DeleteSimpleCutBuffer();
1871    
1872         // set the textclass
1873         simple_cut_buffer_textclass = parameters->textclass;
1874
1875 #ifdef WITH_WARNINGS
1876 #warning Asger: Make cut more intelligent here.
1877 #endif
1878         /* 
1879            White paper for "intelligent" cutting:
1880            
1881            Example: "This is our text."
1882            Using " our " as selection, cutting will give "This istext.".
1883            Using "our" as selection, cutting will give "This is text.".
1884            Using " our" as selection, cutting will give "This is text.".
1885            Using "our " as selection, cutting will give "This is text.".
1886            
1887            All those four selections will (however) paste identically:
1888            Pasting with the cursor right after the "is" will give the
1889            original text with all four selections.
1890            
1891            The rationale is to be intelligent such that words are copied,
1892            cut and pasted in a functional manner.
1893            
1894            This is not implemented yet. (Asger)
1895
1896            The changes below sees to do a lot of what you want. However
1897            I have not verified that all cases work as they should:
1898                      - cut in single row
1899                      - cut in multiple row
1900                      - cut with insets
1901                      - cut across footnotes and paragraph
1902            My simplistic tests show that the idea are basically sound but
1903            there are some items to fix up...we only need to find them
1904            first.
1905
1906            As do redo Asger's example above (with | beeing the cursor in the
1907            result after cutting.):
1908            
1909            Example: "This is our 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            Using "our "  as selection, cutting will give "This is |text.".
1914
1915            (Lgb)
1916         */
1917
1918 #ifndef FIX_DOUBLE_SPACE
1919         bool space_wrapped =
1920                 sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos);
1921         if (sel_end_cursor.pos > 0
1922             && sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos - 1)) {
1923                 // please break before a space at the end
1924                 sel_end_cursor.pos--;
1925                 space_wrapped = true;
1926         }
1927         // cut behind a space if there is one
1928         while (sel_start_cursor.par->Last() > sel_start_cursor.pos
1929                && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
1930                && (sel_start_cursor.par != sel_end_cursor.par
1931                    || sel_start_cursor.pos < sel_end_cursor.pos))
1932                 sel_start_cursor.pos++; 
1933 #endif
1934         // there are two cases: cut only within one paragraph or
1935         // more than one paragraph
1936    
1937         if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos) 
1938             == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
1939                 // only within one paragraph
1940                 simple_cut_buffer = new LyXParagraph;
1941                 LyXParagraph::size_type i =
1942                         sel_start_cursor.pos;
1943                 for (; i < sel_end_cursor.pos; ++i) {
1944                         /* table stuff -- begin */
1945                         if (sel_start_cursor.par->table
1946                             && sel_start_cursor.par->IsNewline(sel_start_cursor.pos)) {
1947                                 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
1948                                 sel_start_cursor.pos++;
1949                         } else {
1950                                 /* table stuff -- end */
1951                                 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
1952                                 sel_start_cursor.par->Erase(sel_start_cursor.pos);
1953                         }
1954                         simple_cut_buffer->InsertFromMinibuffer(simple_cut_buffer->Last());
1955                 }
1956 #ifndef FIX_DOUBLE_SPACE
1957                 // check for double spaces
1958                 if (sel_start_cursor.pos &&
1959                     sel_start_cursor.par->Last() > sel_start_cursor.pos
1960                     && sel_start_cursor.par
1961                     ->IsLineSeparator(sel_start_cursor.pos - 1)
1962                     && sel_start_cursor.par
1963                     ->IsLineSeparator(sel_start_cursor.pos)) {
1964                         sel_start_cursor.par->Erase(sel_start_cursor.pos);
1965                 }
1966                 if (space_wrapped)
1967                         simple_cut_buffer->InsertChar(i - sel_start_cursor.pos,
1968                                                       ' ');
1969 #endif
1970                 endpar = sel_end_cursor.par->Next();
1971         } else {
1972                 // cut more than one paragraph
1973    
1974                 sel_end_cursor.par
1975                         ->BreakParagraphConservative(sel_end_cursor.pos);
1976 #ifndef FIX_DOUBLE_SPACE
1977                 // insert a space at the end if there was one
1978                 if (space_wrapped)
1979                         sel_end_cursor.par
1980                                 ->InsertChar(sel_end_cursor.par->Last(), ' ');
1981 #endif
1982                 sel_end_cursor.par = sel_end_cursor.par->Next();
1983                 sel_end_cursor.pos = 0;
1984    
1985                 cursor = sel_end_cursor;
1986
1987 #ifndef FIX_DOUBLE_SPACE
1988                 // please break behind a space, if there is one.
1989                 // The space should be copied too
1990                 if (sel_start_cursor.par
1991                     ->IsLineSeparator(sel_start_cursor.pos))
1992                         sel_start_cursor.pos++;
1993 #endif   
1994                 sel_start_cursor.par
1995                         ->BreakParagraphConservative(sel_start_cursor.pos);
1996 #ifndef FIX_DOUBLE_SPACE
1997                 if (!sel_start_cursor.pos
1998                     || sel_start_cursor.par
1999                     ->IsLineSeparator(sel_start_cursor.pos - 1)
2000                     || sel_start_cursor.par
2001                     ->IsNewline(sel_start_cursor.pos - 1)) {
2002                         sel_start_cursor.par->Next()->InsertChar(0, ' ');
2003                 }
2004 #endif
2005                 // store the endparagraph for redoing later
2006                 endpar = sel_end_cursor.par->Next(); /* needed because
2007                                                         the sel_end_
2008                                                         cursor.par
2009                                                         will be pasted! */
2010    
2011                 // store the selection
2012                 simple_cut_buffer = sel_start_cursor.par
2013                         ->ParFromPos(sel_start_cursor.pos)->next;
2014                 simple_cut_buffer->previous = 0;
2015                 sel_end_cursor.par->previous->next = 0;
2016
2017                 // cut the selection
2018                 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->next 
2019                         = sel_end_cursor.par;
2020    
2021                 sel_end_cursor.par->previous 
2022                         = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
2023
2024                 // care about footnotes
2025                 if (simple_cut_buffer->footnoteflag) {
2026                         LyXParagraph * tmppar = simple_cut_buffer;
2027                         while (tmppar){
2028                                 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
2029                                 tmppar = tmppar->next;
2030                         }
2031                 }
2032
2033                 // the cut selection should begin with standard layout
2034                 simple_cut_buffer->Clear(); 
2035    
2036                 // paste the paragraphs again, if possible
2037                 if (doclear)
2038                         sel_start_cursor.par->Next()->ClearParagraph();
2039                 if (sel_start_cursor.par->FirstPhysicalPar()->HasSameLayout(sel_start_cursor.par->Next())
2040                     || 
2041                     !sel_start_cursor.par->Next()->Last())
2042                         sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->PasteParagraph();
2043
2044 #ifndef FIX_DOUBLE_SPACE
2045                 // maybe a forgotten blank
2046                 if (sel_start_cursor.pos 
2047                     && sel_start_cursor.par
2048                     ->IsLineSeparator(sel_start_cursor.pos)
2049                     && sel_start_cursor.par
2050                     ->IsLineSeparator(sel_start_cursor.pos - 1)) {
2051                         sel_start_cursor.par->Erase(sel_start_cursor.pos);
2052                 }
2053 #endif
2054         }
2055
2056         // sometimes necessary
2057         if (doclear)
2058                 sel_start_cursor.par->ClearParagraph();
2059
2060         RedoParagraphs(sel_start_cursor, endpar);
2061    
2062         ClearSelection();
2063         cursor = sel_start_cursor;
2064         SetCursor(cursor.par, cursor.pos);
2065         sel_cursor = cursor;
2066         UpdateCounters(cursor.row);
2067 }
2068
2069     
2070 void LyXText::CopySelection()
2071 {
2072         // this doesnt make sense, if there is no selection
2073         if (!selection)
2074                 return;
2075
2076         // ok we have a selection. This is always between sel_start_cursor
2077         // and sel_end cursor
2078         LyXParagraph * tmppar;
2079    
2080         /* check wether there are half footnotes in the selection */
2081         if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2082             || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2083                 tmppar = sel_start_cursor.par;
2084                 while (tmppar != sel_end_cursor.par) {
2085                         if (tmppar->footnoteflag !=
2086                             sel_end_cursor.par->footnoteflag) {
2087                                 WriteAlert(_("Impossible operation"),
2088                                            _("Don't know what to do"
2089                                              " with half floats."),
2090                                            _("sorry."));
2091                                 return;
2092                         }
2093                         tmppar = tmppar->Next();
2094                 }
2095         }
2096
2097         /* table stuff -- begin */
2098         if (sel_start_cursor.par->table || sel_end_cursor.par->table){
2099                 if ( sel_start_cursor.par != sel_end_cursor.par){
2100                         WriteAlert(_("Impossible operation"),
2101                                    _("Don't know what to do with half tables."),
2102                                    _("sorry."));
2103                         return;
2104                 }
2105         }
2106         /* table stuff -- end */
2107    
2108         // delete the simple_cut_buffer
2109         DeleteSimpleCutBuffer();
2110
2111         // set the textclass
2112         simple_cut_buffer_textclass = parameters->textclass;
2113
2114 #ifdef FIX_DOUBLE_SPACE
2115         // copy behind a space if there is one
2116         while (sel_start_cursor.par->Last() > sel_start_cursor.pos
2117                && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
2118                && (sel_start_cursor.par != sel_end_cursor.par
2119                    || sel_start_cursor.pos < sel_end_cursor.pos))
2120                 sel_start_cursor.pos++; 
2121 #endif
2122         // there are two cases: copy only within one paragraph
2123         // or more than one paragraph
2124         if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos) 
2125             == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2126                 // only within one paragraph
2127                 simple_cut_buffer = new LyXParagraph;
2128                 LyXParagraph::size_type i = 0;
2129                 for (i = sel_start_cursor.pos; i < sel_end_cursor.pos; ++i){
2130                         sel_start_cursor.par->CopyIntoMinibuffer(i);
2131                         simple_cut_buffer->InsertFromMinibuffer(i - sel_start_cursor.pos);
2132                 }
2133         } else {
2134                 // copy more than one paragraph
2135                 // clone the paragraphs within the selection
2136                 tmppar =
2137                         sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
2138                 simple_cut_buffer = tmppar->Clone();
2139                 LyXParagraph *tmppar2 = simple_cut_buffer;
2140      
2141                 while (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)
2142                        && tmppar->next) {
2143                         tmppar = tmppar->next;
2144                         tmppar2->next = tmppar->Clone();
2145                         tmppar2->next->previous = tmppar2;
2146                         tmppar2 = tmppar2->next;
2147                 }
2148                 tmppar2->next = 0;
2149
2150                 // care about footnotes
2151                 if (simple_cut_buffer->footnoteflag) {
2152                         tmppar = simple_cut_buffer;
2153                         while (tmppar){
2154                                 tmppar->footnoteflag =
2155                                         LyXParagraph::NO_FOOTNOTE;
2156                                 tmppar = tmppar->next;
2157                         }
2158                 }
2159                 
2160                 // the simple_cut_buffer paragraph is too big
2161                 LyXParagraph::size_type tmpi2 =
2162                         sel_start_cursor.par->PositionInParFromPos(sel_start_cursor.pos);
2163                 for (; tmpi2; --tmpi2)
2164                         simple_cut_buffer->Erase(0);
2165                 
2166                 // now tmppar 2 is too big, delete all after sel_end_cursor.pos
2167      
2168                 tmpi2 = sel_end_cursor.par->PositionInParFromPos(sel_end_cursor.pos);
2169                 while (tmppar2->size() > tmpi2) {
2170                         tmppar2->Erase(tmppar2->text.size() - 1);
2171                 }
2172         }
2173 }
2174           
2175
2176 void LyXText::PasteSelection()
2177 {
2178         // this does not make sense, if there is nothing to paste
2179         if (!simple_cut_buffer)
2180                 return;
2181
2182         LyXParagraph * tmppar;
2183         LyXParagraph * endpar;
2184
2185         LyXCursor tmpcursor;
2186
2187         // be carefull with footnotes in footnotes
2188         if (cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2189       
2190                 // check whether the cut_buffer includes a footnote
2191                 tmppar = simple_cut_buffer;
2192                 while (tmppar
2193                        && tmppar->footnoteflag == LyXParagraph::NO_FOOTNOTE)
2194                         tmppar = tmppar->next;
2195       
2196                 if (tmppar) {
2197                         WriteAlert(_("Impossible operation"),
2198                                    _("Can't paste float into float!"),
2199                                    _("Sorry."));
2200                         return;
2201                 }
2202         }
2203
2204         /* table stuff -- begin */
2205         if (cursor.par->table) {
2206                 if (simple_cut_buffer->next) {
2207                         WriteAlert(_("Impossible operation"),
2208                                    _("Table cell cannot include more than one paragraph!"),
2209                                    _("Sorry."));
2210                         return;
2211                 }
2212         }
2213         /* table stuff -- end */
2214    
2215         SetUndo(Undo::INSERT, 
2216                 cursor.par->ParFromPos(cursor.pos)->previous, 
2217                 cursor.par->ParFromPos(cursor.pos)->next); 
2218
2219         tmpcursor = cursor;
2220
2221         // There are two cases: cutbuffer only one paragraph or many
2222         if (!simple_cut_buffer->next) {
2223                 // only within a paragraph
2224
2225 #ifndef FIX_DOUBLE_SPACE
2226                 // please break behind a space, if there is one
2227                 while (tmpcursor.par->Last() > tmpcursor.pos
2228                        && tmpcursor.par->IsLineSeparator(tmpcursor.pos))
2229                         tmpcursor.pos++; 
2230 #endif
2231                 tmppar = simple_cut_buffer->Clone();
2232                 /* table stuff -- begin */
2233                 bool table_too_small = false;
2234                 if (tmpcursor.par->table) {
2235                         while (simple_cut_buffer->text.size()
2236                                && !table_too_small) {
2237                                 if (simple_cut_buffer->IsNewline(0)){
2238                                         while(tmpcursor.pos < tmpcursor.par->Last() && !tmpcursor.par->IsNewline(tmpcursor.pos))
2239                                                 tmpcursor.pos++;
2240                                         simple_cut_buffer->Erase(0);
2241                                         if (tmpcursor.pos < tmpcursor.par->Last())
2242                                                 tmpcursor.pos++;
2243                                         else
2244                                                 table_too_small = true;
2245                                 } else {
2246 #ifdef FIX_DOUBLE_SPACE
2247                                         // This is an attempt to fix the
2248                                         // "never insert a space at the
2249                                         // beginning of a paragraph" problem.
2250                                         if (tmpcursor.pos == 0
2251                                             && simple_cut_buffer->IsLineSeparator(0)) {
2252                                                 simple_cut_buffer->Erase(0);
2253                                         } else {
2254                                                 simple_cut_buffer->CutIntoMinibuffer(0);
2255                                                 simple_cut_buffer->Erase(0);
2256                                                 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2257                                                 tmpcursor.pos++;
2258                                         }
2259 #else
2260                                         simple_cut_buffer->CutIntoMinibuffer(0);
2261                                         simple_cut_buffer->Erase(0);
2262                                         tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2263                                         tmpcursor.pos++;
2264 #endif
2265                                 }
2266                         }
2267                 } else {
2268                         /* table stuff -- end */
2269                         // Some provisions should be done here for checking
2270                         // if we are inserting at the beginning of a
2271                         // paragraph. If there are a space at the beginning
2272                         // of the text to insert and we are inserting at
2273                         // the beginning of the paragraph the space should
2274                         // be removed.
2275                         while (simple_cut_buffer->text.size()) {
2276 #ifdef FIX_DOUBLE_SPACE
2277                                 // This is an attempt to fix the
2278                                 // "never insert a space at the
2279                                 // beginning of a paragraph" problem.
2280                                 if (tmpcursor.pos == 0
2281                                     && simple_cut_buffer->IsLineSeparator(0)) {
2282                                         simple_cut_buffer->Erase(0);
2283                                 } else {
2284                                         simple_cut_buffer->CutIntoMinibuffer(0);
2285                                         simple_cut_buffer->Erase(0);
2286                                         tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2287                                         tmpcursor.pos++;
2288                                 }
2289 #else
2290                                 simple_cut_buffer->CutIntoMinibuffer(0);
2291                                 simple_cut_buffer->Erase(0);
2292                                 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2293                                 tmpcursor.pos++;
2294 #endif
2295                         }
2296                 }
2297                 delete simple_cut_buffer;
2298                 simple_cut_buffer = tmppar;
2299                 endpar = tmpcursor.par->Next();
2300         } else {
2301                 // many paragraphs
2302
2303                 // make a copy of the simple cut_buffer
2304                 tmppar = simple_cut_buffer;
2305                 LyXParagraph * simple_cut_clone = tmppar->Clone();
2306                 LyXParagraph * tmppar2 = simple_cut_clone;
2307                 if (cursor.par->footnoteflag){
2308                         tmppar->footnoteflag = cursor.par->footnoteflag;
2309                         tmppar->footnotekind = cursor.par->footnotekind;
2310                 }
2311                 while (tmppar->next) {
2312                         tmppar = tmppar->next;
2313                         tmppar2->next = tmppar->Clone();
2314                         tmppar2->next->previous = tmppar2;
2315                         tmppar2 = tmppar2->next;
2316                         if (cursor.par->footnoteflag){
2317                                 tmppar->footnoteflag = cursor.par->footnoteflag;
2318                                 tmppar->footnotekind = cursor.par->footnotekind;
2319                         }
2320                 }
2321      
2322                 // make sure there is no class difference
2323                 SwitchLayoutsBetweenClasses(simple_cut_buffer_textclass,
2324                                             parameters->textclass,
2325                                             simple_cut_buffer);
2326      
2327                 // make the simple_cut_buffer exactly the same layout than
2328                 // the cursor paragraph
2329                 simple_cut_buffer->MakeSameLayout(cursor.par);
2330      
2331                 // find the end of the buffer
2332                 LyXParagraph * lastbuffer = simple_cut_buffer;
2333                 while (lastbuffer->Next())
2334                         lastbuffer = lastbuffer->Next();
2335      
2336 #ifndef FIX_DOUBLE_SPACE
2337                 // Please break behind a space, if there is one. The space 
2338                 // should be copied too.
2339                 if (cursor.par->Last() > cursor.pos
2340                     && cursor.par->IsLineSeparator(cursor.pos))
2341                         cursor.pos++; 
2342 #endif
2343                 bool paste_the_end = false;
2344
2345                 // open the paragraph for inserting the simple_cut_buffer
2346                 // if necessary
2347                 if (cursor.par->Last() > cursor.pos || !cursor.par->Next()){
2348                         cursor.par->BreakParagraphConservative(cursor.pos);
2349                         paste_the_end = true;
2350                 }
2351
2352 #ifndef FIX_DOUBLE_SPACE
2353                 // be careful with double spaces
2354                 if ((!cursor.par->Last()
2355                      || cursor.par->IsLineSeparator(cursor.pos - 1)
2356                      || cursor.par->IsNewline(cursor.pos - 1))
2357                     && simple_cut_buffer->text.size()
2358                     && simple_cut_buffer->IsLineSeparator(0))
2359                         simple_cut_buffer->Erase(0);
2360 #endif
2361                 // set the end for redoing later
2362                 endpar = cursor.par->ParFromPos(cursor.pos)->next->Next();
2363      
2364                 // paste it!
2365                 lastbuffer->ParFromPos(lastbuffer->Last())->next =
2366                         cursor.par->ParFromPos(cursor.pos)->next;
2367                 cursor.par->ParFromPos(cursor.pos)->next->previous =
2368                         lastbuffer->ParFromPos(lastbuffer->Last());
2369      
2370                 cursor.par->ParFromPos(cursor.pos)->next = simple_cut_buffer;
2371                 simple_cut_buffer->previous =
2372                         cursor.par->ParFromPos(cursor.pos);
2373    
2374                 if (cursor.par->ParFromPos(cursor.pos)->Next() == lastbuffer)
2375                         lastbuffer = cursor.par;
2376      
2377                 cursor.par->ParFromPos(cursor.pos)->PasteParagraph();
2378      
2379                 // store the new cursor position
2380                 tmpcursor.par = lastbuffer;
2381                 tmpcursor.pos = lastbuffer->Last();
2382      
2383                 // maybe some pasting
2384                 if (lastbuffer->Next() && paste_the_end) {
2385                         if (lastbuffer->Next()->HasSameLayout(lastbuffer)) {
2386 #ifndef FIX_DOUBLE_SPACE
2387                                 // be careful with double spaces
2388                                 if ((!lastbuffer->Last()
2389                                      || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2390                                      || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2391                                     && lastbuffer->Next()->Last()
2392                                     && lastbuffer->Next()->IsLineSeparator(0))
2393                                         lastbuffer->Next()->Erase(0);
2394 #endif
2395                                 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2396          
2397                         } else if (!lastbuffer->Next()->Last()) {
2398                                 lastbuffer->Next()->MakeSameLayout(lastbuffer);
2399 #ifndef FIX_DOUBLE_SPACE
2400                                 // be careful witth double spaces
2401                                 if ((!lastbuffer->Last()
2402                                      || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2403                                      || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2404                                     && lastbuffer->Next()->Last()
2405                                     && lastbuffer->Next()->IsLineSeparator(0))
2406                                         lastbuffer->Next()->Erase(0);
2407 #endif
2408                                 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2409          
2410                         } else if (!lastbuffer->Last()) {
2411                                 lastbuffer->MakeSameLayout(lastbuffer->next);
2412 #ifndef FIX_DOUBLE_SPACE
2413                                 // be careful witth double spaces
2414                                 if ((!lastbuffer->Last()
2415                                      || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2416                                      || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2417                                     && lastbuffer->Next()->Last()
2418                                     && lastbuffer->Next()->IsLineSeparator(0))
2419                                         lastbuffer->Next()->Erase(0);
2420 #endif
2421                                 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2422          
2423                         } else
2424                                 lastbuffer->Next()->ClearParagraph();
2425                 }
2426
2427                 // restore the simple cut buffer
2428                 simple_cut_buffer = simple_cut_clone;
2429         }
2430
2431         RedoParagraphs(cursor, endpar);
2432     
2433         SetCursor(cursor.par, cursor.pos);
2434         ClearSelection();
2435    
2436         sel_cursor = cursor;
2437         SetCursor(tmpcursor.par, tmpcursor.pos);
2438         SetSelection();
2439         UpdateCounters(cursor.row);
2440 }
2441    
2442
2443 // returns a pointer to the very first LyXParagraph
2444 LyXParagraph * LyXText::FirstParagraph() const
2445 {
2446         return params->paragraph;
2447 }
2448
2449
2450 // returns true if the specified string is at the specified position
2451 bool LyXText::IsStringInText(LyXParagraph * par,
2452                              LyXParagraph::size_type pos,
2453                              char const * str) const
2454 {
2455         if (par) {
2456                 int i = 0;
2457                 while (pos + i < par->Last() && str[i] && 
2458                        str[i] == par->GetChar(pos + i)) {
2459                         ++i;
2460                 }
2461                 if (!str[i])
2462                         return true;
2463         }
2464         return false;
2465 }
2466
2467
2468 // sets the selection over the number of characters of string, no check!!
2469 void LyXText::SetSelectionOverString(char const * string)
2470 {
2471         sel_cursor = cursor;
2472         for (int i = 0; string[i]; ++i)
2473                 CursorRight();
2474         SetSelection();
2475 }
2476
2477
2478 // simple replacing. The font of the first selected character is used
2479 void LyXText::ReplaceSelectionWithString(char const * str)
2480 {
2481         SetCursorParUndo();
2482         FreezeUndo();
2483
2484         if (!selection) { // create a dummy selection
2485                 sel_end_cursor = cursor;
2486                 sel_start_cursor = cursor;
2487         }
2488
2489         // Get font setting before we cut
2490         LyXParagraph::size_type pos = sel_end_cursor.pos;
2491         LyXFont font = sel_start_cursor.par->GetFontSettings(sel_start_cursor.pos);
2492
2493         // Insert the new string
2494         for (int i = 0; str[i]; ++i) {
2495                 sel_end_cursor.par->InsertChar(pos, str[i]);
2496                 sel_end_cursor.par->SetFont(pos, font);
2497                 ++pos;
2498         }
2499
2500         // Cut the selection
2501         CutSelection();
2502
2503         UnFreezeUndo();
2504 }
2505
2506
2507 // if the string can be found: return true and set the cursor to
2508 // the new position
2509 bool LyXText::SearchForward(char const * str) const
2510 {
2511         LyXParagraph * par = cursor.par;
2512         LyXParagraph::size_type pos = cursor.pos;
2513         while (par && !IsStringInText(par, pos, str)) {
2514                 if (pos < par->Last() - 1)
2515                         ++pos;
2516                 else {
2517                         pos = 0;
2518                         par = par->Next();
2519                 }
2520         }
2521         if (par) {
2522                 SetCursor(par, pos);
2523                 return true;
2524         }
2525         else
2526                 return false;
2527 }
2528
2529
2530 bool LyXText::SearchBackward(char const * string) const
2531 {
2532         LyXParagraph * par = cursor.par;
2533         int pos = cursor.pos;
2534
2535         do {
2536                 if (pos > 0)
2537                         --pos;
2538                 else {
2539                         // We skip empty paragraphs (Asger)
2540                         do {
2541                                 par = par->Previous();
2542                                 if (par)
2543                                         pos = par->Last() - 1;
2544                         } while (par && pos < 0);
2545                 }
2546         } while (par && !IsStringInText(par, pos, string));
2547   
2548         if (par) {
2549                 SetCursor(par, pos);
2550                 return true;
2551         } else
2552                 return false;
2553 }
2554
2555
2556 void LyXText::InsertStringA(LyXParagraph::TextContainer const & text)
2557 {
2558         char * str = new char[text.size() + 1];
2559         copy(text.begin(), text.end(), str);
2560         str[text.size()] = '\0';
2561         InsertStringA(str);
2562         delete [] str;
2563 }
2564
2565
2566 // needed to insert the selection
2567 void LyXText::InsertStringA(char const * s)
2568 {
2569         string str(s);
2570         LyXParagraph * par = cursor.par;
2571         LyXParagraph::size_type pos = cursor.pos;
2572         LyXParagraph::size_type a = 0;
2573         int cell = 0;
2574         LyXParagraph * endpar = cursor.par->Next();
2575         
2576         SetCursorParUndo();
2577         
2578         bool flag =
2579                 textclasslist.Style(parameters->textclass, 
2580                                     cursor.par->GetLayout()).isEnvironment();
2581         // only to be sure, should not be neccessary
2582         ClearSelection();
2583         
2584         // insert the string, don't insert doublespace
2585         string::size_type i = 0;
2586         while (i < str.length()) {
2587                 if (str[i] != '\n') {
2588                         if (str[i] == ' ' 
2589                             && i + 1 < str.length() && str[i + 1] != ' '
2590                             && pos && par->GetChar(pos - 1)!= ' ') {
2591                                 par->InsertChar(pos,' ');
2592                                 ++pos;
2593                         } else if (par->table) {
2594                                 if (str[i] == '\t') {
2595                                         while((pos < par->size()) &&
2596                                               (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2597                                                 ++pos;
2598                                         if (pos < par->size())
2599                                                 ++pos;
2600                                         else // no more fields to fill skip the rest
2601                                                 break;
2602                                 } else if ((str[i] != 13) &&
2603                                            ((str[i] & 127) >= ' ')) {
2604                                         par->InsertChar(pos, str[i]);
2605                                         ++pos;
2606                                 }
2607                         } else if (str[i] == ' ') {
2608 #if 1
2609                                 InsetSpecialChar * new_inset =
2610                                         new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2611                                 par->InsertInset(pos, new_inset);
2612 #else
2613                                 par->InsertChar(pos, LyXParagraph::META_PROTECTED_SEPARATOR);
2614 #endif
2615                                 ++pos;
2616                         } else if (str[i] == '\t') {
2617                                 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2618 #if 1
2619                                 InsetSpecialChar * new_inset =
2620                                         new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2621                                 par->InsertInset(pos, new_inset);
2622 #else
2623                                         par->InsertChar(a, LyXParagraph::META_PROTECTED_SEPARATOR);
2624 #endif
2625                                 }
2626                                 pos = a;
2627                         } else if (str[i]!= 13 && 
2628                                    // Ignore unprintables
2629                                    (str[i] & 127) >= ' ') {
2630                                 par->InsertChar(pos, str[i]);
2631                                 ++pos;
2632                         }
2633                 } else {
2634                         if (par->table) {
2635                                 if (i + 1 >= str.length()) {
2636                                         ++pos;
2637                                         break;
2638                                 }
2639                                 while((pos < par->size()) &&
2640                                       (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2641                                         ++pos;
2642                                 ++pos;
2643                                 cell = NumberOfCell(par, pos);
2644                                 while((pos < par->size()) &&
2645                                       !(par->table->IsFirstCell(cell))) {
2646
2647                                         while((pos < par->size()) &&
2648                                               (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2649                                                 ++pos;
2650                                         ++pos;
2651                                         cell = NumberOfCell(par, pos);
2652                                 }
2653                                 if (pos >= par->size())
2654                                         // no more fields to fill skip the rest
2655                                         break;
2656                         } else {
2657                                 if (!par->text.size()) {
2658 #if 1
2659                                         InsetSpecialChar * new_inset =
2660                                                 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2661                                         par->InsertInset(pos, new_inset);
2662 #else
2663                                         par->InsertChar(pos, LyXParagraph::META_PROTECTED_SEPARATOR);
2664 #endif
2665                                         ++pos;
2666                                 }
2667                                 par->BreakParagraph(pos, flag);
2668                                 par = par->Next();
2669                                 pos = 0;
2670                         }
2671                 }
2672                 ++i;
2673         }
2674         
2675         RedoParagraphs(cursor, endpar);
2676         SetCursor(cursor.par, cursor.pos);
2677         sel_cursor = cursor;
2678         SetCursor(par, pos);
2679         SetSelection();
2680 }
2681
2682
2683 void LyXText::InsertStringB(LyXParagraph::TextContainer const & text)
2684 {
2685         char * str = new char[text.size() + 1];
2686         copy(text.begin(), text.end(), str);
2687         str[text.size()] = '\0';
2688         InsertStringB(str);
2689         delete [] str;
2690 }
2691
2692
2693 /* turns double-CR to single CR, others where converted into one blank and 13s 
2694  * that are ignored .Double spaces are also converted into one. Spaces at
2695  * the beginning of a paragraph are forbidden. tabs are converted into one
2696  * space. then InsertStringA is called */ 
2697 void LyXText::InsertStringB(char const * s)
2698 {
2699         string str(s);
2700         LyXParagraph * par = cursor.par;
2701         string::size_type i = 1;
2702         while (i < str.length()) {
2703                 if (str[i] == '\t' && !par->table)
2704                         str[i] = ' ';
2705                 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2706                         str[i] = 13;
2707                 if (str[i] == '\n' && i + 1 < str.length() && !par->table){
2708                         if (str[i + 1] != '\n') {
2709                                 if (str[i - 1] != ' ')
2710                                         str[i] = ' ';
2711                                 else
2712                                         str[i] = 13;
2713                         }
2714                         while (i + 1 < str.length() 
2715                                && (str[i + 1] == ' ' 
2716                                    || str[i + 1] == '\t'
2717                                    || str[i + 1] == '\n' 
2718                                    || str[i + 1] == 13)) {
2719                                 str[i + 1] = 13;
2720                                 ++i;
2721                         }
2722                 }
2723                 ++i;
2724         }
2725         InsertStringA(str.c_str());
2726 }
2727
2728
2729 bool LyXText::GotoNextError() const
2730 {
2731         LyXCursor res = cursor;
2732         do {
2733                 if (res.pos < res.par->Last() - 1) {
2734                         res.pos++;
2735                 }
2736                 else  {
2737                         res.par = res.par->Next();
2738                         res.pos = 0;
2739                 }
2740       
2741         } while (res.par && 
2742                  !(res.par->GetChar(res.pos) == LyXParagraph::META_INSET
2743                    && res.par->GetInset(res.pos)->AutoDelete()));
2744    
2745         if (res.par) {
2746                 SetCursor(res.par, res.pos);
2747                 return true;
2748         }
2749         return false;
2750 }
2751
2752
2753 bool LyXText::GotoNextNote() const
2754 {
2755         LyXCursor res = cursor;
2756         do {
2757                 if (res.pos < res.par->Last() - 1) {
2758                         res.pos++;
2759                 } else  {
2760                         res.par = res.par->Next();
2761                         res.pos = 0;
2762                 }
2763       
2764         } while (res.par && 
2765                  !(res.par->GetChar(res.pos) == LyXParagraph::META_INSET
2766                    && res.par->GetInset(res.pos)->LyxCode() == Inset::IGNORE_CODE));
2767    
2768         if (res.par) {
2769                 SetCursor(res.par, res.pos);
2770                 return true;
2771         }
2772         return false;
2773 }
2774
2775
2776 int LyXText::SwitchLayoutsBetweenClasses(LyXTextClassList::size_type class1,
2777                                          LyXTextClassList::size_type class2,
2778                                          LyXParagraph * par)
2779 {
2780         int ret = 0;
2781         if (!par || class1 == class2)
2782                 return ret;
2783         par = par->FirstPhysicalPar();
2784         while (par) {
2785                 string name = textclasslist.NameOfLayout(class1, par->layout);
2786                 int lay = 0;
2787                 pair<bool, LyXTextClass::LayoutList::size_type> pp =
2788                         textclasslist.NumberOfLayout(class2, name);
2789                 if (pp.first) {
2790                         lay = pp.second;
2791                 } else { // layout not found
2792                         // use default layout "Standard" (0)
2793                         lay = 0;
2794                 }
2795                 par->layout = lay;
2796       
2797                 if (name != textclasslist.NameOfLayout(class2, par->layout)) {
2798                         ++ret;
2799                         string s = "Layout had to be changed from\n"
2800                                 + name + " to " + textclasslist.NameOfLayout(class2, par->layout)
2801                                 + "\nbecause of class conversion from\n"
2802                                 + textclasslist.NameOfClass(class1) + " to "
2803                                 + textclasslist.NameOfClass(class2);
2804                         InsetError * new_inset = new InsetError(s);
2805                         par->InsertChar(0, LyXParagraph::META_INSET);
2806                         par->InsertInset(0, new_inset);
2807                 }
2808       
2809                 par = par->next;
2810         }
2811         return ret;
2812 }
2813
2814
2815 void LyXText::CheckParagraph(LyXParagraph * par,
2816                              LyXParagraph::size_type pos)
2817 {
2818   
2819         LyXCursor tmpcursor;
2820
2821         /* table stuff -- begin*/
2822    
2823         if (par->table) {
2824                 CheckParagraphInTable(par, pos);
2825         }
2826         else {
2827                 /* table stuff -- end*/
2828      
2829                 long y = 0;
2830                 LyXParagraph::size_type z;
2831                 Row * row = GetRow(par, pos, y);
2832      
2833                 // is there a break one row above
2834                 if (row->previous && row->previous->par == row->par) {
2835                         z = NextBreakPoint(row->previous, paperwidth);
2836                         if ( z >= row->pos) {
2837                                 // set the dimensions of the row above
2838                                 y -= row->previous->height;
2839                                 refresh_y = y;
2840                                 refresh_row = row->previous;
2841                                 status = LyXText::NEED_MORE_REFRESH;
2842        
2843                                 BreakAgain(row->previous);
2844
2845                                 // set the cursor again. Otherwise
2846                                 // dangling pointers are possible
2847                                 SetCursor(cursor.par, cursor.pos);
2848                                 sel_cursor = cursor;
2849                                 return;
2850                         }
2851                 }
2852
2853                 int tmpheight = row->height;
2854                 LyXParagraph::size_type tmplast = RowLast(row);
2855                 refresh_y = y;
2856                 refresh_row = row;
2857
2858                 BreakAgain(row);
2859                 if (row->height == tmpheight && RowLast(row) == tmplast)
2860                         status = LyXText::NEED_VERY_LITTLE_REFRESH;
2861                 else
2862                         status = LyXText::NEED_MORE_REFRESH; 
2863    
2864                 // check the special right address boxes
2865                 if (textclasslist.Style(parameters->textclass,
2866                                         par->GetLayout()).margintype
2867                     == MARGIN_RIGHT_ADDRESS_BOX) {
2868                         tmpcursor.par = par;
2869                         tmpcursor.row = row;
2870                         tmpcursor.y = y;
2871                         tmpcursor.x = 0;
2872                         tmpcursor.x_fix = 0;
2873                         tmpcursor.pos = pos;
2874                         RedoDrawingOfParagraph(tmpcursor); 
2875                 }
2876    
2877         }
2878
2879         // set the cursor again. Otherwise dangling pointers are possible
2880         // also set the selection
2881    
2882         if (selection) {
2883                 tmpcursor = cursor;
2884                 SetCursorIntern(sel_cursor.par, sel_cursor.pos);
2885                 sel_cursor = cursor; 
2886                 SetCursorIntern(sel_start_cursor.par, sel_start_cursor.pos);
2887                 sel_start_cursor = cursor; 
2888                 SetCursorIntern(sel_end_cursor.par, sel_end_cursor.pos);
2889                 sel_end_cursor = cursor; 
2890                 SetCursorIntern(last_sel_cursor.par, last_sel_cursor.pos);
2891                 last_sel_cursor = cursor; 
2892                 cursor = tmpcursor;
2893         }
2894         SetCursorIntern(cursor.par, cursor.pos);
2895 }
2896
2897
2898 // returns 0 if inset wasn't found
2899 int LyXText::UpdateInset(Inset * inset)
2900 {
2901         // first check the current paragraph
2902         int pos = cursor.par->GetPositionOfInset(inset);
2903         if (pos != -1){
2904                 CheckParagraph(cursor.par, pos);
2905                 return 1;
2906         }
2907   
2908         // check every paragraph
2909   
2910         LyXParagraph * par = FirstParagraph();
2911         do {
2912                 // make sure the paragraph is open
2913                 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2914                         pos = par->GetPositionOfInset(inset);
2915                         if (pos != -1){
2916                                 CheckParagraph(par, pos);
2917                                 return 1;
2918                         }
2919                 }
2920                 par = par->Next();
2921         } while (par);
2922   
2923         return 0;
2924 }
2925
2926
2927 void LyXText::SetCursor(LyXParagraph * par,
2928                         LyXParagraph::size_type pos, bool setfont) const
2929 {
2930         LyXCursor old_cursor = cursor;
2931         SetCursorIntern(par, pos, setfont);
2932         DeleteEmptyParagraphMechanism(old_cursor);
2933 }
2934
2935
2936 void LyXText::SetCursorIntern(LyXParagraph * par,
2937                               LyXParagraph::size_type pos, bool setfont) const
2938 {
2939         long y;
2940         Row * row;
2941         LyXParagraph * tmppar;
2942         LyXParagraph::size_type vpos,cursor_vpos;
2943
2944         // correct the cursor position if impossible
2945         if (pos > par->Last()){
2946                 tmppar = par->ParFromPos(pos);
2947                 pos = par->PositionInParFromPos(pos);
2948                 par = tmppar;
2949         }
2950         if (par->IsDummy() && par->previous &&
2951             par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2952                 while (par->previous &&
2953                        ((par->previous->IsDummy() && par->previous->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) ||
2954                         (par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE))) {
2955                         par = par->previous ;
2956                         if (par->IsDummy() &&
2957                             par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
2958                                 pos += par->text.size() + 1;
2959                 }
2960                 if (par->previous) {
2961                         par = par->previous;
2962                 }
2963                 pos += par->text.size() + 1;
2964         }
2965
2966         cursor.par = par;
2967         cursor.pos = pos;
2968
2969         if (setfont)
2970                 if (cursor.pos && 
2971                     (cursor.pos == cursor.par->Last() || cursor.par->IsSeparator(cursor.pos)
2972                      || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
2973                          && !cursor.par->IsSeparator(cursor.pos))
2974                      || (cursor.par->table && cursor.par->IsNewline(cursor.pos))
2975                      )) {
2976                         current_font = cursor.par->GetFontSettings(cursor.pos - 1);
2977                         real_current_font = GetFont(cursor.par, cursor.pos - 1);
2978                 } else {
2979                         current_font = cursor.par->GetFontSettings(cursor.pos);
2980                         real_current_font = GetFont(cursor.par, cursor.pos);
2981                         if (pos == 0 && par->size() == 0 
2982                             && owner_->buffer()->params.getDocumentDirection() == LYX_DIR_RIGHT_TO_LEFT) {
2983                                 current_font.setDirection(LyXFont::RTL_DIR);
2984                                 real_current_font.setDirection(LyXFont::RTL_DIR);
2985                         }
2986                 }
2987
2988         /* get the cursor y position in text  */
2989         row = GetRow(par, pos, y);
2990         /* y is now the beginning of the cursor row */ 
2991         y += row->baseline;
2992         /* y is now the cursor baseline */ 
2993         cursor.y = y;
2994    
2995         /* now get the cursors x position */
2996         float x;
2997         float fill_separator, fill_hfill, fill_label_hfill;
2998         PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
2999
3000         LyXParagraph::size_type last = RowLast(row);
3001         if (row->pos > last)
3002                 cursor_vpos = 0;
3003         else if (pos <= last ) {
3004                 LyXDirection letter_direction =
3005                         row->par->getLetterDirection(pos);
3006                 LyXDirection font_direction =
3007                         real_current_font.getFontDirection();
3008                 if (letter_direction == font_direction || pos == 0)
3009                         cursor_vpos = (letter_direction == LYX_DIR_LEFT_TO_RIGHT)
3010                                 ? log2vis(pos) : log2vis(pos)+1;
3011                 else
3012                         cursor_vpos = (font_direction == LYX_DIR_LEFT_TO_RIGHT)
3013                                 ? log2vis(pos-1)+1 : log2vis(pos-1);
3014         } else
3015                 cursor_vpos = (row->par->getLetterDirection(last) == LYX_DIR_LEFT_TO_RIGHT)
3016                         ? log2vis(last)+1 : log2vis(last);
3017
3018         /* table stuff -- begin*/
3019         if (row->par->table) {
3020                 int cell = NumberOfCell(row->par, row->pos);
3021                 float x_old = x;
3022                 x += row->par->table->GetBeginningOfTextInCell(cell);
3023                 for (vpos = row->pos; vpos < cursor_vpos; ++vpos)  {
3024                         pos = vis2log(vpos);
3025                         if (row->par->IsNewline(pos)) {
3026                                 x = x_old + row->par->table->WidthOfColumn(cell);
3027                                 x_old = x;
3028                                 ++cell;
3029                                 x += row->par->table->GetBeginningOfTextInCell(cell);
3030                         } else {
3031                                 x += SingleWidth(row->par, pos);
3032                         }
3033                 }
3034         } else {
3035                 /* table stuff -- end*/
3036                 LyXParagraph::size_type main_body =
3037                         BeginningOfMainBody(row->par);
3038                 if (main_body > 0 &&
3039                     (main_body-1 > last || 
3040                      !row->par->IsLineSeparator(main_body-1)))
3041                         main_body = 0;
3042
3043                 for (vpos = row->pos; vpos < cursor_vpos; ++vpos)  {
3044                         pos = vis2log(vpos);
3045                         if (main_body > 0 && pos == main_body-1) {
3046                                 x += fill_label_hfill +
3047                                         GetFont(row->par, -2).stringWidth(
3048                                                     textclasslist.Style(parameters->textclass, row->par->GetLayout()).labelsep);
3049                                 if (row->par->IsLineSeparator(main_body-1))
3050                                         x -= SingleWidth(row->par, main_body-1);
3051                         }
3052       
3053                         x += SingleWidth(row->par, pos);
3054                         if (HfillExpansion(row, pos)) {
3055                                 if (pos >= main_body)
3056                                         x += fill_hfill;
3057                                 else 
3058                                         x += fill_label_hfill;
3059                         }
3060                         else if (pos >= main_body && row->par->IsSeparator(pos)) {
3061                                 x+= fill_separator;
3062                         }
3063                 }
3064         }
3065    
3066         cursor.x = int(x);
3067    
3068         cursor.x_fix = cursor.x;
3069         cursor.row = row;
3070 }
3071
3072
3073 void LyXText::SetCursorFromCoordinates(int x, long y) const
3074 {
3075         LyXCursor old_cursor = cursor;
3076    
3077         /* get the row first */ 
3078    
3079         Row * row = GetRowNearY(y);
3080    
3081         cursor.par = row->par;
3082    
3083         int column = GetColumnNearX(row, x);
3084         cursor.pos = row->pos + column;
3085         cursor.x = x;
3086         cursor.y = y + row->baseline;
3087    
3088         cursor.row = row;
3089     
3090         if (cursor.pos && 
3091             (cursor.pos == cursor.par->Last()
3092              || cursor.par->IsSeparator(cursor.pos)
3093              || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
3094                  && !cursor.par->IsSeparator(cursor.pos))
3095              || (cursor.par->table && cursor.par->IsNewline(cursor.pos))
3096                     )) {
3097                 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
3098                 real_current_font = GetFont(cursor.par, cursor.pos - 1);
3099         } else {
3100                 current_font = cursor.par->GetFontSettings(cursor.pos);
3101                 real_current_font = GetFont(cursor.par, cursor.pos);
3102         }
3103         DeleteEmptyParagraphMechanism(old_cursor);
3104 }
3105
3106
3107 void LyXText::CursorLeft() const
3108 {
3109         CursorLeftIntern();
3110         if (cursor.par->table) {
3111                 int cell = NumberOfCell(cursor.par, cursor.pos);
3112                 if (cursor.par->table->IsContRow(cell) &&
3113                     cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3114                         CursorUp();
3115                 }
3116         }
3117 }
3118
3119
3120 void LyXText::CursorLeftIntern() const
3121 {
3122         if (cursor.pos > 0) {
3123                 SetCursor(cursor.par, cursor.pos - 1);
3124         }
3125         else if (cursor.par->Previous()) {
3126                 SetCursor(cursor.par->Previous(), cursor.par->Previous()->Last());
3127         }
3128 }
3129
3130
3131 void LyXText::CursorRight() const
3132 {
3133         CursorRightIntern();
3134         if (cursor.par->table) {
3135                 int cell = NumberOfCell(cursor.par, cursor.pos);
3136                 if (cursor.par->table->IsContRow(cell) &&
3137                     cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3138                         CursorUp();
3139                 }
3140         }
3141 }
3142
3143
3144 void LyXText::CursorRightIntern() const
3145 {
3146         if (cursor.pos < cursor.par->Last()) {
3147                 SetCursor(cursor.par, cursor.pos + 1);
3148         }
3149         else if (cursor.par->Next()) {
3150                 SetCursor(cursor.par->Next(), 0);
3151         }
3152 }
3153
3154
3155 void LyXText::CursorUp() const
3156 {
3157         SetCursorFromCoordinates(cursor.x_fix, 
3158                                  cursor.y - cursor.row->baseline - 1);
3159         if (cursor.par->table) {
3160                 int cell = NumberOfCell(cursor.par, cursor.pos);
3161                 if (cursor.par->table->IsContRow(cell) &&
3162                     cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3163                         CursorUp();
3164                 }
3165         }
3166 }
3167
3168
3169 void LyXText::CursorDown() const
3170 {
3171         if (cursor.par->table &&
3172             cursor.par->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par, cursor.pos)) &&
3173             !cursor.par->next)
3174                 return;
3175         SetCursorFromCoordinates(cursor.x_fix, 
3176                                  cursor.y - cursor.row->baseline
3177                                  + cursor.row->height + 1);
3178         if (cursor.par->table) {
3179                 int cell = NumberOfCell(cursor.par, cursor.pos);
3180                 int cell_above = cursor.par->table->GetCellAbove(cell);
3181                 while(cursor.par->table &&
3182                       cursor.par->table->IsContRow(cell) &&
3183                       (cursor.par->table->CellHasContRow(cell_above)<0)) {
3184                     SetCursorFromCoordinates(cursor.x_fix, 
3185                                              cursor.y - cursor.row->baseline
3186                                              + cursor.row->height + 1);
3187                     if (cursor.par->table) {
3188                         cell = NumberOfCell(cursor.par, cursor.pos);
3189                         cell_above = cursor.par->table->GetCellAbove(cell);
3190                     }
3191                 }
3192         }
3193 }
3194
3195
3196 void LyXText::CursorUpParagraph() const
3197 {
3198         if (cursor.pos > 0) {
3199                 SetCursor(cursor.par, 0);
3200         }
3201         else if (cursor.par->Previous()) {
3202                 SetCursor(cursor.par->Previous(), 0);
3203         }
3204 }
3205
3206
3207 void LyXText::CursorDownParagraph() const
3208 {
3209         if (cursor.par->Next()) {
3210                 SetCursor(cursor.par->Next(), 0);
3211         } else {
3212                 SetCursor(cursor.par, cursor.par->Last());
3213         }
3214 }
3215
3216
3217
3218 void LyXText::DeleteEmptyParagraphMechanism(LyXCursor const & old_cursor) const
3219 {
3220         bool deleted = false;
3221         
3222         // this is the delete-empty-paragraph-mechanism.
3223         if (selection) return;
3224
3225 #ifdef FIX_DOUBLE_SPACE
3226         /* Ok I'll put some comments here about what is missing.
3227            I have fixed BackSpace (and thus Delete) to not delete
3228            double-spaces automagically. I have also changed Cut,
3229            Copy and Paste to hopefully do some sensible things.
3230            There are still some small problems that can lead to
3231            double spaces stored in the document file or space at
3232            the beginning of paragraphs. This happens if you have
3233            the cursor betwenn to spaces and then save. Or if you
3234            cut and paste and the selection have a space at the
3235            beginning and then save right after the paste. I am
3236            sure none of these are very hard to fix, but I will
3237            put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3238            that I can get some feedback. (Lgb)
3239         */
3240
3241         // If old_cursor.pos == 0 and old_cursor.pos(1) == LineSeparator
3242         // delete the LineSeparator.
3243         // MISSING
3244
3245         // If old_cursor.pos == 1 and old_cursor.pos(0) == LineSeparator
3246         // delete the LineSeparator.
3247         // MISSING
3248
3249         // If the pos around the old_cursor were spaces, delete one of them.
3250         if (!(old_cursor.par == cursor.par && old_cursor.pos == cursor.pos)
3251             && old_cursor.pos > 0
3252             && old_cursor.pos < old_cursor.par->Last()
3253             && old_cursor.par->IsLineSeparator(old_cursor.pos)
3254             && old_cursor.par->IsLineSeparator(old_cursor.pos - 1)) {
3255                 old_cursor.par->Erase(old_cursor.pos - 1);
3256                 RedoParagraphs(old_cursor, old_cursor.par->Next());
3257                 // or RedoDrawingOfParagraph(old_cursor);
3258                 // correct cursor
3259                 if (old_cursor.par == cursor.par &&
3260                     cursor.pos > old_cursor.pos)
3261                         SetCursor(cursor.par, cursor.pos - 1);
3262                 else
3263                         SetCursor(cursor.par, cursor.pos);
3264                 return;
3265         }
3266 #endif
3267         //
3268         // Paragraph should not be deleted if empty
3269         if ((textclasslist.Style(parameters->textclass,
3270                                  old_cursor.par->GetLayout())).keepempty)
3271                 return;
3272
3273         LyXCursor tmpcursor;
3274
3275         if (old_cursor.par != cursor.par) {
3276                 if ( (old_cursor.par->Last() == 0
3277                       || (old_cursor.par->Last() == 1
3278                           && (old_cursor.par->IsLineSeparator(0))))
3279                      && old_cursor.par->FirstPhysicalPar()
3280                      == old_cursor.par->LastPhysicalPar()) {
3281                         
3282                         // ok, we will delete anything
3283                         
3284                         // make sure that you do not delete any environments
3285                         if ((old_cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3286                              !(old_cursor.row->previous 
3287                                && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3288                              && !(old_cursor.row->next 
3289                                   && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3290                             || 
3291                             (old_cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE &&
3292                              ((old_cursor.row->previous 
3293                                && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3294                               || 
3295                               (old_cursor.row->next
3296                                && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3297                                     )) {
3298                                 status = LyXText::NEED_MORE_REFRESH;
3299                                 deleted = true;
3300                                 
3301                                 if (old_cursor.row->previous) {
3302                                         refresh_row = old_cursor.row->previous;
3303                                         refresh_y = old_cursor.y - old_cursor.row->baseline - refresh_row->height;
3304                                         tmpcursor = cursor;
3305                                         cursor = old_cursor; // that undo can restore the right cursor position
3306                                         LyXParagraph * endpar = old_cursor.par->next;
3307                                         if (endpar && endpar->GetDepth()) {
3308                                                 while (endpar && endpar->GetDepth()) {
3309                                                         endpar = endpar->LastPhysicalPar()->Next();
3310                                                 }
3311                                         }
3312                                         SetUndo(Undo::DELETE,
3313                                                 old_cursor.par->previous,
3314                                                 endpar);
3315                                         cursor = tmpcursor;
3316
3317                                         // delete old row
3318                                         RemoveRow(old_cursor.row);
3319                                         if (params->paragraph == old_cursor.par) {
3320                                                 params->paragraph = params->paragraph->next;
3321                                         }
3322                                         // delete old par
3323                                         delete old_cursor.par;
3324                                         
3325                                         /* Breakagain the next par. Needed
3326                                          * because of the parindent that
3327                                          * can occur or dissappear. The
3328                                          * next row can change its height,
3329                                          * if there is another layout before */
3330                                         if (refresh_row->next) {
3331                                                 BreakAgain(refresh_row->next);
3332                                                 UpdateCounters(refresh_row);
3333                                         }
3334                                         SetHeightOfRow(refresh_row);
3335                                 } else {
3336                                         refresh_row = old_cursor.row->next;
3337                                         refresh_y = old_cursor.y - old_cursor.row->baseline;
3338                                         
3339                                         tmpcursor = cursor;
3340                                         cursor = old_cursor; // that undo can restore the right cursor position
3341                                         LyXParagraph *endpar = old_cursor.par->next;
3342                                         if (endpar && endpar->GetDepth()) {
3343                                                 while (endpar && endpar->GetDepth()) {
3344                                                         endpar = endpar->LastPhysicalPar()->Next();
3345                                                 }
3346                                         }
3347                                         SetUndo(Undo::DELETE,
3348                                                 old_cursor.par->previous,
3349                                                 endpar);
3350                                         cursor = tmpcursor;
3351
3352                                         // delete old row
3353                                         RemoveRow(old_cursor.row);
3354                                         // delete old par
3355                                         if (params->paragraph == old_cursor.par) {
3356                                                 params->paragraph = params->paragraph->next;
3357                                         }
3358                                         delete old_cursor.par;
3359                                         
3360                                         /* Breakagain the next par. Needed
3361                                            because of the parindent that can
3362                                            occur or dissappear.
3363                                            The next row can change its height,
3364                                            if there is another layout before
3365                                         */ 
3366                                         if (refresh_row) {
3367                                                 BreakAgain(refresh_row);
3368                                                 UpdateCounters(refresh_row->previous);
3369                                         }
3370                                 }
3371                                 
3372                                 // correct cursor y
3373                                 SetCursor(cursor.par, cursor.pos);
3374                                 
3375                                 /* if (cursor.y > old_cursor.y)
3376                                    cursor.y -= old_cursor.row->height; */ 
3377          
3378                                 if (sel_cursor.par  == old_cursor.par
3379                                     && sel_cursor.pos == sel_cursor.pos) {
3380                                         // correct selection
3381                                         sel_cursor = cursor;
3382                                 }
3383                         }
3384                 }
3385                 if (!deleted) {
3386                         if (old_cursor.par->ClearParagraph()){
3387                                 RedoParagraphs(old_cursor, old_cursor.par->Next());
3388                                 // correct cursor y
3389                                 SetCursor(cursor.par, cursor.pos);
3390                                 sel_cursor = cursor;
3391                         }
3392                 }
3393         }
3394 }
3395
3396
3397 LyXParagraph * LyXText::GetParFromID(int id)
3398 {
3399         LyXParagraph * result = FirstParagraph();
3400         while (result && result->id() != id)
3401                 result = result->next;
3402         return result;
3403 }
3404
3405
3406 // undo functions
3407 bool LyXText::TextUndo()
3408 {
3409         // returns false if no undo possible
3410         Undo * undo = params->undostack.pop();
3411         if (undo) {
3412                 FinishUndo();
3413                 if (!undo_frozen)
3414                         params->redostack
3415                                 .push(CreateUndo(undo->kind, 
3416                                                  GetParFromID(undo->number_of_before_par),
3417                                                  GetParFromID(undo->number_of_behind_par)));
3418         }
3419         return TextHandleUndo(undo);
3420 }
3421
3422
3423 bool LyXText::TextRedo()
3424 {
3425         // returns false if no redo possible
3426         Undo * undo = params->redostack.pop();
3427         if (undo) {
3428                 FinishUndo();
3429                 if (!undo_frozen)
3430                         params->undostack
3431                                 .push(CreateUndo(undo->kind, 
3432                                                  GetParFromID(undo->number_of_before_par),
3433                                                  GetParFromID(undo->number_of_behind_par)));
3434         }
3435         return TextHandleUndo(undo);
3436 }
3437
3438
3439 bool LyXText::TextHandleUndo(Undo * undo)
3440 {
3441         // returns false if no undo possible
3442         bool result = false;
3443         if (undo) {
3444                 LyXParagraph * before =
3445                         GetParFromID(undo->number_of_before_par); 
3446                 LyXParagraph * behind =
3447                         GetParFromID(undo->number_of_behind_par); 
3448                 LyXParagraph * tmppar;
3449                 LyXParagraph * tmppar2;
3450                 LyXParagraph * tmppar3;
3451                 LyXParagraph * tmppar4;
3452                 LyXParagraph * endpar;
3453                 LyXParagraph * tmppar5;
3454     
3455                 // if there's no before take the beginning
3456                 // of the document for redoing
3457                 if (!before)
3458                         SetCursorIntern(FirstParagraph(), 0);
3459
3460                 // replace the paragraphs with the undo informations
3461
3462                 tmppar3 = undo->par;
3463                 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3464                 tmppar4 = tmppar3;
3465                 if (tmppar4){
3466                         while (tmppar4->next)
3467                                 tmppar4 = tmppar4->next;
3468                 } // get last undo par
3469     
3470                 // now remove the old text if there is any
3471                 if (before != behind || (!behind && !before)){
3472                         if (before)
3473                                 tmppar5 = before->next;
3474                         else
3475                                 tmppar5 = params->paragraph;
3476                         tmppar2 = tmppar3;
3477                         while (tmppar5 && tmppar5 != behind){
3478                                 tmppar = tmppar5;
3479                                 tmppar5 = tmppar5->next;
3480                                 // a memory optimization for edit: Only layout information
3481                                 // is stored in the undo. So restore the text informations.
3482                                 if (undo->kind == Undo::EDIT){
3483                                         tmppar2->text = tmppar->text;
3484                                         tmppar->text.clear();
3485                                         tmppar2 = tmppar2->next;
3486                                 }
3487                                 if ( currentrow && currentrow->par == tmppar )
3488                                         currentrow = currentrow -> previous;
3489                                 // Commenting out this might remove the error
3490                                 // reported by Purify, but it might also
3491                                 // introduce a memory leak. We need to
3492                                 // check this (Lgb)
3493                                 //delete tmppar;
3494                         }
3495                 }
3496     
3497                 // put the new stuff in the list if there is one
3498                 if (tmppar3){
3499                         if (before)
3500                                 before->next = tmppar3;
3501                         else
3502                                 params->paragraph = tmppar3;
3503                         tmppar3->previous = before;
3504                 }
3505                 else {
3506                         if (!before)
3507                                 params->paragraph = behind;
3508                 }
3509                 if (tmppar4) {
3510                         tmppar4->next = behind;
3511                         if (behind)
3512                                 behind->previous = tmppar4;
3513                 }
3514     
3515     
3516                 // Set the cursor for redoing
3517                 if (before){
3518                         SetCursorIntern(before->FirstSelfrowPar(), 0);
3519                         // check wether before points to a closed float and open it if necessary
3520                         if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3521                             && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3522                                 tmppar4 = before;
3523                                 while (tmppar4->previous && 
3524                                        tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3525                                         tmppar4 = tmppar4->previous;
3526                                 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3527                                         tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3528                                         tmppar4 = tmppar4->next;
3529                                 }
3530                         }
3531                 }
3532     
3533                 // open a cosed footnote at the end if necessary
3534                 if (behind && behind->previous && 
3535                     behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3536                     behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3537                         while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3538                                 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3539                                 behind = behind->next;
3540                         }
3541                 }
3542     
3543                 // calculate the endpar for redoing the paragraphs.
3544                 if (behind){
3545                         if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3546                                 endpar = behind->LastPhysicalPar()->Next();
3547                         else
3548                                 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3549                 }
3550                 else
3551                         endpar = behind;
3552     
3553                 tmppar = GetParFromID(undo->number_of_cursor_par);
3554                 RedoParagraphs(cursor, endpar); 
3555                 if (tmppar){
3556                         SetCursorIntern(tmppar, undo->cursor_pos);
3557                         UpdateCounters(cursor.row);
3558                 }
3559                 result = true;
3560                 delete undo;
3561         }
3562         FinishUndo();
3563         return result;
3564 }
3565
3566
3567 void LyXText::FinishUndo()
3568 {
3569         // makes sure the next operation will be stored
3570         undo_finished = True;
3571 }
3572
3573
3574 void LyXText::FreezeUndo()
3575 {
3576         // this is dangerous and for internal use only
3577         undo_frozen = True;
3578 }
3579
3580
3581 void LyXText::UnFreezeUndo()
3582 {
3583         // this is dangerous and for internal use only
3584         undo_frozen = false;
3585 }
3586
3587
3588 void LyXText::SetUndo(Undo::undo_kind kind, LyXParagraph const * before,
3589                       LyXParagraph const * behind) const
3590 {
3591         if (!undo_frozen)
3592                 params->undostack.push(CreateUndo(kind, before, behind));
3593         params->redostack.clear();
3594 }
3595
3596
3597 void LyXText::SetRedo(Undo::undo_kind kind, LyXParagraph const * before,
3598                       LyXParagraph const * behind)
3599 {
3600         params->redostack.push(CreateUndo(kind, before, behind));
3601 }
3602
3603
3604 Undo * LyXText::CreateUndo(Undo::undo_kind kind, LyXParagraph const * before,
3605                           LyXParagraph const * behind) const
3606 {
3607         int before_number = -1;
3608         int behind_number = -1;
3609         if (before)
3610                 before_number = before->id();
3611         if (behind)
3612                 behind_number = behind->id();
3613         // Undo::EDIT  and Undo::FINISH are
3614         // always finished. (no overlapping there)
3615         // overlapping only with insert and delete inside one paragraph: 
3616         // Nobody wants all removed  character
3617         // appear one by one when undoing. 
3618         // EDIT is special since only layout information, not the
3619         // contents of a paragaph are stored.
3620         if (!undo_finished && kind != Undo::EDIT && 
3621             kind != Undo::FINISH){
3622                 // check wether storing is needed
3623                 if (!params->undostack.empty() && 
3624                     params->undostack.top()->kind == kind &&
3625                     params->undostack.top()->number_of_before_par ==  before_number &&
3626                     params->undostack.top()->number_of_behind_par ==  behind_number ){
3627                         // no undo needed
3628                         return 0;
3629                 }
3630         }
3631         // create a new Undo
3632         LyXParagraph * undopar;
3633         LyXParagraph * tmppar;
3634         LyXParagraph * tmppar2;
3635
3636         LyXParagraph * start = 0;
3637         LyXParagraph * end = 0;
3638   
3639         if (before)
3640                 start = before->next;
3641         else
3642                 start = FirstParagraph();
3643         if (behind)
3644                 end = behind->previous;
3645         else {
3646                 end = FirstParagraph();
3647                 while (end->next)
3648                         end = end->next;
3649         }
3650
3651         if (start && end
3652             && start != end->next
3653             && (before != behind || (!before && !behind))) {
3654                 tmppar = start;
3655                 tmppar2 = tmppar->Clone();
3656                 tmppar2->id(tmppar->id());
3657
3658                 // a memory optimization: Just store the layout information
3659                 // when only edit
3660                 if (kind == Undo::EDIT){
3661                         tmppar2->text.clear();
3662                 }
3663
3664                 undopar = tmppar2;
3665   
3666                 while (tmppar != end && tmppar->next) {
3667                         tmppar = tmppar->next;
3668                         tmppar2->next = tmppar->Clone();
3669                         tmppar2->next->id(tmppar->id());
3670                         // a memory optimization: Just store the layout
3671                         // information when only edit
3672                         if (kind == Undo::EDIT){
3673                                 tmppar2->next->text.clear();
3674                         }
3675                         tmppar2->next->previous = tmppar2;
3676                         tmppar2 = tmppar2->next;
3677                 }
3678                 tmppar2->next = 0;
3679         } else
3680                 undopar = 0; // nothing to replace (undo of delete maybe)
3681   
3682         int cursor_par = cursor.par->ParFromPos(cursor.pos)->id();
3683         int cursor_pos =  cursor.par->PositionInParFromPos(cursor.pos);
3684
3685         Undo * undo = new Undo(kind, 
3686                                before_number, behind_number,  
3687                                cursor_par, cursor_pos, 
3688                                undopar);
3689   
3690         undo_finished = false;
3691         return undo;
3692 }
3693
3694
3695 void LyXText::SetCursorParUndo()
3696 {
3697         SetUndo(Undo::FINISH, 
3698                 cursor.par->ParFromPos(cursor.pos)->previous, 
3699                 cursor.par->ParFromPos(cursor.pos)->next); 
3700 }
3701
3702
3703 void LyXText::RemoveTableRow(LyXCursor * cur) const
3704 {
3705         int cell = -1;
3706         int cell_org = 0;
3707         int ocell = 0;
3708     
3709         // move to the previous row
3710         int cell_act = NumberOfCell(cur->par, cur->pos);
3711         if (cell < 0)
3712                 cell = cell_act;
3713         while (cur->pos && !cur->par->IsNewline(cur->pos - 1))
3714                 cur->pos--;
3715         while (cur->pos && 
3716                !cur->par->table->IsFirstCell(cell_act)) {
3717                 cur->pos--;
3718                 while (cur->pos && !cur->par->IsNewline(cur->pos - 1))
3719                         cur->pos--;
3720                 --cell;
3721                 --cell_act;
3722         }
3723         // now we have to pay attention if the actual table is the
3724         //   main row of TableContRows and if yes to delete all of them
3725         if (!cell_org)
3726                 cell_org = cell;
3727         do {
3728                 ocell = cell;
3729                 // delete up to the next row
3730                 while (cur->pos < cur->par->Last() && 
3731                        (cell_act == ocell
3732                         || !cur->par->table->IsFirstCell(cell_act))) {
3733                         while (cur->pos < cur->par->Last() &&
3734                                !cur->par->IsNewline(cur->pos))
3735                                 cur->par->Erase(cur->pos);
3736                         ++cell;
3737                         ++cell_act;
3738                         if (cur->pos < cur->par->Last())
3739                                 cur->par->Erase(cur->pos);
3740                 }
3741                 if (cur->pos && cur->pos == cur->par->Last()) {
3742                         cur->pos--;
3743                         cur->par->Erase(cur->pos); // no newline at very end!
3744                 }
3745         } while (((cell + 1) < cur->par->table->GetNumberOfCells()) &&
3746                  !cur->par->table->IsContRow(cell_org) &&
3747                  cur->par->table->IsContRow(cell));
3748         cur->par->table->DeleteRow(cell_org);
3749         return;
3750 }
3751
3752
3753 bool LyXText::IsEmptyTableCell() const
3754 {
3755         LyXParagraph::size_type pos = cursor.pos - 1;
3756         while (pos >= 0 && pos < cursor.par->Last()
3757                && !cursor.par->IsNewline(pos))
3758                 --pos;
3759         return cursor.par->IsNewline(pos + 1);
3760 }
3761
3762
3763 void LyXText::toggleAppendix(){
3764         LyXParagraph * par = cursor.par->FirstPhysicalPar();
3765         bool start = !par->start_of_appendix;
3766
3767         // ensure that we have only one start_of_appendix in this document
3768         LyXParagraph * tmp = FirstParagraph();
3769         for (; tmp; tmp = tmp->next)
3770                 tmp->start_of_appendix = 0;
3771         par->start_of_appendix = start;
3772
3773         // we can set the refreshing parameters now
3774         status = LyXText::NEED_MORE_REFRESH;
3775         refresh_y = 0;
3776         refresh_row = 0; // not needed for full update
3777         UpdateCounters(0);
3778         SetCursor(cursor.par, cursor.pos);
3779 }
3780