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