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