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