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