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