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