]> git.lyx.org Git - lyx.git/blob - src/text2.C
mathed31.diff
[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();
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();
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();
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();
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() const
1212 {
1213         if (selection)
1214                 status = LyXText::NEED_MORE_REFRESH;
1215         selection = false;
1216         mark_set = false;
1217 }
1218
1219
1220 void LyXText::CursorHome(BufferView * bview) const
1221 {
1222         SetCursor(bview, cursor.par(), cursor.row()->pos());
1223 }
1224
1225
1226 void LyXText::CursorEnd(BufferView * bview) const
1227 {
1228         if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1229                 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1230         else {
1231                 if (cursor.par()->Last() && 
1232                     (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1233                      || cursor.par()->IsNewline(RowLast(cursor.row()))))
1234                         SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1235                 else
1236                         SetCursor(bview,cursor.par(), RowLast(cursor.row()) + 1);
1237         }
1238 }
1239
1240
1241 void  LyXText::CursorTop(BufferView * bview) const
1242 {
1243         while (cursor.par()->Previous())
1244                 cursor.par(cursor.par()->Previous());
1245         SetCursor(bview, cursor.par(), 0);
1246 }
1247
1248
1249 void  LyXText::CursorBottom(BufferView * bview) const
1250 {
1251         while (cursor.par()->Next())
1252                 cursor.par(cursor.par()->Next());
1253         SetCursor(bview, cursor.par(), cursor.par()->Last());
1254 }
1255    
1256    
1257 /* returns a pointer to the row near the specified y-coordinate
1258 * (relative to the whole text). y is set to the real beginning
1259 * of this row */
1260 Row * LyXText::GetRowNearY(int & y) const
1261 {
1262         Row * tmprow = firstrow;
1263         int tmpy = 0;
1264
1265         while (tmprow->next() && tmpy + tmprow->height() <= y) {
1266                 tmpy += tmprow->height();
1267                 tmprow = tmprow->next();
1268         }
1269
1270         y = tmpy;   // return the real y
1271         return tmprow;
1272 }
1273
1274
1275 void LyXText::ToggleFree(BufferView * bview,
1276                          LyXFont const & font, bool toggleall)
1277 {
1278         // If the mask is completely neutral, tell user
1279         if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1280                 // Could only happen with user style
1281                 bview->owner()->getMiniBuffer()
1282                         ->Set(_("No font change defined. Use Character under"
1283                                 " the Layout menu to define font change."));
1284                 return;
1285         }
1286
1287         // Try implicit word selection
1288         // If there is a change in the language the implicit word selection 
1289         // is disabled.
1290         LyXCursor resetCursor = cursor;
1291         bool implicitSelection = (font.language() == ignore_language
1292                                   && font.number() == LyXFont::IGNORE)
1293                 ? SelectWordWhenUnderCursor(bview) : false;
1294
1295         // Set font
1296         SetFont(bview, font, toggleall);
1297
1298         /* Implicit selections are cleared afterwards and cursor is set to the
1299            original position. */
1300         if (implicitSelection) {
1301                 ClearSelection();
1302                 cursor = resetCursor;
1303                 SetCursor(bview, cursor.par(), cursor.pos());
1304                 sel_cursor = cursor;
1305         }
1306         if (inset_owner)
1307                 inset_owner->SetUpdateStatus(bview, InsetText::CURSOR_PAR);
1308 }
1309
1310
1311 LyXParagraph::size_type
1312 LyXText::BeginningOfMainBody(Buffer const * buf,
1313                              LyXParagraph const * par) const
1314 {
1315         if (textclasslist.Style(buf->params.textclass,
1316                                 par->GetLayout()).labeltype != LABEL_MANUAL)
1317                 return 0;
1318         else
1319                 return par->BeginningOfMainBody();
1320 }
1321
1322
1323 #ifndef NEW_INSETS
1324 /* if there is a selection, reset every environment you can find
1325 * in the selection, otherwise just the environment you are in */ 
1326 void LyXText::MeltFootnoteEnvironment(BufferView * bview)
1327 {
1328         LyXParagraph * tmppar, * firsttmppar;
1329    
1330         ClearSelection();
1331    
1332         /* is is only allowed, if the cursor is IN an open footnote.
1333          * Otherwise it is too dangerous */ 
1334         if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1335                 return;
1336    
1337         SetUndo(bview->buffer(), Undo::FINISH, 
1338                 cursor.par()->PreviousBeforeFootnote()->previous,
1339                 cursor.par()->NextAfterFootnote()->next);
1340
1341         /* ok, move to the beginning of the footnote. */ 
1342         while (cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1343                 cursor.par(cursor.par()->Previous());
1344    
1345         SetCursor(bview, cursor.par(), cursor.par()->Last());
1346         /* this is just faster than using CursorLeft(); */ 
1347    
1348         firsttmppar = cursor.par()->ParFromPos(cursor.pos());
1349         tmppar = firsttmppar;
1350         /* tmppar is now the paragraph right before the footnote */
1351
1352         bool first_footnote_par_is_not_empty = tmppar->next->size();
1353    
1354         while (tmppar->next
1355                && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1356                 tmppar = tmppar->next;   /* I use next instead of Next(),
1357                                           * because there cannot be any
1358                                           * footnotes in a footnote
1359                                           * environment */
1360                 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1361       
1362                 /* remember the captions and empty paragraphs */
1363                 if ((textclasslist.Style(bview->buffer()->params.textclass,
1364                                          tmppar->GetLayout())
1365                      .labeltype == LABEL_SENSITIVE)
1366                     || !tmppar->Last())
1367                         tmppar->SetLayout(bview->buffer()->params, 0);
1368         }
1369    
1370         // now we will paste the ex-footnote, if the layouts allow it
1371         // first restore the layout of the paragraph right behind
1372         // the footnote
1373         if (tmppar->next) 
1374                 tmppar->next->MakeSameLayout(cursor.par());
1375
1376         // first the end
1377         if (!tmppar->GetLayout()
1378             || (tmppar->Next()
1379                 && (!tmppar->Next()->Last()
1380                     || tmppar->Next()->HasSameLayout(tmppar)))) {
1381                 if (tmppar->Next()->Last()
1382                     && tmppar->Next()->IsLineSeparator(0))
1383                         tmppar->Next()->Erase(0);
1384                 tmppar->PasteParagraph(bview->buffer()->params);
1385         }
1386
1387         tmppar = tmppar->Next();  /* make sure tmppar cannot be touched
1388                                    * by the pasting of the beginning */
1389
1390         /* then the beginning */ 
1391         /* if there is no space between the text and the footnote, so we insert
1392          * a blank 
1393          * (only if the previous par and the footnotepar are not empty!) */
1394         if (!firsttmppar->next->GetLayout()
1395             || firsttmppar->HasSameLayout(firsttmppar->next)) {
1396                 if (firsttmppar->size()
1397                     && !firsttmppar->IsSeparator(firsttmppar->size() - 1)
1398                     && first_footnote_par_is_not_empty) {
1399                         firsttmppar->next->InsertChar(0, ' ');
1400                 }
1401                 firsttmppar->PasteParagraph(bview->buffer()->params);
1402         }
1403    
1404         /* now redo the paragaphs */
1405         RedoParagraphs(bview, cursor, tmppar);
1406    
1407         SetCursor(bview, cursor.par(), cursor.pos());
1408    
1409         /* sometimes it can happen, that there is a counter change */ 
1410         Row * row = cursor.row();
1411         while (row->next() && row->par() != tmppar && row->next()->par() != tmppar)
1412                 row = row->next();
1413         UpdateCounters(bview, row);
1414    
1415    
1416         ClearSelection();
1417 }
1418 #endif
1419
1420
1421 /* the DTP switches for paragraphs. LyX will store them in the 
1422 * first physicla paragraph. When a paragraph is broken, the top settings 
1423 * rest, the bottom settings are given to the new one. So I can make shure, 
1424 * they do not duplicate themself and you cannnot make dirty things with 
1425 * them!  */ 
1426
1427 void LyXText::SetParagraph(BufferView * bview,
1428                            bool line_top, bool line_bottom,
1429                            bool pagebreak_top, bool pagebreak_bottom,
1430                            VSpace const & space_top,
1431                            VSpace const & space_bottom,
1432                            LyXAlignment align, 
1433                            string labelwidthstring,
1434                            bool noindent) 
1435 {
1436         LyXCursor tmpcursor = cursor;
1437         if (!selection) {
1438                 sel_start_cursor = cursor;
1439                 sel_end_cursor = cursor;
1440         }
1441
1442         // make sure that the depth behind the selection are restored, too
1443 #ifndef NEW_INSETS
1444         LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1445 #else
1446         LyXParagraph * endpar = sel_end_cursor.par()->Next();
1447 #endif
1448         LyXParagraph * undoendpar = endpar;
1449
1450         if (endpar && endpar->GetDepth()) {
1451                 while (endpar && endpar->GetDepth()) {
1452 #ifndef NEW_INSETS
1453                         endpar = endpar->LastPhysicalPar()->Next();
1454 #else
1455                         endpar = endpar->Next();
1456 #endif
1457                         undoendpar = endpar;
1458                 }
1459         }
1460         else if (endpar) {
1461                 endpar = endpar->Next(); // because of parindents etc.
1462         }
1463    
1464         SetUndo(bview->buffer(), Undo::EDIT,
1465 #ifndef NEW_INSETS
1466                 sel_start_cursor
1467                 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1468 #else
1469                 sel_start_cursor.par()->previous,
1470 #endif
1471                 undoendpar);
1472
1473         
1474         LyXParagraph * tmppar = sel_end_cursor.par();
1475 #ifndef NEW_INSETS
1476         while (tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1477                 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1478 #else
1479         while (tmppar != sel_start_cursor.par()->Previous()) {
1480                 SetCursor(bview, tmppar, 0);
1481 #endif
1482                 status = LyXText::NEED_MORE_REFRESH;
1483                 refresh_row = cursor.row();
1484                 refresh_y = cursor.y() - cursor.row()->baseline();
1485 #ifndef NEW_INSETS
1486                 if (cursor.par()->footnoteflag ==
1487                     sel_start_cursor.par()->footnoteflag) {
1488 #endif
1489                         cursor.par()->line_top = line_top;
1490                         cursor.par()->line_bottom = line_bottom;
1491                         cursor.par()->pagebreak_top = pagebreak_top;
1492                         cursor.par()->pagebreak_bottom = pagebreak_bottom;
1493                         cursor.par()->added_space_top = space_top;
1494                         cursor.par()->added_space_bottom = space_bottom;
1495                         // does the layout allow the new alignment?
1496                         if (align == LYX_ALIGN_LAYOUT)
1497                                 align = textclasslist
1498                                         .Style(bview->buffer()->params.textclass,
1499                                                cursor.par()->GetLayout()).align;
1500                         if (align & textclasslist
1501                             .Style(bview->buffer()->params.textclass,
1502                                    cursor.par()->GetLayout()).alignpossible) {
1503                                 if (align == textclasslist
1504                                     .Style(bview->buffer()->params.textclass,
1505                                            cursor.par()->GetLayout()).align)
1506                                         cursor.par()->align = LYX_ALIGN_LAYOUT;
1507                                 else
1508                                         cursor.par()->align = align;
1509                         }
1510                         cursor.par()->SetLabelWidthString(labelwidthstring);
1511                         cursor.par()->noindent = noindent;
1512 #ifndef NEW_INSETS
1513                 }
1514                 
1515                 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1516 #else
1517                 tmppar = cursor.par()->Previous();
1518 #endif
1519         }
1520         
1521         RedoParagraphs(bview, sel_start_cursor, endpar);
1522         
1523         ClearSelection();
1524         SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1525         sel_cursor = cursor;
1526         SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1527         SetSelection(bview);
1528         SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1529         if (inset_owner)
1530             bview->updateInset(inset_owner, true);
1531 }
1532
1533
1534 void LyXText::SetParagraphExtraOpt(BufferView * bview, int type,
1535                                    string const & width,
1536                                    string const & widthp,
1537                                    int alignment, bool hfill,
1538                                    bool start_minipage)
1539 {
1540         LyXCursor tmpcursor = cursor;
1541         LyXParagraph * tmppar;
1542         if (!selection) {
1543                 sel_start_cursor = cursor;
1544                 sel_end_cursor = cursor;
1545         }
1546
1547         // make sure that the depth behind the selection are restored, too
1548 #ifndef NEW_INSETS
1549         LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1550 #else
1551         LyXParagraph * endpar = sel_end_cursor.par()->Next();
1552 #endif
1553         LyXParagraph * undoendpar = endpar;
1554
1555         if (endpar && endpar->GetDepth()) {
1556                 while (endpar && endpar->GetDepth()) {
1557 #ifndef NEW_INSETS
1558                         endpar = endpar->LastPhysicalPar()->Next();
1559 #else
1560                         endpar = endpar->Next();
1561 #endif
1562                         undoendpar = endpar;
1563                 }
1564         }
1565         else if (endpar) {
1566                 endpar = endpar->Next(); // because of parindents etc.
1567         }
1568    
1569         SetUndo(bview->buffer(), Undo::EDIT,
1570 #ifndef NEW_INSETS
1571                 sel_start_cursor
1572                 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1573 #else
1574                 sel_start_cursor.par()->previous,
1575 #endif
1576                 undoendpar);
1577         
1578         tmppar = sel_end_cursor.par();
1579 #ifndef NEW_INSETS
1580         while(tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1581                 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1582 #else
1583         while(tmppar != sel_start_cursor.par()->Previous()) {
1584                 SetCursor(bview, tmppar, 0);
1585 #endif
1586                 status = LyXText::NEED_MORE_REFRESH;
1587                 refresh_row = cursor.row();
1588                 refresh_y = cursor.y() - cursor.row()->baseline();
1589 #ifndef NEW_INSETS
1590                 if (cursor.par()->footnoteflag ==
1591                     sel_start_cursor.par()->footnoteflag) {
1592 #endif
1593                         if (type == LyXParagraph::PEXTRA_NONE) {
1594                                 if (cursor.par()->pextra_type != LyXParagraph::PEXTRA_NONE) {
1595                                         cursor.par()->UnsetPExtraType(bview->buffer()->params);
1596                                         cursor.par()->pextra_type = LyXParagraph::PEXTRA_NONE;
1597                                 }
1598                         } else {
1599                                 cursor.par()->SetPExtraType(bview->buffer()->params,
1600                                                           type, width, widthp);
1601                                 cursor.par()->pextra_hfill = hfill;
1602                                 cursor.par()->pextra_start_minipage = start_minipage;
1603                                 cursor.par()->pextra_alignment = alignment;
1604                         }
1605 #ifndef NEW_INSETS
1606                 }
1607                 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1608 #else
1609                 tmppar = cursor.par()->Previous();
1610 #endif
1611         }
1612         RedoParagraphs(bview, sel_start_cursor, endpar);
1613         ClearSelection();
1614         SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1615         sel_cursor = cursor;
1616         SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1617         SetSelection(bview);
1618         SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1619 }
1620
1621
1622 char loweralphaCounter(int n)
1623 {
1624         if (n < 1 || n > 26)
1625                 return '?';
1626         else
1627                 return 'a' + n - 1;
1628 }
1629
1630
1631 static inline
1632 char alphaCounter(int n)
1633 {
1634         if (n < 1 || n > 26)
1635                 return '?';
1636         else
1637                 return 'A' + n - 1;
1638 }
1639
1640
1641 static inline
1642 char hebrewCounter(int n)
1643 {
1644         static const char hebrew[22] = {
1645                 'à', 'á', 'â', 'ã', 'ä', 'Ã¥', 'æ', 'ç', 'è',
1646                 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö', 
1647                 '÷', 'ø', 'ù', 'ú'
1648         };
1649         if (n < 1 || n > 22)
1650                 return '?';
1651         else
1652                 return hebrew[n-1];
1653 }
1654
1655
1656 static inline
1657 string const romanCounter(int n)
1658 {
1659         static char const * roman[20] = {
1660                 "i",   "ii",  "iii", "iv", "v",
1661                 "vi",  "vii", "viii", "ix", "x",
1662                 "xi",  "xii", "xiii", "xiv", "xv",
1663                 "xvi", "xvii", "xviii", "xix", "xx"
1664         };
1665         if (n < 1 || n > 20)
1666                 return "??";
1667         else
1668                 return roman[n-1];
1669 }
1670
1671
1672 // set the counter of a paragraph. This includes the labels
1673 void LyXText::SetCounter(Buffer const * buf, LyXParagraph * par) const
1674 {
1675 #ifndef NEW_INSETS
1676         // this is only relevant for the beginning of paragraph
1677         par = par->FirstPhysicalPar();
1678 #endif
1679         LyXLayout const & layout =
1680                 textclasslist.Style(buf->params.textclass, 
1681                                     par->GetLayout());
1682
1683         LyXTextClass const & textclass =
1684                 textclasslist.TextClass(buf->params.textclass);
1685
1686         /* copy the prev-counters to this one, unless this is the start of a 
1687            footnote or of a bibliography or the very first paragraph */
1688         if (par->Previous()
1689 #ifndef NEW_INSETS
1690             && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE 
1691                     && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1692                     && par->footnotekind == LyXParagraph::FOOTNOTE)
1693 #endif
1694             && !(textclasslist.Style(buf->params.textclass,
1695                                 par->Previous()->GetLayout()
1696                                 ).labeltype != LABEL_BIBLIO
1697                  && layout.labeltype == LABEL_BIBLIO)) {
1698                 for (int i = 0; i < 10; ++i) {
1699                         par->setCounter(i, par->Previous()->GetFirstCounter(i));
1700                 }
1701 #ifndef NEW_INSETS
1702                 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1703 #else
1704                 par->appendix = par->Previous()->appendix;
1705 #endif
1706                 if (!par->appendix && par->start_of_appendix){
1707                   par->appendix = true;
1708                   for (int i = 0; i < 10; ++i) {
1709                     par->setCounter(i, 0);
1710                   }  
1711                 }
1712 #ifndef NEW_INSETS
1713                 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1714                 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1715 #else
1716                 par->enumdepth = par->Previous()->enumdepth;
1717                 par->itemdepth = par->Previous()->itemdepth;
1718 #endif
1719         } else {
1720                 for (int i = 0; i < 10; ++i) {
1721                         par->setCounter(i, 0);
1722                 }  
1723                 par->appendix = par->start_of_appendix;
1724                 par->enumdepth = 0;
1725                 par->itemdepth = 0;
1726         }
1727
1728 #ifndef NEW_INSETS
1729         // if this is an open marginnote and this is the first
1730         // entry in the marginnote and the enclosing
1731         // environment is an enum/item then correct for the
1732         // LaTeX behaviour (ARRae)
1733         if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1734            && par->footnotekind == LyXParagraph::MARGIN
1735            && par->Previous()
1736            && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1737            && (par->PreviousBeforeFootnote()
1738                && textclasslist.Style(buf->params.textclass,
1739                                  par->PreviousBeforeFootnote()->GetLayout()
1740                                  ).labeltype >= LABEL_COUNTER_ENUMI)) {
1741                 // Any itemize or enumerate environment in a marginnote
1742                 // that is embedded in an itemize or enumerate
1743                 // paragraph is seen by LaTeX as being at a deeper
1744                 // level within that enclosing itemization/enumeration
1745                 // even if there is a "standard" layout at the start of
1746                 // the marginnote.
1747                 par->enumdepth++;
1748                 par->itemdepth++;
1749         }
1750 #endif
1751         /* Maybe we have to increment the enumeration depth.
1752          * BUT, enumeration in a footnote is considered in isolation from its
1753          *      surrounding paragraph so don't increment if this is the
1754          *      first line of the footnote
1755          * AND, bibliographies can't have their depth changed ie. they
1756          *      are always of depth 0
1757          */
1758         if (par->Previous()
1759             && par->Previous()->GetDepth() < par->GetDepth()
1760             && textclasslist.Style(buf->params.textclass,
1761                               par->Previous()->GetLayout()
1762                              ).labeltype == LABEL_COUNTER_ENUMI
1763             && par->enumdepth < 3
1764 #ifndef NEW_INSETS
1765             && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE 
1766                     && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1767                     && par->footnotekind == LyXParagraph::FOOTNOTE)
1768 #endif
1769             && layout.labeltype != LABEL_BIBLIO) {
1770                 par->enumdepth++;
1771         }
1772
1773         /* Maybe we have to decrement the enumeration depth, see note above */
1774         if (par->Previous()
1775             && par->Previous()->GetDepth() > par->GetDepth()
1776 #ifndef NEW_INSETS
1777             && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1778                     && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1779                     && par->footnotekind == LyXParagraph::FOOTNOTE)
1780 #endif
1781             && layout.labeltype != LABEL_BIBLIO) {
1782                 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1783                 par->setCounter(6 + par->enumdepth,
1784                         par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1785                 /* reset the counters.
1786                  * A depth change is like a breaking layout
1787                  */
1788                 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1789                         par->setCounter(i, 0);
1790         }
1791    
1792         if (!par->labelstring.empty()) {
1793                 par->labelstring.erase();
1794         }
1795    
1796         if (layout.margintype == MARGIN_MANUAL) {
1797                 if (par->labelwidthstring.empty()) {
1798                         par->SetLabelWidthString(layout.labelstring());
1799                 }
1800         } else {
1801                 par->SetLabelWidthString(string());
1802         }
1803    
1804         /* is it a layout that has an automatic label ? */ 
1805         if (layout.labeltype >=  LABEL_COUNTER_CHAPTER) {
1806       
1807                 int i = layout.labeltype - LABEL_COUNTER_CHAPTER;
1808                 if (i >= 0 && i<= buf->params.secnumdepth) {
1809                         par->incCounter(i);     // increment the counter  
1810          
1811                         // Is there a label? Useful for Chapter layout
1812                         if (!par->appendix){
1813                                 if (!layout.labelstring().empty())
1814                                         par->labelstring = layout.labelstring();
1815                                 else
1816                                         par->labelstring.erase();
1817                         } else {
1818                                 if (!layout.labelstring_appendix().empty())
1819                                         par->labelstring = layout.labelstring_appendix();
1820                                 else
1821                                         par->labelstring.erase();
1822                         }
1823
1824                         std::ostringstream s;
1825
1826                         if (!par->appendix) {
1827                                 switch (2 * LABEL_COUNTER_CHAPTER -
1828                                         textclass.maxcounter() + i) {
1829                                 case LABEL_COUNTER_CHAPTER:
1830                                         s << par->getCounter(i);
1831                                         break;
1832                                 case LABEL_COUNTER_SECTION:
1833                                         s << par->getCounter(i - 1) << '.'
1834                                            << par->getCounter(i);
1835                                         break;
1836                                 case LABEL_COUNTER_SUBSECTION:
1837                                         s << par->getCounter(i - 2) << '.'
1838                                           << par->getCounter(i - 1) << '.'
1839                                           << par->getCounter(i);
1840                                         break;
1841                                 case LABEL_COUNTER_SUBSUBSECTION:
1842                                         s << par->getCounter(i - 3) << '.'
1843                                           << par->getCounter(i - 2) << '.'
1844                                           << par->getCounter(i - 1) << '.'
1845                                           << par->getCounter(i);
1846                                         
1847                                         break;
1848                                 case LABEL_COUNTER_PARAGRAPH:
1849                                         s << par->getCounter(i - 4) << '.'
1850                                           << par->getCounter(i - 3) << '.'
1851                                           << par->getCounter(i - 2) << '.'
1852                                           << par->getCounter(i - 1) << '.'
1853                                           << par->getCounter(i);
1854                                         break;
1855                                 case LABEL_COUNTER_SUBPARAGRAPH:
1856                                         s << par->getCounter(i - 5) << '.'
1857                                           << par->getCounter(i - 4) << '.'
1858                                           << par->getCounter(i - 3) << '.'
1859                                           << par->getCounter(i - 2) << '.'
1860                                           << par->getCounter(i - 1) << '.'
1861                                           << par->getCounter(i);
1862
1863                                         break;
1864                                 default:
1865                                         // Can this ever be reached? And in the
1866                                         // case it is, how can this be correct?
1867                                         // (Lgb)
1868                                         s << par->getCounter(i) << '.';
1869                                         break;
1870                                 }
1871                         } else { // appendix
1872                                 switch (2 * LABEL_COUNTER_CHAPTER - textclass.maxcounter() + i) {
1873                                 case LABEL_COUNTER_CHAPTER:
1874                                         if (par->isRightToLeftPar(buf->params))
1875                                                 s << hebrewCounter(par->getCounter(i));
1876                                         else
1877                                                 s << alphaCounter(par->getCounter(i));
1878                                         break;
1879                                 case LABEL_COUNTER_SECTION:
1880                                         if (par->isRightToLeftPar(buf->params))
1881                                                 s << hebrewCounter(par->getCounter(i - 1));
1882                                         else
1883                                                 s << alphaCounter(par->getCounter(i - 1));
1884
1885                                         s << '.'
1886                                           << par->getCounter(i);
1887
1888                                         break;
1889                                 case LABEL_COUNTER_SUBSECTION:
1890                                         if (par->isRightToLeftPar(buf->params))
1891                                                 s << hebrewCounter(par->getCounter(i - 2));
1892                                         else
1893                                                 s << alphaCounter(par->getCounter(i - 2));
1894
1895                                         s << '.'
1896                                           << par->getCounter(i-1) << '.'
1897                                           << par->getCounter(i);
1898
1899                                         break;
1900                                 case LABEL_COUNTER_SUBSUBSECTION:
1901                                         if (par->isRightToLeftPar(buf->params))
1902                                                 s << hebrewCounter(par->getCounter(i-3));
1903                                         else
1904                                                 s << alphaCounter(par->getCounter(i-3));
1905
1906                                         s << '.'
1907                                           << par->getCounter(i-2) << '.'
1908                                           << par->getCounter(i-1) << '.'
1909                                           << par->getCounter(i);
1910
1911                                         break;
1912                                 case LABEL_COUNTER_PARAGRAPH:
1913                                         if (par->isRightToLeftPar(buf->params))
1914                                                 s << hebrewCounter(par->getCounter(i-4));
1915                                         else
1916                                                 s << alphaCounter(par->getCounter(i-4));
1917
1918                                         s << '.'
1919                                           << par->getCounter(i-3) << '.'
1920                                           << par->getCounter(i-2) << '.'
1921                                           << par->getCounter(i-1) << '.'
1922                                           << par->getCounter(i);
1923
1924                                         break;
1925                                 case LABEL_COUNTER_SUBPARAGRAPH:
1926                                         if (par->isRightToLeftPar(buf->params))
1927                                                 s << hebrewCounter(par->getCounter(i-5));
1928                                         else
1929                                                 s << alphaCounter(par->getCounter(i-5));
1930
1931                                         s << '.'
1932                                           << par->getCounter(i-4) << '.'
1933                                           << par->getCounter(i-3) << '.'
1934                                           << par->getCounter(i-2) << '.'
1935                                           << par->getCounter(i-1) << '.'
1936                                           << par->getCounter(i);
1937
1938                                         break;
1939                                 default:
1940                                         // Can this ever be reached? And in the
1941                                         // case it is, how can this be correct?
1942                                         // (Lgb)
1943                                         s << par->getCounter(i) << '.';
1944                                         
1945                                         break;
1946                                 }
1947                         }
1948
1949                         par->labelstring += s.str().c_str();
1950                         // We really want to remove the c_str as soon as
1951                         // possible...
1952                         
1953                         for (i++; i < 10; ++i) {
1954                                 // reset the following counters
1955                                 par->setCounter(i, 0);
1956                         }
1957                 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1958                         for (i++; i < 10; ++i) {
1959                                 // reset the following counters
1960                                 par->setCounter(i, 0);
1961                         }
1962                 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1963                         par->incCounter(i + par->enumdepth);
1964                         int number = par->getCounter(i + par->enumdepth);
1965
1966                         std::ostringstream s;
1967
1968                         switch (par->enumdepth) {
1969                         case 1:
1970                                 if (par->isRightToLeftPar(buf->params))
1971                                         s << '('
1972                                           << hebrewCounter(number)
1973                                           << ')';
1974                                 else
1975                                         s << '('
1976                                           << loweralphaCounter(number)
1977                                           << ')';
1978                                 break;
1979                         case 2:
1980                                 if (par->isRightToLeftPar(buf->params))
1981                                         s << '.' << romanCounter(number);
1982                                 else
1983                                         s << romanCounter(number) << '.';
1984                                 break;
1985                         case 3:
1986                                 if (par->isRightToLeftPar(buf->params))
1987                                         s << '.'
1988                                           << alphaCounter(number);
1989                                 else
1990                                         s << alphaCounter(number)
1991                                           << '.';
1992                                 break;
1993                         default:
1994                                 if (par->isRightToLeftPar(buf->params))
1995                                         s << '.' << number;
1996                                 else
1997                                         s << number << '.';
1998                                 break;
1999                         }
2000
2001                         par->labelstring = s.str().c_str();
2002                         // we really want to get rid of that c_str()
2003
2004                         for (i += par->enumdepth + 1; i < 10; ++i)
2005                                 par->setCounter(i, 0);  /* reset the following counters  */
2006          
2007                 } 
2008         } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
2009                 int i = LABEL_COUNTER_ENUMI - LABEL_COUNTER_CHAPTER + par->enumdepth;
2010                 par->incCounter(i);
2011                 int number = par->getCounter(i);
2012                 if (!par->bibkey) {
2013                         InsetCommandParams p( "bibitem" );
2014                         par->bibkey = new InsetBibKey(p);
2015                 }
2016                 par->bibkey->setCounter(number);
2017                 par->labelstring = layout.labelstring();
2018                 
2019                 // In biblio should't be following counters but...
2020         } else {
2021                 string s = layout.labelstring();
2022                 
2023                 // the caption hack:
2024                 if (layout.labeltype == LABEL_SENSITIVE) {
2025                         bool isOK (par->InInset() && par->InInset()->owner() &&
2026                                    (par->InInset()->owner()->LyxCode() == Inset::FLOAT_CODE));
2027 #ifndef NEW_INSETS
2028                         if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2029                             && (par->footnotekind == LyXParagraph::FIG
2030                                 || par->footnotekind == LyXParagraph::WIDE_FIG)) {
2031                                 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2032                                         ? ":øåéà" : "Figure:";
2033                         } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2034                                  && (par->footnotekind == LyXParagraph::TAB
2035                                      || par->footnotekind == LyXParagraph::WIDE_TAB)) {
2036                                 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2037                                         ? ":äìáè" : "Table:";
2038                         } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2039                                    && par->footnotekind == LyXParagraph::ALGORITHM) {
2040                                 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2041                                         ? ":íúéøåâìà" : "Algorithm:";
2042                         } else
2043 #endif
2044                         if (isOK) {
2045                                 InsetFloat * tmp = static_cast<InsetFloat*>(par->InInset()->owner());
2046                                 Floating const & fl
2047                                         = floatList.getType(tmp->type());
2048                                 // We should get the correct number here too.
2049                                 s = fl.name() + " #:";
2050                         } else {
2051                                 /* par->SetLayout(0); 
2052                                    s = layout->labelstring;  */
2053                                 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2054                                         ? " :úåòîùî Ã¸Ã±Ã§" : "Senseless: ";
2055                         }
2056                 }
2057                 par->labelstring = s;
2058                 
2059                 /* reset the enumeration counter. They are always resetted
2060                  * when there is any other layout between */ 
2061                 for (int i = 6 + par->enumdepth; i < 10; ++i)
2062                         par->setCounter(i, 0);
2063         }
2064 }
2065
2066
2067 /* Updates all counters BEHIND the row. Changed paragraphs
2068 * with a dynamic left margin will be rebroken. */ 
2069 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
2070 {
2071         LyXParagraph * par;
2072         if (!row) {
2073                 row = firstrow;
2074                 par = row->par();
2075         } else {
2076                 if (row->par()->next
2077 #ifndef NEW_INSETS
2078                     && row->par()->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
2079 #endif
2080                         ) {
2081 #ifndef NEW_INSETS
2082                         par = row->par()->LastPhysicalPar()->Next();
2083 #else
2084                         par = row->par()->Next();
2085 #endif
2086                 } else {
2087                         par = row->par()->next;
2088                 }
2089         }
2090
2091         while (par) {
2092                 while (row->par() != par)
2093                         row = row->next();
2094                 
2095                 SetCounter(bview->buffer(), par);
2096                 
2097                 /* now  check for the headline layouts. remember that they
2098                  * have a dynamic left margin */ 
2099                 if (
2100 #ifndef NEW_INSETS
2101                         !par->IsDummy() &&
2102 #endif
2103                     ( textclasslist.Style(bview->buffer()->params.textclass,
2104                                              par->layout).margintype == MARGIN_DYNAMIC
2105                          || textclasslist.Style(bview->buffer()->params.textclass,
2106                                                 par->layout).labeltype == LABEL_SENSITIVE)
2107                         ) {
2108          
2109                         /* Rebreak the paragraph */ 
2110                         RemoveParagraph(row);
2111                         AppendParagraph(bview, row);
2112
2113 #ifndef NEW_INSETS
2114                         /* think about the damned open footnotes! */ 
2115                         while (par->Next() &&
2116                                (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
2117                                 || par->Next()->IsDummy())){
2118                                 par = par->Next();
2119                                 if (par->IsDummy()) {
2120                                         while (row->par() != par)
2121                                                 row = row->next();
2122                                         RemoveParagraph(row);
2123                                         AppendParagraph(bview, row);
2124                                 }
2125                         }
2126 #endif
2127                 }
2128 #ifndef NEW_INSETS
2129                 par = par->LastPhysicalPar()->Next();
2130 #else
2131                 par = par->Next();
2132 #endif
2133      
2134         }
2135 }
2136
2137
2138 /* insets an inset. */ 
2139 void LyXText::InsertInset(BufferView * bview, Inset * inset)
2140 {
2141         if (!cursor.par()->InsertInsetAllowed(inset))
2142                 return;
2143         SetUndo(bview->buffer(), Undo::INSERT,
2144 #ifndef NEW_INSETS
2145                 cursor.par()->ParFromPos(cursor.pos())->previous, 
2146                 cursor.par()->ParFromPos(cursor.pos())->next
2147 #else
2148                 cursor.par()->previous, 
2149                 cursor.par()->next
2150 #endif
2151                 );
2152         cursor.par()->InsertInset(cursor.pos(), inset);
2153         InsertChar(bview, LyXParagraph::META_INSET);  /* just to rebreak and refresh correctly.
2154                                       * The character will not be inserted a
2155                                       * second time */
2156 #if 1
2157         // If we enter a highly editable inset the cursor should be to before
2158         // the inset. This couldn't happen before as Undo was not handled inside
2159         // inset now after the Undo LyX tries to call inset->Edit(...) again
2160         // and cannot do this as the cursor is behind the inset and GetInset
2161         // does not return the inset!
2162         if (inset->Editable() == Inset::HIGHLY_EDITABLE) {
2163                 CursorLeft(bview, true);
2164         }
2165 #endif
2166 }
2167
2168
2169 void LyXText::copyEnvironmentType()
2170 {
2171         copylayouttype = cursor.par()->GetLayout();
2172 }
2173
2174
2175 void LyXText::pasteEnvironmentType(BufferView * bview)
2176 {
2177         SetLayout(bview, copylayouttype);
2178 }
2179
2180
2181 void LyXText::CutSelection(BufferView * bview, bool doclear)
2182 {
2183         // Stuff what we got on the clipboard. Even if there is no selection.
2184
2185         // There is a problem with having the stuffing here in that the
2186         // larger the selection the slower LyX will get. This can be
2187         // solved by running the line below only when the selection has
2188         // finished. The solution used currently just works, to make it
2189         // faster we need to be more clever and probably also have more
2190         // calls to stuffClipboard. (Lgb)
2191         bview->stuffClipboard(selectionAsString(bview->buffer()));
2192
2193         // This doesn't make sense, if there is no selection
2194         if (!selection)
2195                 return;
2196    
2197         // OK, we have a selection. This is always between sel_start_cursor
2198         // and sel_end_cursor
2199 #ifndef NEW_INSETS
2200         // Check whether there are half footnotes in the selection
2201         if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2202             || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2203         LyXParagraph * tmppar = sel_start_cursor.par();
2204                 while (tmppar != sel_end_cursor.par()){
2205                         if (tmppar->footnoteflag != sel_end_cursor.par()->footnoteflag) {
2206                                 WriteAlert(_("Impossible operation"),
2207                                            _("Don't know what to do with half floats."),
2208                                            _("sorry."));
2209                                 return;
2210                         }
2211                         tmppar = tmppar->Next();
2212                 }
2213         }
2214 #endif
2215
2216         // make sure that the depth behind the selection are restored, too
2217 #ifndef NEW_INSETS
2218         LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
2219 #else
2220         LyXParagraph * endpar = sel_end_cursor.par()->Next();
2221 #endif
2222         LyXParagraph * undoendpar = endpar;
2223     
2224         if (endpar && endpar->GetDepth()) {
2225                 while (endpar && endpar->GetDepth()) {
2226 #ifndef NEW_INSETS
2227                         endpar = endpar->LastPhysicalPar()->Next();
2228 #else
2229                         endpar = endpar->Next();
2230 #endif
2231                         undoendpar = endpar;
2232                 }
2233         } else if (endpar) {
2234                 endpar = endpar->Next(); // because of parindents etc.
2235         }
2236     
2237         SetUndo(bview->buffer(), Undo::DELETE,
2238 #ifndef NEW_INSETS
2239                 sel_start_cursor
2240                 .par()->ParFromPos(sel_start_cursor.pos())->previous,
2241 #else
2242                 sel_start_cursor.par()->previous,
2243 #endif
2244                 undoendpar);
2245     
2246         CutAndPaste cap;
2247
2248         // there are two cases: cut only within one paragraph or
2249         // more than one paragraph
2250 #ifndef NEW_INSETS
2251         if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos()) 
2252             == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos()))
2253 #else
2254         if (sel_start_cursor.par() == sel_end_cursor.par())
2255 #endif
2256                 {
2257                 // only within one paragraph
2258                 endpar = sel_start_cursor.par();
2259                 int pos = sel_end_cursor.pos();
2260                 cap.cutSelection(sel_start_cursor.par(), &endpar,
2261                                  sel_start_cursor.pos(), pos,
2262                                  bview->buffer()->params.textclass, doclear);
2263                 sel_end_cursor.pos(pos);
2264         } else {
2265                 endpar = sel_end_cursor.par();
2266
2267                 int pos = sel_end_cursor.pos();
2268                 cap.cutSelection(sel_start_cursor.par(), &endpar,
2269                                  sel_start_cursor.pos(), pos,
2270                                  bview->buffer()->params.textclass, doclear);
2271                 cursor.par(endpar);
2272                 sel_end_cursor.par(endpar);
2273                 sel_end_cursor.pos(pos);
2274                 cursor.pos(sel_end_cursor.pos());
2275         }
2276         endpar = endpar->Next();
2277
2278         // sometimes necessary
2279         if (doclear)
2280                 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
2281
2282         RedoParagraphs(bview, sel_start_cursor, endpar);
2283    
2284         ClearSelection();
2285         cursor = sel_start_cursor;
2286         SetCursor(bview, cursor.par(), cursor.pos());
2287         sel_cursor = cursor;
2288         UpdateCounters(bview, cursor.row());
2289 }
2290
2291
2292 void LyXText::CopySelection(BufferView * bview)
2293 {
2294         // Stuff what we got on the clipboard. Even if there is no selection.
2295
2296         // There is a problem with having the stuffing here in that the
2297         // larger the selection the slower LyX will get. This can be
2298         // solved by running the line below only when the selection has
2299         // finished. The solution used currently just works, to make it
2300         // faster we need to be more clever and probably also have more
2301         // calls to stuffClipboard. (Lgb)
2302         bview->stuffClipboard(selectionAsString(bview->buffer()));
2303
2304         // this doesnt make sense, if there is no selection
2305         if (!selection)
2306                 return;
2307
2308         // ok we have a selection. This is always between sel_start_cursor
2309         // and sel_end cursor
2310
2311 #ifndef NEW_INSETS
2312         /* check wether there are half footnotes in the selection */
2313         if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2314             || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2315                 LyXParagraph * tmppar = sel_start_cursor.par();
2316                 while (tmppar != sel_end_cursor.par()) {
2317                         if (tmppar->footnoteflag !=
2318                             sel_end_cursor.par()->footnoteflag) {
2319                                 WriteAlert(_("Impossible operation"),
2320                                            _("Don't know what to do"
2321                                              " with half floats."),
2322                                            _("sorry."));
2323                                 return;
2324                         }
2325                         tmppar = tmppar->Next();
2326                 }
2327         }
2328 #endif
2329    
2330         // copy behind a space if there is one
2331         while (sel_start_cursor.par()->Last() > sel_start_cursor.pos()
2332                && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
2333                && (sel_start_cursor.par() != sel_end_cursor.par()
2334                    || sel_start_cursor.pos() < sel_end_cursor.pos()))
2335                 sel_start_cursor.pos(sel_start_cursor.pos() + 1); 
2336
2337         CutAndPaste cap;
2338
2339         cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
2340                           sel_start_cursor.pos(), sel_end_cursor.pos(),
2341                           bview->buffer()->params.textclass);
2342 }
2343
2344
2345 void LyXText::PasteSelection(BufferView * bview)
2346 {
2347         CutAndPaste cap;
2348
2349         // this does not make sense, if there is nothing to paste
2350         if (!cap.checkPastePossible(cursor.par(), cursor.pos()))
2351                 return;
2352
2353         SetUndo(bview->buffer(), Undo::INSERT,
2354 #ifndef NEW_INSETS
2355                 cursor.par()->ParFromPos(cursor.pos())->previous, 
2356                 cursor.par()->ParFromPos(cursor.pos())->next
2357 #else
2358                 cursor.par()->previous, 
2359                 cursor.par()->next
2360 #endif
2361                 ); 
2362
2363         LyXParagraph * endpar;
2364         LyXParagraph * actpar = cursor.par();
2365
2366         int pos = cursor.pos();
2367         cap.pasteSelection(&actpar, &endpar, pos, bview->buffer()->params.textclass);
2368     
2369         RedoParagraphs(bview, cursor, endpar);
2370         
2371         SetCursor(bview, cursor.par(), cursor.pos());
2372         ClearSelection();
2373    
2374         sel_cursor = cursor;
2375         SetCursor(bview, actpar, pos);
2376         SetSelection(bview);
2377         UpdateCounters(bview, cursor.row());
2378 }
2379
2380
2381 // returns a pointer to the very first LyXParagraph
2382 LyXParagraph * LyXText::FirstParagraph() const
2383 {
2384         return OwnerParagraph();
2385 }
2386
2387
2388 // returns true if the specified string is at the specified position
2389 bool LyXText::IsStringInText(LyXParagraph * par,
2390                              LyXParagraph::size_type pos,
2391                              string const & str) const
2392 {
2393         if (!par)
2394                 return false;
2395
2396         LyXParagraph::size_type i = 0;
2397         while (pos + i < par->Last()
2398                && string::size_type(i) < str.length()
2399                && str[i] == par->GetChar(pos + i)) {
2400                 ++i;
2401         }
2402         if (str.length() == string::size_type(i))
2403                 return true;
2404         return false;
2405 }
2406
2407
2408 // sets the selection over the number of characters of string, no check!!
2409 void LyXText::SetSelectionOverString(BufferView * bview, string const & str)
2410 {
2411         sel_cursor = cursor;
2412         for (int i = 0; str[i]; ++i)
2413                 CursorRight(bview);
2414         SetSelection(bview);
2415 }
2416
2417
2418 // simple replacing. The font of the first selected character is used
2419 void LyXText::ReplaceSelectionWithString(BufferView * bview,
2420                                          string const & str)
2421 {
2422         SetCursorParUndo(bview->buffer());
2423         FreezeUndo();
2424
2425         if (!selection) { // create a dummy selection
2426                 sel_end_cursor = cursor;
2427                 sel_start_cursor = cursor;
2428         }
2429
2430         // Get font setting before we cut
2431         LyXParagraph::size_type pos = sel_end_cursor.pos();
2432         LyXFont const font = sel_start_cursor.par()
2433                 ->GetFontSettings(bview->buffer()->params,
2434                                   sel_start_cursor.pos());
2435
2436         // Insert the new string
2437         for (string::const_iterator cit = str.begin(); cit != str.end(); ++cit) {
2438                 sel_end_cursor.par()->InsertChar(pos, (*cit), font);
2439                 ++pos;
2440         }
2441         
2442         // Cut the selection
2443         CutSelection(bview);
2444
2445         UnFreezeUndo();
2446 }
2447
2448
2449 // if the string can be found: return true and set the cursor to
2450 // the new position
2451 bool LyXText::SearchForward(BufferView * bview, string const & str) const
2452 {
2453         LyXParagraph * par = cursor.par();
2454         LyXParagraph::size_type pos = cursor.pos();
2455         while (par && !IsStringInText(par, pos, str)) {
2456                 if (pos < par->Last() - 1)
2457                         ++pos;
2458                 else {
2459                         pos = 0;
2460                         par = par->Next();
2461                 }
2462         }
2463         if (par) {
2464                 SetCursor(bview, par, pos);
2465                 return true;
2466         }
2467         else
2468                 return false;
2469 }
2470
2471
2472 bool LyXText::SearchBackward(BufferView * bview, string const & str) const
2473 {
2474         LyXParagraph * par = cursor.par();
2475         int pos = cursor.pos();
2476
2477         do {
2478                 if (pos > 0)
2479                         --pos;
2480                 else {
2481                         // We skip empty paragraphs (Asger)
2482                         do {
2483                                 par = par->Previous();
2484                                 if (par)
2485                                         pos = par->Last() - 1;
2486                         } while (par && pos < 0);
2487                 }
2488         } while (par && !IsStringInText(par, pos, str));
2489   
2490         if (par) {
2491                 SetCursor(bview, par, pos);
2492                 return true;
2493         } else
2494                 return false;
2495 }
2496
2497
2498 // needed to insert the selection
2499 void LyXText::InsertStringA(BufferView * bview, string const & str)
2500 {
2501         LyXParagraph * par = cursor.par();
2502         LyXParagraph::size_type pos = cursor.pos();
2503         LyXParagraph::size_type a = 0;
2504         LyXParagraph * endpar = cursor.par()->Next();
2505         
2506         SetCursorParUndo(bview->buffer());
2507         
2508         bool flag =
2509                 textclasslist.Style(bview->buffer()->params.textclass, 
2510                                     cursor.par()->GetLayout()).isEnvironment();
2511         // only to be sure, should not be neccessary
2512         ClearSelection();
2513         
2514         // insert the string, don't insert doublespace
2515         string::size_type i = 0;
2516         while (i < str.length()) {
2517                 if (str[i] != '\n') {
2518                         if (str[i] == ' ' 
2519                             && i + 1 < str.length() && str[i + 1] != ' '
2520                             && pos && par->GetChar(pos - 1)!= ' ') {
2521                                 par->InsertChar(pos, ' ', current_font);
2522                                 ++pos;
2523                         } else if (str[i] == ' ') {
2524                                 InsetSpecialChar * new_inset =
2525                                         new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2526                                 if (par->InsertInsetAllowed(new_inset)) {
2527                                         par->InsertInset(pos, new_inset,
2528                                                          current_font);
2529                                 } else {
2530                                         delete new_inset;
2531                                 }
2532                                 ++pos;
2533                         } else if (str[i] == '\t') {
2534                                 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2535                                 InsetSpecialChar * new_inset =
2536                                         new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2537                                 if (par->InsertInsetAllowed(new_inset)) {
2538                                         par->InsertInset(pos, new_inset,
2539                                                          current_font);
2540                                 } else {
2541                                         delete new_inset;
2542                                 }
2543                                 }
2544                                 pos = a;
2545                         } else if (str[i] != 13 && 
2546                                    // Ignore unprintables
2547                                    (str[i] & 127) >= ' ') {
2548                                 par->InsertChar(pos, str[i], current_font);
2549                                 ++pos;
2550                         }
2551                 } else {
2552                         if (!par->size()) { // par is empty
2553                                 InsetSpecialChar * new_inset =
2554                                         new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2555                                 if (par->InsertInsetAllowed(new_inset)) {
2556                                         par->InsertInset(pos,
2557                                                          new_inset,
2558                                                          current_font);
2559                                 } else {
2560                                         delete new_inset;
2561                                 }
2562                                 ++pos;
2563                         }
2564                         par->BreakParagraph(bview->buffer()->params, pos, flag);
2565                         par = par->Next();
2566                         pos = 0;
2567                 }
2568                 ++i;
2569         }
2570         
2571         RedoParagraphs(bview, cursor, endpar);
2572         SetCursor(bview, cursor.par(), cursor.pos());
2573         sel_cursor = cursor;
2574         SetCursor(bview, par, pos);
2575         SetSelection(bview);
2576 }
2577
2578
2579 /* turns double-CR to single CR, others where converted into one blank and 13s 
2580  * that are ignored .Double spaces are also converted into one. Spaces at
2581  * the beginning of a paragraph are forbidden. tabs are converted into one
2582  * space. then InsertStringA is called */ 
2583 void LyXText::InsertStringB(BufferView * bview, string const & s)
2584 {
2585         string str(s);
2586         string::size_type i = 1;
2587         while (i < str.length()) {
2588                 if (str[i] == '\t')
2589                         str[i] = ' ';
2590                 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2591                         str[i] = 13;
2592                 if (str[i] == '\n' && i + 1 < str.length()) {
2593                         if (str[i + 1] != '\n') {
2594                                 if (str[i - 1] != ' ')
2595                                         str[i] = ' ';
2596                                 else
2597                                         str[i] = 13;
2598                         }
2599                         while (i + 1 < str.length() 
2600                                && (str[i + 1] == ' ' 
2601                                    || str[i + 1] == '\t'
2602                                    || str[i + 1] == '\n' 
2603                                    || str[i + 1] == 13)) {
2604                                 str[i + 1] = 13;
2605                                 ++i;
2606                         }
2607                 }
2608                 ++i;
2609         }
2610         InsertStringA(bview, str);
2611 }
2612
2613
2614 bool LyXText::GotoNextInset(BufferView * bview,
2615                             std::vector<Inset::Code> const & codes,
2616                             string const & contents) const
2617 {
2618         LyXCursor res = cursor;
2619         Inset * inset;
2620         do {
2621                 if (res.pos() < res.par()->Last() - 1) {
2622                         res.pos(res.pos() + 1);
2623                 } else  {
2624                         res.par(res.par()->Next());
2625                         res.pos(0);
2626                 }
2627       
2628         } while (res.par() && 
2629                  !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2630                    && (inset = res.par()->GetInset(res.pos())) != 0
2631                    && find(codes.begin(), codes.end(), inset->LyxCode())
2632                       != codes.end()
2633                    && (contents.empty() ||
2634                        static_cast<InsetCommand *>(res.par()->GetInset(res.pos()))->getContents()
2635                        == contents)));
2636
2637         if (res.par()) {
2638                 SetCursor(bview, res.par(), res.pos());
2639                 return true;
2640         }
2641         return false;
2642 }
2643
2644
2645 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
2646                              LyXParagraph::size_type pos)
2647 {
2648         LyXCursor tmpcursor;                    
2649
2650         int y = 0;
2651         LyXParagraph::size_type z;
2652         Row * row = GetRow(par, pos, y);
2653         
2654         // is there a break one row above
2655         if (row->previous() && row->previous()->par() == row->par()) {
2656                 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
2657                 if (z >= row->pos()) {
2658                         // set the dimensions of the row above
2659                         y -= row->previous()->height();
2660                         refresh_y = y;
2661                         refresh_row = row->previous();
2662                         status = LyXText::NEED_MORE_REFRESH;
2663                         
2664                         BreakAgain(bview, row->previous());
2665                         
2666                         // set the cursor again. Otherwise
2667                         // dangling pointers are possible
2668                         SetCursor(bview, cursor.par(), cursor.pos(),
2669                                   false, cursor.boundary());
2670                         sel_cursor = cursor;
2671                         return;
2672                 }
2673         }
2674
2675         int const tmpheight = row->height();
2676         LyXParagraph::size_type const tmplast = RowLast(row);
2677         refresh_y = y;
2678         refresh_row = row;
2679         
2680         BreakAgain(bview, row);
2681         if (row->height() == tmpheight && RowLast(row) == tmplast)
2682                 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2683         else
2684                 status = LyXText::NEED_MORE_REFRESH; 
2685         
2686         // check the special right address boxes
2687         if (textclasslist.Style(bview->buffer()->params.textclass,
2688                                 par->GetLayout()).margintype
2689             == MARGIN_RIGHT_ADDRESS_BOX) {
2690                 tmpcursor.par(par);
2691                 tmpcursor.row(row);
2692                 tmpcursor.y(y);
2693                 tmpcursor.x(0);
2694                 tmpcursor.x_fix(0);
2695                 tmpcursor.pos(pos);
2696                 RedoDrawingOfParagraph(bview, tmpcursor); 
2697         }
2698
2699         // set the cursor again. Otherwise dangling pointers are possible
2700         // also set the selection
2701    
2702         if (selection) {
2703                 tmpcursor = cursor;
2704                 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos(),
2705                                 false, sel_cursor.boundary());
2706                 sel_cursor = cursor; 
2707                 SetCursorIntern(bview, sel_start_cursor.par(),
2708                                 sel_start_cursor.pos(),
2709                                 false, sel_start_cursor.boundary());
2710                 sel_start_cursor = cursor; 
2711                 SetCursorIntern(bview, sel_end_cursor.par(),
2712                                 sel_end_cursor.pos(),
2713                                 false, sel_end_cursor.boundary());
2714                 sel_end_cursor = cursor; 
2715                 SetCursorIntern(bview, last_sel_cursor.par(),
2716                                 last_sel_cursor.pos(),
2717                                 false, last_sel_cursor.boundary());
2718                 last_sel_cursor = cursor; 
2719                 cursor = tmpcursor;
2720         }
2721         SetCursorIntern(bview, cursor.par(), cursor.pos(),
2722                         false, cursor.boundary());
2723 }
2724
2725
2726 // returns false if inset wasn't found
2727 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2728 {
2729         // first check the current paragraph
2730         int pos = cursor.par()->GetPositionOfInset(inset);
2731         if (pos != -1){
2732                 CheckParagraph(bview, cursor.par(), pos);
2733                 return true;
2734         }
2735   
2736         // check every paragraph
2737   
2738         LyXParagraph * par = FirstParagraph();
2739         do {
2740 #ifndef NEW_INSETS
2741                 // make sure the paragraph is open
2742                 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2743 #endif
2744                         pos = par->GetPositionOfInset(inset);
2745                         if (pos != -1){
2746                                 CheckParagraph(bview, par, pos);
2747                                 return true;
2748                         }
2749 #ifndef NEW_INSETS
2750                 }
2751 #endif
2752                 par = par->Next();
2753         } while (par);
2754   
2755         return false;
2756 }
2757
2758
2759 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2760                         LyXParagraph::size_type pos, 
2761                         bool setfont, bool boundary) const
2762 {
2763         LyXCursor old_cursor = cursor;
2764         SetCursorIntern(bview, par, pos, setfont, boundary);
2765         DeleteEmptyParagraphMechanism(bview, old_cursor);
2766 }
2767
2768
2769 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2770                         LyXParagraph::size_type pos, bool boundary) const
2771 {
2772 #ifndef NEW_INSETS
2773         // correct the cursor position if impossible
2774         if (pos > par->Last()){
2775                 LyXParagraph * tmppar = par->ParFromPos(pos);
2776                 pos = par->PositionInParFromPos(pos);
2777                 par = tmppar;
2778         }
2779         if (par->IsDummy() && par->previous &&
2780             par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2781                 while (par->previous &&
2782                        ((par->previous->IsDummy() &&
2783                          (par->previous->previous->footnoteflag ==
2784                           LyXParagraph::CLOSED_FOOTNOTE)) ||
2785                         (par->previous->footnoteflag ==
2786                          LyXParagraph::CLOSED_FOOTNOTE))) {
2787                         par = par->previous ;
2788                         if (par->IsDummy() &&
2789                             (par->previous->footnoteflag ==
2790                              LyXParagraph::CLOSED_FOOTNOTE))
2791                                 pos += par->size() + 1;
2792                 }
2793                 if (par->previous) {
2794                         par = par->previous;
2795                 }
2796                 pos += par->size() + 1;
2797         }
2798 #endif
2799         cur.par(par);
2800         cur.pos(pos);
2801         cur.boundary(boundary);
2802
2803         /* get the cursor y position in text  */
2804         int y = 0;
2805         Row * row = GetRow(par, pos, y);
2806         /* y is now the beginning of the cursor row */ 
2807         y += row->baseline();
2808         /* y is now the cursor baseline */ 
2809         cur.y(y);
2810    
2811         /* now get the cursors x position */
2812         float x;
2813         float fill_separator, fill_hfill, fill_label_hfill;
2814         PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2815                        fill_label_hfill);
2816         LyXParagraph::size_type cursor_vpos = 0;
2817         LyXParagraph::size_type last = RowLastPrintable(row);
2818
2819         if (pos > last + 1)   // This shouldn't happen.
2820                 pos = last + 1;
2821         else if (pos < row->pos())
2822                 pos = row->pos();
2823
2824         if (last < row->pos())
2825                 cursor_vpos = row->pos();
2826         else if (pos > last && !boundary)
2827                 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2828                         ? row->pos() : last + 1; 
2829         else if (pos > row->pos() &&
2830                  (pos > last || boundary))
2831                 /// Place cursor after char at (logical) position pos - 1
2832                 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2833                         ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2834         else
2835                 /// Place cursor before char at (logical) position pos
2836                 cursor_vpos = (bidi_level(pos) % 2 == 0)
2837                         ? log2vis(pos) : log2vis(pos) + 1;
2838         
2839         LyXParagraph::size_type main_body =
2840                 BeginningOfMainBody(bview->buffer(), row->par());
2841         if ((main_body > 0) &&
2842             ((main_body-1 > last) || 
2843              !row->par()->IsLineSeparator(main_body-1)))
2844                 main_body = 0;
2845         
2846         for (LyXParagraph::size_type vpos = row->pos();
2847              vpos < cursor_vpos; ++vpos) {
2848                 pos = vis2log(vpos);
2849                 if (main_body > 0 && pos == main_body - 1) {
2850                         x += fill_label_hfill +
2851                                 lyxfont::width(textclasslist.Style(
2852                                         bview->buffer()->params.textclass,
2853                                         row->par()->GetLayout())
2854                                                .labelsep,
2855                                                GetFont(bview->buffer(), row->par(), -2));
2856                         if (row->par()->IsLineSeparator(main_body-1))
2857                                 x -= SingleWidth(bview, row->par(),main_body-1);
2858                 }
2859                 if (HfillExpansion(bview->buffer(), row, pos)) {
2860                         x += SingleWidth(bview, row->par(), pos);
2861                         if (pos >= main_body)
2862                                 x += fill_hfill;
2863                         else 
2864                                 x += fill_label_hfill;
2865                 } else if (row->par()->IsSeparator(pos)) {
2866                         x += SingleWidth(bview, row->par(), pos);
2867                         if (pos >= main_body)
2868                                 x += fill_separator;
2869                 } else
2870                         x += SingleWidth(bview, row->par(), pos);
2871         }
2872         
2873         cur.x(int(x));
2874         cur.x_fix(cur.x());
2875         cur.row(row);
2876 }
2877
2878
2879 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
2880                               LyXParagraph::size_type pos,
2881                               bool setfont, bool boundary) const
2882 {
2883         SetCursor(bview, cursor, par, pos, boundary);
2884         if (setfont)
2885                 SetCurrentFont(bview);
2886 }
2887
2888
2889 void LyXText::SetCurrentFont(BufferView * bview) const
2890 {
2891         LyXParagraph::size_type pos = cursor.pos();
2892         if (cursor.boundary() && pos > 0)
2893                 --pos;
2894
2895         if (pos > 0) {
2896                 if (pos == cursor.par()->Last())
2897                         --pos;
2898                 else if (cursor.par()->IsSeparator(pos)) {
2899                         if (pos > cursor.row()->pos() &&
2900                             bidi_level(pos) % 2 == 
2901                             bidi_level(pos - 1) % 2)
2902                                 --pos;
2903                         else if (pos + 1 < cursor.par()->Last())
2904                                 ++pos;
2905                 }
2906         }
2907
2908         current_font =
2909                 cursor.par()->GetFontSettings(bview->buffer()->params, pos);
2910         real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
2911
2912         if (cursor.pos() == cursor.par()->Last() &&
2913             IsBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
2914             !cursor.boundary()) {
2915                 Language const * lang =
2916                         cursor.par()->getParLanguage(bview->buffer()->params);
2917                 current_font.setLanguage(lang);
2918                 real_current_font.setLanguage(lang);
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 }