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