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