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