]> git.lyx.org Git - lyx.git/blob - src/text2.C
add boost
[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 #ifndef NO_PEXTRA
1558 void LyXText::SetParagraphExtraOpt(BufferView * bview, int type,
1559                                    string const & width,
1560                                    string const & widthp,
1561                                    int alignment, bool hfill,
1562                                    bool start_minipage)
1563 {
1564         LyXCursor tmpcursor = cursor;
1565         LyXParagraph * tmppar;
1566         if (!selection) {
1567                 sel_start_cursor = cursor;
1568                 sel_end_cursor = cursor;
1569         }
1570
1571         // make sure that the depth behind the selection are restored, too
1572 #ifndef NEW_INSETS
1573         LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->next();
1574 #else
1575         LyXParagraph * endpar = sel_end_cursor.par()->next();
1576 #endif
1577         LyXParagraph * undoendpar = endpar;
1578
1579         if (endpar && endpar->GetDepth()) {
1580                 while (endpar && endpar->GetDepth()) {
1581 #ifndef NEW_INSETS
1582                         endpar = endpar->LastPhysicalPar()->next();
1583 #else
1584                         endpar = endpar->next();
1585 #endif
1586                         undoendpar = endpar;
1587                 }
1588         }
1589         else if (endpar) {
1590                 endpar = endpar->next(); // because of parindents etc.
1591         }
1592    
1593         SetUndo(bview->buffer(), Undo::EDIT,
1594 #ifndef NEW_INSETS
1595                 sel_start_cursor
1596                 .par()->ParFromPos(sel_start_cursor.pos())->previous_,
1597 #else
1598                 sel_start_cursor.par()->previous(),
1599 #endif
1600                 undoendpar);
1601         
1602         tmppar = sel_end_cursor.par();
1603 #ifndef NEW_INSETS
1604         while(tmppar != sel_start_cursor.par()->FirstPhysicalPar()->previous()) {
1605                 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1606 #else
1607         while(tmppar != sel_start_cursor.par()->previous()) {
1608                 SetCursor(bview, tmppar, 0);
1609 #endif
1610                 status = LyXText::NEED_MORE_REFRESH;
1611                 refresh_row = cursor.row();
1612                 refresh_y = cursor.y() - cursor.row()->baseline();
1613 #ifndef NEW_INSETS
1614                 if (cursor.par()->footnoteflag ==
1615                     sel_start_cursor.par()->footnoteflag) {
1616 #endif
1617 #ifndef NO_PEXTRA
1618                         if (type == LyXParagraph::PEXTRA_NONE) {
1619                                 if (cursor.par()->params.pextraType() != LyXParagraph::PEXTRA_NONE) {
1620                                         cursor.par()->UnsetPExtraType(bview->buffer()->params);
1621                                         cursor.par()->params.pextraType(LyXParagraph::PEXTRA_NONE);
1622                                 }
1623                         } else {
1624                                 cursor.par()->SetPExtraType(bview->buffer()->params,
1625                                                           type, width, widthp);
1626                                 cursor.par()->params.pextraHfill(hfill);
1627                                 cursor.par()->params.pextraStartMinipage(start_minipage);
1628                                 cursor.par()->params.pextraAlignment(alignment);
1629                         }
1630 #endif
1631 #ifndef NEW_INSETS
1632                 }
1633                 tmppar = cursor.par()->FirstPhysicalPar()->previous();
1634 #else
1635                 tmppar = cursor.par()->previous();
1636 #endif
1637         }
1638         RedoParagraphs(bview, sel_start_cursor, endpar);
1639         ClearSelection(bview);
1640         SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1641         sel_cursor = cursor;
1642         SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1643         SetSelection(bview);
1644         SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1645 }
1646 #endif
1647         
1648
1649 char loweralphaCounter(int n)
1650 {
1651         if (n < 1 || n > 26)
1652                 return '?';
1653         else
1654                 return 'a' + n - 1;
1655 }
1656
1657
1658 static inline
1659 char alphaCounter(int n)
1660 {
1661         if (n < 1 || n > 26)
1662                 return '?';
1663         else
1664                 return 'A' + n - 1;
1665 }
1666
1667
1668 static inline
1669 char hebrewCounter(int n)
1670 {
1671         static const char hebrew[22] = {
1672                 'à', 'á', 'â', 'ã', 'ä', 'Ã¥', 'æ', 'ç', 'è',
1673                 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö', 
1674                 '÷', 'ø', 'ù', 'ú'
1675         };
1676         if (n < 1 || n > 22)
1677                 return '?';
1678         else
1679                 return hebrew[n-1];
1680 }
1681
1682
1683 static inline
1684 string const romanCounter(int n)
1685 {
1686         static char const * roman[20] = {
1687                 "i",   "ii",  "iii", "iv", "v",
1688                 "vi",  "vii", "viii", "ix", "x",
1689                 "xi",  "xii", "xiii", "xiv", "xv",
1690                 "xvi", "xvii", "xviii", "xix", "xx"
1691         };
1692         if (n < 1 || n > 20)
1693                 return "??";
1694         else
1695                 return roman[n-1];
1696 }
1697
1698
1699 // set the counter of a paragraph. This includes the labels
1700 void LyXText::SetCounter(Buffer const * buf, LyXParagraph * par) const
1701 {
1702 #ifndef NEW_INSETS
1703         // this is only relevant for the beginning of paragraph
1704         par = par->FirstPhysicalPar();
1705 #endif
1706         LyXLayout const & layout =
1707                 textclasslist.Style(buf->params.textclass, 
1708                                     par->GetLayout());
1709
1710         LyXTextClass const & textclass =
1711                 textclasslist.TextClass(buf->params.textclass);
1712
1713         /* copy the prev-counters to this one, unless this is the start of a 
1714            footnote or of a bibliography or the very first paragraph */
1715         if (par->previous()
1716 #ifndef NEW_INSETS
1717             && !(par->previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE 
1718                     && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1719                     && par->footnotekind == LyXParagraph::FOOTNOTE)
1720 #endif
1721             && !(textclasslist.Style(buf->params.textclass,
1722                                 par->previous()->GetLayout()
1723                                 ).labeltype != LABEL_BIBLIO
1724                  && layout.labeltype == LABEL_BIBLIO)) {
1725                 for (int i = 0; i < 10; ++i) {
1726                         par->setCounter(i, par->previous()->GetFirstCounter(i));
1727                 }
1728 #ifndef NEW_INSETS
1729                 par->params.appendix(par->previous()->FirstPhysicalPar()->params.appendix());
1730 #else
1731                 par->params.appendix(par->previous()->params.appendix());
1732 #endif
1733                 if (!par->params.appendix() && par->params.startOfAppendix()) {
1734                   par->params.appendix(true);
1735                   for (int i = 0; i < 10; ++i) {
1736                     par->setCounter(i, 0);
1737                   }  
1738                 }
1739 #ifndef NEW_INSETS
1740                 par->enumdepth = par->previous()->FirstPhysicalPar()->enumdepth;
1741                 par->itemdepth = par->previous()->FirstPhysicalPar()->itemdepth;
1742 #else
1743                 par->enumdepth = par->previous()->enumdepth;
1744                 par->itemdepth = par->previous()->itemdepth;
1745 #endif
1746         } else {
1747                 for (int i = 0; i < 10; ++i) {
1748                         par->setCounter(i, 0);
1749                 }  
1750                 par->params.appendix(par->params.startOfAppendix());
1751                 par->enumdepth = 0;
1752                 par->itemdepth = 0;
1753         }
1754
1755 #ifndef NEW_INSETS
1756         // if this is an open marginnote and this is the first
1757         // entry in the marginnote and the enclosing
1758         // environment is an enum/item then correct for the
1759         // LaTeX behaviour (ARRae)
1760         if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1761            && par->footnotekind == LyXParagraph::MARGIN
1762            && par->previous()
1763            && par->previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1764            && (par->PreviousBeforeFootnote()
1765                && textclasslist.Style(buf->params.textclass,
1766                                  par->PreviousBeforeFootnote()->GetLayout()
1767                                  ).labeltype >= LABEL_COUNTER_ENUMI)) {
1768                 // Any itemize or enumerate environment in a marginnote
1769                 // that is embedded in an itemize or enumerate
1770                 // paragraph is seen by LaTeX as being at a deeper
1771                 // level within that enclosing itemization/enumeration
1772                 // even if there is a "standard" layout at the start of
1773                 // the marginnote.
1774                 par->enumdepth++;
1775                 par->itemdepth++;
1776         }
1777 #endif
1778         /* Maybe we have to increment the enumeration depth.
1779          * BUT, enumeration in a footnote is considered in isolation from its
1780          *      surrounding paragraph so don't increment if this is the
1781          *      first line of the footnote
1782          * AND, bibliographies can't have their depth changed ie. they
1783          *      are always of depth 0
1784          */
1785         if (par->previous()
1786             && par->previous()->GetDepth() < par->GetDepth()
1787             && textclasslist.Style(buf->params.textclass,
1788                               par->previous()->GetLayout()
1789                              ).labeltype == LABEL_COUNTER_ENUMI
1790             && par->enumdepth < 3
1791 #ifndef NEW_INSETS
1792             && !(par->previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE 
1793                     && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1794                     && par->footnotekind == LyXParagraph::FOOTNOTE)
1795 #endif
1796             && layout.labeltype != LABEL_BIBLIO) {
1797                 par->enumdepth++;
1798         }
1799
1800         /* Maybe we have to decrement the enumeration depth, see note above */
1801         if (par->previous()
1802             && par->previous()->GetDepth() > par->GetDepth()
1803 #ifndef NEW_INSETS
1804             && !(par->previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1805                     && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1806                     && par->footnotekind == LyXParagraph::FOOTNOTE)
1807 #endif
1808             && layout.labeltype != LABEL_BIBLIO) {
1809                 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1810                 par->setCounter(6 + par->enumdepth,
1811                         par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1812                 /* reset the counters.
1813                  * A depth change is like a breaking layout
1814                  */
1815                 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1816                         par->setCounter(i, 0);
1817         }
1818    
1819         if (!par->params.labelString().empty()) {
1820                 par->params.labelString(string());
1821         }
1822    
1823         if (layout.margintype == MARGIN_MANUAL) {
1824                 if (par->params.labelWidthString().empty()) {
1825                         par->SetLabelWidthString(layout.labelstring());
1826                 }
1827         } else {
1828                 par->SetLabelWidthString(string());
1829         }
1830    
1831         /* is it a layout that has an automatic label ? */ 
1832         if (layout.labeltype >=  LABEL_COUNTER_CHAPTER) {
1833       
1834                 int i = layout.labeltype - LABEL_COUNTER_CHAPTER;
1835                 if (i >= 0 && i<= buf->params.secnumdepth) {
1836                         par->incCounter(i);     // increment the counter  
1837          
1838                         // Is there a label? Useful for Chapter layout
1839                         if (!par->params.appendix()) {
1840                                 if (!layout.labelstring().empty())
1841                                         par->params.labelString(layout.labelstring());
1842                                 else
1843                                         par->params.labelString(string());
1844                         } else {
1845                                 if (!layout.labelstring_appendix().empty())
1846                                         par->params.labelString(layout.labelstring_appendix());
1847                                 else
1848                                         par->params.labelString(string());
1849                         }
1850
1851                         std::ostringstream s;
1852
1853                         if (!par->params.appendix()) {
1854                                 switch (2 * LABEL_COUNTER_CHAPTER -
1855                                         textclass.maxcounter() + i) {
1856                                 case LABEL_COUNTER_CHAPTER:
1857                                         s << par->getCounter(i);
1858                                         break;
1859                                 case LABEL_COUNTER_SECTION:
1860                                         s << par->getCounter(i - 1) << '.'
1861                                            << par->getCounter(i);
1862                                         break;
1863                                 case LABEL_COUNTER_SUBSECTION:
1864                                         s << par->getCounter(i - 2) << '.'
1865                                           << par->getCounter(i - 1) << '.'
1866                                           << par->getCounter(i);
1867                                         break;
1868                                 case LABEL_COUNTER_SUBSUBSECTION:
1869                                         s << par->getCounter(i - 3) << '.'
1870                                           << par->getCounter(i - 2) << '.'
1871                                           << par->getCounter(i - 1) << '.'
1872                                           << par->getCounter(i);
1873                                         
1874                                         break;
1875                                 case LABEL_COUNTER_PARAGRAPH:
1876                                         s << par->getCounter(i - 4) << '.'
1877                                           << par->getCounter(i - 3) << '.'
1878                                           << par->getCounter(i - 2) << '.'
1879                                           << par->getCounter(i - 1) << '.'
1880                                           << par->getCounter(i);
1881                                         break;
1882                                 case LABEL_COUNTER_SUBPARAGRAPH:
1883                                         s << par->getCounter(i - 5) << '.'
1884                                           << par->getCounter(i - 4) << '.'
1885                                           << par->getCounter(i - 3) << '.'
1886                                           << par->getCounter(i - 2) << '.'
1887                                           << par->getCounter(i - 1) << '.'
1888                                           << par->getCounter(i);
1889
1890                                         break;
1891                                 default:
1892                                         // Can this ever be reached? And in the
1893                                         // case it is, how can this be correct?
1894                                         // (Lgb)
1895                                         s << par->getCounter(i) << '.';
1896                                         break;
1897                                 }
1898                         } else { // appendix
1899                                 switch (2 * LABEL_COUNTER_CHAPTER - textclass.maxcounter() + i) {
1900                                 case LABEL_COUNTER_CHAPTER:
1901                                         if (par->isRightToLeftPar(buf->params))
1902                                                 s << hebrewCounter(par->getCounter(i));
1903                                         else
1904                                                 s << alphaCounter(par->getCounter(i));
1905                                         break;
1906                                 case LABEL_COUNTER_SECTION:
1907                                         if (par->isRightToLeftPar(buf->params))
1908                                                 s << hebrewCounter(par->getCounter(i - 1));
1909                                         else
1910                                                 s << alphaCounter(par->getCounter(i - 1));
1911
1912                                         s << '.'
1913                                           << par->getCounter(i);
1914
1915                                         break;
1916                                 case LABEL_COUNTER_SUBSECTION:
1917                                         if (par->isRightToLeftPar(buf->params))
1918                                                 s << hebrewCounter(par->getCounter(i - 2));
1919                                         else
1920                                                 s << alphaCounter(par->getCounter(i - 2));
1921
1922                                         s << '.'
1923                                           << par->getCounter(i-1) << '.'
1924                                           << par->getCounter(i);
1925
1926                                         break;
1927                                 case LABEL_COUNTER_SUBSUBSECTION:
1928                                         if (par->isRightToLeftPar(buf->params))
1929                                                 s << hebrewCounter(par->getCounter(i-3));
1930                                         else
1931                                                 s << alphaCounter(par->getCounter(i-3));
1932
1933                                         s << '.'
1934                                           << par->getCounter(i-2) << '.'
1935                                           << par->getCounter(i-1) << '.'
1936                                           << par->getCounter(i);
1937
1938                                         break;
1939                                 case LABEL_COUNTER_PARAGRAPH:
1940                                         if (par->isRightToLeftPar(buf->params))
1941                                                 s << hebrewCounter(par->getCounter(i-4));
1942                                         else
1943                                                 s << alphaCounter(par->getCounter(i-4));
1944
1945                                         s << '.'
1946                                           << par->getCounter(i-3) << '.'
1947                                           << par->getCounter(i-2) << '.'
1948                                           << par->getCounter(i-1) << '.'
1949                                           << par->getCounter(i);
1950
1951                                         break;
1952                                 case LABEL_COUNTER_SUBPARAGRAPH:
1953                                         if (par->isRightToLeftPar(buf->params))
1954                                                 s << hebrewCounter(par->getCounter(i-5));
1955                                         else
1956                                                 s << alphaCounter(par->getCounter(i-5));
1957
1958                                         s << '.'
1959                                           << par->getCounter(i-4) << '.'
1960                                           << par->getCounter(i-3) << '.'
1961                                           << par->getCounter(i-2) << '.'
1962                                           << par->getCounter(i-1) << '.'
1963                                           << par->getCounter(i);
1964
1965                                         break;
1966                                 default:
1967                                         // Can this ever be reached? And in the
1968                                         // case it is, how can this be correct?
1969                                         // (Lgb)
1970                                         s << par->getCounter(i) << '.';
1971                                         
1972                                         break;
1973                                 }
1974                         }
1975
1976                         par->params.labelString(par->params.labelString() +s.str().c_str());
1977                         // We really want to remove the c_str as soon as
1978                         // possible...
1979                         
1980                         for (i++; i < 10; ++i) {
1981                                 // reset the following counters
1982                                 par->setCounter(i, 0);
1983                         }
1984                 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1985                         for (i++; i < 10; ++i) {
1986                                 // reset the following counters
1987                                 par->setCounter(i, 0);
1988                         }
1989                 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1990                         par->incCounter(i + par->enumdepth);
1991                         int number = par->getCounter(i + par->enumdepth);
1992
1993                         std::ostringstream s;
1994
1995                         switch (par->enumdepth) {
1996                         case 1:
1997                                 if (par->isRightToLeftPar(buf->params))
1998                                         s << '('
1999                                           << hebrewCounter(number)
2000                                           << ')';
2001                                 else
2002                                         s << '('
2003                                           << loweralphaCounter(number)
2004                                           << ')';
2005                                 break;
2006                         case 2:
2007                                 if (par->isRightToLeftPar(buf->params))
2008                                         s << '.' << romanCounter(number);
2009                                 else
2010                                         s << romanCounter(number) << '.';
2011                                 break;
2012                         case 3:
2013                                 if (par->isRightToLeftPar(buf->params))
2014                                         s << '.'
2015                                           << alphaCounter(number);
2016                                 else
2017                                         s << alphaCounter(number)
2018                                           << '.';
2019                                 break;
2020                         default:
2021                                 if (par->isRightToLeftPar(buf->params))
2022                                         s << '.' << number;
2023                                 else
2024                                         s << number << '.';
2025                                 break;
2026                         }
2027
2028                         par->params.labelString(s.str().c_str());
2029                         // we really want to get rid of that c_str()
2030
2031                         for (i += par->enumdepth + 1; i < 10; ++i)
2032                                 par->setCounter(i, 0);  /* reset the following counters  */
2033          
2034                 } 
2035         } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
2036                 int i = LABEL_COUNTER_ENUMI - LABEL_COUNTER_CHAPTER + par->enumdepth;
2037                 par->incCounter(i);
2038                 int number = par->getCounter(i);
2039                 if (!par->bibkey) {
2040                         InsetCommandParams p( "bibitem" );
2041                         par->bibkey = new InsetBibKey(p);
2042                 }
2043                 par->bibkey->setCounter(number);
2044                 par->params.labelString(layout.labelstring());
2045                 
2046                 // In biblio should't be following counters but...
2047         } else {
2048                 string s = layout.labelstring();
2049                 
2050                 // the caption hack:
2051                 if (layout.labeltype == LABEL_SENSITIVE) {
2052                         bool isOK (par->InInset() && par->InInset()->owner() &&
2053                                    (par->InInset()->owner()->LyxCode() == Inset::FLOAT_CODE));
2054 #ifndef NEW_INSETS
2055                         if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2056                             && (par->footnotekind == LyXParagraph::FIG
2057                                 || par->footnotekind == LyXParagraph::WIDE_FIG)) {
2058                                 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2059                                         ? ":øåéà" : "Figure:";
2060                         } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2061                                  && (par->footnotekind == LyXParagraph::TAB
2062                                      || par->footnotekind == LyXParagraph::WIDE_TAB)) {
2063                                 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2064                                         ? ":äìáè" : "Table:";
2065                         } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2066                                    && par->footnotekind == LyXParagraph::ALGORITHM) {
2067                                 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2068                                         ? ":íúéøåâìà" : "Algorithm:";
2069                         } else
2070 #endif
2071                         if (isOK) {
2072                                 InsetFloat * tmp = static_cast<InsetFloat*>(par->InInset()->owner());
2073                                 Floating const & fl
2074                                         = floatList.getType(tmp->type());
2075                                 // We should get the correct number here too.
2076                                 s = fl.name() + " #:";
2077                         } else {
2078                                 /* par->SetLayout(0); 
2079                                    s = layout->labelstring;  */
2080                                 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2081                                         ? " :úåòîùî Ã¸Ã±Ã§" : "Senseless: ";
2082                         }
2083                 }
2084                 par->params.labelString(s);
2085                 
2086                 /* reset the enumeration counter. They are always resetted
2087                  * when there is any other layout between */ 
2088                 for (int i = 6 + par->enumdepth; i < 10; ++i)
2089                         par->setCounter(i, 0);
2090         }
2091 }
2092
2093
2094 /* Updates all counters BEHIND the row. Changed paragraphs
2095 * with a dynamic left margin will be rebroken. */ 
2096 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
2097 {
2098         LyXParagraph * par;
2099 #ifndef NEW_INSETS
2100         if (!row) {
2101                 row = firstrow;
2102                 par = row->par();
2103         } else if (row->par()->next_
2104                    && row->par()->next_->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
2105                 par = row->par()->LastPhysicalPar()->next();
2106         } else {
2107                 par = row->par()->next_;
2108         }
2109 #else
2110         if (!row) {
2111                 row = firstrow;
2112                 par = row->par();
2113         } else {
2114                 par = row->par()->next();
2115         }
2116 #endif
2117
2118         while (par) {
2119                 while (row->par() != par)
2120                         row = row->next();
2121                 
2122                 SetCounter(bview->buffer(), par);
2123                 
2124                 /* now  check for the headline layouts. remember that they
2125                  * have a dynamic left margin */ 
2126                 if (
2127 #ifndef NEW_INSETS
2128                         !par->IsDummy() &&
2129 #endif
2130                     ( textclasslist.Style(bview->buffer()->params.textclass,
2131                                              par->layout).margintype == MARGIN_DYNAMIC
2132                          || textclasslist.Style(bview->buffer()->params.textclass,
2133                                                 par->layout).labeltype == LABEL_SENSITIVE)
2134                         ) {
2135          
2136                         /* Rebreak the paragraph */ 
2137                         RemoveParagraph(row);
2138                         AppendParagraph(bview, row);
2139
2140 #ifndef NEW_INSETS
2141                         /* think about the damned open footnotes! */ 
2142                         while (par->next() &&
2143                                (par->next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
2144                                 || par->next()->IsDummy())){
2145                                 par = par->next();
2146                                 if (par->IsDummy()) {
2147                                         while (row->par() != par)
2148                                                 row = row->next();
2149                                         RemoveParagraph(row);
2150                                         AppendParagraph(bview, row);
2151                                 }
2152                         }
2153 #endif
2154                 }
2155 #ifndef NEW_INSETS
2156                 par = par->LastPhysicalPar()->next();
2157 #else
2158                 par = par->next();
2159 #endif
2160      
2161         }
2162 }
2163
2164
2165 /* insets an inset. */ 
2166 void LyXText::InsertInset(BufferView * bview, Inset * inset)
2167 {
2168         if (!cursor.par()->InsertInsetAllowed(inset))
2169                 return;
2170         SetUndo(bview->buffer(), Undo::INSERT,
2171 #ifndef NEW_INSETS
2172                 cursor.par()->ParFromPos(cursor.pos())->previous_,
2173                 cursor.par()->ParFromPos(cursor.pos())->next_
2174 #else
2175                 cursor.par()->previous(),
2176                 cursor.par()->next()
2177 #endif
2178                 );
2179         cursor.par()->InsertInset(cursor.pos(), inset);
2180         InsertChar(bview, LyXParagraph::META_INSET);  /* just to rebreak and refresh correctly.
2181                                       * The character will not be inserted a
2182                                       * second time */
2183 #if 1
2184         // If we enter a highly editable inset the cursor should be to before
2185         // the inset. This couldn't happen before as Undo was not handled inside
2186         // inset now after the Undo LyX tries to call inset->Edit(...) again
2187         // and cannot do this as the cursor is behind the inset and GetInset
2188         // does not return the inset!
2189         if (inset->Editable() == Inset::HIGHLY_EDITABLE) {
2190                 CursorLeft(bview, true);
2191         }
2192 #endif
2193 }
2194
2195
2196 void LyXText::copyEnvironmentType()
2197 {
2198         copylayouttype = cursor.par()->GetLayout();
2199 }
2200
2201
2202 void LyXText::pasteEnvironmentType(BufferView * bview)
2203 {
2204         SetLayout(bview, copylayouttype);
2205 }
2206
2207
2208 void LyXText::CutSelection(BufferView * bview, bool doclear)
2209 {
2210         // Stuff what we got on the clipboard. Even if there is no selection.
2211
2212         // There is a problem with having the stuffing here in that the
2213         // larger the selection the slower LyX will get. This can be
2214         // solved by running the line below only when the selection has
2215         // finished. The solution used currently just works, to make it
2216         // faster we need to be more clever and probably also have more
2217         // calls to stuffClipboard. (Lgb)
2218         bview->stuffClipboard(selectionAsString(bview->buffer()));
2219
2220         // This doesn't make sense, if there is no selection
2221         if (!selection)
2222                 return;
2223    
2224         // OK, we have a selection. This is always between sel_start_cursor
2225         // and sel_end_cursor
2226 #ifndef NEW_INSETS
2227         // Check whether there are half footnotes in the selection
2228         if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2229             || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2230         LyXParagraph * tmppar = sel_start_cursor.par();
2231                 while (tmppar != sel_end_cursor.par()){
2232                         if (tmppar->footnoteflag != sel_end_cursor.par()->footnoteflag) {
2233                                 WriteAlert(_("Impossible operation"),
2234                                            _("Don't know what to do with half floats."),
2235                                            _("sorry."));
2236                                 return;
2237                         }
2238                         tmppar = tmppar->next();
2239                 }
2240         }
2241 #endif
2242
2243         // make sure that the depth behind the selection are restored, too
2244 #ifndef NEW_INSETS
2245         LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->next();
2246 #else
2247         LyXParagraph * endpar = sel_end_cursor.par()->next();
2248 #endif
2249         LyXParagraph * undoendpar = endpar;
2250     
2251         if (endpar && endpar->GetDepth()) {
2252                 while (endpar && endpar->GetDepth()) {
2253 #ifndef NEW_INSETS
2254                         endpar = endpar->LastPhysicalPar()->next();
2255 #else
2256                         endpar = endpar->next();
2257 #endif
2258                         undoendpar = endpar;
2259                 }
2260         } else if (endpar) {
2261                 endpar = endpar->next(); // because of parindents etc.
2262         }
2263     
2264         SetUndo(bview->buffer(), Undo::DELETE,
2265 #ifndef NEW_INSETS
2266                 sel_start_cursor
2267                 .par()->ParFromPos(sel_start_cursor.pos())->previous_,
2268 #else
2269                 sel_start_cursor.par()->previous(),
2270 #endif
2271                 undoendpar);
2272     
2273         CutAndPaste cap;
2274
2275         // there are two cases: cut only within one paragraph or
2276         // more than one paragraph
2277 #ifndef NEW_INSETS
2278         if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos()) 
2279             == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos()))
2280 #else
2281         if (sel_start_cursor.par() == sel_end_cursor.par())
2282 #endif
2283                 {
2284                 // only within one paragraph
2285                 endpar = sel_start_cursor.par();
2286                 int pos = sel_end_cursor.pos();
2287                 cap.cutSelection(sel_start_cursor.par(), &endpar,
2288                                  sel_start_cursor.pos(), pos,
2289                                  bview->buffer()->params.textclass, doclear);
2290                 sel_end_cursor.pos(pos);
2291         } else {
2292                 endpar = sel_end_cursor.par();
2293
2294                 int pos = sel_end_cursor.pos();
2295                 cap.cutSelection(sel_start_cursor.par(), &endpar,
2296                                  sel_start_cursor.pos(), pos,
2297                                  bview->buffer()->params.textclass, doclear);
2298                 cursor.par(endpar);
2299                 sel_end_cursor.par(endpar);
2300                 sel_end_cursor.pos(pos);
2301                 cursor.pos(sel_end_cursor.pos());
2302         }
2303         endpar = endpar->next();
2304
2305         // sometimes necessary
2306         if (doclear)
2307                 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
2308
2309         RedoParagraphs(bview, sel_start_cursor, endpar);
2310    
2311         ClearSelection(bview);
2312         cursor = sel_start_cursor;
2313         SetCursor(bview, cursor.par(), cursor.pos());
2314         sel_cursor = cursor;
2315         UpdateCounters(bview, cursor.row());
2316 }
2317
2318
2319 void LyXText::CopySelection(BufferView * bview)
2320 {
2321         // Stuff what we got on the clipboard. Even if there is no selection.
2322
2323         // There is a problem with having the stuffing here in that the
2324         // larger the selection the slower LyX will get. This can be
2325         // solved by running the line below only when the selection has
2326         // finished. The solution used currently just works, to make it
2327         // faster we need to be more clever and probably also have more
2328         // calls to stuffClipboard. (Lgb)
2329         bview->stuffClipboard(selectionAsString(bview->buffer()));
2330
2331         // this doesnt make sense, if there is no selection
2332         if (!selection)
2333                 return;
2334
2335         // ok we have a selection. This is always between sel_start_cursor
2336         // and sel_end cursor
2337
2338 #ifndef NEW_INSETS
2339         /* check wether there are half footnotes in the selection */
2340         if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2341             || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2342                 LyXParagraph * tmppar = sel_start_cursor.par();
2343                 while (tmppar != sel_end_cursor.par()) {
2344                         if (tmppar->footnoteflag !=
2345                             sel_end_cursor.par()->footnoteflag) {
2346                                 WriteAlert(_("Impossible operation"),
2347                                            _("Don't know what to do"
2348                                              " with half floats."),
2349                                            _("sorry."));
2350                                 return;
2351                         }
2352                         tmppar = tmppar->next();
2353                 }
2354         }
2355 #endif
2356    
2357         // copy behind a space if there is one
2358 #ifndef NEW_INSETS
2359         while (sel_start_cursor.par()->Last() > sel_start_cursor.pos()
2360 #else
2361         while (sel_start_cursor.par()->size() > sel_start_cursor.pos()
2362 #endif
2363                && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
2364                && (sel_start_cursor.par() != sel_end_cursor.par()
2365                    || sel_start_cursor.pos() < sel_end_cursor.pos()))
2366                 sel_start_cursor.pos(sel_start_cursor.pos() + 1); 
2367
2368         CutAndPaste cap;
2369
2370         cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
2371                           sel_start_cursor.pos(), sel_end_cursor.pos(),
2372                           bview->buffer()->params.textclass);
2373 }
2374
2375
2376 void LyXText::PasteSelection(BufferView * bview)
2377 {
2378         CutAndPaste cap;
2379
2380         // this does not make sense, if there is nothing to paste
2381         if (!cap.checkPastePossible(cursor.par()))
2382                 return;
2383
2384         SetUndo(bview->buffer(), Undo::INSERT,
2385 #ifndef NEW_INSETS
2386                 cursor.par()->ParFromPos(cursor.pos())->previous_,
2387                 cursor.par()->ParFromPos(cursor.pos())->next_
2388 #else
2389                 cursor.par()->previous(),
2390                 cursor.par()->next()
2391 #endif
2392                 ); 
2393
2394         LyXParagraph * endpar;
2395         LyXParagraph * actpar = cursor.par();
2396
2397         int pos = cursor.pos();
2398         cap.pasteSelection(&actpar, &endpar, pos, bview->buffer()->params.textclass);
2399     
2400         RedoParagraphs(bview, cursor, endpar);
2401         
2402         SetCursor(bview, cursor.par(), cursor.pos());
2403         ClearSelection(bview);
2404    
2405         sel_cursor = cursor;
2406         SetCursor(bview, actpar, pos);
2407         SetSelection(bview);
2408         UpdateCounters(bview, cursor.row());
2409 }
2410
2411
2412 // returns a pointer to the very first LyXParagraph
2413 LyXParagraph * LyXText::FirstParagraph() const
2414 {
2415         return OwnerParagraph();
2416 }
2417
2418
2419 // sets the selection over the number of characters of string, no check!!
2420 void LyXText::SetSelectionOverString(BufferView * bview, string const & str)
2421 {
2422         sel_cursor = cursor;
2423         for (int i = 0; str[i]; ++i)
2424                 CursorRight(bview);
2425         SetSelection(bview);
2426 }
2427
2428
2429 // simple replacing. The font of the first selected character is used
2430 void LyXText::ReplaceSelectionWithString(BufferView * bview,
2431                                          string const & str)
2432 {
2433         SetCursorParUndo(bview->buffer());
2434         FreezeUndo();
2435
2436         if (!selection) { // create a dummy selection
2437                 sel_end_cursor = cursor;
2438                 sel_start_cursor = cursor;
2439         }
2440
2441         // Get font setting before we cut
2442         LyXParagraph::size_type pos = sel_end_cursor.pos();
2443         LyXFont const font = sel_start_cursor.par()
2444                 ->GetFontSettings(bview->buffer()->params,
2445                                   sel_start_cursor.pos());
2446
2447         // Insert the new string
2448         for (string::const_iterator cit = str.begin(); cit != str.end(); ++cit) {
2449                 sel_end_cursor.par()->InsertChar(pos, (*cit), font);
2450                 ++pos;
2451         }
2452         
2453         // Cut the selection
2454         CutSelection(bview);
2455
2456         UnFreezeUndo();
2457 }
2458
2459
2460 // needed to insert the selection
2461 void LyXText::InsertStringA(BufferView * bview, string const & str)
2462 {
2463         LyXParagraph * par = cursor.par();
2464         LyXParagraph::size_type pos = cursor.pos();
2465         LyXParagraph::size_type a = 0;
2466         LyXParagraph * endpar = cursor.par()->next();
2467         
2468         SetCursorParUndo(bview->buffer());
2469         
2470         bool flag =
2471                 textclasslist.Style(bview->buffer()->params.textclass, 
2472                                     cursor.par()->GetLayout()).isEnvironment();
2473         // only to be sure, should not be neccessary
2474         ClearSelection(bview);
2475         
2476         // insert the string, don't insert doublespace
2477         string::size_type i = 0;
2478         while (i < str.length()) {
2479                 if (str[i] != '\n') {
2480                         if (str[i] == ' ' 
2481                             && i + 1 < str.length() && str[i + 1] != ' '
2482                             && pos && par->GetChar(pos - 1)!= ' ') {
2483                                 par->InsertChar(pos, ' ', current_font);
2484                                 ++pos;
2485                         } else if (str[i] == ' ') {
2486                                 InsetSpecialChar * new_inset =
2487                                         new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2488                                 if (par->InsertInsetAllowed(new_inset)) {
2489                                         par->InsertInset(pos, new_inset,
2490                                                          current_font);
2491                                 } else {
2492                                         delete new_inset;
2493                                 }
2494                                 ++pos;
2495                         } else if (str[i] == '\t') {
2496                                 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2497                                 InsetSpecialChar * new_inset =
2498                                         new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2499                                 if (par->InsertInsetAllowed(new_inset)) {
2500                                         par->InsertInset(pos, new_inset,
2501                                                          current_font);
2502                                 } else {
2503                                         delete new_inset;
2504                                 }
2505                                 }
2506                                 pos = a;
2507                         } else if (str[i] != 13 && 
2508                                    // Ignore unprintables
2509                                    (str[i] & 127) >= ' ') {
2510                                 par->InsertChar(pos, str[i], current_font);
2511                                 ++pos;
2512                         }
2513                 } else {
2514                         if (!par->size()) { // par is empty
2515                                 InsetSpecialChar * new_inset =
2516                                         new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2517                                 if (par->InsertInsetAllowed(new_inset)) {
2518                                         par->InsertInset(pos,
2519                                                          new_inset,
2520                                                          current_font);
2521                                 } else {
2522                                         delete new_inset;
2523                                 }
2524                                 ++pos;
2525                         }
2526                         par->BreakParagraph(bview->buffer()->params, pos, flag);
2527                         par = par->next();
2528                         pos = 0;
2529                 }
2530                 ++i;
2531         }
2532         
2533         RedoParagraphs(bview, cursor, endpar);
2534         SetCursor(bview, cursor.par(), cursor.pos());
2535         sel_cursor = cursor;
2536         SetCursor(bview, par, pos);
2537         SetSelection(bview);
2538 }
2539
2540
2541 /* turns double-CR to single CR, others where converted into one blank and 13s 
2542  * that are ignored .Double spaces are also converted into one. Spaces at
2543  * the beginning of a paragraph are forbidden. tabs are converted into one
2544  * space. then InsertStringA is called */ 
2545 void LyXText::InsertStringB(BufferView * bview, string const & s)
2546 {
2547         string str(s);
2548         string::size_type i = 1;
2549         while (i < str.length()) {
2550                 if (str[i] == '\t')
2551                         str[i] = ' ';
2552                 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2553                         str[i] = 13;
2554                 if (str[i] == '\n' && i + 1 < str.length()) {
2555                         if (str[i + 1] != '\n') {
2556                                 if (str[i - 1] != ' ')
2557                                         str[i] = ' ';
2558                                 else
2559                                         str[i] = 13;
2560                         }
2561                         while (i + 1 < str.length() 
2562                                && (str[i + 1] == ' ' 
2563                                    || str[i + 1] == '\t'
2564                                    || str[i + 1] == '\n' 
2565                                    || str[i + 1] == 13)) {
2566                                 str[i + 1] = 13;
2567                                 ++i;
2568                         }
2569                 }
2570                 ++i;
2571         }
2572         InsertStringA(bview, str);
2573 }
2574
2575
2576 bool LyXText::GotoNextInset(BufferView * bview,
2577                             std::vector<Inset::Code> const & codes,
2578                             string const & contents) const
2579 {
2580         LyXCursor res = cursor;
2581         Inset * inset;
2582         do {
2583 #ifndef NEW_INSETS
2584                 if (res.pos() < res.par()->Last() - 1) {
2585 #else
2586                 if (res.pos() < res.par()->size() - 1) {
2587 #endif
2588                         res.pos(res.pos() + 1);
2589                 } else  {
2590                         res.par(res.par()->next());
2591                         res.pos(0);
2592                 }
2593       
2594         } while (res.par() && 
2595                  !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2596                    && (inset = res.par()->GetInset(res.pos())) != 0
2597                    && find(codes.begin(), codes.end(), inset->LyxCode())
2598                       != codes.end()
2599                    && (contents.empty() ||
2600                        static_cast<InsetCommand *>(res.par()->GetInset(res.pos()))->getContents()
2601                        == contents)));
2602
2603         if (res.par()) {
2604                 SetCursor(bview, res.par(), res.pos());
2605                 return true;
2606         }
2607         return false;
2608 }
2609
2610
2611 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
2612                              LyXParagraph::size_type pos)
2613 {
2614         LyXCursor tmpcursor;                    
2615
2616         int y = 0;
2617         LyXParagraph::size_type z;
2618         Row * row = GetRow(par, pos, y);
2619         
2620         // is there a break one row above
2621         if (row->previous() && row->previous()->par() == row->par()) {
2622                 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
2623                 if (z >= row->pos()) {
2624                         // set the dimensions of the row above
2625                         y -= row->previous()->height();
2626                         refresh_y = y;
2627                         refresh_row = row->previous();
2628                         status = LyXText::NEED_MORE_REFRESH;
2629                         
2630                         BreakAgain(bview, row->previous());
2631                         
2632                         // set the cursor again. Otherwise
2633                         // dangling pointers are possible
2634                         SetCursor(bview, cursor.par(), cursor.pos(),
2635                                   false, cursor.boundary());
2636                         sel_cursor = cursor;
2637                         return;
2638                 }
2639         }
2640
2641         int const tmpheight = row->height();
2642         LyXParagraph::size_type const tmplast = RowLast(row);
2643         refresh_y = y;
2644         refresh_row = row;
2645         
2646         BreakAgain(bview, row);
2647         if (row->height() == tmpheight && RowLast(row) == tmplast)
2648                 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2649         else
2650                 status = LyXText::NEED_MORE_REFRESH; 
2651         
2652         // check the special right address boxes
2653         if (textclasslist.Style(bview->buffer()->params.textclass,
2654                                 par->GetLayout()).margintype
2655             == MARGIN_RIGHT_ADDRESS_BOX) {
2656                 tmpcursor.par(par);
2657                 tmpcursor.row(row);
2658                 tmpcursor.y(y);
2659                 tmpcursor.x(0);
2660                 tmpcursor.x_fix(0);
2661                 tmpcursor.pos(pos);
2662                 RedoDrawingOfParagraph(bview, tmpcursor); 
2663         }
2664
2665         // set the cursor again. Otherwise dangling pointers are possible
2666         // also set the selection
2667    
2668         if (selection) {
2669                 tmpcursor = cursor;
2670                 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos(),
2671                                 false, sel_cursor.boundary());
2672                 sel_cursor = cursor; 
2673                 SetCursorIntern(bview, sel_start_cursor.par(),
2674                                 sel_start_cursor.pos(),
2675                                 false, sel_start_cursor.boundary());
2676                 sel_start_cursor = cursor; 
2677                 SetCursorIntern(bview, sel_end_cursor.par(),
2678                                 sel_end_cursor.pos(),
2679                                 false, sel_end_cursor.boundary());
2680                 sel_end_cursor = cursor; 
2681                 SetCursorIntern(bview, last_sel_cursor.par(),
2682                                 last_sel_cursor.pos(),
2683                                 false, last_sel_cursor.boundary());
2684                 last_sel_cursor = cursor; 
2685                 cursor = tmpcursor;
2686         }
2687         SetCursorIntern(bview, cursor.par(), cursor.pos(),
2688                         false, cursor.boundary());
2689 }
2690
2691
2692 // returns false if inset wasn't found
2693 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2694 {
2695         // first check the current paragraph
2696         int pos = cursor.par()->GetPositionOfInset(inset);
2697         if (pos != -1){
2698                 CheckParagraph(bview, cursor.par(), pos);
2699                 return true;
2700         }
2701   
2702         // check every paragraph
2703   
2704         LyXParagraph * par = FirstParagraph();
2705         do {
2706 #ifndef NEW_INSETS
2707                 // make sure the paragraph is open
2708                 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2709 #endif
2710                         pos = par->GetPositionOfInset(inset);
2711                         if (pos != -1){
2712                                 CheckParagraph(bview, par, pos);
2713                                 return true;
2714                         }
2715 #ifndef NEW_INSETS
2716                 }
2717 #endif
2718                 par = par->next();
2719         } while (par);
2720   
2721         return false;
2722 }
2723
2724
2725 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2726                         LyXParagraph::size_type pos, 
2727                         bool setfont, bool boundary) const
2728 {
2729         LyXCursor old_cursor = cursor;
2730         SetCursorIntern(bview, par, pos, setfont, boundary);
2731         DeleteEmptyParagraphMechanism(bview, old_cursor);
2732 }
2733
2734
2735 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2736                         LyXParagraph::size_type pos, bool boundary) const
2737 {
2738 #ifndef NEW_INSETS
2739         // correct the cursor position if impossible
2740         if (pos > par->Last()){
2741                 LyXParagraph * tmppar = par->ParFromPos(pos);
2742                 pos = par->PositionInParFromPos(pos);
2743                 par = tmppar;
2744         }
2745         if (par->IsDummy() && par->previous_ &&
2746             par->previous_->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2747                 while (par->previous_ &&
2748                        ((par->previous_->IsDummy() &&
2749                          (par->previous_->previous_->footnoteflag ==
2750                           LyXParagraph::CLOSED_FOOTNOTE)) ||
2751                         (par->previous_->footnoteflag ==
2752                          LyXParagraph::CLOSED_FOOTNOTE))) {
2753                         par = par->previous_;
2754                         if (par->IsDummy() &&
2755                             (par->previous_->footnoteflag ==
2756                              LyXParagraph::CLOSED_FOOTNOTE))
2757                                 pos += par->size() + 1;
2758                 }
2759                 if (par->previous_) {
2760                         par = par->previous_;
2761                 }
2762                 pos += par->size() + 1;
2763         }
2764 #endif
2765         cur.par(par);
2766         cur.pos(pos);
2767         cur.boundary(boundary);
2768
2769         /* get the cursor y position in text  */
2770         int y = 0;
2771         Row * row = GetRow(par, pos, y);
2772         /* y is now the beginning of the cursor row */ 
2773         y += row->baseline();
2774         /* y is now the cursor baseline */ 
2775         cur.y(y);
2776    
2777         /* now get the cursors x position */
2778         float x;
2779         float fill_separator, fill_hfill, fill_label_hfill;
2780         PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2781                        fill_label_hfill);
2782         LyXParagraph::size_type cursor_vpos = 0;
2783         LyXParagraph::size_type last = RowLastPrintable(row);
2784
2785         if (pos > last + 1)   // This shouldn't happen.
2786                 pos = last + 1;
2787         else if (pos < row->pos())
2788                 pos = row->pos();
2789
2790         if (last < row->pos())
2791                 cursor_vpos = row->pos();
2792         else if (pos > last && !boundary)
2793                 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2794                         ? row->pos() : last + 1; 
2795         else if (pos > row->pos() &&
2796                  (pos > last || boundary))
2797                 /// Place cursor after char at (logical) position pos - 1
2798                 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2799                         ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2800         else
2801                 /// Place cursor before char at (logical) position pos
2802                 cursor_vpos = (bidi_level(pos) % 2 == 0)
2803                         ? log2vis(pos) : log2vis(pos) + 1;
2804         
2805         LyXParagraph::size_type main_body =
2806                 BeginningOfMainBody(bview->buffer(), row->par());
2807         if ((main_body > 0) &&
2808             ((main_body-1 > last) || 
2809              !row->par()->IsLineSeparator(main_body-1)))
2810                 main_body = 0;
2811         
2812         for (LyXParagraph::size_type vpos = row->pos();
2813              vpos < cursor_vpos; ++vpos) {
2814                 pos = vis2log(vpos);
2815                 if (main_body > 0 && pos == main_body - 1) {
2816                         x += fill_label_hfill +
2817                                 lyxfont::width(textclasslist.Style(
2818                                         bview->buffer()->params.textclass,
2819                                         row->par()->GetLayout())
2820                                                .labelsep,
2821                                                GetFont(bview->buffer(), row->par(), -2));
2822                         if (row->par()->IsLineSeparator(main_body-1))
2823                                 x -= SingleWidth(bview, row->par(),main_body-1);
2824                 }
2825                 if (HfillExpansion(bview->buffer(), row, pos)) {
2826                         x += SingleWidth(bview, row->par(), pos);
2827                         if (pos >= main_body)
2828                                 x += fill_hfill;
2829                         else 
2830                                 x += fill_label_hfill;
2831                 } else if (row->par()->IsSeparator(pos)) {
2832                         x += SingleWidth(bview, row->par(), pos);
2833                         if (pos >= main_body)
2834                                 x += fill_separator;
2835                 } else
2836                         x += SingleWidth(bview, row->par(), pos);
2837         }
2838         
2839         cur.x(int(x));
2840         cur.x_fix(cur.x());
2841         cur.row(row);
2842 }
2843
2844
2845 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
2846                               LyXParagraph::size_type pos,
2847                               bool setfont, bool boundary) const
2848 {
2849         SetCursor(bview, cursor, par, pos, boundary);
2850         if (setfont)
2851                 SetCurrentFont(bview);
2852 }
2853
2854
2855 void LyXText::SetCurrentFont(BufferView * bview) const
2856 {
2857         LyXParagraph::size_type pos = cursor.pos();
2858         if (cursor.boundary() && pos > 0)
2859                 --pos;
2860
2861         if (pos > 0) {
2862 #ifndef NEW_INSETS
2863                 if (pos == cursor.par()->Last())
2864 #else
2865                 if (pos == cursor.par()->size())
2866 #endif
2867                         --pos;
2868                 else if (cursor.par()->IsSeparator(pos)) {
2869                         if (pos > cursor.row()->pos() &&
2870                             bidi_level(pos) % 2 == 
2871                             bidi_level(pos - 1) % 2)
2872                                 --pos;
2873 #ifndef NEW_INSETS
2874                         else if (pos + 1 < cursor.par()->Last())
2875 #else
2876                         else if (pos + 1 < cursor.par()->size())
2877 #endif
2878                                 ++pos;
2879                 }
2880         }
2881
2882         current_font =
2883                 cursor.par()->GetFontSettings(bview->buffer()->params, pos);
2884         real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
2885
2886 #ifndef NEW_INSETS
2887         if (cursor.pos() == cursor.par()->Last() &&
2888 #else
2889         if (cursor.pos() == cursor.par()->size() &&
2890 #endif
2891             IsBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
2892             !cursor.boundary()) {
2893                 Language const * lang =
2894                         cursor.par()->getParLanguage(bview->buffer()->params);
2895                 current_font.setLanguage(lang);
2896                 current_font.setNumber(LyXFont::OFF);
2897                 real_current_font.setLanguage(lang);
2898                 real_current_font.setNumber(LyXFont::OFF);
2899         }
2900 }
2901
2902
2903 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, int y) const
2904 {
2905         LyXCursor old_cursor = cursor;
2906    
2907         /* get the row first */ 
2908    
2909         Row * row = GetRowNearY(y);
2910         cursor.par(row->par());
2911
2912         bool bound = false;
2913         int column = GetColumnNearX(bview, row, x, bound);
2914         cursor.pos(row->pos() + column);
2915         cursor.x(x);
2916         cursor.y(y + row->baseline());
2917         cursor.row(row);
2918         cursor.boundary(bound);
2919         SetCurrentFont(bview);
2920         DeleteEmptyParagraphMechanism(bview, old_cursor);
2921 }
2922
2923
2924 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
2925                                        int x, int y) const
2926 {
2927         /* get the row first */ 
2928    
2929         Row * row = GetRowNearY(y);
2930         bool bound = false;
2931         int column = GetColumnNearX(bview, row, x, bound);
2932    
2933         cur.par(row->par());
2934         cur.pos(row->pos() + column);
2935         cur.x(x);
2936         cur.y(y + row->baseline());
2937         cur.row(row);
2938         cur.boundary(bound);
2939 }
2940
2941
2942 void LyXText::CursorLeft(BufferView * bview, bool internal) const
2943 {
2944         if (cursor.pos() > 0) {
2945                 bool boundary = cursor.boundary();
2946                 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
2947                 if (!internal && !boundary &&
2948                     IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
2949                         SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
2950         } else if (cursor.par()->previous()) { // steps into the above paragraph.
2951                 LyXParagraph * par = cursor.par()->previous();
2952 #ifndef NEW_INSETS
2953                 SetCursor(bview, par, par->Last());
2954 #else
2955                 SetCursor(bview, par, par->size());
2956 #endif
2957         }
2958 }
2959
2960
2961 void LyXText::CursorRight(BufferView * bview, bool internal) const
2962 {
2963         if (!internal && cursor.boundary() &&
2964             !cursor.par()->IsNewline(cursor.pos()))
2965                 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
2966 #ifndef NEW_INSETS
2967         else if (cursor.pos() < cursor.par()->Last()) {
2968 #else
2969         else if (cursor.pos() < cursor.par()->size()) {
2970 #endif
2971                 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
2972                 if (!internal &&
2973                     IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
2974                         SetCursor(bview, cursor.par(), cursor.pos(), true, true);
2975         } else if (cursor.par()->next())
2976                 SetCursor(bview, cursor.par()->next(), 0);
2977 }
2978
2979
2980 void LyXText::CursorUp(BufferView * bview) const
2981 {
2982         SetCursorFromCoordinates(bview, cursor.x_fix(), 
2983                                  cursor.y() - cursor.row()->baseline() - 1);
2984 }
2985
2986
2987 void LyXText::CursorDown(BufferView * bview) const
2988 {
2989         SetCursorFromCoordinates(bview, cursor.x_fix(), 
2990                                  cursor.y() - cursor.row()->baseline()
2991                                  + cursor.row()->height() + 1);
2992 }
2993
2994
2995 void LyXText::CursorUpParagraph(BufferView * bview) const
2996 {
2997         if (cursor.pos() > 0) {
2998                 SetCursor(bview, cursor.par(), 0);
2999         }
3000         else if (cursor.par()->previous()) {
3001                 SetCursor(bview, cursor.par()->previous(), 0);
3002         }
3003 }
3004
3005
3006 void LyXText::CursorDownParagraph(BufferView * bview) const
3007 {
3008         if (cursor.par()->next()) {
3009                 SetCursor(bview, cursor.par()->next(), 0);
3010         } else {
3011 #ifndef NEW_INSETS
3012                 SetCursor(bview, cursor.par(), cursor.par()->Last());
3013 #else
3014                 SetCursor(bview, cursor.par(), cursor.par()->size());
3015 #endif
3016         }
3017 }
3018
3019
3020 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
3021                                             LyXCursor const & old_cursor) const
3022 {
3023         // Would be wrong to delete anything if we have a selection.
3024         if (selection) return;
3025
3026         // We allow all kinds of "mumbo-jumbo" when freespacing.
3027         if (textclasslist.Style(bview->buffer()->params.textclass,
3028                                 old_cursor.par()->GetLayout()).free_spacing)
3029                 return;
3030
3031         bool deleted = false;
3032         
3033         /* Ok I'll put some comments here about what is missing.
3034            I have fixed BackSpace (and thus Delete) to not delete
3035            double-spaces automagically. I have also changed Cut,
3036            Copy and Paste to hopefully do some sensible things.
3037            There are still some small problems that can lead to
3038            double spaces stored in the document file or space at
3039            the beginning of paragraphs. This happens if you have
3040            the cursor betwenn to spaces and then save. Or if you
3041            cut and paste and the selection have a space at the
3042            beginning and then save right after the paste. I am
3043            sure none of these are very hard to fix, but I will
3044            put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3045            that I can get some feedback. (Lgb)
3046         */
3047
3048         // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
3049         // delete the LineSeparator.
3050         // MISSING
3051
3052         // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
3053         // delete the LineSeparator.
3054         // MISSING
3055
3056         // If the pos around the old_cursor were spaces, delete one of them.
3057         if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) { 
3058                 // Only if the cursor has really moved
3059                 
3060                 if (old_cursor.pos() > 0
3061 #ifndef NEW_INSETS
3062                     && old_cursor.pos() < old_cursor.par()->Last()
3063 #else
3064                     && old_cursor.pos() < old_cursor.par()->size()
3065 #endif
3066                     && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3067                     && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3068                         old_cursor.par()->Erase(old_cursor.pos() - 1);
3069                         RedoParagraphs(bview, old_cursor, old_cursor.par()->next());
3070                         // correct cursor
3071                         if (old_cursor.par() == cursor.par() &&
3072                             cursor.pos() > old_cursor.pos()) {
3073                                 SetCursorIntern(bview, cursor.par(),
3074                                                 cursor.pos() - 1);
3075                         } else
3076                                 SetCursorIntern(bview, cursor.par(),
3077                                                 cursor.pos());
3078                         return;
3079                 }
3080         }
3081
3082         // Do not delete empty paragraphs with keepempty set.
3083         if ((textclasslist.Style(bview->buffer()->params.textclass,
3084                                  old_cursor.par()->GetLayout())).keepempty)
3085                 return;
3086
3087         LyXCursor tmpcursor;
3088
3089 #ifndef NEW_INSETS
3090         if (old_cursor.par() != cursor.par()) {
3091                 if ((old_cursor.par()->Last() == 0
3092                       || (old_cursor.par()->Last() == 1
3093                           && old_cursor.par()->IsLineSeparator(0)))
3094                      && old_cursor.par()->FirstPhysicalPar()
3095                      == old_cursor.par()->LastPhysicalPar()
3096 #else
3097         if (old_cursor.par() != cursor.par()) {
3098                 if ((old_cursor.par()->size() == 0
3099                       || (old_cursor.par()->size() == 1
3100                           && old_cursor.par()->IsLineSeparator(0)))
3101 #endif
3102                         ) {
3103                         // ok, we will delete anything
3104                         
3105                         // make sure that you do not delete any environments
3106 #ifndef NEW_INSETS
3107                         if ((
3108                                 old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3109                              !(old_cursor.row()->previous() 
3110                                && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3111                              && !(old_cursor.row()->next() 
3112                                   && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3113                             || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3114                                 && ((old_cursor.row()->previous() 
3115                                      && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3116                                     || (old_cursor.row()->next()
3117                                         && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3118                                     )) {
3119 #endif
3120                                 status = LyXText::NEED_MORE_REFRESH;
3121                                 deleted = true;
3122                                 
3123                                 if (old_cursor.row()->previous()) {
3124                                         refresh_row = old_cursor.row()->previous();
3125                                         refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3126                                         tmpcursor = cursor;
3127                                         cursor = old_cursor; // that undo can restore the right cursor position
3128 #ifndef NEW_INSETS
3129                                         LyXParagraph * endpar = old_cursor.par()->next_;
3130                                         if (endpar && endpar->GetDepth()) {
3131                                                 while (endpar && endpar->GetDepth()) {
3132                                                         endpar = endpar->LastPhysicalPar()->next();
3133                                                 }
3134                                         }
3135                                         SetUndo(bview->buffer(), Undo::DELETE,
3136                                                 old_cursor.par()->previous_,
3137                                                 endpar);
3138                                         cursor = tmpcursor;
3139
3140                                         // delete old row
3141                                         RemoveRow(old_cursor.row());
3142                                         if (OwnerParagraph() == old_cursor.par()) {
3143                                                 OwnerParagraph(OwnerParagraph()->next_);
3144                                         }
3145 #else
3146                                         LyXParagraph * endpar = old_cursor.par()->next();
3147                                         if (endpar && endpar->GetDepth()) {
3148                                                 while (endpar && endpar->GetDepth()) {
3149                                                         endpar = endpar->next();
3150                                                 }
3151                                         }
3152                                         SetUndo(bview->buffer(), Undo::DELETE,
3153                                                 old_cursor.par()->previous(),
3154                                                 endpar);
3155                                         cursor = tmpcursor;
3156
3157                                         // delete old row
3158                                         RemoveRow(old_cursor.row());
3159                                         if (OwnerParagraph() == old_cursor.par()) {
3160                                                 OwnerParagraph(OwnerParagraph()->next());
3161                                         }
3162 #endif
3163                                         // delete old par
3164                                         delete old_cursor.par();
3165                                         
3166                                         /* Breakagain the next par. Needed
3167                                          * because of the parindent that
3168                                          * can occur or dissappear. The
3169                                          * next row can change its height,
3170                                          * if there is another layout before */
3171                                         if (refresh_row->next()) {
3172                                                 BreakAgain(bview, refresh_row->next());
3173                                                 UpdateCounters(bview, refresh_row);
3174                                         }
3175                                         SetHeightOfRow(bview, refresh_row);
3176                                 } else {
3177                                         refresh_row = old_cursor.row()->next();
3178                                         refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3179                                         
3180                                         tmpcursor = cursor;
3181                                         cursor = old_cursor; // that undo can restore the right cursor position
3182 #ifndef NEW_INSETS
3183                                         LyXParagraph * endpar = old_cursor.par()->next_;
3184                                         if (endpar && endpar->GetDepth()) {
3185                                                 while (endpar && endpar->GetDepth()) {
3186                                                         endpar = endpar->LastPhysicalPar()->next();
3187                                                 }
3188                                         }
3189                                         SetUndo(bview->buffer(), Undo::DELETE,
3190                                                 old_cursor.par()->previous_,
3191                                                 endpar);
3192                                         cursor = tmpcursor;
3193
3194                                         // delete old row
3195                                         RemoveRow(old_cursor.row());
3196                                         // delete old par
3197                                         if (OwnerParagraph() == old_cursor.par()) {
3198                                                 OwnerParagraph(OwnerParagraph()->next_);
3199                                         }
3200 #else
3201                                         LyXParagraph * endpar = old_cursor.par()->next();
3202                                         if (endpar && endpar->GetDepth()) {
3203                                                 while (endpar && endpar->GetDepth()) {
3204                                                         endpar = endpar->next();
3205                                                 }
3206                                         }
3207                                         SetUndo(bview->buffer(), Undo::DELETE,
3208                                                 old_cursor.par()->previous(),
3209                                                 endpar);
3210                                         cursor = tmpcursor;
3211
3212                                         // delete old row
3213                                         RemoveRow(old_cursor.row());
3214                                         // delete old par
3215                                         if (OwnerParagraph() == old_cursor.par()) {
3216                                                 OwnerParagraph(OwnerParagraph()->next());
3217                                         }
3218 #endif
3219                                         delete old_cursor.par();
3220                                         
3221                                         /* Breakagain the next par. Needed
3222                                            because of the parindent that can
3223                                            occur or dissappear.
3224                                            The next row can change its height,
3225                                            if there is another layout before
3226                                         */ 
3227                                         if (refresh_row) {
3228                                                 BreakAgain(bview, refresh_row);
3229                                                 UpdateCounters(bview, refresh_row->previous());
3230                                         }
3231                                 }
3232                                 
3233                                 // correct cursor y
3234
3235                                 SetCursorIntern(bview, cursor.par(), cursor.pos());
3236
3237                                 if (sel_cursor.par()  == old_cursor.par()
3238                                     && sel_cursor.pos() == sel_cursor.pos()) {
3239                                         // correct selection
3240                                         sel_cursor = cursor;
3241                                 }
3242 #ifndef NEW_INSETS
3243                         }
3244 #endif
3245                 }
3246                 if (!deleted) {
3247                         if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
3248                                 RedoParagraphs(bview, old_cursor, old_cursor.par()->next());
3249                                 // correct cursor y
3250                                 SetCursorIntern(bview, cursor.par(), cursor.pos());
3251                                 sel_cursor = cursor;
3252                         }
3253                 }
3254         }
3255 }
3256
3257
3258 #ifndef NEW_INSETS
3259 LyXParagraph * LyXText::GetParFromID(int id)
3260 {
3261         LyXParagraph * result = FirstParagraph();
3262         while (result && result->id() != id)
3263                 result = result->next_;
3264         return result;
3265 }
3266 #else
3267 LyXParagraph * LyXText::GetParFromID(int id)
3268 {
3269         LyXParagraph * result = FirstParagraph();
3270         while (result && result->id() != id)
3271                 result = result->next();
3272         return result;
3273 }
3274 #endif
3275
3276
3277 // undo functions
3278 bool LyXText::TextUndo(BufferView * bview)
3279 {
3280         if (inset_owner)
3281                 return false;
3282         // returns false if no undo possible
3283         Undo * undo = bview->buffer()->undostack.pop();
3284         if (undo) {
3285                 FinishUndo();
3286                 if (!undo_frozen)
3287                         bview->buffer()->redostack
3288                                 .push(CreateUndo(bview->buffer(), undo->kind, 
3289                                                  GetParFromID(undo->number_of_before_par),
3290                                                  GetParFromID(undo->number_of_behind_par)));
3291         }
3292         return TextHandleUndo(bview, undo);
3293 }
3294
3295
3296 bool LyXText::TextRedo(BufferView * bview)
3297 {
3298         if (inset_owner)
3299                 return false;
3300         // returns false if no redo possible
3301         Undo * undo = bview->buffer()->redostack.pop();
3302         if (undo) {
3303                 FinishUndo();
3304                 if (!undo_frozen)
3305                         bview->buffer()->undostack
3306                                 .push(CreateUndo(bview->buffer(), undo->kind, 
3307                                                  GetParFromID(undo->number_of_before_par),
3308                                                  GetParFromID(undo->number_of_behind_par)));
3309         }
3310         return TextHandleUndo(bview, undo);
3311 }
3312
3313
3314 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
3315 {
3316         if (inset_owner)
3317                 return false;
3318         // returns false if no undo possible
3319         bool result = false;
3320         if (undo) {
3321                 LyXParagraph * before =
3322                         GetParFromID(undo->number_of_before_par); 
3323                 LyXParagraph * behind =
3324                         GetParFromID(undo->number_of_behind_par); 
3325                 LyXParagraph * tmppar;
3326                 LyXParagraph * tmppar2;
3327                 LyXParagraph * endpar;
3328                 LyXParagraph * tmppar5;
3329     
3330                 // if there's no before take the beginning
3331                 // of the document for redoing
3332                 if (!before)
3333                         SetCursorIntern(bview, FirstParagraph(), 0);
3334
3335                 // replace the paragraphs with the undo informations
3336
3337                 LyXParagraph * tmppar3 = undo->par;
3338                 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3339                 LyXParagraph * tmppar4 = tmppar3;
3340 #ifndef NEW_INSETS
3341                 if (tmppar4) {
3342                         while (tmppar4->next_)
3343                                 tmppar4 = tmppar4->next_;
3344                 } // get last undo par
3345     
3346                 // now remove the old text if there is any
3347                 if (before != behind || (!behind && !before)) {
3348                         if (before)
3349                                 tmppar5 = before->next();
3350                         else
3351                                 tmppar5 = OwnerParagraph();
3352                         tmppar2 = tmppar3;
3353                         while (tmppar5 && tmppar5 != behind) {
3354                                 tmppar = tmppar5;
3355                                 tmppar5 = tmppar5->next();
3356                                 // a memory optimization for edit: Only layout information
3357                                 // is stored in the undo. So restore the text informations.
3358                                 if (undo->kind == Undo::EDIT) {
3359                                         tmppar2->setContentsFromPar(tmppar);
3360                                         tmppar->clearContents();
3361                                         tmppar2 = tmppar2->next();
3362                                 }
3363                         }
3364                 }
3365     
3366 #else
3367                 if (tmppar4) {
3368                         while (tmppar4->next())
3369                                 tmppar4 = tmppar4->next();
3370                 } // get last undo par
3371     
3372                 // now remove the old text if there is any
3373                 if (before != behind || (!behind && !before)) {
3374                         if (before)
3375                                 tmppar5 = before->next();
3376                         else
3377                                 tmppar5 = OwnerParagraph();
3378                         tmppar2 = tmppar3;
3379                         while (tmppar5 && tmppar5 != behind) {
3380                                 tmppar = tmppar5;
3381                                 tmppar5 = tmppar5->next();
3382                                 // a memory optimization for edit: Only layout information
3383                                 // is stored in the undo. So restore the text informations.
3384                                 if (undo->kind == Undo::EDIT) {
3385                                         tmppar2->setContentsFromPar(tmppar);
3386                                         tmppar->clearContents();
3387                                         tmppar2 = tmppar2->next();
3388                                 }
3389                         }
3390                 }
3391     
3392 #endif
3393                 // put the new stuff in the list if there is one
3394                 if (tmppar3){
3395                         if (before)
3396                                 before->next(tmppar3);
3397                         else
3398                                 OwnerParagraph(tmppar3);
3399                         tmppar3->previous(before);
3400                 } else {
3401                         if (!before)
3402                                 OwnerParagraph(behind);
3403                 }
3404                 if (tmppar4) {
3405                         tmppar4->next(behind);
3406                         if (behind)
3407                                 behind->previous(tmppar4);
3408                 }
3409     
3410     
3411                 // Set the cursor for redoing
3412                 if (before) {
3413 #ifndef NEW_INSETS
3414                         SetCursorIntern(bview, before->FirstSelfrowPar(), 0);
3415 #else
3416                         SetCursorIntern(bview, before, 0);
3417 #endif
3418 #ifndef NEW_INSETS
3419                         // check wether before points to a closed float and open it if necessary
3420                         if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3421                             && before->next_ && before->next_->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3422                                 tmppar4 = before;
3423                                 while (tmppar4->previous_ && 
3424                                        tmppar4->previous_->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3425                                         tmppar4 = tmppar4->previous_;
3426                                 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3427                                         tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3428                                         tmppar4 = tmppar4->next_;
3429                                 }
3430                         }
3431 #endif
3432                 }
3433
3434 #ifndef NEW_INSETS
3435                 // open a cosed footnote at the end if necessary
3436                 if (behind && behind->previous_ && 
3437                     behind->previous_->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3438                     behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3439                         while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3440                                 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3441                                 behind = behind->next_;
3442                         }
3443                 }
3444 #endif
3445     
3446                 // calculate the endpar for redoing the paragraphs.
3447                 if (behind) {
3448 #ifndef NEW_INSETS
3449                         if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3450                                 endpar = behind->LastPhysicalPar()->next();
3451                         else
3452                                 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->next();
3453 #else
3454                                 endpar = behind->next();
3455 #endif
3456                 } else
3457                         endpar = behind;
3458     
3459                 tmppar = GetParFromID(undo->number_of_cursor_par);
3460                 RedoParagraphs(bview, cursor, endpar); 
3461                 if (tmppar){
3462                         SetCursorIntern(bview, tmppar, undo->cursor_pos);
3463                         UpdateCounters(bview, cursor.row());
3464                 }
3465                 result = true;
3466                 delete undo;
3467         }
3468         FinishUndo();
3469         return result;
3470 }
3471
3472
3473 void LyXText::FinishUndo()
3474 {
3475         if (inset_owner)
3476                 return;
3477         // makes sure the next operation will be stored
3478         undo_finished = true;
3479 }
3480
3481
3482 void LyXText::FreezeUndo()
3483 {
3484         if (inset_owner)
3485                 return;
3486         // this is dangerous and for internal use only
3487         undo_frozen = true;
3488 }
3489
3490
3491 void LyXText::UnFreezeUndo()
3492 {
3493         if (inset_owner)
3494                 return;
3495         // this is dangerous and for internal use only
3496         undo_frozen = false;
3497 }
3498
3499
3500 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
3501                       LyXParagraph const * before,
3502                       LyXParagraph const * behind) const
3503 {
3504         if (inset_owner)
3505                 return;
3506         if (!undo_frozen)
3507                 buf->undostack.push(CreateUndo(buf, kind, before, behind));
3508         buf->redostack.clear();
3509 }
3510
3511
3512 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
3513                       LyXParagraph const * before, LyXParagraph const * behind)
3514 {
3515         if (inset_owner)
3516                 return;
3517         buf->redostack.push(CreateUndo(buf, kind, before, behind));
3518 }
3519
3520
3521 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
3522                            LyXParagraph const * before,
3523                            LyXParagraph const * behind) const
3524 {
3525         if (inset_owner)
3526                 return 0;
3527
3528         int before_number = -1;
3529         int behind_number = -1;
3530         if (before)
3531                 before_number = before->id();
3532         if (behind)
3533                 behind_number = behind->id();
3534         // Undo::EDIT  and Undo::FINISH are
3535         // always finished. (no overlapping there)
3536         // overlapping only with insert and delete inside one paragraph: 
3537         // Nobody wants all removed  character
3538         // appear one by one when undoing. 
3539         // EDIT is special since only layout information, not the
3540         // contents of a paragaph are stored.
3541         if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
3542                 // check wether storing is needed
3543                 if (!buf->undostack.empty() && 
3544                     buf->undostack.top()->kind == kind &&
3545                     buf->undostack.top()->number_of_before_par ==  before_number &&
3546                     buf->undostack.top()->number_of_behind_par ==  behind_number ){
3547                         // no undo needed
3548                         return 0;
3549                 }
3550         }
3551         // create a new Undo
3552         LyXParagraph * undopar;
3553         LyXParagraph * tmppar;
3554         LyXParagraph * tmppar2;
3555
3556         LyXParagraph * start = 0;
3557         LyXParagraph * end = 0;
3558
3559 #ifndef NEW_INSETS
3560         if (before)
3561                 start = before->next_;
3562         else
3563                 start = FirstParagraph();
3564         if (behind)
3565                 end = behind->previous_;
3566         else {
3567                 end = FirstParagraph();
3568                 while (end->next_)
3569                         end = end->next_;
3570         }
3571         if (start && end && (start != end->next_) &&
3572             ((before != behind) || (!before && !behind))) {
3573                 tmppar = start;
3574                 tmppar2 = tmppar->Clone();
3575                 tmppar2->id(tmppar->id());
3576
3577                 // a memory optimization: Just store the layout information
3578                 // when only edit
3579                 if (kind == Undo::EDIT){
3580                         //tmppar2->text.clear();
3581                         tmppar2->clearContents();
3582                 }
3583
3584                 undopar = tmppar2;
3585   
3586                 while (tmppar != end && tmppar->next_) {
3587                         tmppar = tmppar->next_;
3588                         tmppar2->next(tmppar->Clone());
3589                         tmppar2->next_->id(tmppar->id());
3590                         // a memory optimization: Just store the layout
3591                         // information when only edit
3592                         if (kind == Undo::EDIT){
3593                                 //tmppar2->next->text.clear();
3594                                 tmppar2->clearContents();
3595                         }
3596                         tmppar2->next_->previous(tmppar2);
3597                         tmppar2 = tmppar2->next_;
3598                 }
3599                 tmppar2->next(0);
3600         } else
3601                 undopar = 0; // nothing to replace (undo of delete maybe)
3602
3603         int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
3604         int cursor_pos =  cursor.par()->PositionInParFromPos(cursor.pos());
3605 #else
3606         if (before)
3607                 start = const_cast<LyXParagraph*>(before->next());
3608         else
3609                 start = FirstParagraph();
3610         if (behind)
3611                 end = const_cast<LyXParagraph*>(behind->previous());
3612         else {
3613                 end = FirstParagraph();
3614                 while (end->next())
3615                         end = end->next();
3616         }
3617         if (start && end && (start != end->next()) &&
3618             ((before != behind) || (!before && !behind))) {
3619                 tmppar = start;
3620                 tmppar2 = tmppar->Clone();
3621                 tmppar2->id(tmppar->id());
3622
3623                 // a memory optimization: Just store the layout information
3624                 // when only edit
3625                 if (kind == Undo::EDIT){
3626                         //tmppar2->text.clear();
3627                         tmppar2->clearContents();
3628                 }
3629
3630                 undopar = tmppar2;
3631   
3632                 while (tmppar != end && tmppar->next()) {
3633                         tmppar = tmppar->next();
3634                         tmppar2->next(tmppar->Clone());
3635                         tmppar2->next()->id(tmppar->id());
3636                         // a memory optimization: Just store the layout
3637                         // information when only edit
3638                         if (kind == Undo::EDIT){
3639                                 //tmppar2->next->text.clear();
3640                                 tmppar2->clearContents();
3641                         }
3642                         tmppar2->next()->previous(tmppar2);
3643                         tmppar2 = tmppar2->next();
3644                 }
3645                 tmppar2->next(0);
3646         } else
3647                 undopar = 0; // nothing to replace (undo of delete maybe)
3648
3649         int cursor_par = cursor.par()->id();
3650         int cursor_pos =  cursor.pos();
3651 #endif
3652         
3653         Undo * undo = new Undo(kind, 
3654                                before_number, behind_number,  
3655                                cursor_par, cursor_pos, 
3656                                undopar);
3657   
3658         undo_finished = false;
3659         return undo;
3660 }
3661
3662
3663 void LyXText::SetCursorParUndo(Buffer * buf)
3664 {
3665         if (inset_owner)
3666                 return;
3667         SetUndo(buf, Undo::FINISH,
3668 #ifndef NEW_INSETS
3669                 cursor.par()->ParFromPos(cursor.pos())->previous_, 
3670                 cursor.par()->ParFromPos(cursor.pos())->next_
3671 #else
3672                 cursor.par()->previous(),
3673                 cursor.par()->next()
3674 #endif
3675                 ); 
3676 }
3677
3678
3679 void LyXText::toggleAppendix(BufferView * bview)
3680 {
3681 #ifndef NEW_INSETS
3682         LyXParagraph * par = cursor.par()->FirstPhysicalPar();
3683 #else
3684         LyXParagraph * par = cursor.par();
3685 #endif
3686         bool start = !par->params.startOfAppendix();
3687
3688         // ensure that we have only one start_of_appendix in this document
3689         LyXParagraph * tmp = FirstParagraph();
3690 #ifndef NEW_INSETS
3691         for (; tmp; tmp = tmp->next_)
3692                 tmp->params.startOfAppendix(false);
3693 #else
3694         for (; tmp; tmp = tmp->next())
3695                 tmp->params.startOfAppendix(false);
3696 #endif
3697         par->params.startOfAppendix(start);
3698
3699         // we can set the refreshing parameters now
3700         status = LyXText::NEED_MORE_REFRESH;
3701         refresh_y = 0;
3702         refresh_row = 0; // not needed for full update
3703         UpdateCounters(bview, 0);
3704         SetCursor(bview, cursor.par(), cursor.pos());
3705 }
3706
3707
3708 LyXParagraph * LyXText::OwnerParagraph() const
3709 {
3710         if (inset_owner)
3711                 return inset_owner->par;
3712
3713         return bv_owner->buffer()->paragraph;
3714 }
3715
3716
3717 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
3718 {
3719         if (inset_owner)
3720                 inset_owner->par = p;
3721         else
3722                 bv_owner->buffer()->paragraph = p;
3723         return 0;
3724 }