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