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