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