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