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