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