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