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