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