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