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