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