]> git.lyx.org Git - lyx.git/blob - src/text2.C
RTL fix
[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->added_space_top = lyxlayout.fill_top ?
594                                 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
595                         fppar->added_space_bottom = 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->added_space_top = lyxlayout.fill_top ?
620                         VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
621                 fppar->added_space_bottom = 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()->depth++;
739 #else
740                                 cursor.par()->depth++;
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()->depth = 0;
756 #else
757                         cursor.par()->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()->depth = 0;
764 #else
765                         cursor.par()->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()->depth)
835                                 cursor.par()->FirstPhysicalPar()->depth--;
836                 }
837 #else
838                         if (cursor.par()->depth)
839                                 cursor.par()->depth--;
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()->line_top = line_top;
1488                         cursor.par()->line_bottom = line_bottom;
1489                         cursor.par()->pagebreak_top = pagebreak_top;
1490                         cursor.par()->pagebreak_bottom = pagebreak_bottom;
1491                         cursor.par()->added_space_top = space_top;
1492                         cursor.par()->added_space_bottom = 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()->align = LYX_ALIGN_LAYOUT;
1505                                 else
1506                                         cursor.par()->align = align;
1507                         }
1508                         cursor.par()->SetLabelWidthString(labelwidthstring);
1509                         cursor.par()->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()->pextra_type != LyXParagraph::PEXTRA_NONE) {
1593                                         cursor.par()->UnsetPExtraType(bview->buffer()->params);
1594                                         cursor.par()->pextra_type = LyXParagraph::PEXTRA_NONE;
1595                                 }
1596                         } else {
1597                                 cursor.par()->SetPExtraType(bview->buffer()->params,
1598                                                           type, width, widthp);
1599                                 cursor.par()->pextra_hfill = hfill;
1600                                 cursor.par()->pextra_start_minipage = start_minipage;
1601                                 cursor.par()->pextra_alignment = 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->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1701 #else
1702                 par->appendix = par->Previous()->appendix;
1703 #endif
1704                 if (!par->appendix && par->start_of_appendix){
1705                   par->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->appendix = par->start_of_appendix;
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->labelstring.empty()) {
1791                 par->labelstring.erase();
1792         }
1793    
1794         if (layout.margintype == MARGIN_MANUAL) {
1795                 if (par->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->appendix){
1811                                 if (!layout.labelstring().empty())
1812                                         par->labelstring = layout.labelstring();
1813                                 else
1814                                         par->labelstring.erase();
1815                         } else {
1816                                 if (!layout.labelstring_appendix().empty())
1817                                         par->labelstring = layout.labelstring_appendix();
1818                                 else
1819                                         par->labelstring.erase();
1820                         }
1821
1822                         std::ostringstream s;
1823
1824                         if (!par->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->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->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->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->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         if (!row) {
2071                 row = firstrow;
2072                 par = row->par();
2073         } else {
2074                 if (row->par()->next
2075 #ifndef NEW_INSETS
2076                     && row->par()->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
2077 #endif
2078                         ) {
2079 #ifndef NEW_INSETS
2080                         par = row->par()->LastPhysicalPar()->Next();
2081 #else
2082                         par = row->par()->Next();
2083 #endif
2084                 } else {
2085                         par = row->par()->next;
2086                 }
2087         }
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 // returns true if the specified string is at the specified position
2387 bool LyXText::IsStringInText(LyXParagraph * par,
2388                              LyXParagraph::size_type pos,
2389                              string const & str) const
2390 {
2391         if (!par)
2392                 return false;
2393
2394         LyXParagraph::size_type i = 0;
2395         while (pos + i < par->Last()
2396                && string::size_type(i) < str.length()
2397                && str[i] == par->GetChar(pos + i)) {
2398                 ++i;
2399         }
2400         if (str.length() == string::size_type(i))
2401                 return true;
2402         return false;
2403 }
2404
2405
2406 // sets the selection over the number of characters of string, no check!!
2407 void LyXText::SetSelectionOverString(BufferView * bview, string const & str)
2408 {
2409         sel_cursor = cursor;
2410         for (int i = 0; str[i]; ++i)
2411                 CursorRight(bview);
2412         SetSelection(bview);
2413 }
2414
2415
2416 // simple replacing. The font of the first selected character is used
2417 void LyXText::ReplaceSelectionWithString(BufferView * bview,
2418                                          string const & str)
2419 {
2420         SetCursorParUndo(bview->buffer());
2421         FreezeUndo();
2422
2423         if (!selection) { // create a dummy selection
2424                 sel_end_cursor = cursor;
2425                 sel_start_cursor = cursor;
2426         }
2427
2428         // Get font setting before we cut
2429         LyXParagraph::size_type pos = sel_end_cursor.pos();
2430         LyXFont const font = sel_start_cursor.par()
2431                 ->GetFontSettings(bview->buffer()->params,
2432                                   sel_start_cursor.pos());
2433
2434         // Insert the new string
2435         for (string::const_iterator cit = str.begin(); cit != str.end(); ++cit) {
2436                 sel_end_cursor.par()->InsertChar(pos, (*cit), font);
2437                 ++pos;
2438         }
2439         
2440         // Cut the selection
2441         CutSelection(bview);
2442
2443         UnFreezeUndo();
2444 }
2445
2446
2447 // if the string can be found: return true and set the cursor to
2448 // the new position
2449 bool LyXText::SearchForward(BufferView * bview, string const & str) const
2450 {
2451         LyXParagraph * par = cursor.par();
2452         LyXParagraph::size_type pos = cursor.pos();
2453         while (par && !IsStringInText(par, pos, str)) {
2454                 if (pos < par->Last() - 1)
2455                         ++pos;
2456                 else {
2457                         pos = 0;
2458                         par = par->Next();
2459                 }
2460         }
2461         if (par) {
2462                 SetCursor(bview, par, pos);
2463                 return true;
2464         }
2465         else
2466                 return false;
2467 }
2468
2469
2470 bool LyXText::SearchBackward(BufferView * bview, string const & str) const
2471 {
2472         LyXParagraph * par = cursor.par();
2473         int pos = cursor.pos();
2474
2475         do {
2476                 if (pos > 0)
2477                         --pos;
2478                 else {
2479                         // We skip empty paragraphs (Asger)
2480                         do {
2481                                 par = par->Previous();
2482                                 if (par)
2483                                         pos = par->Last() - 1;
2484                         } while (par && pos < 0);
2485                 }
2486         } while (par && !IsStringInText(par, pos, str));
2487   
2488         if (par) {
2489                 SetCursor(bview, par, pos);
2490                 return true;
2491         } else
2492                 return false;
2493 }
2494
2495
2496 // needed to insert the selection
2497 void LyXText::InsertStringA(BufferView * bview, string const & str)
2498 {
2499         LyXParagraph * par = cursor.par();
2500         LyXParagraph::size_type pos = cursor.pos();
2501         LyXParagraph::size_type a = 0;
2502         LyXParagraph * endpar = cursor.par()->Next();
2503         
2504         SetCursorParUndo(bview->buffer());
2505         
2506         bool flag =
2507                 textclasslist.Style(bview->buffer()->params.textclass, 
2508                                     cursor.par()->GetLayout()).isEnvironment();
2509         // only to be sure, should not be neccessary
2510         ClearSelection(bview);
2511         
2512         // insert the string, don't insert doublespace
2513         string::size_type i = 0;
2514         while (i < str.length()) {
2515                 if (str[i] != '\n') {
2516                         if (str[i] == ' ' 
2517                             && i + 1 < str.length() && str[i + 1] != ' '
2518                             && pos && par->GetChar(pos - 1)!= ' ') {
2519                                 par->InsertChar(pos, ' ', current_font);
2520                                 ++pos;
2521                         } else if (str[i] == ' ') {
2522                                 InsetSpecialChar * new_inset =
2523                                         new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2524                                 if (par->InsertInsetAllowed(new_inset)) {
2525                                         par->InsertInset(pos, new_inset,
2526                                                          current_font);
2527                                 } else {
2528                                         delete new_inset;
2529                                 }
2530                                 ++pos;
2531                         } else if (str[i] == '\t') {
2532                                 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2533                                 InsetSpecialChar * new_inset =
2534                                         new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2535                                 if (par->InsertInsetAllowed(new_inset)) {
2536                                         par->InsertInset(pos, new_inset,
2537                                                          current_font);
2538                                 } else {
2539                                         delete new_inset;
2540                                 }
2541                                 }
2542                                 pos = a;
2543                         } else if (str[i] != 13 && 
2544                                    // Ignore unprintables
2545                                    (str[i] & 127) >= ' ') {
2546                                 par->InsertChar(pos, str[i], current_font);
2547                                 ++pos;
2548                         }
2549                 } else {
2550                         if (!par->size()) { // par is empty
2551                                 InsetSpecialChar * new_inset =
2552                                         new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2553                                 if (par->InsertInsetAllowed(new_inset)) {
2554                                         par->InsertInset(pos,
2555                                                          new_inset,
2556                                                          current_font);
2557                                 } else {
2558                                         delete new_inset;
2559                                 }
2560                                 ++pos;
2561                         }
2562                         par->BreakParagraph(bview->buffer()->params, pos, flag);
2563                         par = par->Next();
2564                         pos = 0;
2565                 }
2566                 ++i;
2567         }
2568         
2569         RedoParagraphs(bview, cursor, endpar);
2570         SetCursor(bview, cursor.par(), cursor.pos());
2571         sel_cursor = cursor;
2572         SetCursor(bview, par, pos);
2573         SetSelection(bview);
2574 }
2575
2576
2577 /* turns double-CR to single CR, others where converted into one blank and 13s 
2578  * that are ignored .Double spaces are also converted into one. Spaces at
2579  * the beginning of a paragraph are forbidden. tabs are converted into one
2580  * space. then InsertStringA is called */ 
2581 void LyXText::InsertStringB(BufferView * bview, string const & s)
2582 {
2583         string str(s);
2584         string::size_type i = 1;
2585         while (i < str.length()) {
2586                 if (str[i] == '\t')
2587                         str[i] = ' ';
2588                 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2589                         str[i] = 13;
2590                 if (str[i] == '\n' && i + 1 < str.length()) {
2591                         if (str[i + 1] != '\n') {
2592                                 if (str[i - 1] != ' ')
2593                                         str[i] = ' ';
2594                                 else
2595                                         str[i] = 13;
2596                         }
2597                         while (i + 1 < str.length() 
2598                                && (str[i + 1] == ' ' 
2599                                    || str[i + 1] == '\t'
2600                                    || str[i + 1] == '\n' 
2601                                    || str[i + 1] == 13)) {
2602                                 str[i + 1] = 13;
2603                                 ++i;
2604                         }
2605                 }
2606                 ++i;
2607         }
2608         InsertStringA(bview, str);
2609 }
2610
2611
2612 bool LyXText::GotoNextInset(BufferView * bview,
2613                             std::vector<Inset::Code> const & codes,
2614                             string const & contents) const
2615 {
2616         LyXCursor res = cursor;
2617         Inset * inset;
2618         do {
2619                 if (res.pos() < res.par()->Last() - 1) {
2620                         res.pos(res.pos() + 1);
2621                 } else  {
2622                         res.par(res.par()->Next());
2623                         res.pos(0);
2624                 }
2625       
2626         } while (res.par() && 
2627                  !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2628                    && (inset = res.par()->GetInset(res.pos())) != 0
2629                    && find(codes.begin(), codes.end(), inset->LyxCode())
2630                       != codes.end()
2631                    && (contents.empty() ||
2632                        static_cast<InsetCommand *>(res.par()->GetInset(res.pos()))->getContents()
2633                        == contents)));
2634
2635         if (res.par()) {
2636                 SetCursor(bview, res.par(), res.pos());
2637                 return true;
2638         }
2639         return false;
2640 }
2641
2642
2643 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
2644                              LyXParagraph::size_type pos)
2645 {
2646         LyXCursor tmpcursor;                    
2647
2648         int y = 0;
2649         LyXParagraph::size_type z;
2650         Row * row = GetRow(par, pos, y);
2651         
2652         // is there a break one row above
2653         if (row->previous() && row->previous()->par() == row->par()) {
2654                 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
2655                 if (z >= row->pos()) {
2656                         // set the dimensions of the row above
2657                         y -= row->previous()->height();
2658                         refresh_y = y;
2659                         refresh_row = row->previous();
2660                         status = LyXText::NEED_MORE_REFRESH;
2661                         
2662                         BreakAgain(bview, row->previous());
2663                         
2664                         // set the cursor again. Otherwise
2665                         // dangling pointers are possible
2666                         SetCursor(bview, cursor.par(), cursor.pos(),
2667                                   false, cursor.boundary());
2668                         sel_cursor = cursor;
2669                         return;
2670                 }
2671         }
2672
2673         int const tmpheight = row->height();
2674         LyXParagraph::size_type const tmplast = RowLast(row);
2675         refresh_y = y;
2676         refresh_row = row;
2677         
2678         BreakAgain(bview, row);
2679         if (row->height() == tmpheight && RowLast(row) == tmplast)
2680                 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2681         else
2682                 status = LyXText::NEED_MORE_REFRESH; 
2683         
2684         // check the special right address boxes
2685         if (textclasslist.Style(bview->buffer()->params.textclass,
2686                                 par->GetLayout()).margintype
2687             == MARGIN_RIGHT_ADDRESS_BOX) {
2688                 tmpcursor.par(par);
2689                 tmpcursor.row(row);
2690                 tmpcursor.y(y);
2691                 tmpcursor.x(0);
2692                 tmpcursor.x_fix(0);
2693                 tmpcursor.pos(pos);
2694                 RedoDrawingOfParagraph(bview, tmpcursor); 
2695         }
2696
2697         // set the cursor again. Otherwise dangling pointers are possible
2698         // also set the selection
2699    
2700         if (selection) {
2701                 tmpcursor = cursor;
2702                 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos(),
2703                                 false, sel_cursor.boundary());
2704                 sel_cursor = cursor; 
2705                 SetCursorIntern(bview, sel_start_cursor.par(),
2706                                 sel_start_cursor.pos(),
2707                                 false, sel_start_cursor.boundary());
2708                 sel_start_cursor = cursor; 
2709                 SetCursorIntern(bview, sel_end_cursor.par(),
2710                                 sel_end_cursor.pos(),
2711                                 false, sel_end_cursor.boundary());
2712                 sel_end_cursor = cursor; 
2713                 SetCursorIntern(bview, last_sel_cursor.par(),
2714                                 last_sel_cursor.pos(),
2715                                 false, last_sel_cursor.boundary());
2716                 last_sel_cursor = cursor; 
2717                 cursor = tmpcursor;
2718         }
2719         SetCursorIntern(bview, cursor.par(), cursor.pos(),
2720                         false, cursor.boundary());
2721 }
2722
2723
2724 // returns false if inset wasn't found
2725 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2726 {
2727         // first check the current paragraph
2728         int pos = cursor.par()->GetPositionOfInset(inset);
2729         if (pos != -1){
2730                 CheckParagraph(bview, cursor.par(), pos);
2731                 return true;
2732         }
2733   
2734         // check every paragraph
2735   
2736         LyXParagraph * par = FirstParagraph();
2737         do {
2738 #ifndef NEW_INSETS
2739                 // make sure the paragraph is open
2740                 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2741 #endif
2742                         pos = par->GetPositionOfInset(inset);
2743                         if (pos != -1){
2744                                 CheckParagraph(bview, par, pos);
2745                                 return true;
2746                         }
2747 #ifndef NEW_INSETS
2748                 }
2749 #endif
2750                 par = par->Next();
2751         } while (par);
2752   
2753         return false;
2754 }
2755
2756
2757 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2758                         LyXParagraph::size_type pos, 
2759                         bool setfont, bool boundary) const
2760 {
2761         LyXCursor old_cursor = cursor;
2762         SetCursorIntern(bview, par, pos, setfont, boundary);
2763         DeleteEmptyParagraphMechanism(bview, old_cursor);
2764 }
2765
2766
2767 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2768                         LyXParagraph::size_type pos, bool boundary) const
2769 {
2770 #ifndef NEW_INSETS
2771         // correct the cursor position if impossible
2772         if (pos > par->Last()){
2773                 LyXParagraph * tmppar = par->ParFromPos(pos);
2774                 pos = par->PositionInParFromPos(pos);
2775                 par = tmppar;
2776         }
2777         if (par->IsDummy() && par->previous &&
2778             par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2779                 while (par->previous &&
2780                        ((par->previous->IsDummy() &&
2781                          (par->previous->previous->footnoteflag ==
2782                           LyXParagraph::CLOSED_FOOTNOTE)) ||
2783                         (par->previous->footnoteflag ==
2784                          LyXParagraph::CLOSED_FOOTNOTE))) {
2785                         par = par->previous ;
2786                         if (par->IsDummy() &&
2787                             (par->previous->footnoteflag ==
2788                              LyXParagraph::CLOSED_FOOTNOTE))
2789                                 pos += par->size() + 1;
2790                 }
2791                 if (par->previous) {
2792                         par = par->previous;
2793                 }
2794                 pos += par->size() + 1;
2795         }
2796 #endif
2797         cur.par(par);
2798         cur.pos(pos);
2799         cur.boundary(boundary);
2800
2801         /* get the cursor y position in text  */
2802         int y = 0;
2803         Row * row = GetRow(par, pos, y);
2804         /* y is now the beginning of the cursor row */ 
2805         y += row->baseline();
2806         /* y is now the cursor baseline */ 
2807         cur.y(y);
2808    
2809         /* now get the cursors x position */
2810         float x;
2811         float fill_separator, fill_hfill, fill_label_hfill;
2812         PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2813                        fill_label_hfill);
2814         LyXParagraph::size_type cursor_vpos = 0;
2815         LyXParagraph::size_type last = RowLastPrintable(row);
2816
2817         if (pos > last + 1)   // This shouldn't happen.
2818                 pos = last + 1;
2819         else if (pos < row->pos())
2820                 pos = row->pos();
2821
2822         if (last < row->pos())
2823                 cursor_vpos = row->pos();
2824         else if (pos > last && !boundary)
2825                 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2826                         ? row->pos() : last + 1; 
2827         else if (pos > row->pos() &&
2828                  (pos > last || boundary))
2829                 /// Place cursor after char at (logical) position pos - 1
2830                 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2831                         ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2832         else
2833                 /// Place cursor before char at (logical) position pos
2834                 cursor_vpos = (bidi_level(pos) % 2 == 0)
2835                         ? log2vis(pos) : log2vis(pos) + 1;
2836         
2837         LyXParagraph::size_type main_body =
2838                 BeginningOfMainBody(bview->buffer(), row->par());
2839         if ((main_body > 0) &&
2840             ((main_body-1 > last) || 
2841              !row->par()->IsLineSeparator(main_body-1)))
2842                 main_body = 0;
2843         
2844         for (LyXParagraph::size_type vpos = row->pos();
2845              vpos < cursor_vpos; ++vpos) {
2846                 pos = vis2log(vpos);
2847                 if (main_body > 0 && pos == main_body - 1) {
2848                         x += fill_label_hfill +
2849                                 lyxfont::width(textclasslist.Style(
2850                                         bview->buffer()->params.textclass,
2851                                         row->par()->GetLayout())
2852                                                .labelsep,
2853                                                GetFont(bview->buffer(), row->par(), -2));
2854                         if (row->par()->IsLineSeparator(main_body-1))
2855                                 x -= SingleWidth(bview, row->par(),main_body-1);
2856                 }
2857                 if (HfillExpansion(bview->buffer(), row, pos)) {
2858                         x += SingleWidth(bview, row->par(), pos);
2859                         if (pos >= main_body)
2860                                 x += fill_hfill;
2861                         else 
2862                                 x += fill_label_hfill;
2863                 } else if (row->par()->IsSeparator(pos)) {
2864                         x += SingleWidth(bview, row->par(), pos);
2865                         if (pos >= main_body)
2866                                 x += fill_separator;
2867                 } else
2868                         x += SingleWidth(bview, row->par(), pos);
2869         }
2870         
2871         cur.x(int(x));
2872         cur.x_fix(cur.x());
2873         cur.row(row);
2874 }
2875
2876
2877 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
2878                               LyXParagraph::size_type pos,
2879                               bool setfont, bool boundary) const
2880 {
2881         SetCursor(bview, cursor, par, pos, boundary);
2882         if (setfont)
2883                 SetCurrentFont(bview);
2884 }
2885
2886
2887 void LyXText::SetCurrentFont(BufferView * bview) const
2888 {
2889         LyXParagraph::size_type pos = cursor.pos();
2890         if (cursor.boundary() && pos > 0)
2891                 --pos;
2892
2893         if (pos > 0) {
2894                 if (pos == cursor.par()->Last())
2895                         --pos;
2896                 else if (cursor.par()->IsSeparator(pos)) {
2897                         if (pos > cursor.row()->pos() &&
2898                             bidi_level(pos) % 2 == 
2899                             bidi_level(pos - 1) % 2)
2900                                 --pos;
2901                         else if (pos + 1 < cursor.par()->Last())
2902                                 ++pos;
2903                 }
2904         }
2905
2906         current_font =
2907                 cursor.par()->GetFontSettings(bview->buffer()->params, pos);
2908         real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
2909
2910         if (cursor.pos() == cursor.par()->Last() &&
2911             IsBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
2912             !cursor.boundary()) {
2913                 Language const * lang =
2914                         cursor.par()->getParLanguage(bview->buffer()->params);
2915                 current_font.setLanguage(lang);
2916                 current_font.setNumber(LyXFont::OFF);
2917                 real_current_font.setLanguage(lang);
2918                 real_current_font.setNumber(LyXFont::OFF);
2919         }
2920 }
2921
2922
2923 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, int y) const
2924 {
2925         LyXCursor old_cursor = cursor;
2926    
2927         /* get the row first */ 
2928    
2929         Row * row = GetRowNearY(y);
2930         cursor.par(row->par());
2931
2932         bool bound = false;
2933         int column = GetColumnNearX(bview, row, x, bound);
2934         cursor.pos(row->pos() + column);
2935         cursor.x(x);
2936         cursor.y(y + row->baseline());
2937         cursor.row(row);
2938         cursor.boundary(bound);
2939         SetCurrentFont(bview);
2940         DeleteEmptyParagraphMechanism(bview, old_cursor);
2941 }
2942
2943
2944 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
2945                                        int x, int y) const
2946 {
2947         /* get the row first */ 
2948    
2949         Row * row = GetRowNearY(y);
2950         bool bound = false;
2951         int column = GetColumnNearX(bview, row, x, bound);
2952    
2953         cur.par(row->par());
2954         cur.pos(row->pos() + column);
2955         cur.x(x);
2956         cur.y(y + row->baseline());
2957         cur.row(row);
2958         cur.boundary(bound);
2959 }
2960
2961
2962 void LyXText::CursorLeft(BufferView * bview, bool internal) const
2963 {
2964         if (cursor.pos() > 0) {
2965                 bool boundary = cursor.boundary();
2966                 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
2967                 if (!internal && !boundary &&
2968                     IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
2969                         SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
2970         } else if (cursor.par()->Previous()) { // steps into the above paragraph.
2971                 LyXParagraph * par = cursor.par()->Previous();
2972                 SetCursor(bview, par, par->Last());
2973         }
2974 }
2975
2976
2977 void LyXText::CursorRight(BufferView * bview, bool internal) const
2978 {
2979         if (!internal && cursor.boundary() &&
2980             !cursor.par()->IsNewline(cursor.pos()))
2981                 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
2982         else if (cursor.pos() < cursor.par()->Last()) {
2983                 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
2984                 if (!internal &&
2985                     IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
2986                         SetCursor(bview, cursor.par(), cursor.pos(), true, true);
2987         } else if (cursor.par()->Next())
2988                 SetCursor(bview, cursor.par()->Next(), 0);
2989 }
2990
2991
2992 void LyXText::CursorUp(BufferView * bview) const
2993 {
2994         SetCursorFromCoordinates(bview, cursor.x_fix(), 
2995                                  cursor.y() - cursor.row()->baseline() - 1);
2996 }
2997
2998
2999 void LyXText::CursorDown(BufferView * bview) const
3000 {
3001         SetCursorFromCoordinates(bview, cursor.x_fix(), 
3002                                  cursor.y() - cursor.row()->baseline()
3003                                  + cursor.row()->height() + 1);
3004 }
3005
3006
3007 void LyXText::CursorUpParagraph(BufferView * bview) const
3008 {
3009         if (cursor.pos() > 0) {
3010                 SetCursor(bview, cursor.par(), 0);
3011         }
3012         else if (cursor.par()->Previous()) {
3013                 SetCursor(bview, cursor.par()->Previous(), 0);
3014         }
3015 }
3016
3017
3018 void LyXText::CursorDownParagraph(BufferView * bview) const
3019 {
3020         if (cursor.par()->Next()) {
3021                 SetCursor(bview, cursor.par()->Next(), 0);
3022         } else {
3023                 SetCursor(bview, cursor.par(), cursor.par()->Last());
3024         }
3025 }
3026
3027
3028 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
3029                                             LyXCursor const & old_cursor) const
3030 {
3031         // Would be wrong to delete anything if we have a selection.
3032         if (selection) return;
3033
3034         // We allow all kinds of "mumbo-jumbo" when freespacing.
3035         if (textclasslist.Style(bview->buffer()->params.textclass,
3036                                 old_cursor.par()->GetLayout()).free_spacing)
3037                 return;
3038
3039         bool deleted = false;
3040         
3041         /* Ok I'll put some comments here about what is missing.
3042            I have fixed BackSpace (and thus Delete) to not delete
3043            double-spaces automagically. I have also changed Cut,
3044            Copy and Paste to hopefully do some sensible things.
3045            There are still some small problems that can lead to
3046            double spaces stored in the document file or space at
3047            the beginning of paragraphs. This happens if you have
3048            the cursor betwenn to spaces and then save. Or if you
3049            cut and paste and the selection have a space at the
3050            beginning and then save right after the paste. I am
3051            sure none of these are very hard to fix, but I will
3052            put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3053            that I can get some feedback. (Lgb)
3054         */
3055
3056         // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
3057         // delete the LineSeparator.
3058         // MISSING
3059
3060         // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
3061         // delete the LineSeparator.
3062         // MISSING
3063
3064         // If the pos around the old_cursor were spaces, delete one of them.
3065         if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) { 
3066                 // Only if the cursor has really moved
3067                 
3068                 if (old_cursor.pos() > 0
3069                     && old_cursor.pos() < old_cursor.par()->Last()
3070                     && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3071                     && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3072                         old_cursor.par()->Erase(old_cursor.pos() - 1);
3073                         RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3074                         // correct cursor
3075                         if (old_cursor.par() == cursor.par() &&
3076                             cursor.pos() > old_cursor.pos()) {
3077                                 SetCursorIntern(bview, cursor.par(),
3078                                                 cursor.pos() - 1);
3079                         } else
3080                                 SetCursorIntern(bview, cursor.par(),
3081                                                 cursor.pos());
3082                         return;
3083                 }
3084         }
3085
3086         // Do not delete empty paragraphs with keepempty set.
3087         if ((textclasslist.Style(bview->buffer()->params.textclass,
3088                                  old_cursor.par()->GetLayout())).keepempty)
3089                 return;
3090
3091         LyXCursor tmpcursor;
3092
3093         if (old_cursor.par() != cursor.par()) {
3094                 if ((old_cursor.par()->Last() == 0
3095                       || (old_cursor.par()->Last() == 1
3096                           && old_cursor.par()->IsLineSeparator(0)))
3097 #ifndef NEW_INSETS
3098                      && old_cursor.par()->FirstPhysicalPar()
3099                      == old_cursor.par()->LastPhysicalPar()
3100 #endif
3101                         ) {
3102                         // ok, we will delete anything
3103                         
3104                         // make sure that you do not delete any environments
3105 #ifndef NEW_INSETS
3106                         if ((
3107                                 old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3108                              !(old_cursor.row()->previous() 
3109                                && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3110                              && !(old_cursor.row()->next() 
3111                                   && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3112                             || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3113                                 && ((old_cursor.row()->previous() 
3114                                      && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3115                                     || (old_cursor.row()->next()
3116                                         && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3117                                     )) {
3118 #endif
3119                                 status = LyXText::NEED_MORE_REFRESH;
3120                                 deleted = true;
3121                                 
3122                                 if (old_cursor.row()->previous()) {
3123                                         refresh_row = old_cursor.row()->previous();
3124                                         refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3125                                         tmpcursor = cursor;
3126                                         cursor = old_cursor; // that undo can restore the right cursor position
3127                                         LyXParagraph * endpar = old_cursor.par()->next;
3128                                         if (endpar && endpar->GetDepth()) {
3129                                                 while (endpar && endpar->GetDepth()) {
3130 #ifndef NEW_INSETS
3131                                                         endpar = endpar->LastPhysicalPar()->Next();
3132 #else
3133                                                         endpar = endpar->Next();
3134 #endif
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                                         if (OwnerParagraph() == old_cursor.par()) {
3145                                                 OwnerParagraph(OwnerParagraph()->next);
3146                                         }
3147                                         // delete old par
3148                                         delete old_cursor.par();
3149                                         
3150                                         /* Breakagain the next par. Needed
3151                                          * because of the parindent that
3152                                          * can occur or dissappear. The
3153                                          * next row can change its height,
3154                                          * if there is another layout before */
3155                                         if (refresh_row->next()) {
3156                                                 BreakAgain(bview, refresh_row->next());
3157                                                 UpdateCounters(bview, refresh_row);
3158                                         }
3159                                         SetHeightOfRow(bview, refresh_row);
3160                                 } else {
3161                                         refresh_row = old_cursor.row()->next();
3162                                         refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3163                                         
3164                                         tmpcursor = cursor;
3165                                         cursor = old_cursor; // that undo can restore the right cursor position
3166                                         LyXParagraph * endpar = old_cursor.par()->next;
3167                                         if (endpar && endpar->GetDepth()) {
3168                                                 while (endpar && endpar->GetDepth()) {
3169 #ifndef NEW_INSETS
3170                                                         endpar = endpar->LastPhysicalPar()->Next();
3171 #else
3172                                                         endpar = endpar->Next();
3173 #endif
3174                                                 }
3175                                         }
3176                                         SetUndo(bview->buffer(), Undo::DELETE,
3177                                                 old_cursor.par()->previous,
3178                                                 endpar);
3179                                         cursor = tmpcursor;
3180
3181                                         // delete old row
3182                                         RemoveRow(old_cursor.row());
3183                                         // delete old par
3184                                         if (OwnerParagraph() == old_cursor.par()) {
3185                                                 OwnerParagraph(OwnerParagraph()->next);
3186                                         }
3187                                         delete old_cursor.par();
3188                                         
3189                                         /* Breakagain the next par. Needed
3190                                            because of the parindent that can
3191                                            occur or dissappear.
3192                                            The next row can change its height,
3193                                            if there is another layout before
3194                                         */ 
3195                                         if (refresh_row) {
3196                                                 BreakAgain(bview, refresh_row);
3197                                                 UpdateCounters(bview, refresh_row->previous());
3198                                         }
3199                                 }
3200                                 
3201                                 // correct cursor y
3202
3203                                 SetCursorIntern(bview, cursor.par(), cursor.pos());
3204
3205                                 if (sel_cursor.par()  == old_cursor.par()
3206                                     && sel_cursor.pos() == sel_cursor.pos()) {
3207                                         // correct selection
3208                                         sel_cursor = cursor;
3209                                 }
3210 #ifndef NEW_INSETS
3211                         }
3212 #endif
3213                 }
3214                 if (!deleted) {
3215                         if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
3216                                 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3217                                 // correct cursor y
3218                                 SetCursorIntern(bview, cursor.par(), cursor.pos());
3219                                 sel_cursor = cursor;
3220                         }
3221                 }
3222         }
3223 }
3224
3225
3226 LyXParagraph * LyXText::GetParFromID(int id)
3227 {
3228         LyXParagraph * result = FirstParagraph();
3229         while (result && result->id() != id)
3230                 result = result->next;
3231         return result;
3232 }
3233
3234
3235 // undo functions
3236 bool LyXText::TextUndo(BufferView * bview)
3237 {
3238         if (inset_owner)
3239                 return false;
3240         // returns false if no undo possible
3241         Undo * undo = bview->buffer()->undostack.pop();
3242         if (undo) {
3243                 FinishUndo();
3244                 if (!undo_frozen)
3245                         bview->buffer()->redostack
3246                                 .push(CreateUndo(bview->buffer(), undo->kind, 
3247                                                  GetParFromID(undo->number_of_before_par),
3248                                                  GetParFromID(undo->number_of_behind_par)));
3249         }
3250         return TextHandleUndo(bview, undo);
3251 }
3252
3253
3254 bool LyXText::TextRedo(BufferView * bview)
3255 {
3256         if (inset_owner)
3257                 return false;
3258         // returns false if no redo possible
3259         Undo * undo = bview->buffer()->redostack.pop();
3260         if (undo) {
3261                 FinishUndo();
3262                 if (!undo_frozen)
3263                         bview->buffer()->undostack
3264                                 .push(CreateUndo(bview->buffer(), undo->kind, 
3265                                                  GetParFromID(undo->number_of_before_par),
3266                                                  GetParFromID(undo->number_of_behind_par)));
3267         }
3268         return TextHandleUndo(bview, undo);
3269 }
3270
3271
3272 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
3273 {
3274         if (inset_owner)
3275                 return false;
3276         // returns false if no undo possible
3277         bool result = false;
3278         if (undo) {
3279                 LyXParagraph * before =
3280                         GetParFromID(undo->number_of_before_par); 
3281                 LyXParagraph * behind =
3282                         GetParFromID(undo->number_of_behind_par); 
3283                 LyXParagraph * tmppar;
3284                 LyXParagraph * tmppar2;
3285                 LyXParagraph * endpar;
3286                 LyXParagraph * tmppar5;
3287     
3288                 // if there's no before take the beginning
3289                 // of the document for redoing
3290                 if (!before)
3291                         SetCursorIntern(bview, FirstParagraph(), 0);
3292
3293                 // replace the paragraphs with the undo informations
3294
3295                 LyXParagraph * tmppar3 = undo->par;
3296                 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3297                 LyXParagraph * tmppar4 = tmppar3;
3298                 if (tmppar4){
3299                         while (tmppar4->next)
3300                                 tmppar4 = tmppar4->next;
3301                 } // get last undo par
3302     
3303                 // now remove the old text if there is any
3304                 if (before != behind || (!behind && !before)){
3305                         if (before)
3306                                 tmppar5 = before->next;
3307                         else
3308                                 tmppar5 = OwnerParagraph();
3309                         tmppar2 = tmppar3;
3310                         while (tmppar5 && tmppar5 != behind){
3311                                 tmppar = tmppar5;
3312                                 tmppar5 = tmppar5->next;
3313                                 // a memory optimization for edit: Only layout information
3314                                 // is stored in the undo. So restore the text informations.
3315                                 if (undo->kind == Undo::EDIT) {
3316                                         tmppar2->setContentsFromPar(tmppar);
3317                                         tmppar->clearContents();
3318                                         tmppar2 = tmppar2->next;
3319                                 }
3320                         }
3321                 }
3322     
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         if (before)
3490                 start = before->next;
3491         else
3492                 start = FirstParagraph();
3493         if (behind)
3494                 end = behind->previous;
3495         else {
3496                 end = FirstParagraph();
3497                 while (end->next)
3498                         end = end->next;
3499         }
3500
3501         if (start && end && (start != end->next) &&
3502             ((before != behind) || (!before && !behind)))
3503         {
3504                 tmppar = start;
3505                 tmppar2 = tmppar->Clone();
3506                 tmppar2->id(tmppar->id());
3507
3508                 // a memory optimization: Just store the layout information
3509                 // when only edit
3510                 if (kind == Undo::EDIT){
3511                         //tmppar2->text.clear();
3512                         tmppar2->clearContents();
3513                 }
3514
3515                 undopar = tmppar2;
3516   
3517                 while (tmppar != end && tmppar->next) {
3518                         tmppar = tmppar->next;
3519                         tmppar2->next = tmppar->Clone();
3520                         tmppar2->next->id(tmppar->id());
3521                         // a memory optimization: Just store the layout
3522                         // information when only edit
3523                         if (kind == Undo::EDIT){
3524                                 //tmppar2->next->text.clear();
3525                                 tmppar2->clearContents();
3526                         }
3527                         tmppar2->next->previous = tmppar2;
3528                         tmppar2 = tmppar2->next;
3529                 }
3530                 tmppar2->next = 0;
3531         } else
3532                 undopar = 0; // nothing to replace (undo of delete maybe)
3533
3534 #ifndef NEW_INSETS
3535         int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
3536         int cursor_pos =  cursor.par()->PositionInParFromPos(cursor.pos());
3537 #else
3538         int cursor_par = cursor.par()->id();
3539         int cursor_pos =  cursor.pos();
3540 #endif
3541
3542         Undo * undo = new Undo(kind, 
3543                                before_number, behind_number,  
3544                                cursor_par, cursor_pos, 
3545                                undopar);
3546   
3547         undo_finished = false;
3548         return undo;
3549 }
3550
3551
3552 void LyXText::SetCursorParUndo(Buffer * buf)
3553 {
3554         if (inset_owner)
3555                 return;
3556         SetUndo(buf, Undo::FINISH,
3557 #ifndef NEW_INSETS
3558                 cursor.par()->ParFromPos(cursor.pos())->previous, 
3559                 cursor.par()->ParFromPos(cursor.pos())->next
3560 #else
3561                 cursor.par()->previous, 
3562                 cursor.par()->next
3563 #endif
3564                 ); 
3565 }
3566
3567
3568 void LyXText::toggleAppendix(BufferView * bview)
3569 {
3570 #ifndef NEW_INSETS
3571         LyXParagraph * par = cursor.par()->FirstPhysicalPar();
3572 #else
3573         LyXParagraph * par = cursor.par();
3574 #endif
3575         bool start = !par->start_of_appendix;
3576
3577         // ensure that we have only one start_of_appendix in this document
3578         LyXParagraph * tmp = FirstParagraph();
3579         for (; tmp; tmp = tmp->next)
3580                 tmp->start_of_appendix = 0;
3581         par->start_of_appendix = start;
3582
3583         // we can set the refreshing parameters now
3584         status = LyXText::NEED_MORE_REFRESH;
3585         refresh_y = 0;
3586         refresh_row = 0; // not needed for full update
3587         UpdateCounters(bview, 0);
3588         SetCursor(bview, cursor.par(), cursor.pos());
3589 }
3590
3591
3592 LyXParagraph * LyXText::OwnerParagraph() const
3593 {
3594         if (inset_owner)
3595                 return inset_owner->par;
3596
3597         return bv_owner->buffer()->paragraph;
3598 }
3599
3600
3601 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
3602 {
3603         if (inset_owner)
3604                 inset_owner->par = p;
3605         else
3606                 bv_owner->buffer()->paragraph = p;
3607         return 0;
3608 }