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