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