]> git.lyx.org Git - lyx.git/blob - src/text2.C
6515b58c7aef9fdf121a4a9ebebbf47c00046c52
[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.clear();
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.clear();
1493                         }
1494                         else {
1495                                 if (!layout->labelstring_appendix.empty())
1496                                         par->labelstring = layout->labelstring_appendix;
1497                                 else
1498                                         par->labelstring.clear();
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->IsDummy() && par->previous->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) ||
2814                         (par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE))) {
2815                         par = par->previous ;
2816                         if (par->IsDummy() &&
2817                             par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
2818                                 pos += par->last + 1;
2819                 }
2820                 if (par->previous) {
2821                         par = par->previous;
2822                 }
2823                 pos += par->last + 1;
2824         }
2825
2826         cursor.par = par;
2827         cursor.pos = pos;
2828
2829         /* get the cursor y position in text  */
2830         row = GetRow(par, pos, y);
2831         /* y is now the beginning of the cursor row */ 
2832         y += row->baseline;
2833         /* y is now the cursor baseline */ 
2834         cursor.y = y;
2835    
2836         /* now get the cursors x position */
2837    
2838         float x;
2839         float fill_separator, fill_hfill, fill_label_hfill;
2840         left_margin = LabelEnd(row);
2841         PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
2842         int main_body = BeginningOfMainBody(row->par);
2843       
2844         /* table stuff -- begin*/
2845         if (row->par->table) {
2846                 int cell = NumberOfCell(row->par, row->pos);
2847                 float x_old = x;
2848                 x += row->par->table->GetBeginningOfTextInCell(cell);
2849                 for (pos = row->pos; pos < cursor.pos; pos++)  {
2850                         if (row->par->IsNewline(pos)) {
2851                                 x = x_old + row->par->table->WidthOfColumn(cell);
2852                                 x_old = x;
2853                                 cell++;
2854                                 x += row->par->table->GetBeginningOfTextInCell(cell);
2855                         } else {
2856                                 x += SingleWidth(row->par, pos);
2857                         }
2858                 }
2859         } else
2860                 /* table stuff -- end*/
2861
2862                 for (pos = row->pos; pos < cursor.pos; pos++)  {
2863                         if (pos && pos == main_body
2864                             && !row->par->IsLineSeparator(pos - 1)) {
2865                                 x += GetFont(row->par, -2).stringWidth(
2866                                                     lyxstyle.Style(parameters->textclass, row->par->GetLayout())->labelsep);
2867                                 if (x < left_margin)
2868                                         x = left_margin;
2869                         }
2870       
2871                         x += SingleWidth(row->par, pos);
2872                         if (HfillExpansion(row, pos)) {
2873                                 if (pos >= main_body)
2874                                         x += fill_hfill;
2875                                 else 
2876                                         x += fill_label_hfill;
2877                         }
2878                         else if (pos >= main_body && row->par->IsSeparator(pos)) {
2879                                 x+= fill_separator;
2880                         }
2881       
2882                         if (pos + 1 == main_body
2883                             && row->par->IsLineSeparator(pos)) {
2884                                 x += GetFont(row->par, -2).stringWidth(
2885                                                     lyxstyle.Style(parameters->textclass, row->par->GetLayout())->labelsep);
2886                                 if (row->par->IsLineSeparator(pos))
2887                                         x-= SingleWidth(row->par, pos);
2888                                 if (x < left_margin)
2889                                         x = left_margin;
2890                         }
2891                 }
2892    
2893         cursor.x = int(x);
2894    
2895         cursor.x_fix = cursor.x;
2896         cursor.row = row;
2897    
2898         if (cursor.pos && 
2899             (cursor.pos == cursor.par->Last() || cursor.par->IsSeparator(cursor.pos)
2900              || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
2901                  && !cursor.par->IsSeparator(cursor.pos))
2902                     )) {
2903                 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
2904                 real_current_font = GetFont(cursor.par, cursor.pos - 1);
2905         } else {
2906                 current_font = cursor.par->GetFontSettings(cursor.pos);
2907                 real_current_font = GetFont(cursor.par, cursor.pos);
2908         }
2909 }
2910
2911
2912 void LyXText::SetCursorFromCoordinates(int x, long y)
2913 {
2914         Row *row;
2915         int column;
2916
2917         LyXCursor old_cursor;
2918    
2919         old_cursor = cursor;
2920    
2921         /* get the row first */ 
2922    
2923         row = GetRowNearY(y);
2924    
2925         cursor.par = row->par;
2926    
2927         column = GetColumnNearX(row, x);
2928         cursor.pos = row->pos + column;
2929         cursor.x = x;
2930         cursor.y = y + row->baseline;
2931    
2932         cursor.row = row;
2933     
2934         if (cursor.pos && 
2935             (cursor.pos == cursor.par->Last()
2936              || cursor.par->IsSeparator(cursor.pos)
2937              || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
2938                  && !cursor.par->IsSeparator(cursor.pos))
2939                     )) {
2940                 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
2941                 real_current_font = GetFont(cursor.par, cursor.pos - 1);
2942         } else {
2943                 current_font = cursor.par->GetFontSettings(cursor.pos);
2944                 real_current_font = GetFont(cursor.par, cursor.pos);
2945         }
2946         DeleteEmptyParagraphMechanism(old_cursor);
2947 }
2948
2949
2950 void LyXText::CursorLeft()
2951 {
2952         CursorLeftIntern();
2953         if (cursor.par->table) {
2954                 int cell = NumberOfCell(cursor.par, cursor.pos);
2955                 if (cursor.par->table->IsContRow(cell) &&
2956                     cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
2957                         CursorUp();
2958                 }
2959         }
2960 }
2961
2962
2963 void LyXText::CursorLeftIntern()
2964 {
2965         if (cursor.pos > 0) {
2966                 SetCursor(cursor.par, cursor.pos - 1);
2967         }
2968         else if (cursor.par->Previous()) {
2969                 SetCursor(cursor.par->Previous(), cursor.par->Previous()->Last());
2970         }
2971 }
2972
2973
2974 void LyXText::CursorRight()
2975 {
2976         CursorRightIntern();
2977         if (cursor.par->table) {
2978                 int cell = NumberOfCell(cursor.par, cursor.pos);
2979                 if (cursor.par->table->IsContRow(cell) &&
2980                     cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
2981                         CursorUp();
2982                 }
2983         }
2984 }
2985
2986
2987 void LyXText::CursorRightIntern()
2988 {
2989         if (cursor.pos < cursor.par->Last()) {
2990                 SetCursor(cursor.par, cursor.pos + 1);
2991         }
2992         else if (cursor.par->Next()) {
2993                 SetCursor(cursor.par->Next(), 0);
2994         }
2995 }
2996
2997
2998 void LyXText::CursorUp()
2999 {
3000         SetCursorFromCoordinates(cursor.x_fix, 
3001                                  cursor.y - cursor.row->baseline - 1);
3002         if (cursor.par->table) {
3003                 int cell = NumberOfCell(cursor.par, cursor.pos);
3004                 if (cursor.par->table->IsContRow(cell) &&
3005                     cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3006                         CursorUp();
3007                 }
3008         }
3009 }
3010
3011
3012 void LyXText::CursorDown()
3013 {
3014         if (cursor.par->table &&
3015             cursor.par->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par, cursor.pos)) &&
3016             !cursor.par->next)
3017                 return;
3018         SetCursorFromCoordinates(cursor.x_fix, 
3019                                  cursor.y - cursor.row->baseline
3020                                  + cursor.row->height + 1);
3021         if (cursor.par->table) {
3022                 int cell = NumberOfCell(cursor.par, cursor.pos);
3023                 int cell_above = cursor.par->table->GetCellAbove(cell);
3024                 while(cursor.par->table &&
3025                       cursor.par->table->IsContRow(cell) &&
3026                       (cursor.par->table->CellHasContRow(cell_above)<0)) {
3027                     SetCursorFromCoordinates(cursor.x_fix, 
3028                                              cursor.y - cursor.row->baseline
3029                                              + cursor.row->height + 1);
3030                     if (cursor.par->table) {
3031                         cell = NumberOfCell(cursor.par, cursor.pos);
3032                         cell_above = cursor.par->table->GetCellAbove(cell);
3033                     }
3034                 }
3035         }
3036 }
3037
3038
3039 void LyXText::CursorUpParagraph()
3040 {
3041         if (cursor.pos > 0) {
3042                 SetCursor(cursor.par, 0);
3043         }
3044         else if (cursor.par->Previous()) {
3045                 SetCursor(cursor.par->Previous(), 0);
3046         }
3047 }
3048
3049
3050 void LyXText::CursorDownParagraph()
3051 {
3052         if (cursor.par->Next()) {
3053                 SetCursor(cursor.par->Next(), 0);
3054         } else {
3055                 SetCursor(cursor.par,cursor.par->Last());
3056         }
3057 }
3058
3059
3060
3061 void LyXText::DeleteEmptyParagraphMechanism(LyXCursor old_cursor)
3062 {
3063     bool deleted = false;
3064         
3065     /* this is the delete-empty-paragraph-mechanism. */ 
3066     if (selection)
3067         return;
3068
3069     // Paragraph should not be deleted if empty
3070     if ((lyxstyle.Style(parameters->textclass,
3071                         old_cursor.par->GetLayout()))->keepempty)
3072         return;
3073
3074     LyXCursor tmpcursor;
3075
3076     if (old_cursor.par != cursor.par) {
3077         if ( (old_cursor.par->Last() == 0
3078               || (old_cursor.par->Last() == 1
3079                   && (old_cursor.par->IsLineSeparator(0))))
3080              && old_cursor.par->FirstPhysicalPar()
3081              == old_cursor.par->LastPhysicalPar()
3082              //&& (
3083              // impossible to insert your own \caption with
3084              // this set. made it impossible to use the
3085              // optional argument...
3086              // also empty pars in fig or tab never was removed(?)(Lgb)
3087              //lyxstyle.Style(parameters->textclass,
3088 //                                      old_cursor.par->GetLayout())->labeltype!=LABEL_SENSITIVE || 
3089              //     (old_cursor.par->footnoteflag == LyXParagraph::NO_FOOTNOTE
3090              //|| (old_cursor.par->footnotekind != LyXParagraph::FIG
3091              //   && old_cursor.par->footnotekind != LyXParagraph::TAB)))
3092              ) {
3093                         
3094             /* ok, we will delete anything */ 
3095                         
3096             // make sure that you do not delete any environments
3097             if ((old_cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3098                  !(old_cursor.row->previous 
3099                    && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3100                  && !(old_cursor.row->next 
3101                       && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3102                 || 
3103                 (old_cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE &&
3104                  ((old_cursor.row->previous 
3105                    && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3106                   || 
3107                   (old_cursor.row->next
3108                    && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3109                  )){
3110                 status = LyXText::NEED_MORE_REFRESH;
3111                 deleted = true;
3112                                 
3113                 if (old_cursor.row->previous) {
3114                     refresh_row = old_cursor.row->previous;
3115                     refresh_y = old_cursor.y - old_cursor.row->baseline - refresh_row->height;
3116                     tmpcursor = cursor;
3117                     cursor = old_cursor; // that undo can restore the right cursor position
3118                     LyXParagraph *endpar = old_cursor.par->next;
3119                     if (endpar && endpar->GetDepth()) {
3120                         while (endpar && endpar->GetDepth()) {
3121                             endpar = endpar->LastPhysicalPar()->Next();
3122                         }
3123                     }
3124                     SetUndo(Undo::DELETE,
3125                             old_cursor.par->previous,
3126                             endpar);
3127                     cursor = tmpcursor;
3128
3129                     /* delete old row */ 
3130                     RemoveRow(old_cursor.row);
3131                     if (params->paragraph == old_cursor.par) {
3132                         params->paragraph = params->paragraph->next;
3133                     }
3134                     /* delete old par */ 
3135                     delete old_cursor.par;
3136                                         
3137                     /* Breakagain the next par. Needed
3138                      * because of the parindent that
3139                      * can occur or dissappear. The
3140                      * next row can change its height,
3141                      * if there is another layout before */
3142                     if (refresh_row->next) {
3143                         BreakAgain(refresh_row->next);
3144                         UpdateCounters(refresh_row);
3145                     }
3146                     SetHeightOfRow(refresh_row);
3147                 }
3148                 else {
3149                     refresh_row = old_cursor.row->next;
3150                     refresh_y = old_cursor.y - old_cursor.row->baseline;
3151                                         
3152                     tmpcursor = cursor;
3153                     cursor = old_cursor; // that undo can restore the right cursor position
3154                     LyXParagraph *endpar = old_cursor.par->next;
3155                     if (endpar && endpar->GetDepth()) {
3156                         while (endpar && endpar->GetDepth()) {
3157                             endpar = endpar->LastPhysicalPar()->Next();
3158                         }
3159                     }
3160                     SetUndo(Undo::DELETE,
3161                             old_cursor.par->previous,
3162                             endpar);
3163                     cursor = tmpcursor;
3164
3165                     /* delete old row */ 
3166                     RemoveRow(old_cursor.row);
3167                     /* delete old par */ 
3168                     if (params->paragraph == old_cursor.par) {
3169                         params->paragraph = params->paragraph->next;
3170                     }
3171                     delete old_cursor.par;
3172                                         
3173                     /* Breakagain the next par. Needed because of
3174                      * the parindent that can occur or dissappear.
3175                      * The next row can change its height, if there
3176                      * is another layout before */ 
3177                     if (refresh_row) {
3178                         BreakAgain(refresh_row);
3179                         UpdateCounters(refresh_row->previous);
3180                     }
3181                 }
3182                                 
3183                                 /* correct cursor y */
3184                 SetCursor(cursor.par, cursor.pos);
3185                      
3186                                 /* if (cursor.y > old_cursor.y)
3187                                    cursor.y -= old_cursor.row->height; */ 
3188          
3189                 if (sel_cursor.par  == old_cursor.par
3190                     && sel_cursor.pos == sel_cursor.pos) {
3191                     /* correct selection*/ 
3192                     sel_cursor = cursor;
3193                 }
3194             }
3195        
3196         }
3197         if (!deleted){
3198             if (old_cursor.par->ClearParagraph()){
3199                 RedoParagraphs(old_cursor, old_cursor.par->Next());
3200                                 /* correct cursor y */
3201                 SetCursor(cursor.par, cursor.pos);
3202                 sel_cursor = cursor;
3203             }
3204         }
3205     } else if (cursor.par->table && (cursor.row != old_cursor.row)) {
3206         int cell = NumberOfCell(old_cursor.par, old_cursor.pos);
3207         if (old_cursor.par->table->IsContRow(cell) &&
3208             IsEmptyTableRow(&old_cursor)) {
3209             RemoveTableRow(&old_cursor);
3210             RedoParagraph();
3211         }
3212     }
3213 }
3214
3215
3216 LyXParagraph* LyXText::GetParFromID(int id)
3217 {
3218         LyXParagraph* result = FirstParagraph();
3219         while (result && result->GetID() != id)
3220                 result = result->next;
3221         return result;
3222 }
3223
3224
3225 // undo functions
3226 bool  LyXText::TextUndo()
3227 { // returns false if no undo possible
3228         Undo *undo = params->undostack.Pop();
3229         if (undo){
3230                 FinishUndo();
3231                 if (!undo_frozen)
3232                         params->redostack.Push(CreateUndo(undo->kind, 
3233                                                           GetParFromID(undo->number_of_before_par),
3234                                                           GetParFromID(undo->number_of_behind_par)));
3235         }
3236         return TextHandleUndo(undo);
3237 }
3238
3239
3240 bool LyXText::TextRedo()
3241 { // returns false if no redo possible
3242         Undo *undo = params->redostack.Pop();
3243         if (undo){
3244                 FinishUndo();
3245                 if (!undo_frozen)
3246                         params->undostack.Push(CreateUndo(undo->kind, 
3247                                                           GetParFromID(undo->number_of_before_par),
3248                                                           GetParFromID(undo->number_of_behind_par)));
3249         }
3250         return TextHandleUndo(undo);
3251 }
3252
3253
3254 bool LyXText::TextHandleUndo(Undo* undo){ // returns false if no undo possible
3255         bool result = false;
3256         if (undo){
3257                 LyXParagraph* before = GetParFromID(undo->number_of_before_par); 
3258                 LyXParagraph* behind = GetParFromID(undo->number_of_behind_par); 
3259                 LyXParagraph* tmppar;
3260                 LyXParagraph* tmppar2;
3261                 LyXParagraph* tmppar3;
3262                 LyXParagraph* tmppar4;
3263                 LyXParagraph* endpar;
3264                 LyXParagraph* tmppar5;
3265     
3266                 /*
3267                   if (before){
3268                   before->text[before->last] = 0;
3269                   printf("before: %s\n", before->text);
3270                   }
3271                   if (behind){
3272                   behind->text[behind->last] = 0;
3273                   printf("behind: %s\n", behind->text);
3274                   }
3275                   */ 
3276
3277                 // if there's no before take the beginning of the document for redoing
3278                 if (!before)
3279                         SetCursorIntern(FirstParagraph(), 0);
3280
3281                 // replace the paragraphs with the undo informations
3282
3283                 tmppar3 = undo->par;
3284                 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3285                 tmppar4 = tmppar3;
3286                 if (tmppar4){
3287                         while (tmppar4->next)
3288                                 tmppar4 = tmppar4->next;
3289                 } // get last undo par
3290     
3291                 // now remove the old text if there is any
3292                 if (before != behind || (!behind && !before)){
3293                         if (before)
3294                                 tmppar5 = before->next;
3295                         else
3296                                 tmppar5 = params->paragraph;
3297                         tmppar2 = tmppar3;
3298                         while (tmppar5 && tmppar5 != behind){
3299                                 tmppar = tmppar5;
3300                                 tmppar5 = tmppar5->next;
3301                                 // a memory optimization for edit: Only layout information
3302                                 // is stored in the undo. So restore the text informations.
3303                                 if (undo->kind == Undo::EDIT){
3304                                         tmppar2->text = tmppar->text;
3305                                         tmppar->text = 0;
3306                                         tmppar2 = tmppar2->next;
3307                                 }
3308                                 if ( currentrow && currentrow->par == tmppar )
3309                                         currentrow = currentrow -> previous;
3310                                 delete tmppar;
3311                         }
3312                 }
3313     
3314                 // put the new stuff in the list if there is one
3315                 if (tmppar3){
3316                         if (before)
3317                                 before->next = tmppar3;
3318                         else
3319                                 params->paragraph = tmppar3;
3320                         tmppar3->previous = before;
3321                 }
3322                 else {
3323                         if (!before)
3324                                 params->paragraph = behind;
3325                 }
3326                 if (tmppar4) {
3327                         tmppar4->next = behind;
3328                         if (behind)
3329                                 behind->previous = tmppar4;
3330                 }
3331     
3332     
3333                 // Set the cursor for redoing
3334                 if (before){
3335                         SetCursorIntern(before->FirstSelfrowPar(), 0);
3336                         // check wether before points to a closed float and open it if necessary
3337                         if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3338                             && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3339                                 tmppar4 =before;
3340                                 while (tmppar4->previous && 
3341                                        tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3342                                         tmppar4 = tmppar4->previous;
3343                                 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3344                                         tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3345                                         tmppar4 = tmppar4->next;
3346                                 }
3347                         }
3348                 }
3349     
3350                 // open a cosed footnote at the end if necessary
3351                 if (behind && behind->previous && 
3352                     behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3353                     behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3354                         while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3355                                 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3356                                 behind = behind->next;
3357                         }
3358                 }
3359     
3360                 // calculate the endpar for redoing the paragraphs.
3361                 if (behind){
3362                         if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3363                                 endpar = behind->LastPhysicalPar()->Next();
3364                         else
3365                                 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3366                 }
3367                 else
3368                         endpar = behind;
3369     
3370                 tmppar = GetParFromID(undo->number_of_cursor_par);
3371                 RedoParagraphs(cursor, endpar); 
3372                 if (tmppar){
3373                         SetCursorIntern(tmppar, undo->cursor_pos);
3374                         UpdateCounters(cursor.row);
3375                 }
3376                 result = true;
3377                 delete undo;
3378         }
3379         FinishUndo();
3380         return result;
3381 }
3382
3383
3384 void LyXText::FinishUndo()
3385 { // makes sure the next operation will be stored
3386         undo_finished = True;
3387 }
3388
3389
3390 void LyXText::FreezeUndo()
3391 { // this is dangerous and for internal use only
3392         undo_frozen = True;
3393 }
3394
3395
3396 void LyXText::UnFreezeUndo()
3397 { // this is dangerous and for internal use only
3398         undo_frozen = false;
3399 }
3400
3401
3402 void LyXText::SetUndo(Undo::undo_kind kind, LyXParagraph *before, LyXParagraph *behind)
3403 {
3404         if (!undo_frozen)
3405                 params->undostack.Push(CreateUndo(kind, before, behind));
3406         params->redostack.Clear();
3407 }
3408
3409
3410 void LyXText::SetRedo(Undo::undo_kind kind, LyXParagraph *before, LyXParagraph *behind)
3411 {
3412         params->redostack.Push(CreateUndo(kind, before, behind));
3413 }
3414
3415
3416 Undo* LyXText::CreateUndo(Undo::undo_kind kind, LyXParagraph *before,
3417                           LyXParagraph *behind)
3418 {
3419         int before_number = -1;
3420         int behind_number = -1;
3421         if (before)
3422                 before_number = before->GetID();
3423         if (behind)
3424                 behind_number = behind->GetID();
3425         // Undo::EDIT  and Undo::FINISH are
3426         // always finished. (no overlapping there)
3427         // overlapping only with insert and delete inside one paragraph: 
3428         // Nobody wants all removed  character
3429         // appear one by one when undoing. 
3430         // EDIT is special since only layout information, not the
3431         // contents of a paragaph are stored.
3432         if (!undo_finished && kind != Undo::EDIT && 
3433             kind != Undo::FINISH){
3434                 // check wether storing is needed
3435                 if (params->undostack.Top() && 
3436                     params->undostack.Top()->kind == kind &&
3437                     params->undostack.Top()->number_of_before_par ==  before_number &&
3438                     params->undostack.Top()->number_of_behind_par ==  behind_number ){
3439                         // no undo needed
3440                         return 0;
3441                 }
3442         }
3443         // create a new Undo
3444         LyXParagraph* undopar;
3445         LyXParagraph* tmppar;
3446         LyXParagraph *tmppar2;
3447
3448         LyXParagraph* start = 0;
3449         LyXParagraph* end = 0;
3450   
3451         if (before)
3452                 start = before->next;
3453         else
3454                 start = FirstParagraph();
3455         if (behind)
3456                 end = behind->previous;
3457         else {
3458                 end = FirstParagraph();
3459                 while (end->next)
3460                         end = end->next;
3461         }
3462
3463         if (start && end && start != end->next && (before != behind || (!before && !behind))) {
3464                 tmppar = start;
3465                 tmppar2 = tmppar->Clone();
3466                 tmppar2->SetID(tmppar->GetID());
3467
3468                 // a memory optimization: Just store the layout information when only edit
3469                 if (kind == Undo::EDIT){
3470                         if (tmppar2->text)
3471                                 delete[] tmppar2->text;
3472                         tmppar2->text = 0;
3473                 }
3474
3475                 undopar = tmppar2;
3476   
3477                 while (tmppar != end && tmppar->next) {
3478                         tmppar = tmppar->next;
3479                         tmppar2->next = tmppar->Clone();
3480                         tmppar2->next->SetID(tmppar->GetID());
3481                         // a memory optimization: Just store the layout information when only edit
3482                         if (kind == Undo::EDIT){
3483                                 if (tmppar2->next->text)
3484                                         delete[] tmppar2->next->text;
3485                                 tmppar2->next->text = 0;
3486                         }
3487                         tmppar2->next->previous = tmppar2;
3488                         tmppar2=tmppar2->next;
3489                 }
3490                 tmppar2->next = 0;
3491         }
3492         else
3493                 undopar = 0; // nothing to replace (undo of delete maybe)
3494   
3495         int cursor_par = cursor.par->ParFromPos(cursor.pos)->GetID();
3496         int cursor_pos =  cursor.par->PositionInParFromPos(cursor.pos);
3497
3498         Undo* undo = new Undo(kind, 
3499                               before_number, behind_number,  
3500                               cursor_par, cursor_pos, 
3501                               undopar);
3502   
3503         undo_finished = false;
3504         return undo;
3505 }
3506
3507
3508 void LyXText::SetCursorParUndo()
3509 {
3510         SetUndo(Undo::FINISH, 
3511                 cursor.par->ParFromPos(cursor.pos)->previous, 
3512                 cursor.par->ParFromPos(cursor.pos)->next); 
3513 }
3514
3515 void LyXText::RemoveTableRow(LyXCursor *cursor)
3516 {
3517     int
3518         cell_act,
3519         cell = -1,
3520         cell_org = 0,
3521         ocell = 0;
3522     
3523     /* move to the previous row */
3524     cell_act = NumberOfCell(cursor->par, cursor->pos);
3525     if (cell < 0)
3526         cell = cell_act;
3527     while (cursor->pos && !cursor->par->IsNewline(cursor->pos-1))
3528         cursor->pos--;
3529     while (cursor->pos && 
3530            !cursor->par->table->IsFirstCell(cell_act)){
3531         cursor->pos--;
3532         while (cursor->pos && !cursor->par->IsNewline(cursor->pos-1))
3533             cursor->pos--;
3534             cell--;
3535             cell_act--;
3536     }
3537     /* now we have to pay attention if the actual table is the
3538        main row of TableContRows and if yes to delete all of them */
3539     if (!cell_org)
3540         cell_org = cell;
3541     do {
3542         ocell = cell;
3543         /* delete up to the next row */
3544         while (cursor->pos < cursor->par->Last() && 
3545                (cell_act == ocell
3546                 || !cursor->par->table->IsFirstCell(cell_act))){
3547             while (cursor->pos < cursor->par->Last() &&
3548                    !cursor->par->IsNewline(cursor->pos))
3549                 cursor->par->Erase(cursor->pos);
3550             cell++;
3551             cell_act++;
3552             if (cursor->pos < cursor->par->Last())
3553                 cursor->par-> Erase(cursor->pos);
3554         }
3555         if (cursor->pos && cursor->pos == cursor->par->Last()){
3556             cursor->pos--;
3557             cursor->par->Erase(cursor->pos); // no newline at the very end!
3558         }
3559     } while (((cell+1) < cursor->par->table->GetNumberOfCells()) &&
3560              !cursor->par->table->IsContRow(cell_org) &&
3561              cursor->par->table->IsContRow(cell));
3562     cursor->par->table->DeleteRow(cell_org);
3563     return;
3564 }
3565
3566 bool LyXText::IsEmptyTableRow(LyXCursor *old_cursor)
3567 {
3568         if (!old_cursor->par->table)
3569                 return false;
3570 #ifdef I_DONT_KNOW_IF_I_SHOULD_DO_THIS
3571         int
3572                 pos = old_cursor->pos,
3573                 cell = NumberOfCell(old_cursor->par, pos);
3574
3575         // search first charater of this table row
3576         while (pos && !old_cursor->par->table->IsFirstCell(cell)) {
3577                 pos--;
3578                 while (pos && !old_cursor->par->IsNewline(pos-1))
3579                         pos--;
3580                 cell--;
3581         }
3582         if (!old_cursor->par->IsNewline(pos))
3583                 return false;
3584         cell++;
3585         pos++;
3586         while ((pos < old_cursor->par->Last()) &&
3587                !old_cursor->par->table->IsFirstCell(cell)) {
3588                 if (!old_cursor->par->IsNewline(pos))
3589                         return false;
3590                 pos++;
3591                 cell++;
3592         }
3593         return true;
3594 #endif
3595         return false;
3596 }
3597
3598
3599 bool LyXText::IsEmptyTableCell()
3600 {
3601         int pos = cursor.pos - 1;
3602         
3603         while ((pos>=0) && (pos < cursor.par->Last()) &&
3604                !cursor.par->IsNewline(pos))
3605                 pos--;
3606         return cursor.par->IsNewline(pos+1);
3607 }
3608
3609 void LyXText::toggleAppendix(){
3610   LyXParagraph* par = cursor.par->FirstPhysicalPar();
3611   bool start = !par->start_of_appendix;
3612
3613   /* ensure that we have only one start_of_appendix in this document */
3614   LyXParagraph* tmp = FirstParagraph();
3615   for (;tmp;tmp=tmp->next)
3616     tmp->start_of_appendix = 0;
3617   par->start_of_appendix = start;
3618
3619   /* we can set the refreshing parameters now */
3620   status = LyXText::NEED_MORE_REFRESH;
3621   refresh_y = 0;
3622   refresh_row = 0; // not needed for full update
3623   UpdateCounters(0);
3624   SetCursor(cursor.par, cursor.pos);
3625 }
3626