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