]> git.lyx.org Git - lyx.git/blob - src/text2.C
Fix class switching bug
[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,
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,
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         if (selection)
1207                 status = LyXText::NEED_MORE_REFRESH;
1208         selection = false;
1209         mark_set = false;
1210 }
1211
1212
1213 void LyXText::CursorHome(BufferView * bview) const
1214 {
1215         SetCursor(bview, cursor.par(), cursor.row()->pos());
1216 }
1217
1218
1219 void LyXText::CursorEnd(BufferView * bview) const
1220 {
1221         if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1222                 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1223         else {
1224                 if (cursor.par()->Last() && 
1225                     (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1226                      || cursor.par()->IsNewline(RowLast(cursor.row()))))
1227                         SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1228                 else
1229                         SetCursor(bview,cursor.par(), RowLast(cursor.row()) + 1);
1230         }
1231 }
1232
1233
1234 void  LyXText::CursorTop(BufferView * bview) const
1235 {
1236         while (cursor.par()->Previous())
1237                 cursor.par(cursor.par()->Previous());
1238         SetCursor(bview, cursor.par(), 0);
1239 }
1240
1241
1242 void  LyXText::CursorBottom(BufferView * bview) const
1243 {
1244         while (cursor.par()->Next())
1245                 cursor.par(cursor.par()->Next());
1246         SetCursor(bview, cursor.par(), cursor.par()->Last());
1247 }
1248    
1249    
1250 /* returns a pointer to the row near the specified y-coordinate
1251 * (relative to the whole text). y is set to the real beginning
1252 * of this row */
1253 Row * LyXText::GetRowNearY(int & y) const
1254 {
1255         Row * tmprow = firstrow;
1256         int tmpy = 0;
1257
1258         while (tmprow->next() && tmpy + tmprow->height() <= y) {
1259                 tmpy += tmprow->height();
1260                 tmprow = tmprow->next();
1261         }
1262
1263         y = tmpy;   // return the real y
1264         return tmprow;
1265 }
1266
1267
1268 void LyXText::ToggleFree(BufferView * bview,
1269                          LyXFont const & font, bool toggleall)
1270 {
1271         // If the mask is completely neutral, tell user
1272         if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1273                 // Could only happen with user style
1274                 bview->owner()->getMiniBuffer()
1275                         ->Set(_("No font change defined. Use Character under"
1276                                 " the Layout menu to define font change."));
1277                 return;
1278         }
1279
1280         // Try implicit word selection
1281         // If there is a change in the language the implicit word selection 
1282         // is disabled.
1283         LyXCursor resetCursor = cursor;
1284         bool implicitSelection = (font.language() == ignore_language
1285                                   && font.number() == LyXFont::IGNORE)
1286                 ? SelectWordWhenUnderCursor(bview) : false;
1287
1288         // Set font
1289         SetFont(bview, font, toggleall);
1290
1291         /* Implicit selections are cleared afterwards and cursor is set to the
1292            original position. */
1293         if (implicitSelection) {
1294                 ClearSelection();
1295                 cursor = resetCursor;
1296                 SetCursor(bview, cursor.par(), cursor.pos());
1297                 sel_cursor = cursor;
1298         }
1299 }
1300
1301
1302 LyXParagraph::size_type
1303 LyXText::BeginningOfMainBody(Buffer const * buf,
1304                              LyXParagraph const * par) const
1305 {
1306         if (textclasslist.Style(buf->params.textclass,
1307                                 par->GetLayout()).labeltype != LABEL_MANUAL)
1308                 return 0;
1309         else
1310                 return par->BeginningOfMainBody();
1311 }
1312
1313
1314 #ifndef NEW_INSETS
1315 /* if there is a selection, reset every environment you can find
1316 * in the selection, otherwise just the environment you are in */ 
1317 void LyXText::MeltFootnoteEnvironment(BufferView * bview)
1318 {
1319         LyXParagraph * tmppar, * firsttmppar;
1320    
1321         ClearSelection();
1322    
1323         /* is is only allowed, if the cursor is IN an open footnote.
1324          * Otherwise it is too dangerous */ 
1325         if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1326                 return;
1327    
1328         SetUndo(bview->buffer(), Undo::FINISH, 
1329                 cursor.par()->PreviousBeforeFootnote()->previous,
1330                 cursor.par()->NextAfterFootnote()->next);
1331
1332         /* ok, move to the beginning of the footnote. */ 
1333         while (cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1334                 cursor.par(cursor.par()->Previous());
1335    
1336         SetCursor(bview, cursor.par(), cursor.par()->Last());
1337         /* this is just faster than using CursorLeft(); */ 
1338    
1339         firsttmppar = cursor.par()->ParFromPos(cursor.pos());
1340         tmppar = firsttmppar;
1341         /* tmppar is now the paragraph right before the footnote */
1342
1343         bool first_footnote_par_is_not_empty = tmppar->next->size();
1344    
1345         while (tmppar->next
1346                && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1347                 tmppar = tmppar->next;   /* I use next instead of Next(),
1348                                           * because there cannot be any
1349                                           * footnotes in a footnote
1350                                           * environment */
1351                 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1352       
1353                 /* remember the captions and empty paragraphs */
1354                 if ((textclasslist.Style(bview->buffer()->params.textclass,
1355                                          tmppar->GetLayout())
1356                      .labeltype == LABEL_SENSITIVE)
1357                     || !tmppar->Last())
1358                         tmppar->SetLayout(bview->buffer()->params, 0);
1359         }
1360    
1361         // now we will paste the ex-footnote, if the layouts allow it
1362         // first restore the layout of the paragraph right behind
1363         // the footnote
1364         if (tmppar->next) 
1365                 tmppar->next->MakeSameLayout(cursor.par());
1366
1367         // first the end
1368         if (!tmppar->GetLayout()
1369             || (tmppar->Next()
1370                 && (!tmppar->Next()->Last()
1371                     || tmppar->Next()->HasSameLayout(tmppar)))) {
1372                 if (tmppar->Next()->Last()
1373                     && tmppar->Next()->IsLineSeparator(0))
1374                         tmppar->Next()->Erase(0);
1375                 tmppar->PasteParagraph(bview->buffer()->params);
1376         }
1377
1378         tmppar = tmppar->Next();  /* make sure tmppar cannot be touched
1379                                    * by the pasting of the beginning */
1380
1381         /* then the beginning */ 
1382         /* if there is no space between the text and the footnote, so we insert
1383          * a blank 
1384          * (only if the previous par and the footnotepar are not empty!) */
1385         if (!firsttmppar->next->GetLayout()
1386             || firsttmppar->HasSameLayout(firsttmppar->next)) {
1387                 if (firsttmppar->size()
1388                     && !firsttmppar->IsSeparator(firsttmppar->size() - 1)
1389                     && first_footnote_par_is_not_empty) {
1390                         firsttmppar->next->InsertChar(0, ' ');
1391                 }
1392                 firsttmppar->PasteParagraph(bview->buffer()->params);
1393         }
1394    
1395         /* now redo the paragaphs */
1396         RedoParagraphs(bview, cursor, tmppar);
1397    
1398         SetCursor(bview, cursor.par(), cursor.pos());
1399    
1400         /* sometimes it can happen, that there is a counter change */ 
1401         Row * row = cursor.row();
1402         while (row->next() && row->par() != tmppar && row->next()->par() != tmppar)
1403                 row = row->next();
1404         UpdateCounters(bview, row);
1405    
1406    
1407         ClearSelection();
1408 }
1409 #endif
1410
1411
1412 /* the DTP switches for paragraphs. LyX will store them in the 
1413 * first physicla paragraph. When a paragraph is broken, the top settings 
1414 * rest, the bottom settings are given to the new one. So I can make shure, 
1415 * they do not duplicate themself and you cannnot make dirty things with 
1416 * them!  */ 
1417
1418 void LyXText::SetParagraph(BufferView * bview,
1419                            bool line_top, bool line_bottom,
1420                            bool pagebreak_top, bool pagebreak_bottom,
1421                            VSpace const & space_top,
1422                            VSpace const & space_bottom,
1423                            LyXAlignment align, 
1424                            string labelwidthstring,
1425                            bool noindent) 
1426 {
1427         LyXCursor tmpcursor = cursor;
1428         if (!selection) {
1429                 sel_start_cursor = cursor;
1430                 sel_end_cursor = cursor;
1431         }
1432
1433         // make sure that the depth behind the selection are restored, too
1434 #ifndef NEW_INSETS
1435         LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1436 #else
1437         LyXParagraph * endpar = sel_end_cursor.par()->Next();
1438 #endif
1439         LyXParagraph * undoendpar = endpar;
1440
1441         if (endpar && endpar->GetDepth()) {
1442                 while (endpar && endpar->GetDepth()) {
1443 #ifndef NEW_INSETS
1444                         endpar = endpar->LastPhysicalPar()->Next();
1445 #else
1446                         endpar = endpar->Next();
1447 #endif
1448                         undoendpar = endpar;
1449                 }
1450         }
1451         else if (endpar) {
1452                 endpar = endpar->Next(); // because of parindents etc.
1453         }
1454    
1455         SetUndo(bview->buffer(), Undo::EDIT,
1456 #ifndef NEW_INSETS
1457                 sel_start_cursor
1458                 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1459 #else
1460                 sel_start_cursor.par()->previous,
1461 #endif
1462                 undoendpar);
1463
1464         
1465         LyXParagraph * tmppar = sel_end_cursor.par();
1466 #ifndef NEW_INSETS
1467         while (tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1468                 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1469 #else
1470         while (tmppar != sel_start_cursor.par()->Previous()) {
1471                 SetCursor(bview, tmppar, 0);
1472 #endif
1473                 status = LyXText::NEED_MORE_REFRESH;
1474                 refresh_row = cursor.row();
1475                 refresh_y = cursor.y() - cursor.row()->baseline();
1476 #ifndef NEW_INSETS
1477                 if (cursor.par()->footnoteflag ==
1478                     sel_start_cursor.par()->footnoteflag) {
1479 #endif
1480                         cursor.par()->line_top = line_top;
1481                         cursor.par()->line_bottom = line_bottom;
1482                         cursor.par()->pagebreak_top = pagebreak_top;
1483                         cursor.par()->pagebreak_bottom = pagebreak_bottom;
1484                         cursor.par()->added_space_top = space_top;
1485                         cursor.par()->added_space_bottom = space_bottom;
1486                         // does the layout allow the new alignment?
1487                         if (align == LYX_ALIGN_LAYOUT)
1488                                 align = textclasslist
1489                                         .Style(bview->buffer()->params.textclass,
1490                                                cursor.par()->GetLayout()).align;
1491                         if (align & textclasslist
1492                             .Style(bview->buffer()->params.textclass,
1493                                    cursor.par()->GetLayout()).alignpossible) {
1494                                 if (align == textclasslist
1495                                     .Style(bview->buffer()->params.textclass,
1496                                            cursor.par()->GetLayout()).align)
1497                                         cursor.par()->align = LYX_ALIGN_LAYOUT;
1498                                 else
1499                                         cursor.par()->align = align;
1500                         }
1501                         cursor.par()->SetLabelWidthString(labelwidthstring);
1502                         cursor.par()->noindent = noindent;
1503 #ifndef NEW_INSETS
1504                 }
1505                 
1506                 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1507 #else
1508                 tmppar = cursor.par()->Previous();
1509 #endif
1510         }
1511         
1512         RedoParagraphs(bview, sel_start_cursor, endpar);
1513         
1514         ClearSelection();
1515         SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1516         sel_cursor = cursor;
1517         SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1518         SetSelection();
1519         SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1520         if (inset_owner)
1521             bview->updateInset(inset_owner, true);
1522 }
1523
1524
1525 void LyXText::SetParagraphExtraOpt(BufferView * bview, int type,
1526                                    string const & width,
1527                                    string const & widthp,
1528                                    int alignment, bool hfill,
1529                                    bool start_minipage)
1530 {
1531         LyXCursor tmpcursor = cursor;
1532         LyXParagraph * tmppar;
1533         if (!selection) {
1534                 sel_start_cursor = cursor;
1535                 sel_end_cursor = cursor;
1536         }
1537
1538         // make sure that the depth behind the selection are restored, too
1539 #ifndef NEW_INSETS
1540         LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1541 #else
1542         LyXParagraph * endpar = sel_end_cursor.par()->Next();
1543 #endif
1544         LyXParagraph * undoendpar = endpar;
1545
1546         if (endpar && endpar->GetDepth()) {
1547                 while (endpar && endpar->GetDepth()) {
1548 #ifndef NEW_INSETS
1549                         endpar = endpar->LastPhysicalPar()->Next();
1550 #else
1551                         endpar = endpar->Next();
1552 #endif
1553                         undoendpar = endpar;
1554                 }
1555         }
1556         else if (endpar) {
1557                 endpar = endpar->Next(); // because of parindents etc.
1558         }
1559    
1560         SetUndo(bview->buffer(), Undo::EDIT,
1561 #ifndef NEW_INSETS
1562                 sel_start_cursor
1563                 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1564 #else
1565                 sel_start_cursor.par()->previous,
1566 #endif
1567                 undoendpar);
1568         
1569         tmppar = sel_end_cursor.par();
1570 #ifndef NEW_INSETS
1571         while(tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1572                 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1573 #else
1574         while(tmppar != sel_start_cursor.par()->Previous()) {
1575                 SetCursor(bview, tmppar, 0);
1576 #endif
1577                 status = LyXText::NEED_MORE_REFRESH;
1578                 refresh_row = cursor.row();
1579                 refresh_y = cursor.y() - cursor.row()->baseline();
1580 #ifndef NEW_INSETS
1581                 if (cursor.par()->footnoteflag ==
1582                     sel_start_cursor.par()->footnoteflag) {
1583 #endif
1584                         if (type == LyXParagraph::PEXTRA_NONE) {
1585                                 if (cursor.par()->pextra_type != LyXParagraph::PEXTRA_NONE) {
1586                                         cursor.par()->UnsetPExtraType(bview->buffer()->params);
1587                                         cursor.par()->pextra_type = LyXParagraph::PEXTRA_NONE;
1588                                 }
1589                         } else {
1590                                 cursor.par()->SetPExtraType(bview->buffer()->params,
1591                                                           type, width, widthp);
1592                                 cursor.par()->pextra_hfill = hfill;
1593                                 cursor.par()->pextra_start_minipage = start_minipage;
1594                                 cursor.par()->pextra_alignment = alignment;
1595                         }
1596 #ifndef NEW_INSETS
1597                 }
1598                 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1599 #else
1600                 tmppar = cursor.par()->Previous();
1601 #endif
1602         }
1603         RedoParagraphs(bview, sel_start_cursor, endpar);
1604         ClearSelection();
1605         SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1606         sel_cursor = cursor;
1607         SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1608         SetSelection();
1609         SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1610 }
1611
1612
1613 char loweralphaCounter(int n)
1614 {
1615         if (n < 1 || n > 26)
1616                 return '?';
1617         else
1618                 return 'a' + n - 1;
1619 }
1620
1621
1622 static inline
1623 char alphaCounter(int n)
1624 {
1625         if (n < 1 || n > 26)
1626                 return '?';
1627         else
1628                 return 'A' + n - 1;
1629 }
1630
1631
1632 static inline
1633 char hebrewCounter(int n)
1634 {
1635         static const char hebrew[22] = {
1636                 'à', 'á', 'â', 'ã', 'ä', 'Ã¥', 'æ', 'ç', 'è',
1637                 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö', 
1638                 '÷', 'ø', 'ù', 'ú'
1639         };
1640         if (n < 1 || n > 22)
1641                 return '?';
1642         else
1643                 return hebrew[n-1];
1644 }
1645
1646
1647 static inline
1648 string const romanCounter(int n)
1649 {
1650         static char const * roman[20] = {
1651                 "i",   "ii",  "iii", "iv", "v",
1652                 "vi",  "vii", "viii", "ix", "x",
1653                 "xi",  "xii", "xiii", "xiv", "xv",
1654                 "xvi", "xvii", "xviii", "xix", "xx"
1655         };
1656         if (n < 1 || n > 20)
1657                 return "??";
1658         else
1659                 return roman[n-1];
1660 }
1661
1662
1663 // set the counter of a paragraph. This includes the labels
1664 void LyXText::SetCounter(Buffer const * buf, LyXParagraph * par) const
1665 {
1666 #ifndef NEW_INSETS
1667         // this is only relevant for the beginning of paragraph
1668         par = par->FirstPhysicalPar();
1669 #endif
1670         LyXLayout const & layout =
1671                 textclasslist.Style(buf->params.textclass, 
1672                                     par->GetLayout());
1673
1674         LyXTextClass const & textclass =
1675                 textclasslist.TextClass(buf->params.textclass);
1676
1677         /* copy the prev-counters to this one, unless this is the start of a 
1678            footnote or of a bibliography or the very first paragraph */
1679         if (par->Previous()
1680 #ifndef NEW_INSETS
1681             && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE 
1682                     && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1683                     && par->footnotekind == LyXParagraph::FOOTNOTE)
1684 #endif
1685             && !(textclasslist.Style(buf->params.textclass,
1686                                 par->Previous()->GetLayout()
1687                                 ).labeltype != LABEL_BIBLIO
1688                  && layout.labeltype == LABEL_BIBLIO)) {
1689                 for (int i = 0; i < 10; ++i) {
1690                         par->setCounter(i, par->Previous()->GetFirstCounter(i));
1691                 }
1692 #ifndef NEW_INSETS
1693                 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1694 #else
1695                 par->appendix = par->Previous()->appendix;
1696 #endif
1697                 if (!par->appendix && par->start_of_appendix){
1698                   par->appendix = true;
1699                   for (int i = 0; i < 10; ++i) {
1700                     par->setCounter(i, 0);
1701                   }  
1702                 }
1703 #ifndef NEW_INSETS
1704                 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1705                 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1706 #else
1707                 par->enumdepth = par->Previous()->enumdepth;
1708                 par->itemdepth = par->Previous()->itemdepth;
1709 #endif
1710         } else {
1711                 for (int i = 0; i < 10; ++i) {
1712                         par->setCounter(i, 0);
1713                 }  
1714                 par->appendix = par->start_of_appendix;
1715                 par->enumdepth = 0;
1716                 par->itemdepth = 0;
1717         }
1718
1719 #ifndef NEW_INSETS
1720         // if this is an open marginnote and this is the first
1721         // entry in the marginnote and the enclosing
1722         // environment is an enum/item then correct for the
1723         // LaTeX behaviour (ARRae)
1724         if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1725            && par->footnotekind == LyXParagraph::MARGIN
1726            && par->Previous()
1727            && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1728            && (par->PreviousBeforeFootnote()
1729                && textclasslist.Style(buf->params.textclass,
1730                                  par->PreviousBeforeFootnote()->GetLayout()
1731                                  ).labeltype >= LABEL_COUNTER_ENUMI)) {
1732                 // Any itemize or enumerate environment in a marginnote
1733                 // that is embedded in an itemize or enumerate
1734                 // paragraph is seen by LaTeX as being at a deeper
1735                 // level within that enclosing itemization/enumeration
1736                 // even if there is a "standard" layout at the start of
1737                 // the marginnote.
1738                 par->enumdepth++;
1739                 par->itemdepth++;
1740         }
1741 #endif
1742         /* Maybe we have to increment the enumeration depth.
1743          * BUT, enumeration in a footnote is considered in isolation from its
1744          *      surrounding paragraph so don't increment if this is the
1745          *      first line of the footnote
1746          * AND, bibliographies can't have their depth changed ie. they
1747          *      are always of depth 0
1748          */
1749         if (par->Previous()
1750             && par->Previous()->GetDepth() < par->GetDepth()
1751             && textclasslist.Style(buf->params.textclass,
1752                               par->Previous()->GetLayout()
1753                              ).labeltype == LABEL_COUNTER_ENUMI
1754             && par->enumdepth < 3
1755 #ifndef NEW_INSETS
1756             && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE 
1757                     && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1758                     && par->footnotekind == LyXParagraph::FOOTNOTE)
1759 #endif
1760             && layout.labeltype != LABEL_BIBLIO) {
1761                 par->enumdepth++;
1762         }
1763
1764         /* Maybe we have to decrement the enumeration depth, see note above */
1765         if (par->Previous()
1766             && par->Previous()->GetDepth() > par->GetDepth()
1767 #ifndef NEW_INSETS
1768             && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1769                     && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1770                     && par->footnotekind == LyXParagraph::FOOTNOTE)
1771 #endif
1772             && layout.labeltype != LABEL_BIBLIO) {
1773                 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1774                 par->setCounter(6 + par->enumdepth,
1775                         par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1776                 /* reset the counters.
1777                  * A depth change is like a breaking layout
1778                  */
1779                 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1780                         par->setCounter(i, 0);
1781         }
1782    
1783         if (!par->labelstring.empty()) {
1784                 par->labelstring.erase();
1785         }
1786    
1787         if (layout.margintype == MARGIN_MANUAL) {
1788                 if (par->labelwidthstring.empty()) {
1789                         par->SetLabelWidthString(layout.labelstring());
1790                 }
1791         } else {
1792                 par->SetLabelWidthString(string());
1793         }
1794    
1795         /* is it a layout that has an automatic label ? */ 
1796         if (layout.labeltype >=  LABEL_COUNTER_CHAPTER) {
1797       
1798                 int i = layout.labeltype - LABEL_COUNTER_CHAPTER;
1799                 if (i >= 0 && i<= buf->params.secnumdepth) {
1800                         par->incCounter(i);     // increment the counter  
1801          
1802                         // Is there a label? Useful for Chapter layout
1803                         if (!par->appendix){
1804                                 if (!layout.labelstring().empty())
1805                                         par->labelstring = layout.labelstring();
1806                                 else
1807                                         par->labelstring.erase();
1808                         } else {
1809                                 if (!layout.labelstring_appendix().empty())
1810                                         par->labelstring = layout.labelstring_appendix();
1811                                 else
1812                                         par->labelstring.erase();
1813                         }
1814
1815                         std::ostringstream s;
1816
1817                         if (!par->appendix) {
1818                                 switch (2 * LABEL_COUNTER_CHAPTER -
1819                                         textclass.maxcounter() + i) {
1820                                 case LABEL_COUNTER_CHAPTER:
1821                                         s << par->getCounter(i);
1822                                         break;
1823                                 case LABEL_COUNTER_SECTION:
1824                                         s << par->getCounter(i - 1) << '.'
1825                                            << par->getCounter(i);
1826                                         break;
1827                                 case LABEL_COUNTER_SUBSECTION:
1828                                         s << par->getCounter(i - 2) << '.'
1829                                           << par->getCounter(i - 1) << '.'
1830                                           << par->getCounter(i);
1831                                         break;
1832                                 case LABEL_COUNTER_SUBSUBSECTION:
1833                                         s << par->getCounter(i - 3) << '.'
1834                                           << par->getCounter(i - 2) << '.'
1835                                           << par->getCounter(i - 1) << '.'
1836                                           << par->getCounter(i);
1837                                         
1838                                         break;
1839                                 case LABEL_COUNTER_PARAGRAPH:
1840                                         s << par->getCounter(i - 4) << '.'
1841                                           << par->getCounter(i - 3) << '.'
1842                                           << par->getCounter(i - 2) << '.'
1843                                           << par->getCounter(i - 1) << '.'
1844                                           << par->getCounter(i);
1845                                         break;
1846                                 case LABEL_COUNTER_SUBPARAGRAPH:
1847                                         s << par->getCounter(i - 5) << '.'
1848                                           << par->getCounter(i - 4) << '.'
1849                                           << par->getCounter(i - 3) << '.'
1850                                           << par->getCounter(i - 2) << '.'
1851                                           << par->getCounter(i - 1) << '.'
1852                                           << par->getCounter(i);
1853
1854                                         break;
1855                                 default:
1856                                         // Can this ever be reached? And in the
1857                                         // case it is, how can this be correct?
1858                                         // (Lgb)
1859                                         s << par->getCounter(i) << '.';
1860                                         break;
1861                                 }
1862                         } else { // appendix
1863                                 switch (2 * LABEL_COUNTER_CHAPTER - textclass.maxcounter() + i) {
1864                                 case LABEL_COUNTER_CHAPTER:
1865                                         if (par->isRightToLeftPar(buf->params))
1866                                                 s << hebrewCounter(par->getCounter(i));
1867                                         else
1868                                                 s << alphaCounter(par->getCounter(i));
1869                                         break;
1870                                 case LABEL_COUNTER_SECTION:
1871                                         if (par->isRightToLeftPar(buf->params))
1872                                                 s << hebrewCounter(par->getCounter(i - 1));
1873                                         else
1874                                                 s << alphaCounter(par->getCounter(i - 1));
1875
1876                                         s << '.'
1877                                           << par->getCounter(i);
1878
1879                                         break;
1880                                 case LABEL_COUNTER_SUBSECTION:
1881                                         if (par->isRightToLeftPar(buf->params))
1882                                                 s << hebrewCounter(par->getCounter(i - 2));
1883                                         else
1884                                                 s << alphaCounter(par->getCounter(i - 2));
1885
1886                                         s << '.'
1887                                           << par->getCounter(i-1) << '.'
1888                                           << par->getCounter(i);
1889
1890                                         break;
1891                                 case LABEL_COUNTER_SUBSUBSECTION:
1892                                         if (par->isRightToLeftPar(buf->params))
1893                                                 s << hebrewCounter(par->getCounter(i-3));
1894                                         else
1895                                                 s << alphaCounter(par->getCounter(i-3));
1896
1897                                         s << '.'
1898                                           << par->getCounter(i-2) << '.'
1899                                           << par->getCounter(i-1) << '.'
1900                                           << par->getCounter(i);
1901
1902                                         break;
1903                                 case LABEL_COUNTER_PARAGRAPH:
1904                                         if (par->isRightToLeftPar(buf->params))
1905                                                 s << hebrewCounter(par->getCounter(i-4));
1906                                         else
1907                                                 s << alphaCounter(par->getCounter(i-4));
1908
1909                                         s << '.'
1910                                           << par->getCounter(i-3) << '.'
1911                                           << par->getCounter(i-2) << '.'
1912                                           << par->getCounter(i-1) << '.'
1913                                           << par->getCounter(i);
1914
1915                                         break;
1916                                 case LABEL_COUNTER_SUBPARAGRAPH:
1917                                         if (par->isRightToLeftPar(buf->params))
1918                                                 s << hebrewCounter(par->getCounter(i-5));
1919                                         else
1920                                                 s << alphaCounter(par->getCounter(i-5));
1921
1922                                         s << '.'
1923                                           << par->getCounter(i-4) << '.'
1924                                           << par->getCounter(i-3) << '.'
1925                                           << par->getCounter(i-2) << '.'
1926                                           << par->getCounter(i-1) << '.'
1927                                           << par->getCounter(i);
1928
1929                                         break;
1930                                 default:
1931                                         // Can this ever be reached? And in the
1932                                         // case it is, how can this be correct?
1933                                         // (Lgb)
1934                                         s << par->getCounter(i) << '.';
1935                                         
1936                                         break;
1937                                 }
1938                         }
1939
1940                         par->labelstring += s.str().c_str();
1941                         // We really want to remove the c_str as soon as
1942                         // possible...
1943                         
1944                         for (i++; i < 10; ++i) {
1945                                 // reset the following counters
1946                                 par->setCounter(i, 0);
1947                         }
1948                 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1949                         for (i++; i < 10; ++i) {
1950                                 // reset the following counters
1951                                 par->setCounter(i, 0);
1952                         }
1953                 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1954                         par->incCounter(i + par->enumdepth);
1955                         int number = par->getCounter(i + par->enumdepth);
1956
1957                         std::ostringstream s;
1958
1959                         switch (par->enumdepth) {
1960                         case 1:
1961                                 if (par->isRightToLeftPar(buf->params))
1962                                         s << '('
1963                                           << hebrewCounter(number)
1964                                           << ')';
1965                                 else
1966                                         s << '('
1967                                           << loweralphaCounter(number)
1968                                           << ')';
1969                                 break;
1970                         case 2:
1971                                 if (par->isRightToLeftPar(buf->params))
1972                                         s << '.' << romanCounter(number);
1973                                 else
1974                                         s << romanCounter(number) << '.';
1975                                 break;
1976                         case 3:
1977                                 if (par->isRightToLeftPar(buf->params))
1978                                         s << '.'
1979                                           << alphaCounter(number);
1980                                 else
1981                                         s << alphaCounter(number)
1982                                           << '.';
1983                                 break;
1984                         default:
1985                                 if (par->isRightToLeftPar(buf->params))
1986                                         s << '.' << number;
1987                                 else
1988                                         s << number << '.';
1989                                 break;
1990                         }
1991
1992                         par->labelstring = s.str().c_str();
1993                         // we really want to get rid of that c_str()
1994
1995                         for (i += par->enumdepth + 1; i < 10; ++i)
1996                                 par->setCounter(i, 0);  /* reset the following counters  */
1997          
1998                 } 
1999         } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
2000                 int i = LABEL_COUNTER_ENUMI - LABEL_COUNTER_CHAPTER + par->enumdepth;
2001                 par->incCounter(i);
2002                 int number = par->getCounter(i);
2003                 if (!par->bibkey) {
2004                         InsetCommandParams p( "bibitem" );
2005                         par->bibkey = new InsetBibKey(p);
2006                 }
2007                 par->bibkey->setCounter(number);
2008                 par->labelstring = layout.labelstring();
2009                 
2010                 // In biblio should't be following counters but...
2011         } else {
2012                 string s = layout.labelstring();
2013                 
2014                 // the caption hack:
2015                 if (layout.labeltype == LABEL_SENSITIVE) {
2016                         bool isOK (par->InInset() && par->InInset()->owner() &&
2017                                    (par->InInset()->owner()->LyxCode() == Inset::FLOAT_CODE));
2018 #ifndef NEW_INSETS
2019                         if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2020                             && (par->footnotekind == LyXParagraph::FIG
2021                                 || par->footnotekind == LyXParagraph::WIDE_FIG)) {
2022                                 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2023                                         ? ":øåéà" : "Figure:";
2024                         } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2025                                  && (par->footnotekind == LyXParagraph::TAB
2026                                      || par->footnotekind == LyXParagraph::WIDE_TAB)) {
2027                                 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2028                                         ? ":äìáè" : "Table:";
2029                         } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2030                                    && par->footnotekind == LyXParagraph::ALGORITHM) {
2031                                 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2032                                         ? ":íúéøåâìà" : "Algorithm:";
2033                         } else
2034 #endif
2035                         if (isOK) {
2036                                 InsetFloat * tmp = static_cast<InsetFloat*>(par->InInset()->owner());
2037                                 Floating const & fl
2038                                         = floatList.getType(tmp->type());
2039                                 // We should get the correct number here too.
2040                                 s = fl.name() + " #:";
2041                         } else {
2042                                 /* par->SetLayout(0); 
2043                                    s = layout->labelstring;  */
2044                                 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2045                                         ? " :úåòîùî Ã¸Ã±Ã§" : "Senseless: ";
2046                         }
2047                 }
2048                 par->labelstring = s;
2049                 
2050                 /* reset the enumeration counter. They are always resetted
2051                  * when there is any other layout between */ 
2052                 for (int i = 6 + par->enumdepth; i < 10; ++i)
2053                         par->setCounter(i, 0);
2054         }
2055 }
2056
2057
2058 /* Updates all counters BEHIND the row. Changed paragraphs
2059 * with a dynamic left margin will be rebroken. */ 
2060 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
2061 {
2062         LyXParagraph * par;
2063         if (!row) {
2064                 row = firstrow;
2065                 par = row->par();
2066         } else {
2067                 if (row->par()->next
2068 #ifndef NEW_INSETS
2069                     && row->par()->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
2070 #endif
2071                         ) {
2072 #ifndef NEW_INSETS
2073                         par = row->par()->LastPhysicalPar()->Next();
2074 #else
2075                         par = row->par()->Next();
2076 #endif
2077                 } else {
2078                         par = row->par()->next;
2079                 }
2080         }
2081
2082         while (par) {
2083                 while (row->par() != par)
2084                         row = row->next();
2085                 
2086                 SetCounter(bview->buffer(), par);
2087                 
2088                 /* now  check for the headline layouts. remember that they
2089                  * have a dynamic left margin */ 
2090                 if (
2091 #ifndef NEW_INSETS
2092                         !par->IsDummy() &&
2093 #endif
2094                     ( textclasslist.Style(bview->buffer()->params.textclass,
2095                                              par->layout).margintype == MARGIN_DYNAMIC
2096                          || textclasslist.Style(bview->buffer()->params.textclass,
2097                                                 par->layout).labeltype == LABEL_SENSITIVE)
2098                         ) {
2099          
2100                         /* Rebreak the paragraph */ 
2101                         RemoveParagraph(row);
2102                         AppendParagraph(bview, row);
2103
2104 #ifndef NEW_INSETS
2105                         /* think about the damned open footnotes! */ 
2106                         while (par->Next() &&
2107                                (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
2108                                 || par->Next()->IsDummy())){
2109                                 par = par->Next();
2110                                 if (par->IsDummy()) {
2111                                         while (row->par() != par)
2112                                                 row = row->next();
2113                                         RemoveParagraph(row);
2114                                         AppendParagraph(bview, row);
2115                                 }
2116                         }
2117 #endif
2118                 }
2119 #ifndef NEW_INSETS
2120                 par = par->LastPhysicalPar()->Next();
2121 #else
2122                 par = par->Next();
2123 #endif
2124      
2125         }
2126 }
2127
2128
2129 /* insets an inset. */ 
2130 void LyXText::InsertInset(BufferView * bview, Inset * inset)
2131 {
2132         if (!cursor.par()->InsertInsetAllowed(inset))
2133                 return;
2134         SetUndo(bview->buffer(), Undo::INSERT,
2135 #ifndef NEW_INSETS
2136                 cursor.par()->ParFromPos(cursor.pos())->previous, 
2137                 cursor.par()->ParFromPos(cursor.pos())->next
2138 #else
2139                 cursor.par()->previous, 
2140                 cursor.par()->next
2141 #endif
2142                 );
2143         cursor.par()->InsertInset(cursor.pos(), inset);
2144         InsertChar(bview, LyXParagraph::META_INSET);  /* just to rebreak and refresh correctly.
2145                                       * The character will not be inserted a
2146                                       * second time */
2147 #if 1
2148         // If we enter a highly editable inset the cursor should be to before
2149         // the inset. This couldn't happen before as Undo was not handled inside
2150         // inset now after the Undo LyX tries to call inset->Edit(...) again
2151         // and cannot do this as the cursor is behind the inset and GetInset
2152         // does not return the inset!
2153         if (inset->Editable() == Inset::HIGHLY_EDITABLE) {
2154                 CursorLeft(bview, true);
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                                   false, cursor.boundary());
2676                         sel_cursor = cursor;
2677                         return;
2678                 }
2679         }
2680
2681         int const tmpheight = row->height();
2682         LyXParagraph::size_type const tmplast = RowLast(row);
2683         refresh_y = y;
2684         refresh_row = row;
2685         
2686         BreakAgain(bview, row);
2687         if (row->height() == tmpheight && RowLast(row) == tmplast)
2688                 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2689         else
2690                 status = LyXText::NEED_MORE_REFRESH; 
2691         
2692         // check the special right address boxes
2693         if (textclasslist.Style(bview->buffer()->params.textclass,
2694                                 par->GetLayout()).margintype
2695             == MARGIN_RIGHT_ADDRESS_BOX) {
2696                 tmpcursor.par(par);
2697                 tmpcursor.row(row);
2698                 tmpcursor.y(y);
2699                 tmpcursor.x(0);
2700                 tmpcursor.x_fix(0);
2701                 tmpcursor.pos(pos);
2702                 RedoDrawingOfParagraph(bview, tmpcursor); 
2703         }
2704
2705         // set the cursor again. Otherwise dangling pointers are possible
2706         // also set the selection
2707    
2708         if (selection) {
2709                 tmpcursor = cursor;
2710                 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos(),
2711                                 false, sel_cursor.boundary());
2712                 sel_cursor = cursor; 
2713                 SetCursorIntern(bview, sel_start_cursor.par(),
2714                                 sel_start_cursor.pos(),
2715                                 false, sel_start_cursor.boundary());
2716                 sel_start_cursor = cursor; 
2717                 SetCursorIntern(bview, sel_end_cursor.par(),
2718                                 sel_end_cursor.pos(),
2719                                 false, sel_end_cursor.boundary());
2720                 sel_end_cursor = cursor; 
2721                 SetCursorIntern(bview, last_sel_cursor.par(),
2722                                 last_sel_cursor.pos(),
2723                                 false, last_sel_cursor.boundary());
2724                 last_sel_cursor = cursor; 
2725                 cursor = tmpcursor;
2726         }
2727         SetCursorIntern(bview, cursor.par(), cursor.pos(),
2728                         false, cursor.boundary());
2729 }
2730
2731
2732 // returns false if inset wasn't found
2733 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2734 {
2735         // first check the current paragraph
2736         int pos = cursor.par()->GetPositionOfInset(inset);
2737         if (pos != -1){
2738                 CheckParagraph(bview, cursor.par(), pos);
2739                 return true;
2740         }
2741   
2742         // check every paragraph
2743   
2744         LyXParagraph * par = FirstParagraph();
2745         do {
2746 #ifndef NEW_INSETS
2747                 // make sure the paragraph is open
2748                 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2749 #endif
2750                         pos = par->GetPositionOfInset(inset);
2751                         if (pos != -1){
2752                                 CheckParagraph(bview, par, pos);
2753                                 return true;
2754                         }
2755 #ifndef NEW_INSETS
2756                 }
2757 #endif
2758                 par = par->Next();
2759         } while (par);
2760   
2761         return false;
2762 }
2763
2764
2765 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2766                         LyXParagraph::size_type pos, 
2767                         bool setfont, bool boundary) const
2768 {
2769         LyXCursor old_cursor = cursor;
2770         SetCursorIntern(bview, par, pos, setfont, boundary);
2771         DeleteEmptyParagraphMechanism(bview, old_cursor);
2772 }
2773
2774
2775 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2776                         LyXParagraph::size_type pos, bool boundary) const
2777 {
2778 #ifndef NEW_INSETS
2779         // correct the cursor position if impossible
2780         if (pos > par->Last()){
2781                 LyXParagraph * tmppar = par->ParFromPos(pos);
2782                 pos = par->PositionInParFromPos(pos);
2783                 par = tmppar;
2784         }
2785         if (par->IsDummy() && par->previous &&
2786             par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2787                 while (par->previous &&
2788                        ((par->previous->IsDummy() &&
2789                          (par->previous->previous->footnoteflag ==
2790                           LyXParagraph::CLOSED_FOOTNOTE)) ||
2791                         (par->previous->footnoteflag ==
2792                          LyXParagraph::CLOSED_FOOTNOTE))) {
2793                         par = par->previous ;
2794                         if (par->IsDummy() &&
2795                             (par->previous->footnoteflag ==
2796                              LyXParagraph::CLOSED_FOOTNOTE))
2797                                 pos += par->size() + 1;
2798                 }
2799                 if (par->previous) {
2800                         par = par->previous;
2801                 }
2802                 pos += par->size() + 1;
2803         }
2804 #endif
2805         cur.par(par);
2806         cur.pos(pos);
2807         cur.boundary(boundary);
2808
2809         /* get the cursor y position in text  */
2810         int y = 0;
2811         Row * row = GetRow(par, pos, y);
2812         /* y is now the beginning of the cursor row */ 
2813         y += row->baseline();
2814         /* y is now the cursor baseline */ 
2815         cur.y(y);
2816    
2817         /* now get the cursors x position */
2818         float x;
2819         float fill_separator, fill_hfill, fill_label_hfill;
2820         PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2821                        fill_label_hfill);
2822         LyXParagraph::size_type cursor_vpos = 0;
2823         LyXParagraph::size_type last = RowLastPrintable(row);
2824
2825         if (pos > last + 1)   // This shouldn't happen.
2826                 pos = last + 1;
2827         else if (pos < row->pos())
2828                 pos = row->pos();
2829
2830         if (last < row->pos())
2831                 cursor_vpos = row->pos();
2832         else if (pos > last && !boundary)
2833                 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2834                         ? row->pos() : last + 1; 
2835         else if (pos > row->pos() &&
2836                  (pos > last || boundary))
2837                 /// Place cursor after char at (logical) position pos - 1
2838                 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2839                         ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2840         else
2841                 /// Place cursor before char at (logical) position pos
2842                 cursor_vpos = (bidi_level(pos) % 2 == 0)
2843                         ? log2vis(pos) : log2vis(pos) + 1;
2844         
2845         LyXParagraph::size_type main_body =
2846                 BeginningOfMainBody(bview->buffer(), row->par());
2847         if ((main_body > 0) &&
2848             ((main_body-1 > last) || 
2849              !row->par()->IsLineSeparator(main_body-1)))
2850                 main_body = 0;
2851         
2852         for (LyXParagraph::size_type vpos = row->pos();
2853              vpos < cursor_vpos; ++vpos) {
2854                 pos = vis2log(vpos);
2855                 if (main_body > 0 && pos == main_body - 1) {
2856                         x += fill_label_hfill +
2857                                 lyxfont::width(textclasslist.Style(
2858                                         bview->buffer()->params.textclass,
2859                                         row->par()->GetLayout())
2860                                                .labelsep,
2861                                                GetFont(bview->buffer(), row->par(), -2));
2862                         if (row->par()->IsLineSeparator(main_body-1))
2863                                 x -= SingleWidth(bview, row->par(),main_body-1);
2864                 }
2865                 if (HfillExpansion(bview->buffer(), row, pos)) {
2866                         x += SingleWidth(bview, row->par(), pos);
2867                         if (pos >= main_body)
2868                                 x += fill_hfill;
2869                         else 
2870                                 x += fill_label_hfill;
2871                 } else if (row->par()->IsSeparator(pos)) {
2872                         x += SingleWidth(bview, row->par(), pos);
2873                         if (pos >= main_body)
2874                                 x += fill_separator;
2875                 } else
2876                         x += SingleWidth(bview, row->par(), pos);
2877         }
2878         
2879         cur.x(int(x));
2880         cur.x_fix(cur.x());
2881         cur.row(row);
2882 }
2883
2884
2885 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
2886                               LyXParagraph::size_type pos,
2887                               bool setfont, bool boundary) const
2888 {
2889         SetCursor(bview, cursor, par, pos, boundary);
2890         if (setfont)
2891                 SetCurrentFont(bview);
2892 }
2893
2894
2895 void LyXText::SetCurrentFont(BufferView * bview) const
2896 {
2897         LyXParagraph::size_type pos = cursor.pos();
2898         if (cursor.boundary() && pos > 0)
2899                 --pos;
2900
2901         if (pos > 0) {
2902                 if (pos == cursor.par()->Last())
2903                         --pos;
2904                 else if (cursor.par()->IsSeparator(pos)) {
2905                         if (pos > cursor.row()->pos() &&
2906                             bidi_level(pos) % 2 == 
2907                             bidi_level(pos - 1) % 2)
2908                                 --pos;
2909                         else if (pos + 1 < cursor.par()->Last())
2910                                 ++pos;
2911                 }
2912         }
2913
2914         current_font =
2915                 cursor.par()->GetFontSettings(bview->buffer()->params, pos);
2916         real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
2917
2918         if (cursor.pos() == cursor.par()->Last() &&
2919             IsBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
2920             !cursor.boundary()) {
2921                 Language const * lang =
2922                         cursor.par()->getParLanguage(bview->buffer()->params);
2923                 current_font.setLanguage(lang);
2924                 real_current_font.setLanguage(lang);
2925         }
2926 }
2927
2928
2929 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, int y) const
2930 {
2931         LyXCursor old_cursor = cursor;
2932    
2933         /* get the row first */ 
2934    
2935         Row * row = GetRowNearY(y);
2936         cursor.par(row->par());
2937
2938         bool bound = false;
2939         int column = GetColumnNearX(bview, row, x, bound);
2940         cursor.pos(row->pos() + column);
2941         cursor.x(x);
2942         cursor.y(y + row->baseline());
2943         cursor.row(row);
2944         cursor.boundary(bound);
2945         SetCurrentFont(bview);
2946         DeleteEmptyParagraphMechanism(bview, old_cursor);
2947 }
2948
2949
2950 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
2951                                        int x, int y) const
2952 {
2953         /* get the row first */ 
2954    
2955         Row * row = GetRowNearY(y);
2956         bool bound = false;
2957         int column = GetColumnNearX(bview, row, x, bound);
2958    
2959         cur.par(row->par());
2960         cur.pos(row->pos() + column);
2961         cur.x(x);
2962         cur.y(y + row->baseline());
2963         cur.row(row);
2964         cur.boundary(bound);
2965 }
2966
2967
2968 void LyXText::CursorLeft(BufferView * bview, bool internal) const
2969 {
2970         if (cursor.pos() > 0) {
2971                 bool boundary = cursor.boundary();
2972                 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
2973                 if (!internal && !boundary &&
2974                     IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
2975                         SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
2976         } else if (cursor.par()->Previous()) { // steps into the above paragraph.
2977                 LyXParagraph * par = cursor.par()->Previous();
2978                 SetCursor(bview, par, par->Last());
2979         }
2980 }
2981
2982
2983 void LyXText::CursorRight(BufferView * bview, bool internal) const
2984 {
2985         if (!internal && cursor.boundary() &&
2986             !cursor.par()->IsNewline(cursor.pos()))
2987                 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
2988         else if (cursor.pos() < cursor.par()->Last()) {
2989                 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
2990                 if (!internal &&
2991                     IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
2992                         SetCursor(bview, cursor.par(), cursor.pos(), true, true);
2993         } else if (cursor.par()->Next())
2994                 SetCursor(bview, cursor.par()->Next(), 0);
2995 }
2996
2997
2998 void LyXText::CursorUp(BufferView * bview) const
2999 {
3000         SetCursorFromCoordinates(bview, cursor.x_fix(), 
3001                                  cursor.y() - cursor.row()->baseline() - 1);
3002 }
3003
3004
3005 void LyXText::CursorDown(BufferView * bview) const
3006 {
3007         SetCursorFromCoordinates(bview, cursor.x_fix(), 
3008                                  cursor.y() - cursor.row()->baseline()
3009                                  + cursor.row()->height() + 1);
3010 }
3011
3012
3013 void LyXText::CursorUpParagraph(BufferView * bview) const
3014 {
3015         if (cursor.pos() > 0) {
3016                 SetCursor(bview, cursor.par(), 0);
3017         }
3018         else if (cursor.par()->Previous()) {
3019                 SetCursor(bview, cursor.par()->Previous(), 0);
3020         }
3021 }
3022
3023
3024 void LyXText::CursorDownParagraph(BufferView * bview) const
3025 {
3026         if (cursor.par()->Next()) {
3027                 SetCursor(bview, cursor.par()->Next(), 0);
3028         } else {
3029                 SetCursor(bview, cursor.par(), cursor.par()->Last());
3030         }
3031 }
3032
3033
3034 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
3035                                             LyXCursor const & old_cursor) const
3036 {
3037         // Would be wrong to delete anything if we have a selection.
3038         if (selection) return;
3039
3040         // We allow all kinds of "mumbo-jumbo" when freespacing.
3041         if (textclasslist.Style(bview->buffer()->params.textclass,
3042                                 old_cursor.par()->GetLayout()).free_spacing)
3043                 return;
3044
3045         bool deleted = false;
3046         
3047         /* Ok I'll put some comments here about what is missing.
3048            I have fixed BackSpace (and thus Delete) to not delete
3049            double-spaces automagically. I have also changed Cut,
3050            Copy and Paste to hopefully do some sensible things.
3051            There are still some small problems that can lead to
3052            double spaces stored in the document file or space at
3053            the beginning of paragraphs. This happens if you have
3054            the cursor betwenn to spaces and then save. Or if you
3055            cut and paste and the selection have a space at the
3056            beginning and then save right after the paste. I am
3057            sure none of these are very hard to fix, but I will
3058            put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3059            that I can get some feedback. (Lgb)
3060         */
3061
3062         // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
3063         // delete the LineSeparator.
3064         // MISSING
3065
3066         // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
3067         // delete the LineSeparator.
3068         // MISSING
3069
3070         // If the pos around the old_cursor were spaces, delete one of them.
3071         if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) { 
3072                 // Only if the cursor has really moved
3073                 
3074                 if (old_cursor.pos() > 0
3075                     && old_cursor.pos() < old_cursor.par()->Last()
3076                     && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3077                     && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3078                         old_cursor.par()->Erase(old_cursor.pos() - 1);
3079                         RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3080                         // correct cursor
3081                         if (old_cursor.par() == cursor.par() &&
3082                             cursor.pos() > old_cursor.pos()) {
3083                                 SetCursorIntern(bview, cursor.par(),
3084                                                 cursor.pos() - 1);
3085                         } else
3086                                 SetCursorIntern(bview, cursor.par(),
3087                                                 cursor.pos());
3088                         return;
3089                 }
3090         }
3091
3092         // Do not delete empty paragraphs with keepempty set.
3093         if ((textclasslist.Style(bview->buffer()->params.textclass,
3094                                  old_cursor.par()->GetLayout())).keepempty)
3095                 return;
3096
3097         LyXCursor tmpcursor;
3098
3099         if (old_cursor.par() != cursor.par()) {
3100                 if ((old_cursor.par()->Last() == 0
3101                       || (old_cursor.par()->Last() == 1
3102                           && old_cursor.par()->IsLineSeparator(0)))
3103 #ifndef NEW_INSETS
3104                      && old_cursor.par()->FirstPhysicalPar()
3105                      == old_cursor.par()->LastPhysicalPar()
3106 #endif
3107                         ) {
3108                         // ok, we will delete anything
3109                         
3110                         // make sure that you do not delete any environments
3111 #ifndef NEW_INSETS
3112                         if ((
3113                                 old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3114                              !(old_cursor.row()->previous() 
3115                                && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3116                              && !(old_cursor.row()->next() 
3117                                   && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3118                             || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3119                                 && ((old_cursor.row()->previous() 
3120                                      && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3121                                     || (old_cursor.row()->next()
3122                                         && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3123                                     )) {
3124 #endif
3125                                 status = LyXText::NEED_MORE_REFRESH;
3126                                 deleted = true;
3127                                 
3128                                 if (old_cursor.row()->previous()) {
3129                                         refresh_row = old_cursor.row()->previous();
3130                                         refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3131                                         tmpcursor = cursor;
3132                                         cursor = old_cursor; // that undo can restore the right cursor position
3133                                         LyXParagraph * endpar = old_cursor.par()->next;
3134                                         if (endpar && endpar->GetDepth()) {
3135                                                 while (endpar && endpar->GetDepth()) {
3136 #ifndef NEW_INSETS
3137                                                         endpar = endpar->LastPhysicalPar()->Next();
3138 #else
3139                                                         endpar = endpar->Next();
3140 #endif
3141                                                 }
3142                                         }
3143                                         SetUndo(bview->buffer(), Undo::DELETE,
3144                                                 old_cursor.par()->previous,
3145                                                 endpar);
3146                                         cursor = tmpcursor;
3147
3148                                         // delete old row
3149                                         RemoveRow(old_cursor.row());
3150                                         if (OwnerParagraph() == old_cursor.par()) {
3151                                                 OwnerParagraph(OwnerParagraph()->next);
3152                                         }
3153                                         // delete old par
3154                                         delete old_cursor.par();
3155                                         
3156                                         /* Breakagain the next par. Needed
3157                                          * because of the parindent that
3158                                          * can occur or dissappear. The
3159                                          * next row can change its height,
3160                                          * if there is another layout before */
3161                                         if (refresh_row->next()) {
3162                                                 BreakAgain(bview, refresh_row->next());
3163                                                 UpdateCounters(bview, refresh_row);
3164                                         }
3165                                         SetHeightOfRow(bview, refresh_row);
3166                                 } else {
3167                                         refresh_row = old_cursor.row()->next();
3168                                         refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3169                                         
3170                                         tmpcursor = cursor;
3171                                         cursor = old_cursor; // that undo can restore the right cursor position
3172                                         LyXParagraph * endpar = old_cursor.par()->next;
3173                                         if (endpar && endpar->GetDepth()) {
3174                                                 while (endpar && endpar->GetDepth()) {
3175 #ifndef NEW_INSETS
3176                                                         endpar = endpar->LastPhysicalPar()->Next();
3177 #else
3178                                                         endpar = endpar->Next();
3179 #endif
3180                                                 }
3181                                         }
3182                                         SetUndo(bview->buffer(), Undo::DELETE,
3183                                                 old_cursor.par()->previous,
3184                                                 endpar);
3185                                         cursor = tmpcursor;
3186
3187                                         // delete old row
3188                                         RemoveRow(old_cursor.row());
3189                                         // delete old par
3190                                         if (OwnerParagraph() == old_cursor.par()) {
3191                                                 OwnerParagraph(OwnerParagraph()->next);
3192                                         }
3193                                         delete old_cursor.par();
3194                                         
3195                                         /* Breakagain the next par. Needed
3196                                            because of the parindent that can
3197                                            occur or dissappear.
3198                                            The next row can change its height,
3199                                            if there is another layout before
3200                                         */ 
3201                                         if (refresh_row) {
3202                                                 BreakAgain(bview, refresh_row);
3203                                                 UpdateCounters(bview, refresh_row->previous());
3204                                         }
3205                                 }
3206                                 
3207                                 // correct cursor y
3208
3209                                 SetCursorIntern(bview, cursor.par(), cursor.pos());
3210
3211                                 if (sel_cursor.par()  == old_cursor.par()
3212                                     && sel_cursor.pos() == sel_cursor.pos()) {
3213                                         // correct selection
3214                                         sel_cursor = cursor;
3215                                 }
3216 #ifndef NEW_INSETS
3217                         }
3218 #endif
3219                 }
3220                 if (!deleted) {
3221                         if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
3222                                 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3223                                 // correct cursor y
3224                                 SetCursorIntern(bview, cursor.par(), cursor.pos());
3225                                 sel_cursor = cursor;
3226                         }
3227                 }
3228         }
3229 }
3230
3231
3232 LyXParagraph * LyXText::GetParFromID(int id)
3233 {
3234         LyXParagraph * result = FirstParagraph();
3235         while (result && result->id() != id)
3236                 result = result->next;
3237         return result;
3238 }
3239
3240
3241 // undo functions
3242 bool LyXText::TextUndo(BufferView * bview)
3243 {
3244         if (inset_owner)
3245                 return false;
3246         // returns false if no undo possible
3247         Undo * undo = bview->buffer()->undostack.pop();
3248         if (undo) {
3249                 FinishUndo();
3250                 if (!undo_frozen)
3251                         bview->buffer()->redostack
3252                                 .push(CreateUndo(bview->buffer(), undo->kind, 
3253                                                  GetParFromID(undo->number_of_before_par),
3254                                                  GetParFromID(undo->number_of_behind_par)));
3255         }
3256         return TextHandleUndo(bview, undo);
3257 }
3258
3259
3260 bool LyXText::TextRedo(BufferView * bview)
3261 {
3262         if (inset_owner)
3263                 return false;
3264         // returns false if no redo possible
3265         Undo * undo = bview->buffer()->redostack.pop();
3266         if (undo) {
3267                 FinishUndo();
3268                 if (!undo_frozen)
3269                         bview->buffer()->undostack
3270                                 .push(CreateUndo(bview->buffer(), undo->kind, 
3271                                                  GetParFromID(undo->number_of_before_par),
3272                                                  GetParFromID(undo->number_of_behind_par)));
3273         }
3274         return TextHandleUndo(bview, undo);
3275 }
3276
3277
3278 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
3279 {
3280         if (inset_owner)
3281                 return false;
3282         // returns false if no undo possible
3283         bool result = false;
3284         if (undo) {
3285                 LyXParagraph * before =
3286                         GetParFromID(undo->number_of_before_par); 
3287                 LyXParagraph * behind =
3288                         GetParFromID(undo->number_of_behind_par); 
3289                 LyXParagraph * tmppar;
3290                 LyXParagraph * tmppar2;
3291                 LyXParagraph * endpar;
3292                 LyXParagraph * tmppar5;
3293     
3294                 // if there's no before take the beginning
3295                 // of the document for redoing
3296                 if (!before)
3297                         SetCursorIntern(bview, FirstParagraph(), 0);
3298
3299                 // replace the paragraphs with the undo informations
3300
3301                 LyXParagraph * tmppar3 = undo->par;
3302                 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3303                 LyXParagraph * tmppar4 = tmppar3;
3304                 if (tmppar4){
3305                         while (tmppar4->next)
3306                                 tmppar4 = tmppar4->next;
3307                 } // get last undo par
3308     
3309                 // now remove the old text if there is any
3310                 if (before != behind || (!behind && !before)){
3311                         if (before)
3312                                 tmppar5 = before->next;
3313                         else
3314                                 tmppar5 = OwnerParagraph();
3315                         tmppar2 = tmppar3;
3316                         while (tmppar5 && tmppar5 != behind){
3317                                 tmppar = tmppar5;
3318                                 tmppar5 = tmppar5->next;
3319                                 // a memory optimization for edit: Only layout information
3320                                 // is stored in the undo. So restore the text informations.
3321                                 if (undo->kind == Undo::EDIT) {
3322                                         tmppar2->setContentsFromPar(tmppar);
3323                                         tmppar->clearContents();
3324                                         tmppar2 = tmppar2->next;
3325                                 }
3326                         }
3327                 }
3328     
3329                 // put the new stuff in the list if there is one
3330                 if (tmppar3){
3331                         if (before)
3332                                 before->next = tmppar3;
3333                         else
3334                                 OwnerParagraph(tmppar3);
3335                         tmppar3->previous = before;
3336                 } else {
3337                         if (!before)
3338                                 OwnerParagraph(behind);
3339                 }
3340                 if (tmppar4) {
3341                         tmppar4->next = behind;
3342                         if (behind)
3343                                 behind->previous = tmppar4;
3344                 }
3345     
3346     
3347                 // Set the cursor for redoing
3348                 if (before) {
3349 #ifndef NEW_INSETS
3350                         SetCursorIntern(bview, before->FirstSelfrowPar(), 0);
3351 #else
3352                         SetCursorIntern(bview, before, 0);
3353 #endif
3354 #ifndef NEW_INSETS
3355                         // check wether before points to a closed float and open it if necessary
3356                         if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3357                             && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3358                                 tmppar4 = before;
3359                                 while (tmppar4->previous && 
3360                                        tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3361                                         tmppar4 = tmppar4->previous;
3362                                 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3363                                         tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3364                                         tmppar4 = tmppar4->next;
3365                                 }
3366                         }
3367 #endif
3368                 }
3369
3370 #ifndef NEW_INSETS
3371                 // open a cosed footnote at the end if necessary
3372                 if (behind && behind->previous && 
3373                     behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3374                     behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3375                         while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3376                                 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3377                                 behind = behind->next;
3378                         }
3379                 }
3380 #endif
3381     
3382                 // calculate the endpar for redoing the paragraphs.
3383                 if (behind) {
3384 #ifndef NEW_INSETS
3385                         if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3386                                 endpar = behind->LastPhysicalPar()->Next();
3387                         else
3388                                 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3389 #else
3390                                 endpar = behind->Next();
3391 #endif
3392                 } else
3393                         endpar = behind;
3394     
3395                 tmppar = GetParFromID(undo->number_of_cursor_par);
3396                 RedoParagraphs(bview, cursor, endpar); 
3397                 if (tmppar){
3398                         SetCursorIntern(bview, tmppar, undo->cursor_pos);
3399                         UpdateCounters(bview, cursor.row());
3400                 }
3401                 result = true;
3402                 delete undo;
3403         }
3404         FinishUndo();
3405         return result;
3406 }
3407
3408
3409 void LyXText::FinishUndo()
3410 {
3411         if (inset_owner)
3412                 return;
3413         // makes sure the next operation will be stored
3414         undo_finished = true;
3415 }
3416
3417
3418 void LyXText::FreezeUndo()
3419 {
3420         if (inset_owner)
3421                 return;
3422         // this is dangerous and for internal use only
3423         undo_frozen = true;
3424 }
3425
3426
3427 void LyXText::UnFreezeUndo()
3428 {
3429         if (inset_owner)
3430                 return;
3431         // this is dangerous and for internal use only
3432         undo_frozen = false;
3433 }
3434
3435
3436 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
3437                       LyXParagraph const * before,
3438                       LyXParagraph const * behind) const
3439 {
3440         if (inset_owner)
3441                 return;
3442         if (!undo_frozen)
3443                 buf->undostack.push(CreateUndo(buf, kind, before, behind));
3444         buf->redostack.clear();
3445 }
3446
3447
3448 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
3449                       LyXParagraph const * before, LyXParagraph const * behind)
3450 {
3451         if (inset_owner)
3452                 return;
3453         buf->redostack.push(CreateUndo(buf, kind, before, behind));
3454 }
3455
3456
3457 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
3458                            LyXParagraph const * before,
3459                            LyXParagraph const * behind) const
3460 {
3461         if (inset_owner)
3462                 return 0;
3463
3464         int before_number = -1;
3465         int behind_number = -1;
3466         if (before)
3467                 before_number = before->id();
3468         if (behind)
3469                 behind_number = behind->id();
3470         // Undo::EDIT  and Undo::FINISH are
3471         // always finished. (no overlapping there)
3472         // overlapping only with insert and delete inside one paragraph: 
3473         // Nobody wants all removed  character
3474         // appear one by one when undoing. 
3475         // EDIT is special since only layout information, not the
3476         // contents of a paragaph are stored.
3477         if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
3478                 // check wether storing is needed
3479                 if (!buf->undostack.empty() && 
3480                     buf->undostack.top()->kind == kind &&
3481                     buf->undostack.top()->number_of_before_par ==  before_number &&
3482                     buf->undostack.top()->number_of_behind_par ==  behind_number ){
3483                         // no undo needed
3484                         return 0;
3485                 }
3486         }
3487         // create a new Undo
3488         LyXParagraph * undopar;
3489         LyXParagraph * tmppar;
3490         LyXParagraph * tmppar2;
3491
3492         LyXParagraph * start = 0;
3493         LyXParagraph * end = 0;
3494   
3495         if (before)
3496                 start = before->next;
3497         else
3498                 start = FirstParagraph();
3499         if (behind)
3500                 end = behind->previous;
3501         else {
3502                 end = FirstParagraph();
3503                 while (end->next)
3504                         end = end->next;
3505         }
3506
3507         if (start && end && (start != end->next) &&
3508             ((before != behind) || (!before && !behind)))
3509         {
3510                 tmppar = start;
3511                 tmppar2 = tmppar->Clone();
3512                 tmppar2->id(tmppar->id());
3513
3514                 // a memory optimization: Just store the layout information
3515                 // when only edit
3516                 if (kind == Undo::EDIT){
3517                         //tmppar2->text.clear();
3518                         tmppar2->clearContents();
3519                 }
3520
3521                 undopar = tmppar2;
3522   
3523                 while (tmppar != end && tmppar->next) {
3524                         tmppar = tmppar->next;
3525                         tmppar2->next = tmppar->Clone();
3526                         tmppar2->next->id(tmppar->id());
3527                         // a memory optimization: Just store the layout
3528                         // information when only edit
3529                         if (kind == Undo::EDIT){
3530                                 //tmppar2->next->text.clear();
3531                                 tmppar2->clearContents();
3532                         }
3533                         tmppar2->next->previous = tmppar2;
3534                         tmppar2 = tmppar2->next;
3535                 }
3536                 tmppar2->next = 0;
3537         } else
3538                 undopar = 0; // nothing to replace (undo of delete maybe)
3539
3540 #ifndef NEW_INSETS
3541         int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
3542         int cursor_pos =  cursor.par()->PositionInParFromPos(cursor.pos());
3543 #else
3544         int cursor_par = cursor.par()->id();
3545         int cursor_pos =  cursor.pos();
3546 #endif
3547
3548         Undo * undo = new Undo(kind, 
3549                                before_number, behind_number,  
3550                                cursor_par, cursor_pos, 
3551                                undopar);
3552   
3553         undo_finished = false;
3554         return undo;
3555 }
3556
3557
3558 void LyXText::SetCursorParUndo(Buffer * buf)
3559 {
3560         if (inset_owner)
3561                 return;
3562         SetUndo(buf, Undo::FINISH,
3563 #ifndef NEW_INSETS
3564                 cursor.par()->ParFromPos(cursor.pos())->previous, 
3565                 cursor.par()->ParFromPos(cursor.pos())->next
3566 #else
3567                 cursor.par()->previous, 
3568                 cursor.par()->next
3569 #endif
3570                 ); 
3571 }
3572
3573
3574 void LyXText::toggleAppendix(BufferView * bview)
3575 {
3576 #ifndef NEW_INSETS
3577         LyXParagraph * par = cursor.par()->FirstPhysicalPar();
3578 #else
3579         LyXParagraph * par = cursor.par();
3580 #endif
3581         bool start = !par->start_of_appendix;
3582
3583         // ensure that we have only one start_of_appendix in this document
3584         LyXParagraph * tmp = FirstParagraph();
3585         for (; tmp; tmp = tmp->next)
3586                 tmp->start_of_appendix = 0;
3587         par->start_of_appendix = start;
3588
3589         // we can set the refreshing parameters now
3590         status = LyXText::NEED_MORE_REFRESH;
3591         refresh_y = 0;
3592         refresh_row = 0; // not needed for full update
3593         UpdateCounters(bview, 0);
3594         SetCursor(bview, cursor.par(), cursor.pos());
3595 }
3596
3597
3598 LyXParagraph * LyXText::OwnerParagraph() const
3599 {
3600         if (inset_owner)
3601                 return inset_owner->par;
3602
3603         return bv_owner->buffer()->paragraph;
3604 }
3605
3606
3607 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
3608 {
3609         if (inset_owner)
3610                 inset_owner->par = p;
3611         else
3612                 bv_owner->buffer()->paragraph = p;
3613         return 0;
3614 }